Portfolio#
API documentation for tradeexecutor.state.portfolio.Portfolio Python class in Trading Strategy framework.
- class Portfolio[source]#
Bases:
object
Represents a trading portfolio on DEX markets.
Multiple trading pair issue: We do not identify the actual assets we have purchased, but the trading pairs that we used to purchase them. Thus, each position marks “openness” in a certain trading pair. For example open position of WBNB-BUSD means we have bought X BNB tokens through WBNB-BUSD trading pair. But because this is DEX market, we could enter and exit through WBNB-USDT, WBNB-ETH, etc. and our position is not really tied to a trading pair. However, because all TradFi trading view the world through trading pairs, we keep the tradition here.
- __init__(next_position_id=1, next_trade_id=1, next_balance_update_id=1, open_positions=<factory>, reserves=<factory>, closed_positions=<factory>, frozen_positions=<factory>, revalue_failures_as_zero=False, pending_positions=<factory>, expired_positions=<factory>)#
- Parameters:
next_position_id (int) –
next_trade_id (int) –
next_balance_update_id (int) –
open_positions (Dict[int, TradingPosition]) –
reserves (Dict[str, ReservePosition]) –
closed_positions (Dict[int, TradingPosition]) –
frozen_positions (Dict[int, TradingPosition]) –
revalue_failures_as_zero (bool) –
pending_positions (Dict[int, TradingPosition]) –
expired_positions (Dict[int, TradingPosition]) –
- Return type:
None
Methods
__init__
([next_position_id, next_trade_id, ...])adjust_reserves
(asset, amount[, reason])Add or remove assets from the cash reserves.
Get a new balance update event id.
check_for_nonce_reuse
(nonce)A helper assert to see we are not generating invalid transactions somewhere.
close_position
(position, executed_at)Move a position from open positions to closed ones.
correct_open_position_balance
(position, ...)Create an accounting entry trade that correct the balance.
create_trade
(strategy_cycle_at, pair, ...[, ...])Create a trade.
find_position_for_trade
(trade[, pending])Find a position that a trade belongs for.
from_dict
(kvs, *[, infer_missing])from_json
(s, *[, parse_float, parse_int, ...])get_all_loan_nav
([include_interest, ...])Get net asset value we can theoretically free from leveraged positions.
get_all_positions
([pending])Get open, closed and frozen, positions.
Get all pairs for which we have or had positions.
Iterate through all trades: completed, failed and in progress
get_borrowed
()get_cash
()Get how much reserve stablecoins we have.
get_closed_positions_for_pair
(pair[, ...])Get closed position for a trading pair.
Get the value of the portfolio based on the latest pricing.
Alias for get_cash()
Return currently open credit positions.
Get lis of all positions for which we need to sync the on-chain interest
Gets the default reserve currency associated with this state.
Get the default reserve position.
get_equity_for_pair
(pair)Return how much equity allocation we have in a certain trading pair.
Get all positions with already executed trades.
Get a position by a trading pair smart contract address identifier.
Get first and last trades overall.
Get the value of trading positions that are frozen currently.
How much we invested at the beginning of a backtest.
Deprecated.
Return currently open credit positions.
Get the value of current trading positions plus unexecuted trades.
What is our Net Asset Value (NAV) across all open loan positions.
get_net_asset_value
([include_interest])Calculate portfolio value if every position would be closed now.
Get open and frozen, positions.
Get loans across all positions.
get_open_position_for_asset
(asset)Get open position for a trading pair.
Get Open position for a trading pair.
Get currently open positions.
Return the current holdings in different trading pairs.
Return the current ownerships.
Get pending position for a trading pair.
get_position_by_id
(position_id)Get any position open/closed/frozen by id.
get_position_by_trading_pair
(pair[, pending])Get open position by a trading pair smart contract address identifier.
Get the equity tied tot the current trading positions.
Get positions that were closed at a specific timestamp.
Get the profit of currently open margiend positions.
Get reserves assets.
get_reserve_position
(asset)Get reserves for a certain reserve asset.
Return the only trading pair a single pair strategy has been trading.
Get the total interest claimed from the positions.
Get the value of the portfolio based on the latest pricing.
Get the total interest repaid from the positions.
get_trade_by_id
(trade_id)Look up any trade in all positions.
get_trade_by_tx_hash
(tx_hash)Find a trade that contains a particular transaction.
How long this portfolio has trading history.
Get positions that have been repaired.
Get the profit of currently open margiend positions.
Get the profit of currently open positions.
has_trading_capital
([threshold_usd])Does this strategy have non-zero deposits and total equity?
Do we have any trades that have capital allocated, but not executed yet.
initialise_reserves
(asset)Create the initial reserve currency list.
is_empty
()This portfolio has no open or past trades or any reserves.
Allocate capital from reserves to trade instance.
open_new_position
(ts, pair, assumed_price, ...)Opens a new trading position.
return_capital_to_reserves
(trade[, ...])Return capital to reserves after a spot sell or collateral returned.
schema
(*[, infer_missing, only, exclude, ...])to_dict
([encode_json])to_json
(*[, skipkeys, ensure_ascii, ...])update_reserves
(new_reserves)Update current reserves.
Attributes
Each balance update event gets it unique id as a running counter.
Each position gets it unique running counter id.
Each trade gets it unique id as a running counter.
Mark positions that we cannot value as zero
Currently open trading positions
Currently held reserve assets
Trades completed in the past
Positions that have failed sells, or otherwise immovable and need manual clean up.
Positions which have not been opened yet, but are waiting the trade order trigger to happen.
Positions from
pending_positions
that never triggered- next_trade_id: int = 1#
Each trade gets it unique id as a running counter. Trade ids are unique across different positions.
- open_positions: Dict[int, TradingPosition]#
Currently open trading positions
- reserves: Dict[str, ReservePosition]#
Currently held reserve assets
Token -> reserve position mapping.
For migration code, see
ReservePosition
.Set by
initialise_reserves()
.
- closed_positions: Dict[int, TradingPosition]#
Trades completed in the past
- frozen_positions: Dict[int, TradingPosition]#
Positions that have failed sells, or otherwise immovable and need manual clean up. Failure reasons could include - blockchain halted - ERC-20 token tax fees - rug pull token - transfer disabled
- revalue_failures_as_zero: bool = False#
Mark positions that we cannot value as zero
This is a backtesting issue workaround flag for disappearing markets. E.g. MKR-USDC liquidity disappears here https://tradingstrategy.ai/trading-view/ethereum/uniswap-v3/mkr-usdc-fee-5#7d
TODO: Not supported yet.
- pending_positions: Dict[int, TradingPosition]#
Positions which have not been opened yet, but are waiting the trade order trigger to happen.
When a trigger happens, the
Will be pruned when these order expire.
- expired_positions: Dict[int, TradingPosition]#
Positions from
pending_positions
that never triggeredStored for diagnostics.
- get_position_by_id(position_id)[source]#
Get any position open/closed/frozen by id.
Always assume the position for a position_id exists.
- Parameters:
position_id (int) – Internal running counter id for the position inside this portfolio.
- Returns:
Always returns
- Throw:
Fails with py:class:AssertionError if there is no such position.
- Return type:
- get_trade_by_id(trade_id)[source]#
Look up any trade in all positions.
- Returns:
Found trade or
- Parameters:
trade_id (int) –
- Return type:
- get_trade_by_tx_hash(tx_hash)[source]#
Find a trade that contains a particular transaction.
- Parameters:
tx_hash (str) – Ethereum transaction hash
- Returns:
None if the portfolio does not contain such a trade
- Return type:
- get_all_positions(pending=False)[source]#
Get open, closed and frozen, positions.
- Parameters:
pending – Include hypotethical market limit positions.
- Return type:
- get_open_and_frozen_positions()[source]#
Get open and frozen, positions.
These are all the positions where we have capital tied at the moment.
- Return type:
- get_executed_positions()[source]#
Get all positions with already executed trades.
Ignore positions that are still pending - they have only planned trades.
- Return type:
- get_open_position_for_pair(pair)[source]#
Get Open position for a trading pair.
- Parameters:
pair (TradingPairIdentifier) –
- Return type:
- get_pending_position_for_pair(pair)[source]#
Get pending position for a trading pair.
Used to check if we already have market limit ready for a pair
- Parameters:
pair (TradingPairIdentifier) –
- Return type:
- get_closed_positions_for_pair(pair, include_test_position=False)[source]#
Get closed position for a trading pair.
- Parameters:
pair (TradingPairIdentifier) –
include_test_position (bool) –
- Return type:
- get_open_position_for_asset(asset)[source]#
Get open position for a trading pair.
Check all open positions where asset is a base token
- Returns:
Tingle open position or None
- Raises:
MultipleOpenPositionsWithAsset – If more than one position is open
- Parameters:
asset (AssetIdentifier) –
- Return type:
- get_open_quantities_by_position_id()[source]#
Return the current ownerships.
Keyed by position id -> quantity.
- get_open_quantities_by_internal_id()[source]#
Return the current holdings in different trading pairs.
Keyed by trading pair internal id -> quantity.
- open_new_position(ts, pair, assumed_price, reserve_currency, reserve_currency_price)[source]#
Opens a new trading position.
Marks the position opened.
Does not add any trades yet
Marks the current value of the portfolio at the trade opening time, as we need to use this for the risk calculations
- Parameters:
ts (datetime) –
pair (TradingPairIdentifier) –
assumed_price (float) –
reserve_currency (AssetIdentifier) –
reserve_currency_price (float) –
- Return type:
- get_position_by_trading_pair(pair, pending=False)[source]#
Get open position by a trading pair smart contract address identifier.
Get the first open position for a trading pair
Optioonally check
Frozen positions not included
See also
- Parameters:
pending – Check also pending positions that wait market limit open and are not yet triggered
pair (TradingPairIdentifier) –
- Return type:
- get_existing_open_position_by_trading_pair(pair)[source]#
Get a position by a trading pair smart contract address identifier.
The position must have already executed trades (cannot be planned position(.
- Parameters:
pair (TradingPairIdentifier) –
- Return type:
- get_positions_closed_at(ts)[source]#
Get positions that were closed at a specific timestamp.
Useful to display closed positions after the rebalance.
- Parameters:
ts (datetime) –
- Return type:
- create_trade(strategy_cycle_at, pair, quantity, reserve, assumed_price, trade_type, reserve_currency, reserve_currency_price, notes=None, pair_fee=None, lp_fees_estimated=None, planned_mid_price=None, price_structure=None, position=None, slippage_tolerance=None, leverage=None, closing=False, planned_collateral_consumption=None, planned_collateral_allocation=None, flags=None, pending=False)[source]#
Create a trade.
Trade can be opened by knowing how much you want to buy (quantity) or how much cash you have to buy (reserve).
- Parameters:
strategy_cycle_at (datetime) – The strategy cycle timestamp for which this trade was executed.
trade_id – Trade id allocated by the portfolio
quantity (Optional[Decimal]) –
How many units this trade does.
Positive for buys, negative for sells in the spot market.
assumed_price (float) –
The planned execution price.
This is the price we expect to pay per quantity unit after the execution. This is the mid price + any LP fees included.
trade_type (TradeType) – What kind of a trade is this.
reserve_currency (AssetIdentifier) –
Which portfolio reserve we use for this trade.
- param reserve_currency_price:
If the quote token is not USD, then the exchange rate between USD and quote token we assume we have.
Actual exchange rate may depend on the execution.
notes (Optional[str]) – Any human-readable remarks we want to tell about this trade.
pair_fee (Optional[float]) – The fee tier from the trading pair / overriden fee.
lp_fees_estimated (Optional[float]) – HOw much we estimate to pay in LP fees (dollar)
planned_mid_price (Optional[float]) – What was the mid-price of the trading pair when we started to plan this trade.
How many reserve units this trade produces/consumes.
I.e. dollar amount for buys/sells.
price_structure (Optional[TradePricing]) –
The full planned price structure for this trade.
The state of the market at the time of planning the trade, and what fees we assumed we are going to get.
position (Optional[TradingPosition]) –
Override the position for the trade.
Use for repair trades.
slippage_tolerance (Optional[float]) –
Slippage tolerance for this trade.
See
tradeexecutor.state.trade.TradeExecution.slippage_tolerance
for details.pending –
Do not generate a new open position.
Used when adding take profit triggers to market limit position.
pair (TradingPairIdentifier) –
reserve_currency_price (float) –
- Returns:
Tuple of entries
Trade position (old/new)
New trade
True if a a new position was opened
- Return type:
Get the equity tied tot the current trading positions.
TODO: Rename this function - also deals with loans not just equity
Includes open positions
Does not include frozen positions
- Return type:
Get net asset value we can theoretically free from leveraged positions.
- Parameters:
include_interest – Include accumulated interest in the calculations
include_trading_fees – Include trading fees in the calculations
- Return type:
- get_frozen_position_equity()[source]#
Get the value of trading positions that are frozen currently.
- Return type:
- get_live_position_equity()[source]#
Get the value of current trading positions plus unexecuted trades.
- Return type:
- get_total_equity()[source]#
Get the value of the portfolio based on the latest pricing.
This includes
Equity Value of the positions
…and cash in the hand
But not
Leverage/loan based positions (equity is in collateral)
See also
get_theoretical_value()
- Return type:
- get_net_asset_value(include_interest=True)[source]#
Calculate portfolio value if every position would be closed now.
This includes
Cash
Equity hold in spot positions
Net asset value hold in leveraged positions
TODO: Net asset value calculation does not account for fees paid to close a short position.
- Return type:
- get_unrealised_profit_usd()[source]#
Get the profit of currently open positions.
This profit includes spot market equity i.e. holding tokens
See also
get_unrealised_profit_in_leveraged_positions()
.- Return type:
- get_unrealised_profit_in_leveraged_positions()[source]#
Get the profit of currently open margiend positions.
This profit is not included in the portfolio total equity
See also
get_unrealised_profit_usd()
.- Return type:
- get_realised_profit_in_leveraged_positions()[source]#
Get the profit of currently open margiend positions.
This profit is not included in the portfolio total equity
See also
get_unrealised_profit_usd()
.- Return type:
- get_closed_profit_usd()[source]#
Get the value of the portfolio based on the latest pricing.
- Return type:
- find_position_for_trade(trade, pending=False)[source]#
Find a position that a trade belongs for.
- Parameters:
pending – Include pending positions (not yet trading for market limit)
- Return type:
- get_reserve_position(asset)[source]#
Get reserves for a certain reserve asset.
- Raises:
KeyError – If we do not have reserves for the asset
- Parameters:
asset (AssetIdentifier) –
- Return type:
- get_default_reserve_position()[source]#
Get the default reserve position.
Assume portfolio has only one reserve asset.
- Raises:
AssertionError – If there is not exactly one reserve position
- Return type:
- get_reserve_assets()[source]#
Get reserves assets.
Reserve assets are registered with the state when it is initialised.
- Returns:
If the state is not properly initialised, the reserve asset list is empty.
- Return type:
- get_equity_for_pair(pair)[source]#
Return how much equity allocation we have in a certain trading pair.
- Parameters:
pair (TradingPairIdentifier) –
- Return type:
- close_position(position, executed_at)[source]#
Move a position from open positions to closed ones.
See also
TradingPosition.can_be_closed()
.- Parameters:
position (TradingPosition) – Trading position where the trades and balance updates quantity equals to zero
executed_at (datetime) – Wall clock time
- adjust_reserves(asset, amount, reason=None)[source]#
Add or remove assets from the cash reserves.
For internal accounting of the portfolio state.
- Parameters:
asset (AssetIdentifier) – Reserve asset
amount (Decimal) – Negative to reduce portfolio reserves, positive to increase
reason (str) –
- :param reason
Human-readable loggable reason why this happened
- move_capital_from_reserves_to_spot_trade(trade, underflow_check=True)[source]#
Allocate capital from reserves to trade instance.
Total equity of the porfolio stays the same.
- Parameters:
trade (TradeExecution) –
- return_capital_to_reserves(trade, underflow_check=True)[source]#
Return capital to reserves after a spot sell or collateral returned.
- Parameters:
trade (TradeExecution) –
- has_unexecuted_trades()[source]#
Do we have any trades that have capital allocated, but not executed yet.
- Return type:
- update_reserves(new_reserves)[source]#
Update current reserves.
Overrides current amounts of reserves.
E.g. in the case users have deposited more capital.
- Parameters:
new_reserves (List[ReservePosition]) –
- check_for_nonce_reuse(nonce)[source]#
A helper assert to see we are not generating invalid transactions somewhere.
- Raise:
AssertionError
- Parameters:
nonce (int) –
- get_default_reserve_asset()[source]#
Gets the default reserve currency associated with this state.
For strategies that use only one reserve currency. This is the first in the reserve currency list.
See also
- Returns:
Tuple (Reserve currency asset, its latest US dollar exchanage rate)
Return (None, 1.0) if the strategy has not seen any deposits yet.
- Return type:
- get_all_trades()[source]#
Iterate through all trades: completed, failed and in progress
- Return type:
- get_trading_history_duration()[source]#
How long this portfolio has trading history.
Calculated as the difference between first and last executed trade.
- get_initial_cash()[source]#
How much we invested at the beginning of a backtest.
Note
Only applicable to the backtest. Will fail for live strategies.
Assumes we track the performance against the US dollar
Assume there has been only one deposit event
This deposit happened at the start of the backtest
TODO: Shoud not be used, as we have new SyncModel instance for backtesters. Code will be removed.
- initialise_reserves(asset)[source]#
Create the initial reserve currency list.
Currently we assume there can be only one reserve currency.
- Parameters:
asset (AssetIdentifier) –
- get_single_pair()[source]#
Return the only trading pair a single pair strategy has been trading.
- Raises:
NotSinglePair –
This may happen when
Strategy has not traded yet
Strategy has traded multiple pairs
- Return type:
- correct_open_position_balance(position, expected_amount, actual_amount, strategy_cycle_ts, block_number, balance_update_id)[source]#
Create an accounting entry trade that correct the balance.
- Parameters:
- Return type:
- get_current_interest_positions()[source]#
Get lis of all positions for which we need to sync the on-chain interest
- Return type:
- get_loan_net_asset_value()[source]#
What is our Net Asset Value (NAV) across all open loan positions.
- Return type:
- has_trading_capital(threshold_usd=0.15)[source]#
Does this strategy have non-zero deposits and total equity?
Check the reserves.
If we have zero deposits, do not attempt to trade
The actual amount is a bit above zero to account for rounding errors
- Returns:
If we have any capital to trade
- Return type:
- get_total_claimed_interest()[source]#
Get the total interest claimed from the positions.
- Return type:
- __init__(next_position_id=1, next_trade_id=1, next_balance_update_id=1, open_positions=<factory>, reserves=<factory>, closed_positions=<factory>, frozen_positions=<factory>, revalue_failures_as_zero=False, pending_positions=<factory>, expired_positions=<factory>)#
- Parameters:
next_position_id (int) –
next_trade_id (int) –
next_balance_update_id (int) –
open_positions (Dict[int, TradingPosition]) –
reserves (Dict[str, ReservePosition]) –
closed_positions (Dict[int, TradingPosition]) –
frozen_positions (Dict[int, TradingPosition]) –
revalue_failures_as_zero (bool) –
pending_positions (Dict[int, TradingPosition]) –
expired_positions (Dict[int, TradingPosition]) –
- Return type:
None