Skip to content

Trade

A Trade represents a position on Market.


Trade Class

Trade object representation.

Attributes:

Name Type Description
epic estrade.epic.Epic

epic of this trade

strategy estrade.strategy.BaseStrategy

strategy that generated this trade

direction estrade.enums.TradeDirection

direction of this trade

open_quantity int

Quantities opened on trade initialisation.

closes List[estrade.trade.TradeClose]

List of closes of this trade.

open_value float

open tick value of the current instance

current_close_value float

current market value to close this trade.

max_result float

max result of this instance

min_result float

min result of this instance

ref str

reference of this instance (see estrade.mixins.ref.RefMixin)

datetime arrow.Arrow

datetime of open (see estrade.mixins.timed.TimedMixin)

meta Dict[str, Any]

Dictionary free of use (see estrade.mixins.meta.MetaMixin)

status estrade.enums.TransactionStatus

Transaction status of this trade (see TransactionStatus)

closed: bool property readonly

Check if the trade is closed.

Returns:

Type Description
bool

True if all the open quantities closed.

closed_quantities: int property readonly

Return closed quantities of the trade.

Returns:

Type Description
int

Sum of closed quantities.

closed_result: float property readonly

Return closed result of the current trade.

Returns:

Type Description
float

sum of closes result.

closed_result_avg: float property readonly

Average result of the closed quantities.

Returns:

Type Description
float

sum of closes average result (does not takes quantities into account).

datetime: Arrow inherited property writable

Object datetime.

Returns:

Type Description
Arrow

object datetime

datetime_utc: Arrow inherited property readonly

Object datetime as UTC.

Returns:

Type Description
Arrow

datetime as UTC, this method is useful when datetime is zoned.

limit_absolute: Optional[float] inherited property writable

Limit value of the current trade.

Returns:

Type Description
Optional[float]

limit value.

limit_relative: Optional[float] inherited property writable

Limit value of the current trade relative to open value.

Returns:

Type Description
Optional[float]

limit value.

opened_quantities: int property readonly

Return opened quantities of the trade.

Returns:

Type Description
int

Sum of opened quantities.

opened_result: float property readonly

Return result of the opened quantities.

Returns:

Type Description
float

difference between open and last value multiplied by open quantities.

opened_result_avg: float property readonly

Average result per opened quantity.

Returns:

Type Description
float

difference between open and last value.

ref: str inherited property writable

Return ref of current instance.

Returns:

Type Description
str

reference of current instance.

result: float property readonly

Trade current result.

Returns:

Type Description
float

trade result

result_avg: float property readonly

Trade average result per quantity.

Returns:

Type Description
float

trade average result (does not takes quantities into account)

stop_absolute: Optional[float] inherited property writable

Stop value of the current trade.

Returns:

Type Description
Optional[float]

stop value.

stop_relative: Optional[float] inherited property writable

Stop value of the current trade relative to open value.

Returns:

Type Description
Optional[float]

stop value.

__init__(self, direction, quantity, open_value, open_datetime, epic, current_close_value=None, status=<TransactionStatus.CREATED: 0>, strategy=None, stop_absolute=None, limit_absolute=None, stop_relative=None, limit_relative=None, ref=None, meta=None) special

Create a new trade instance.

Parameters:

Name Type Description Default
direction TradeDirection

trade direction (buy or sell)

required
quantity int

quantity of the trade.

required
open_value float

market value to open the Trade with

required
open_datetime Arrow

datetime of the trade open

required
status Optional[estrade.enums.TransactionStatus]

operation status

<TransactionStatus.CREATED: 0>
epic Epic

Epic instance having at least one tick.

required
strategy Optional[BaseStrategy]

Strategy instance

None
stop_absolute Optional[float]

stop value for this trade

None
stop_relative Optional[float]

stop value relative to open for this trade

None
limit_absolute Optional[float]

limit value for this trade

None
limit_relative Optional[float]

limit value relative to open for this trade

None
ref Optional[str]

trade reference

None
meta Optional[Dict[str, Any]]

trade metadata

