TradeExecution#
tradeexecutor.state.trade.TradeExecution Python class in Trading Strategy framework.
- class TradeExecution[source]#
Bases:
object
Trade execution tracker.
One TradeExecution instance can only represent one swap
Each trade has a reserve currency that we use to trade the token (usually USDC).
Each trade can be
Buy: swap quote token -> base token
Sell: swap base token -> quote token
When doing a buy planned_reserve (fiat) is the input. This yields to executed_quantity of tokens that may be different from planned_quantity.
When doing a sell planned_quantity (token) is the input. This yields to executed_reserve of fiat that might be different from `planned_reserve.
Trade execution has four states
Planning: The execution object is prepared
Capital allocation and transaction creation: We move reserve from out portfolio to the trade in internal accounting
Transaction broadcast: trade cannot be cancelled in this point
Resolving the trade: We check the Ethereum transaction receipt to see how well we succeeded in the trade
There trade state is resolved based on the market variables (usually timestamps).
- __init__(trade_id, position_id, trade_type, pair, opened_at, planned_quantity, planned_reserve, planned_price, reserve_currency, reserve_currency_exchange_rate=None, planned_mid_price=None, planned_max_slippage=None, started_at=None, reserve_currency_allocated=None, broadcasted_at=None, executed_at=None, failed_at=None, executed_price=None, executed_quantity=None, executed_reserve=None, slippage_tolerance=None, fee_tier=<property object>, lp_fees_paid=None, lp_fees_estimated=<property object>, lp_fee_exchange_rate=None, native_token_price=None, retry_of=None, blockchain_transactions=<factory>, notes=None, repaired_at=None, repaired_trade_id=None, price_structure=None)#
- Parameters:
trade_id (int) –
position_id (int) –
trade_type (TradeType) –
pair (TradingPairIdentifier) –
opened_at (datetime.datetime | None) –
planned_quantity (Decimal) –
planned_reserve (Decimal) –
planned_price (float) –
reserve_currency (AssetIdentifier) –
blockchain_transactions (List[BlockchainTransaction]) –
price_structure (Optional[TradePricing]) –
- Return type:
None
Methods
__init__
(trade_id, position_id, trade_type, ...)Get the expected amount fo token balance change in a wallet for this trade.
from_dict
(kvs, *[, infer_missing])from_json
(s, *[, parse_float, parse_int, ...])get_allocated_value
()Returns the token quantity and reserve currency quantity for this trade.
How long it took between strategy decision cycle starting and the strategy to make a decision.
Get the planned or executed quantity of the base token.
Get the planned or executed quantity of the quote token.
Estimate the USD value of this trade.
How long it took between strategy decision cycle starting and the trade executed.
When this trade should be executed.
Get the transaction that failed this trade.
Get total swap fees paid for trade.
get_full_debug_dump_str
()User friendly description for this trade
How we fund this trade.
What asset we receive out from this trade
Get the maximum gas fee set to all transactions in this trade.
get_planned_reserve
()get_planned_value
()Get the planned or executed quantity of the base token.
Return the amount of USD token for the buy as raw token units.
Return the amount of USD token for the buy as raw token units.
What was the reserve stablecoin exchange trade for this trade.
Get the planned or executed quantity of the quote token.
Get the transaction failure reason.
Resolve the trade status.
Get estimated or realised value of this trade.
Does this trade contribute towards the trading position equity.
This trade is an accounting correction.
is_buy
()Did this trade ever execute.
This trade was succcessfully completed.
This trade was succcessfully completed.
This trade is still in planning, unallocated.
This trade is part of the normal strategy rebalance.
This trade needs repair, but is not repaired yet.
This trade is fixes a frozen position and counters another trade.
The automatic execution failed and this was later repaired.
is_sell
()This trade has a txid allocated.
This trade is made to close stop loss on a position.
This trade was succcessfully completed.
This trade is made to close take profit on a position.
Was this trade based on a trigger signal.
We could not confirm this trade back from the blockchain after broadcasting.
mark_broadcasted
(broadcasted_at)mark_failed
(failed_at)mark_success
(executed_at, executed_price, ...)Mark trade success.
Get diagnostics output for the trade.
schema
(*[, infer_missing, only, exclude, ...])Set the physical transactions needed to perform this trade.
to_dict
([encode_json])to_json
(*[, skipkeys, ensure_ascii, ...])Attributes
When this trade entered mempool
Timestamp of the block where the txid was first mined.
What was the actual price we received
How much underlying token we traded, the actual realised amount.
How much reserves we spend for this traded, the actual realised amount.
The trade did not go through.
LP fee % recorded before the execution starts.
What is the conversation rate between quote token and US dollar used in LP fee conversion.
LP fees estimated in the USD
LP fees paid, currency convereted to the USD.
USD price per blockchain native currency unit, at the time of execution
Human readable notes about this trade
How much slippage we could initially tolerate, 0.01 is 1% slippage.
What we thought was the mid-price when we made the decision to tale this trade
Related TradePricing instance
Trade was manually repaired
Which is the trade that this trade is repairing.
How much reserves was moved on this trade before execution
What is the reserve currency exchange rate used for this trade
retry_of
Slippage tolerance for this trade.
When this trade was decided
Alias for oepned_at
Trade id is unique among all trades in the same portfolio
Position id is unique among all trades in the same portfolio
Spot, margin, lending, etc.
Which trading pair this trade was for
What was the strategy cycle timestamp for it was created.
Positive for buy, negative for sell.
How many reserve tokens (USD) we use in this trade
What we thought the execution price for this trade would have been at the moment of strategy decision.
Which reserve currency we are going to take.
Associated blockchain transaction details.
- pair: TradingPairIdentifier#
Which trading pair this trade was for
- opened_at: datetime.datetime | None#
What was the strategy cycle timestamp for it was created.
Naive UTC timestamp.
If the trade was executed by a take profit/stop loss trigger then this is the trigger timestamp (not wall clock time)
Not available if the trade was done outside the strategy execution (manual trades, accounting corrections).
See also
- planned_reserve: Decimal#
How many reserve tokens (USD) we use in this trade
Always a position number (only the sign of
planned_quantity
changes between buy/sell)For buys, Always known accurately for buys.
For sells, an estimation based on
planned_price
Expressed in
reserve_currency
.
- planned_price: float#
What we thought the execution price for this trade would have been at the moment of strategy decision.
This price includes any fees we pay for LPs, and should become executed_price if the execution is perfect.
For the market price see
planned_mid_price
.
- reserve_currency: AssetIdentifier#
Which reserve currency we are going to take. Note that pair.quote might be different from reserve currency. This is because we can do three-way trades like BUSD -> BNB -> Cake when our routing model supports this.
- reserve_currency_exchange_rate: Optional[float] = None#
What is the reserve currency exchange rate used for this trade
Access using
get_reserve_currency_exchange_rate
.USDC/USD exchange rate.
If not set (legacy) assume 1.0 reset assets / USD
- planned_mid_price: Optional[float] = None#
What we thought was the mid-price when we made the decision to tale this trade
This is the market price of the asset at the time of the trade decision.
- planned_max_slippage: Optional[float] = None#
How much slippage we could initially tolerate, 0.01 is 1% slippage.
- started_at: Optional[datetime] = None#
When this trade was decided
Wall clock time.
For backtested trades, this is always set to opened_at.
- reserve_currency_allocated: Optional[Decimal] = None#
How much reserves was moved on this trade before execution
- executed_at: Optional[datetime] = None#
Timestamp of the block where the txid was first mined.
For failed trades, this is not set until repaired, but instead we set
failed_at
.
- failed_at: Optional[datetime] = None#
The trade did not go through. The timestamp when we figured this out.
- executed_price: Optional[float] = None#
What was the actual price we received
This may be None for even if
closed_at
is set. This is because invalid trades (execution failed) may be marked close.
- executed_quantity: Optional[Decimal] = None#
How much underlying token we traded, the actual realised amount. Positive for buy, negative for sell
- executed_reserve: Optional[Decimal] = None#
How much reserves we spend for this traded, the actual realised amount.
- slippage_tolerance: Optional[float] = None#
Slippage tolerance for this trade.
Examples
0: no slippage toleranc eallowed at all
0.01: 1% slippage tolerance
1: MEV bots can steal all your money
We estimate executed_quantity = planned_quantity * slippage_tolerance. If any trade outcome exceeds the slippage tolerance the trade fails.
If you are usinga vault-based trading, slippage tolerance must be always set to calculate the asset delta.
See also
calculate_asset_deltas()
.
- lp_fees_paid: Optional[float] = None#
LP fees paid, currency convereted to the USD.
The value is read back from the realised trade. LP fee is usually % of the trade. For Uniswap style exchanges fees are always taken from amount in token and directly passed to the LPs as the part of the swap, these is no separate fee information.
- lp_fee_exchange_rate: Optional[float] = None#
What is the conversation rate between quote token and US dollar used in LP fee conversion.
We set this exchange rate before the trade is started. Both lp_fees_estimated and lp_fees_paid need to use the same exchange rate, even though it would not be timestamp accurte.
- native_token_price: Optional[float] = None#
USD price per blockchain native currency unit, at the time of execution
Used for converting tx fees and gas units to dollars
- blockchain_transactions: List[BlockchainTransaction]#
Associated blockchain transaction details. Each trade contains 1 … n blockchain transactions. Typically this is approve() + swap() for Uniswap v2 or just swap() if we have the prior approval and approve does not need to be done for the hot wallet anymore.
- notes: Optional[str] = None#
Human readable notes about this trade
Used to mark test trades from command line. Special case; not worth to display unless the field is filled in.
- repaired_at: Optional[datetime] = None#
Trade was manually repaired
E.g. failed broadcast issue was fixed. Marked when the repair command is called.
- repaired_trade_id: Optional[datetime] = None#
Which is the trade that this trade is repairing.
This trade makes a opposing trade to the trade referred here, making accounting match again and unfreezing the position.
For the repair trade
Strategy cycle is set to the original broken trade
- price_structure: Optional[TradePricing] = None#
Related TradePricing instance
TradePricing instance can refer to more than one swap
- pretty_print()[source]#
Get diagnostics output for the trade.
Use Python pprint module.
- Return type:
- property strategy_cycle_at#
Alias for oepned_at
- property fee_tier: float | None#
LP fee % recorded before the execution starts.
Recorded as multiplier
Not available in the case this is ignored in backtesting or not supported by routers/trading pairs.
Used to calculate
lp_fees_estimated
.Sourced from Uniswap v2 router or Uniswap v3 pool information.
- property lp_fees_estimated: float#
LP fees estimated in the USD
This is set before the execution and is mostly useful for backtesting.
- get_reserve_currency_exchange_rate()[source]#
What was the reserve stablecoin exchange trade for this trade.
- Returns:
1.0 if not set
- Return type:
- is_accounted_for_equity()[source]#
Does this trade contribute towards the trading position equity.
Failed trades are reverted. Only their fees account.
- Return type:
- is_unfinished()[source]#
We could not confirm this trade back from the blockchain after broadcasting.
- Return type:
- is_repaired()[source]#
The automatic execution failed and this was later repaired.
A manual repair command was issued and it manaeged to correctly repair this trade and underlying transactions.
See also
is_repair_trade()
.- Return type:
- is_repair_trade()[source]#
This trade is fixes a frozen position and counters another trade.
- Return type:
- is_accounting_correction()[source]#
This trade is an accounting correction.
This is a virtual trade made to have the
- Return type:
- get_status()[source]#
Resolve the trade status.
Based on the different state variables set on this item, figure out what is the best status for this trade.
- Return type:
- get_executed_value()[source]#
Estimate the USD value of this trade.
Based on the
Exact quantity and exact crypto price we got executed at
USD exchange rate known at the time of the execution
- Return type:
- get_raw_planned_reserve()[source]#
Return the amount of USD token for the buy as raw token units.
- Return type:
- get_raw_planned_quantity()[source]#
Return the amount of USD token for the buy as raw token units.
- Return type:
- get_position_quantity()[source]#
Get the planned or executed quantity of the base token.
Positive for buy, negative for sell.
- Return type:
- get_reserve_quantity()[source]#
Get the planned or executed quantity of the quote token.
Negative for buy, positive for sell.
- Return type:
- get_equity_for_position()[source]#
Get the planned or executed quantity of the base token.
Positive for buy, negative for sell.
- Return type:
- get_equity_for_reserve()[source]#
Get the planned or executed quantity of the quote token.
Negative for buy, positive for sell.
- Return type:
- get_value()[source]#
Get estimated or realised value of this trade.
Value is always a positive number.
- Return type:
- get_credit_debit()[source]#
Returns the token quantity and reserve currency quantity for this trade.
If buy this is (+trading position quantity/-reserve currency quantity).
If sell this is (-trading position quantity/-reserve currency quantity).
- get_fees_paid()[source]#
Get total swap fees paid for trade. Returns 0 instead of None
- Returns:
total amount of lp fees (swap fees) paid in US dollars
- Return type:
- get_execution_sort_position()[source]#
When this trade should be executed.
Lower, negative, trades should be executed first.
We need to execute sells first because we need to have cash in hand to execute buys.
- Returns:
Sortable int
- Return type:
- get_decision_lag()[source]#
How long it took between strategy decision cycle starting and the strategy to make a decision.
- Return type:
- get_execution_lag()[source]#
How long it took between strategy decision cycle starting and the trade executed.
- get_failed_transaction()[source]#
Get the transaction that failed this trade.
Extract the EVM revert reason from the underlying transactions.
Each trade can consist of multiple transactions
Iterate transactions from the last to first and return the first failure reason
- Return type:
- get_revert_reason()[source]#
Get the transaction failure reason.
Extract the EVM revert reason from the underlying transactions.
Each trade can consist of multiple transactions
Iterate transactions from the last to first and return the first failure reason
See also
- __init__(trade_id, position_id, trade_type, pair, opened_at, planned_quantity, planned_reserve, planned_price, reserve_currency, reserve_currency_exchange_rate=None, planned_mid_price=None, planned_max_slippage=None, started_at=None, reserve_currency_allocated=None, broadcasted_at=None, executed_at=None, failed_at=None, executed_price=None, executed_quantity=None, executed_reserve=None, slippage_tolerance=None, fee_tier=<property object>, lp_fees_paid=None, lp_fees_estimated=<property object>, lp_fee_exchange_rate=None, native_token_price=None, retry_of=None, blockchain_transactions=<factory>, notes=None, repaired_at=None, repaired_trade_id=None, price_structure=None)#
- Parameters:
trade_id (int) –
position_id (int) –
trade_type (TradeType) –
pair (TradingPairIdentifier) –
opened_at (datetime.datetime | None) –
planned_quantity (Decimal) –
planned_reserve (Decimal) –
planned_price (float) –
reserve_currency (AssetIdentifier) –
blockchain_transactions (List[BlockchainTransaction]) –
price_structure (Optional[TradePricing]) –
- Return type:
None
- mark_success(executed_at, executed_price, executed_quantity, executed_reserve, lp_fees, native_token_price, force=False)[source]#
Mark trade success.
Called by execution engine when we get a confirmation from the blockchain our blockchain txs where good
Called by repair to force trades to good state
- set_blockchain_transactions(txs)[source]#
Set the physical transactions needed to perform this trade.
- Parameters:
txs (List[BlockchainTransaction]) –
- get_planned_max_gas_price()[source]#
Get the maximum gas fee set to all transactions in this trade.
- Return type:
- calculate_asset_deltas()[source]#
Get the expected amount fo token balance change in a wallet for this trade.
Needed for vault based trading to work, as they run slippage tolerance checks on expectd inputs and outputs.
Each trade has minimum of two asset deltas
The token you spent to buu/sell (input)
The token you receive (output)
The output will always have
slippage_tolerance
applied. Input is passed as is.- Returns:
List of asset deltas [input, output]
- Return type: