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 |
datetime |
arrow.Arrow |
datetime of open
(see |
meta |
Dict[str, Any] |
Dictionary free of use
(see |
status |
estrade.enums.TransactionStatus |
Transaction status of this trade
(see |
closed: bool
property
readonly
Check if the trade is closed.
Returns:
Type | Description |
---|---|
bool |
|
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 |
|
required |
strategy |
Optional[BaseStrategy] |
|
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 |
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 |
{} |
Returns:
Type | Description |
---|---|
TradeClose |
The |
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 |
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 |
{} |
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
Parameters:
Name | Type | Description | Default |
---|---|---|---|
tick |
Tick |
|
required |
kwargs |
Any |
Arguments with the same constraints as the
[ |
{} |
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 |
|
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)