None
Source code in estrade/trade.py
def __init__(
    self,
    direction: TradeDirection,
    quantity: int,
    open_value: float,
    open_datetime: arrow.Arrow,
    epic: "Epic",
    current_close_value: Optional[float] = None,
    status: Optional[TransactionStatus] = TransactionStatus.CREATED,
    strategy: Optional["BaseStrategy"] = None,
    stop_absolute: Optional[float] = None,
    limit_absolute: Optional[float] = None,
    stop_relative: Optional[float] = None,
    limit_relative: Optional[float] = None,
    ref: Optional[str] = None,
    meta: Optional[Dict[str, Any]] = None,
) -> None:
    """
    Create a new trade instance.

    Arguments:
        direction: trade direction (buy or sell)
        quantity: quantity of the trade.
        open_value: market value to open the Trade with
        open_datetime: datetime of the trade open
        status: operation status
        epic: [`Epic`][estrade.epic.Epic] instance having at least one tick.
        strategy: [`Strategy`][estrade.strategy.BaseStrategy] instance
        stop_absolute (Optional[float]): stop value for this trade
        stop_relative (Optional[float]): stop value relative to open for this trade
        limit_absolute (Optional[float]): limit value for this trade
        limit_relative (Optional[float]): limit value relative to open for
            this trade
        ref: trade reference
        meta: trade metadata
    """
    self.epic = epic
    self.strategy = strategy  # TODO: test Strategy type
    self.direction = direction  # TODO: check invalid direction
    self.open_quantity = quantity  # TODO: check positive
    self.closes: List[TradeClose] = []

    self.open_value = open_value
    self.current_close_value = current_close_value or open_value

    self.max_result: float = self.result
    self.min_result: float = self.result

    StopLimitMixin.__init__(
        self,
        stop_absolute=stop_absolute,
        stop_relative=stop_relative,
        limit_absolute=limit_absolute,
        limit_relative=limit_relative,
    )

    RefMixin.__init__(self, ref)
    TimedMixin.__init__(self, open_datetime)
    MetaMixin.__init__(self, meta)
    TransactionMixin.__init__(self, status)

    # self.epic.trade_provider.open_trade(self)
    logger.info(
        "New %s trade created: %s @ %s", self.direction, self.ref, self.open_value
    )

close(self, close_value, datetime=None, quantity=None, **kwargs)

Close (totally or partially) a trade.

This method create a new instance of TradeClose and adds it to this instance closes.

Parameters:

Name Type Description Default
close_value float

the market value at which the close is performed.

required
datetime Union[datetime.datetime, arrow.arrow.Arrow]

datetime of the closing.

None
quantity Optional[int]

quantity to close, default to the remaining open quantities if not provided.

None

Returns:

Type Description
TradeClose

The TradeClose instance created.

Source code in estrade/trade.py
def close(
    self,
    close_value: float,
    datetime: Optional[Union[pydatetime, arrow.Arrow]] = None,
    quantity: Optional[int] = None,
    **kwargs,
) -> "TradeClose":
    """
    Close (totally or partially) a trade.

    This method create a new instance of [`TradeClose`][estrade.trade.TradeClose]
    and adds it to this instance `closes`.

    Arguments:
        close_value: the market value at which the close is performed.
        datetime: datetime of the closing.
        quantity: quantity to close, default to the remaining open quantities if
            not provided.

    Returns:
        The [`TradeClose`][estrade.trade.TradeClose] instance created.

    """
    quantity = quantity or self.opened_quantities
    datetime = datetime or self.epic.last_tick.datetime

    if quantity > self.opened_quantities:
        logger.error(
            f"Impossible to close {quantity} when only "
            f"{self.opened_quantities} are opened."
        )
        quantity = self.opened_quantities

    logger.info(
        "Close %s quantities of trade %s @ %s", quantity, self.ref, close_value
    )
    new_close = TradeClose(
        trade=self,
        close_value=close_value,
        quantity=quantity,
        datetime=datetime,
        **kwargs,
    )
    self.closes.append(new_close)
    return new_close

close_from_epic(self, **kwargs)

Close Trade with its Epic last tick.

Parameters:

Name Type Description Default
kwargs

see TradeClose arguments

{}

Returns:

Type Description
TradeClose

The TradeClose instance created.

Source code in estrade/trade.py
def close_from_epic(self, **kwargs) -> "TradeClose":
    """
    Close Trade with its Epic last tick.

    Arguments:
        kwargs: see [`TradeClose`][estrade.trade.TradeClose] arguments

    Returns:
        The [`TradeClose`][estrade.trade.TradeClose] instance created.
    """
    trade_close = self.close_from_tick(self.epic.last_tick, **kwargs)

    return trade_close

close_from_tick(self, tick, **kwargs)

Close current Trade from a Tick instance.

Parameters:

Name Type Description Default
tick Tick

Tick instance to use to close the current trade.

required

Returns:

Type Description
TradeClose

The TradeClose instance created.

Source code in estrade/trade.py
def close_from_tick(self, tick: "Tick", **kwargs) -> "TradeClose":
    """
    Close current Trade from a Tick instance.

    Arguments:
        tick: Tick instance to use to close the current trade.

    Returns:
        The [`TradeClose`][estrade.trade.TradeClose] instance created.
    """
    # update current trade with tick to set self.current_close_value
    self.update_from_tick(tick)

    trade_close = self.close(
        datetime=tick.datetime,
        close_value=self.current_close_value,
        **kwargs,
    )
    return trade_close

open_from_epic(epic, **kwargs) staticmethod

Open a trade from an Epic current last tick.

Parameters:

Name Type Description Default
epic Epic

Epic instance to open the Trade from

required
kwargs Any

see Trade __init__ method arguments

{}

Returns:

Type Description
Trade

opened trade instance.

Source code in estrade/trade.py
@staticmethod
def open_from_epic(epic: "Epic", **kwargs: Any) -> "Trade":
    """
    Open a trade from an Epic current last tick.

    Arguments:
        epic: Epic instance to open the Trade from
        kwargs: see [`Trade`][estrade.trade.Trade] `__init__` method arguments

    Returns:
        opened trade instance.
    """
    new_trade = Trade.open_from_tick(
        tick=epic.last_tick,
        epic=epic,
        **kwargs,
    )

    return new_trade

open_from_tick(tick, epic, **kwargs) staticmethod

Open a Trade from a Tick.

Parameters:

Name Type Description Default
tick Tick

Tick instance.

required
kwargs Any

Arguments with the same constraints as the [Trade][estrade.trade.Trade.init]

{}
Source code in estrade/trade.py
@staticmethod
def open_from_tick(tick: "Tick", epic: "Epic", **kwargs: Any) -> "Trade":
    """
    Open a [`Trade`][estrade.trade.Trade] from a [`Tick`][estrade.tick.Tick].

    Arguments:
        tick: [`Tick`][estrade.tick.Tick] instance.
        kwargs: Arguments with the same constraints as the
            [`Trade`][estrade.trade.Trade.__init__]
    """
    if kwargs["direction"] == TradeDirection.BUY:
        kwargs["open_value"] = tick.ask
        kwargs["current_close_value"] = tick.bid
    elif kwargs["direction"] == TradeDirection.SELL:
        kwargs["open_value"] = tick.bid
        kwargs["current_close_value"] = tick.ask
    else:
        raise TradeException("Invalid direction")

    kwargs["open_datetime"] = tick.datetime

    trade = Trade(
        epic=epic,
        **kwargs,
    )
    return trade

update(self, current_close_value)

Update trade with the current market value.

Parameters:

Name Type Description Default
current_close_value float

the current market value to close this Trade.

required

Example

# import arrow
#
# from estrade import Epic, Tick, Trade
# from estrade.enums import TradeDirection


# def test_update_buy():
#     now = arrow.utcnow()
#     epic = Epic()
#     tick = Tick(bid=54.3, ask=68.9, datetime=now)
#     epic.on_new_tick(tick)
#     trade = Trade(
#         epic=epic,
#         direction=TradeDirection.BUY,
#         quantity=4,
#     )
#
#     trade.update(bid=100.6)
#     assert trade.result == round(100.6 - 68.9, 2) * 4
#     assert trade.max_result == round(100.6 - 68.9, 2) * 4
#     assert trade.min_result == round(54.3 - 68.9, 2) * 4
#
#     trade.update(bid=23.7)
#     assert trade.result == round(23.7 - 68.9, 2) * 4
#     assert trade.max_result == round(100.6 - 68.9, 2) * 4
#     assert trade.min_result == round(23.7 - 68.9, 2) * 4
#
#
# def test_update_sell():
#     now = arrow.utcnow()
#     epic = Epic()
#     tick = Tick(bid=76.3, ask=76.4, datetime=now)
#     epic.on_new_tick(tick)
#     trade = Trade(
#         epic=epic,
#         direction=TradeDirection.SELL,
#         quantity=9,
#     )
#
#     trade.update(ask=89.6)
#     assert trade.result == round(76.3 - 89.6, 2) * 9
#     assert trade.max_result == round(76.3 - 76.4, 2) * 9
#     assert trade.min_result == round(76.3 - 89.6, 2) * 9
#
#     trade.update(ask=55.2)
#     assert trade.result == round(76.3 - 55.2, 2) * 9
#     assert trade.max_result == round(76.3 - 55.2, 2) * 9
#     assert trade.min_result == round(76.3 - 89.6, 2) * 9
Source code in estrade/trade.py
def update(self, current_close_value: float) -> None:
    """
    Update trade with the current market value.

    Arguments:
        current_close_value: the current market value to close this Trade.

    !!! example

        ```python
        --8<-- "tests/doc/reference/trade/test_update.py"
        ```
    """
    if self.closed:
        logger.error("Cannot update a closed trade.")
        return

    self.current_close_value = current_close_value

    if self._stop_limit_reached():
        self.close(
            close_value=self.current_close_value,
            meta={"close_reason": "stop_limit_reached"},
        )

    self._update_min_max()

update_from_epic(self)

Update current trade from its Epic current value.

Source code in estrade/trade.py
def update_from_epic(self) -> None:
    """Update current trade from its Epic current value."""
    self.update_from_tick(self.epic.last_tick)

update_from_tick(self, tick)

Update current trade from the input Tick.

Parameters:

Name Type Description Default
tick Tick

Tick instance to use to update the trade result.

required
Source code in estrade/trade.py
def update_from_tick(self, tick: "Tick") -> None:
    """
    Update current trade from the input Tick.

    Arguments:
        tick: Tick instance to use to update the trade result.
    """
    if self.direction == TradeDirection.BUY:
        current_close_value = tick.bid
    else:
        current_close_value = tick.ask

    self.update(current_close_value)

update_limit_absolute(self, limit_absolute) inherited

Add a limit by its absolute value on the current instance.

Parameters:

Name Type Description Default
limit_absolute float

limit absolute value

required
Source code in estrade/trade.py
def update_limit_absolute(self, limit_absolute: float) -> None:
    """
    Add a limit by its absolute value on the current instance.

    Arguments:
        limit_absolute: limit absolute value
    """
    self.limit_absolute = limit_absolute
    self.epic.trade_provider.update_limit(trade=self)  # type: ignore

update_limit_relative(self, limit_relative) inherited

Add a limit by its relative value on the current instance.

Parameters:

Name Type Description Default
limit_relative float

limit absolute value

required

Note

limit is relative to the trade open value.

Source code in estrade/trade.py
def update_limit_relative(self, limit_relative: float) -> None:
    """
    Add a limit by its relative value on the current instance.

    Arguments:
        limit_relative: limit absolute value

    !!! note

        limit is relative to the trade open value.
    """
    self.limit_relative = limit_relative
    self.epic.trade_provider.update_limit(trade=self)  # type: ignore

update_stop_absolute(self, stop_absolute) inherited

Add a stop by its absolute value on the current instance.

Parameters:

Name Type Description Default
stop_absolute float

stop absolute value

required
Source code in estrade/trade.py
def update_stop_absolute(self, stop_absolute: float) -> None:
    """
    Add a stop by its absolute value on the current instance.

    Arguments:
        stop_absolute: stop absolute value
    """
    self.stop_absolute = stop_absolute
    self.epic.trade_provider.update_stop(trade=self)  # type: ignore

update_stop_relative(self, stop_relative) inherited

Add a stop by its relative value on the current instance.

Parameters:

Name Type Description Default
stop_relative float

stop absolute value

required

Note

stop is relative to the trade open value.

Source code in estrade/trade.py
def update_stop_relative(self, stop_relative: float) -> None:
    """
    Add a stop by its relative value on the current instance.

    Arguments:
        stop_relative: stop absolute value

    !!! note

        stop is relative to the trade open value.
    """
    self.stop_relative = stop_relative
    self.epic.trade_provider.update_stop(trade=self)  # type: ignore

TradeClose Class

Partial close of a Trade.

datetime: Arrow inherited property writable

Object datetime.

Returns:

Type Description
Arrow

object datetime

datetime_utc: Arrow inherited property readonly

Object datetime as UTC.

Returns:

Type Description
Arrow

datetime as UTC, this method is useful when datetime is zoned.

ref: str inherited property writable

Return ref of current instance.

Returns:

Type Description
str

reference of current instance.

result: float property readonly

Trade total result.

Returns:

Type Description
float

Total result of this close per quantity.

result_avg: float property readonly

Trade average result.

Average result per quantity.

Returns:

Type Description
float

Average result of this close per quantity.

__init__(self, trade, close_value, quantity, datetime, status=<TransactionStatus.CREATED: 0>, ref=None, meta=None) special

Create a new partial close of a trade.

Parameters:

Name Type Description Default
trade Trade

Trade instance.

required
close_value float

current market value at close time.

required
quantity int

closed quantities

required
datetime Union[datetime.datetime, arrow.arrow.Arrow]

close datetime

required
ref Optional[str]

an optional name for this close

None
meta Optional[Dict[Any, Any]]

trade close metadata

None
Source code in estrade/trade.py
def __init__(
    self,
    trade: Trade,
    close_value: float,
    quantity: int,
    datetime: Union[pydatetime, arrow.Arrow],
    status: Optional[TransactionStatus] = TransactionStatus.CREATED,
    ref: Optional[str] = None,
    meta: Optional[Dict[Any, Any]] = None,
) -> None:
    """
    Create a new partial close of a trade.

    Arguments:
        trade: [`Trade`][estrade.trade.Trade] instance.
        close_value: current market value at close time.
        quantity: closed quantities
        datetime: close datetime
        ref: an optional name for this close
        meta: trade close metadata
    """
    self.trade = trade
    self.close_value = close_value
    self.quantity = quantity

    TransactionMixin.__init__(self, status)
    TimedMixin.__init__(self, datetime)
    MetaMixin.__init__(self, meta)
    RefMixin.__init__(self, ref)