PositionManager#
API documentation for tradeexecutor.strategy.pandas_trader.position_manager.PositionManager Python class in Trading Strategy framework.
- class PositionManager[source]#
- Bases: - object- An utility class to open and close new trade positions. - PositionManager hides away the complex logic reason about trades. It is designed to be used in a trading strategy’s decide_trades() function as an utility class to generate trades a list of - TradeExecutionobjects.- It offers a simple interface for trading for people who are used to TradingView’s Pine Script or similar limited trade scripting environment. - PositionManager helps about - How to have up-to-date price information 
- Setting take profit/stop loss parameters for positions 
- Converting between US dollar prices, crypto prices 
- Converting between quantity and value of a trade 
- Caring whether we have an existing position open for the trading pair already 
- Shortcut methods for trading strategies that trade only a single trading pair 
 - PositionManager takes the price feed and current execution state as an input and produces the execution instructions to change positions. - Below are some recipes how to use position manager. - Position manager is usually instiated at your decide_trades function as the following: - from typing import List, Dict from tradeexecutor.state.visualisation import PlotKind from tradeexecutor.state.trade import TradeExecution from tradeexecutor.strategy.pricing_model import PricingModel from tradeexecutor.strategy.pandas_trader.position_manager import PositionManager from tradeexecutor.state.state import State from tradingstrategy.universe import Universe def decide_trades( timestamp: pd.Timestamp, universe: Universe, state: State, pricing_model: PricingModel, cycle_debug_data: Dict) -> List[TradeExecution]: # Create a position manager helper class that allows us easily to create # opening/closing trades for different positions position_manager = PositionManager(timestamp, universe, state, pricing_model) - How to check if you have an open position using - is_any_open()and then open a new position:- # List of any trades we decide on this cycle. # Because the strategy is simple, there can be # only zero (do nothing) or 1 (open or close) trades # decides trades = [] if not position_manager.is_any_open(): buy_amount = cash * position_size trades += position_manager.open_1x_long(pair, buy_amount) return trades - How to check the entry price and open quantity of your latest position. See also - decimal.Decimalabout arbitrary precision decimal numbers in Python.- # Will throw an exception if there is no position open current_position = position_manager.get_current_position() # Quantity is the open amount in tokens. # This is expressed in Python Decimal class, # because Ethereum token balances are accurate up to 18 decimals # and this kind of accuracy cannot be expressed in floating point numbers. quantity = current_position.get_quantity() assert quantity == Decimal('0.03045760003971992547285959728') # The current price is the price of the trading pair # that was recorded on the last price feed sync. # This is a 64-bit floating point, as the current price # is always approximation based on market conditions. price = current_position.get_current_price() assert price == 1641.6263899583264 # The opening price is the price of the first trade # that was made for this position. This is the actual # executed price of the trade, expressed as floating # point for the convenience. price = current_position.get_opening_price() assert price == 1641.6263899583264 - __init__(timestamp, universe, state, pricing_model, default_slippage_tolerance=None, trading_pair_cache=Cache({}, maxsize=50000, currsize=0), routing_model=None, routing_state=None)[source]#
- Create a new PositionManager instance. - Call within decide_trades function. - Parameters:
- timestamp (Union[datetime, Timestamp]) – The timestamp of the current strategy cycle 
- universe (tradingstrategy.universe.Universe | tradeexecutor.strategy.trading_strategy_universe.TradingStrategyUniverse) – Trading universe of available assets 
- state (State) – Current state of the trade execution 
- pricing_model (PricingModel) – The model to estimate prices for any trades 
- default_slippage_tolerance (float) – - The max slippage tolerance parameter set for any trades if not overriden trade-by-trade basis. - Default to 1.7% max slippage or 170 BPS. 
- trading_pair_cache – - Trading pair cache. - Used to speed up trading pair look up on multipair strategies. - See - get_trading_pair().
- routing_model (RoutingModel) – - Needed for position enter checks. 
- routing_state (RoutingState) – - Needed for position enter checks. 
 
 
 - Methods - __init__(timestamp, universe, state, ...[, ...])- Create a new PositionManager instance. - add_cash_to_credit_supply(cash[, ...])- Deposit the cash to the strategy's default credit position. - adjust_credit_supply_position(position[, ...])- Increase/decrease credit supply position. - adjust_position(pair, dollar_delta, ...[, ...])- Adjust holdings for a certain position. - adjust_short(position, new_value[, notes, ...])- Increase/decrease short based on the amount of collateral. - calculate_credit_flow_needed(trades, ...[, ...])- How much cash we need ton this cycle. - check_enough_cash(trades)- Check that we have enough cash to cover buys. - check_enter_position(trading_pair)- Check if we can open a position for a pair. - close_all([credit_supply])- Close all open positions. - close_credit_supply_position(position[, ...])- Close a credit supply position - close_position(position[, trade_type, ...])- Close a single position. - close_short(position[, quantity, notes, ...])- Close a short position - close_short_position(position[, quantity, ...])- Legacy. - close_spot_position(position[, trade_type, ...])- Close a single spot market trading position. - estimate_asset_quantity(pair, dollar_amount)- Convert dollar amount to the quantity of a token. - get_closed_positions_for_pair(pair[, ...])- Get closed positions for a specific trading pair. - Get the available cash in hand. - Get the current single credit supply position. - Get the current single long position. - Return the active portfolio of the strategy. - Get the current single position. - get_current_position_for_pair(pair[, pending])- Get the current open position for a specific trading pair. - Get the current single short position. - Get the position that was last closed. - get_pair_fee([pair, direction])- Estimate the trading/LP fees for a trading pair. - Get the amount of cash needed to settle the redemptions. - get_trading_pair(pair)- Get a trading pair identifier by its internal id, description or DEXPair data object. - Do we have any credit supply positions open. - Do we have any long positions open. - Do we have any positions open. - Do we have any short positions open. - is_problematic_pair(pair)- Check if trading pair is on any manual blacklist. - log(msg[, level, prefix])- Log debug info. - manage_credit_flow(flow[, ...])- Create trades to adjust cash/credit supply positions. - open_1x_long(pair, value[, take_profit_pct, ...])- Deprecated function for opening a spot position. - Move reserve currency to a credit supply position. - open_short(pair, value, *[, leverage, ...])- Open a short position. - open_spot(pair, value[, take_profit_pct, ...])- Open a spot position. - open_spot_with_market_limit(pair, value, ...)- Create a pending position open waiting for market limit - prepare_take_profit_trades(position, levels)- Set multiple take profit levels, and prepare trades for them. - set_market_limit_trigger(trades, price[, ...])- Set a trade to have a triggered execution. - update_stop_loss(position, stop_loss[, trailing])- Update the stop loss for the given position. - __init__(timestamp, universe, state, pricing_model, default_slippage_tolerance=None, trading_pair_cache=Cache({}, maxsize=50000, currsize=0), routing_model=None, routing_state=None)[source]#
- Create a new PositionManager instance. - Call within decide_trades function. - Parameters:
- timestamp (Union[datetime, Timestamp]) – The timestamp of the current strategy cycle 
- universe (tradingstrategy.universe.Universe | tradeexecutor.strategy.trading_strategy_universe.TradingStrategyUniverse) – Trading universe of available assets 
- state (State) – Current state of the trade execution 
- pricing_model (PricingModel) – The model to estimate prices for any trades 
- default_slippage_tolerance (float) – - The max slippage tolerance parameter set for any trades if not overriden trade-by-trade basis. - Default to 1.7% max slippage or 170 BPS. 
- trading_pair_cache – - Trading pair cache. - Used to speed up trading pair look up on multipair strategies. - See - get_trading_pair().
- routing_model (RoutingModel) – - Needed for position enter checks. 
- routing_state (RoutingState) – - Needed for position enter checks. 
 
 
 - is_any_credit_supply_position_open()[source]#
- Do we have any credit supply positions open. - See also - Return type:
 
 - get_current_cash()[source]#
- Get the available cash in hand. - Cash that sits in the strategy treasury 
- Cash not in the open trading positions 
- Cash not allocated to the trading positions that are going to be opened on this cycle 
 - Returns:
- US Dollar amount 
- Return type:
 
 - get_current_position()[source]#
- Get the current single position. - This is a shortcut function for trading strategies that operate only a single trading pair and a single position. - See also - Returns:
- Currently open trading position 
- Raises:
- NoSingleOpenPositionError – If you do not have a position open or there are multiple positions open. 
- Return type:
 
 - is_problematic_pair(pair)[source]#
- Check if trading pair is on any manual blacklist. - Is a rugpull 
- Get rid of any open position at any price 
 - Returns:
- True: avoid trade, set slippage to max when selling. 
- Parameters:
- pair (TradingPairIdentifier) – 
- Return type:
 
 - get_current_long_position()[source]#
- Get the current single long position. - This is a shortcut function for trading strategies that operate only a single trading pair and a single long position. - See also - Returns:
- Currently open long trading position 
- Raises:
- NoSingleOpenPositionError – If you do not have a position open or there are multiple positions open. 
 
 - get_current_short_position()[source]#
- Get the current single short position. - This is a shortcut function for trading strategies that operate only a single trading pair and a single short position. - If you have multiple short positions open use - get_current_position_for_pair()to distinguish between them.- # aave_usdc is an instance of TradingPairIdentifier aave_shorting_pair = strategy_universe.get_shorting_pair(aave_usdc) aave_short_position = position_manager.get_current_position_for_pair(aave_shorting_pair) - See also - Returns:
- Currently open short trading position 
- Raises:
- NoSingleOpenPositionError – If you do not have a position open or there are multiple positions open. 
 
 - get_current_credit_supply_position()[source]#
- Get the current single credit supply position. - This is a shortcut function for trading strategies that operate only a single trading pair and a single credit supply position. - See also - Returns:
- Currently open credit supply trading position 
- Raises:
- NoSingleOpenPositionError – If you do not have a position open or there are multiple positions open. 
 
 - get_current_position_for_pair(pair, pending=False)[source]#
- Get the current open position for a specific trading pair. - Parameters:
- pending – Check also pending positions that wait market limit open and are not yet triggered 
- pair (TradingPairIdentifier) – 
 
- Returns:
- Currently open trading position. - If there is no open position return None. 
- Return type:
 
 - get_closed_positions_for_pair(pair, include_test_position=False)[source]#
- Get closed positions for a specific trading pair. - Returns:
- All closed trading position of a trading pair - If there is no closed position return empty list. 
- Parameters:
- pair (TradingPairIdentifier) – 
- include_test_position (bool) – 
 
- Return type:
 
 - get_last_closed_position()[source]#
- Get the position that was last closed. - If multiple positions are closed at the same time, return a random position. - Example: - last_position = position_manager.get_last_closed_position() if last_position: ago = timestamp - last_position.closed_at print(f"Last position was closed {ago}") else: print("Strategy has not decided any position before") - Returns:
- None if the strategy has not closed any positions 
- Return type:
 
 - get_trading_pair(pair)[source]#
- Get a trading pair identifier by its internal id, description or DEXPair data object. - Example: - # List of pair descriptions we used to look up pair metadata our_pairs = [ (ChainId.centralised_exchange, "binance", "BTC", "USDT"), (ChainId.centralised_exchange, "binance", "ETH", "USDT"), ] # Resolve our pair metadata for our two pair strategy position_manager = PositionManager(timestamp, strategy_universe, state, pricing_model) btc_pair = position_manager.get_trading_pair(our_pairs[0]) eth_pair = position_manager.get_trading_pair(our_pairs[1]) position_manager.log(f"BTC pair data is: {btc_pair}") - Note that internal integer ids are not stable over multiple trade cycles and might be reset. Always use (chain id, smart contract) for persistent pair identifier. 
 - get_pair_fee(pair=None, direction='buy')[source]#
- Estimate the trading/LP fees for a trading pair. - This information can come either from the exchange itself (Uni v2 compatibles), or from the trading pair (Uni v3). - The return value is used to fill the fee values for any newly opened trades. - Parameters:
- pair (Optional[TradingPairIdentifier]) – - Trading pair for which we want to have the fee. - Can be left empty if the underlying exchange is always offering the same fee. 
- direction (Literal['buy', 'sell']) – Needed for spot and token tax. 
 
- Returns:
- The estimated trading fee, expressed as %. - Returns None if the fee information is not available. This can be different from zero fees. 
- Return type:
 
 - open_1x_long(pair, value, take_profit_pct=None, stop_loss_pct=None, trailing_stop_loss_pct=None, stop_loss_usd=None, notes=None, slippage_tolerance=None, take_profit_usd=None)[source]#
- Deprecated function for opening a spot position. - Use - open_spot()instead.- Parameters:
- pair (Union[DEXPair, TradingPairIdentifier]) – 
- value (float | decimal.Decimal) – 
 
- Return type:
 
 - open_spot(pair, value, take_profit_pct=None, stop_loss_pct=None, trailing_stop_loss_pct=None, stop_loss_usd=None, notes=None, slippage_tolerance=None, flags=None, take_profit_usd=None)[source]#
- Open a spot position. - For simple buy and hold trades 
- Open a spot market buy. 
- Checks that there is not existing position - cannot increase position 
 - See also - adjust_position()if you want increase/decrease an existing position size
- close_position()if you want exit an position
 - Parameters:
- pair (Optional[Union[DEXPair, TradingPairIdentifier]]) – Trading pair where we take the position 
- value (float | decimal.Decimal) – How large position to open, in US dollar terms 
- take_profit_pct (Optional[float]) – If set, set the position take profit relative to the current market price. 1.0 is the current market price. If asset opening price is $1000, take_profit_pct=1.05 will sell the asset when price reaches $1050. 
- stop_loss_pct (Optional[float]) – If set, set the position to trigger stop loss relative to the current market price. 1.0 is the current market price. If asset opening price is $1000, stop_loss_pct=0.95 will sell the asset when price reaches 950. 
- trailing_stop_loss_pct (Optional[float]) – If set, set the position to trigger trailing stop loss relative to the current market price. Cannot be used with stop_loss_pct or stop_loss_usd. 
- stop_loss_usd (Optional[float]) – If set, set the position to trigger stop loss at the given dollar price. Cannot be used with stop_loss_pct or trailing_stop_loss_pct. 
- slippage_tolerance (Optional[float]) – - Slippage tolerance for this trade. - Use - default_slippage_toleranceif not set.
- take_profit_usd (Optional[float]) – If set, set the position take profit at the given dollar price. Cannot be used with take_profit_pct. 
 
- Returns:
- A list of new trades. Opening a position may general several trades for complex DeFi positions, though usually the result contains only a single trade. 
- Return type:
 
 - adjust_position(pair, dollar_delta, quantity_delta, weight, stop_loss=None, take_profit=None, trailing_stop_loss=None, slippage_tolerance=None, override_stop_loss=False, notes=None, flags=None, pending=False, position=None, trigger_price=None, other_data=None)[source]#
- Adjust holdings for a certain position. - Used to rebalance positions. - This method rarely needs to be called directly, but is usually part of portfolio construction strategy that is using - tradeexecutor.strategy.alpha_model.AlphaModel.- A new position is opened if no existing position is open. If everything is sold, the old position is closed - If the rebalance is sell (dollar_amount_delta is negative), then calculate the quantity of the asset to sell based on the latest available market price on the position. - Example how to partially reduce position: - pair = strategy_universe.get_pair_by_human_description((ChainId.base, "uniswap-v3", "DogInMe", "WETH")) position = position_manager.get_current_position_for_pair(pair) trades = position_manager.close_position(position) t = trades[0] assert t.is_sell() - Example how to increase position: - pair = strategy_universe.get_pair_by_human_description((ChainId.base, "uniswap-v3", "DogInMe", "WETH")) dollar_delta = 0.1 # Buy 0.1 more on the existing position position = position_manager.get_current_position_for_pair(pair) quantity_delta = dollar_delta * position.get_current_price() trades = position_manager.adjust_position( pair=pair, dollar_delta=dollar_delta, quantity_delta=quantity_delta, weight=1, ) - Warning - Adjust position cannot be used to close an existing position, because epsilons in quantity math. Use - close_position()] for this.- Parameters:
- pair (TradingPairIdentifier) – Trading pair which position we adjust 
- dollar_delta (float) – - How much we want to increase/decrease the position in US dollar terms. - Positive: increase position 
- Negative: decrease position 
 - TODO: If you are selling the assets, you need to calculate the expected dollar estimate yourself at the moment. 
- quantity_delta (float | decimal.Decimal) – - How much we want to increase/decrease the position in the asset unit terms. - Used only when decreasing existing positions (selling). Set to - Noneif not selling.- Must be negative. 
- weight (float) – - What is the weight of the asset in the new target portfolio 0….1. Currently only used to detect condition “sell all” instead of trying to match quantity/price conversion. - Relevant for portfolio construction strategies. - If unsure and buying, set to 1. - If unsure and selling, set to 1. 
- Set the stop loss for the position. - Use 0…1 based on the current mid price. E.g. 0.98 = 2% stop loss under the current mid price. - Sets the initial stop loss. If you want to override this for an existing position you need to use override_stop_loss parameter. 
- take_profit (Optional[float]) – - Set the take profit for the position. - Use 0…1 based on the current mid price. E.g. 1.02 = 2% take profit over the current mid-price. 
- slippage_tolerance (Optional[float]) – - Slippage tolerance for this trade. - Use - default_slippage_toleranceif not set.
- override_stop_loss – If not set and a position has already stop loss set, do not modify it. 
- Human-readable plain text notes on the trade. - Used for diagnostics. 
- pending – - Do not generate a new open position. - Used when adding take profit triggers to market limit position. 
- position (tradeexecutor.state.position.TradingPosition | None) – The existing position to be used with pending 
- other_data (None | dict) – Added diagnostics payload. 
- flags (Optional[set[tradeexecutor.state.trade.TradeFlag]]) – 
- trigger_price (float | None) – 
 
- Returns:
- List of trades to be executed to get to the desired position level. 
- Return type:
 
 - close_spot_position(position, trade_type=TradeType.rebalance, notes=None, slippage_tolerance=None, flags=None, quantity=None, pending=False, trigger_price=None)[source]#
- Close a single spot market trading position. - See - close_position()for usage.- Parameters:
- Return type:
 
 - close_credit_supply_position(position, quantity=None, notes=None, trade_type=TradeType.rebalance, flags=None)[source]#
- Close a credit supply position - Parameters:
- position (TradingPosition) – - Position to close. - Must be a credit supply position. 
- quantity (float | decimal.Decimal | None) – - How much of the quantity we reduce. - If not given close the full position. 
- trade_type (TradeType) – 
 
- Returns:
- New trades to be executed 
- Return type:
 
 - close_position(position, trade_type=None, notes=None, slippage_tolerance=None, flags=None, pending=False, trigger_price=None)[source]#
- Close a single position. - The position may already have piled up selling trades. In this case calling close_position() again on the same position does nothing and None is returned. - Parameters:
- position (TradingPosition) – Position to be closed 
- trade_type (tradeexecutor.state.trade.TradeType | None) – What’s the reason to close the position 
- slippage_tolerance (Optional[float]) – - Slippage tolerance for this trade. - Use - default_slippage_toleranceif not set.
- pending (bool) – 
- trigger_price (float | None) – 
 
- Returns:
- Get list of trades needed to close this position. - return list of trades. 
- Return type:
 
 - close_all(credit_supply=True)[source]#
- Close all open positions. - Parameters:
- credit_supply – Set to false not to automatically close credit supply positions. 
- Returns:
- List of trades that will close existing positions 
- Return type:
 
 - estimate_asset_quantity(pair, dollar_amount)[source]#
- Convert dollar amount to the quantity of a token. - Use the market mid-price of the timestamp. - Parameters:
- pair (TradingPairIdentifier) – Trading pair of which base pair we estimate. 
- dollar_amount (float) – Get the asset quantity for this many dollars. 
 
- Returns:
- Asset quantity. - The sign of the asset quantity is the same as the sign of dollar_amount parameter. - We return as float, because the exact quantity is never known due the price fluctuations and slippage. 
- Return type:
 
 - update_stop_loss(position, stop_loss, trailing=False)[source]#
- Update the stop loss for the given position. - Example: - profit_pct = position.get_unrealised_profit_pct() or 0 if profit_pct > parameters.trailing_stop_loss_activation_level - 1: new_trailing_stop_loss = close_price - atr_trailing_stop_loss * parameters.trailing_stop_loss_activation_fract position_manager.update_stop_loss( position, new_trailing_stop_loss, trailing=True, ) - Parameters:
- position (TradingPosition) – - Position to update. - For multipair strategies, this parameter is always needed. 
- stop_loss (float) – Stop loss in US dollar terms 
- trailing – - Only update the stop loss if the new stop loss gives better profit than the previous one. - For manual trailing stop loss management, instead of using a fixed percent value. - E.g. for spot position move stop loss only higher. 
- mid_price – Mid price of the pair (https://tradingstrategy.ai/glossary/mid-price). Provide when possible for most complete statistical analysis. In certain cases, it may not be easily available, so it’s optional. 
 
 
 - open_credit_supply_position_for_reserves(amount, flags=None, notes=None, lending_reserve_identifier=None)[source]#
- Move reserve currency to a credit supply position. - Parameters:
- Returns:
- List of trades that will open this credit position 
- Return type:
 
 - adjust_credit_supply_position(position, new_value=None, delta=None, trade_type=TradeType.rebalance, flags=None, notes=None)[source]#
- Increase/decrease credit supply position. - Credit position is already open 
- The amount of position is changing 
- Any excess collateral is returned to cash reserves, any new collateral is moved for the cash reserves to the short 
 - Parameters:
- position (TradingPosition) – - Position to adjust. - Must be a credit supply position. 
- new_value (float) – The allocated collateral for this position after the trade in US Dollar reserves. 
- delta (float) – - Collateral added to the credit position. - Positive = add more collateral. 
- trade_type (TradeType) – 
- notes (str | None) – 
 
- Returns:
- New trades to be executed 
- Return type:
 
 - add_cash_to_credit_supply(cash, min_usd_threshold=1.0)[source]#
- Deposit the cash to the strategy’s default credit position. - Put the amount of the cash into the credit position 
- Switch between - open_credit_supply_position_for_reserves()and- adjust_credit_supply_position(), so we do not need to know if we have an existing credit supply open
- Cannot reduce the credit position 
 - Example: - trades = position_manager.add_cash_to_credit_supply( cash * 0.98, ) return trades - Parameters:
- Returns:
- Trades done 
- Return type:
 
 - open_short(pair, value, *, leverage=1.0, take_profit_pct=None, stop_loss_pct=None, trailing_stop_loss_pct=None, notes=None, flags=None)[source]#
- Open a short position. - NOTE: take_profit_pct and stop_loss_pct are more related to capital at risk percentage than to the price. So this will likely be changed in the future. - Parameters:
- pair (Union[DEXPair, TradingPairIdentifier]) – - Trading pair where we take the position. - For lending protocol shorts must be the underlying spot pair. 
- value (float) – - How much cash reserves we allocate to open this position. - In US dollars. - For example to open 2x short where we allocate $1000 from our reserves, this value is $1000. 
- leverage (float) – Leverage level to use for the short position 
- take_profit_pct (float | None) – If set, set the position take profit relative to the current market price. 1.0 is the current market price. If asset opening price is $1000, take_profit_pct=1.05 will buy back the asset when price reaches $950. 
- stop_loss_pct (float | None) – If set, set the position to trigger stop loss relative to the current market price. 1.0 is the current market price. If asset opening price is $1000, stop_loss_pct=0.98 will buy back the asset when price reaches $1020. 
- trailing_stop_loss_pct (float | None) – If set, set the position to trigger trailing stop loss relative to the current market price. Cannot be used with stop_loss_pct. 
- notes (str | None) – 
 
- Returns:
- List of trades that will open this credit position 
- Return type:
 
 - close_short_position(position, quantity=None, notes=None, trade_type=TradeType.rebalance)[source]#
- Legacy. - Use - close_short().- Parameters:
- position (TradingPosition) – 
- quantity (float | decimal.Decimal | None) – 
- trade_type (TradeType) – 
 
- Return type:
 
 - close_short(position, quantity=None, notes=None, trade_type=TradeType.rebalance, flags=None)[source]#
- Close a short position - Buy back the shorted token 
- Release collateral and return it as cash to the reserves 
- Move any gained interest back to the reserves as well 
 - Parameters:
- position (TradingPosition) – - Position to close. - Must be a short position. 
- quantity (float | decimal.Decimal | None) – - How much of the quantity we reduce. - If not given close the full position. 
- trade_type (TradeType) – 
 
- Returns:
- New trades to be executed 
- Return type:
 
 - adjust_short(position, new_value, notes=None, trade_type=TradeType.rebalance, minimum_rebalance_trade_threshold=0.0, flags=None)[source]#
- Increase/decrease short based on the amount of collateral. - Short adjust used in alpha model. - Short is already open 
- The amount of short is changing 
- We want to maintain the existing leverage 
- Any excess collateral is returned to cash reserves, any new collateral is moved for the cash reserves to the short 
- Cannot be used to open/close position 
 - See also - Parameters:
- position (TradingPosition) – - Position to close. - Must be a short position. 
- new_value (float) – - The allocated collateral for this position after the trade in US Dollar reserves. - The absolute amunt of reserve currency we will use for this short. 
- quantity – - How much of the quantity we reduce. - If not given close the full position. 
- price – The spot price of the underlying pair. 
- trade_type (TradeType) – 
- minimum_rebalance_trade_threshold (float) – 
 
- Returns:
- New trades to be executed 
- Return type:
 
 - set_market_limit_trigger(trades, price, expires_at=None)[source]#
- Set a trade to have a triggered execution. - See - open_spot_with_market_limit()for usage
- The created trade is not executed immediately, but later when a trigger condition is meet 
- Spot open supported only for now 
 - Parameters:
- trades (List[TradeExecution]) – List of trades to apply for 
- price (float) – 
- expires_at (datetime.datetime | None) – 
 
 
 - open_spot_with_market_limit(pair, value, trigger_price, expires_at, notes=None)[source]#
- Create a pending position open waiting for market limit - This position does not open on this decision cycle, but is pending until the trigger threshold is reached 
- The position will expire and may be never opened 
 - Example: - midnight_price = indicators.get_price() if midnight_price is None: # Skip cycle 1 # We do not have the previous day price available at the first cycle return [] # Only set a trigger open if we do not have any position open/pending yet if not position_manager.get_current_position_for_pair(pair, pending=True): position_manager.log(f"Setting up a new market limit trigger position for {pair}") # Set market limit if we break above level during the day, # with a conditional open position position, pending_trades = position_manager.open_spot_with_market_limit( pair=pair, value=cash*0.99, # Cannot do 100% because of floating point rounding errors trigger_price=midnight_price * 1.01, expires_at=input.timestamp + pd.Timedelta(hours=24), notes="Market limit test open trade", ) assert len(portfolio.pending_positions) == 1 assert len(portfolio.open_positions) == 0 # We do not know the accurage quantity we need to close, # because of occuring slippage, # but we use the close flag below to close the remaining] # amount total_quantity = position.get_pending_quantity() assert total_quantity > 0 # Set two take profits to 1.5% and 2% price increase # First will close 2/3 of position # The second will close the remaining position position_manager.prepare_take_profit_trades( position, [ (midnight_price * 1.015, -total_quantity * 2 / 3, False), (midnight_price * 1.02, -total_quantity * 1 / 3, True), ] ) else: position_manager.log("Existing position pending - do not create new") - Parameters:
- pair (TradingPairIdentifier) – Trading pair 
- value (float) – Open amount in reserve currency 
- trigger_price (float) – In which price level we will trigger 
- expires_at (Timestamp) – When the market limit order expires 
- notes (str | None) – Human-readable notes on this 
 
- Returns:
- Tuple (Pending position, relevant market limit trades) 
- Return type:
- tuple[tradeexecutor.state.position.TradingPosition, list[tradeexecutor.state.trade.TradeExecution]] 
 
 - prepare_take_profit_trades(position, levels)[source]#
- Set multiple take profit levels, and prepare trades for them. - Populate position.pending_trades with triggered trades to take profit when the price moves 
- Any triggers are added on the top of the existing triggers, no triggers are removed 
- If you want to reset the take profit triggers you need to call TODO 
- For usage see - open_spot_with_market_limit().
 - Note - Currently there might be a mismatch between planned quantity and executed quantity, so make sure there is enough rounding error left. The take profit with the closing flag set will always execute the remaining quantity. - Example how to set 24h cloes after opening: - # Set market limit if we break above level during the day, # with a conditional open position position, pending_trades = position_manager.open_spot_with_market_limit( pair=pair, value=cash*0.99, # Cannot do 100% because of floating point rounding errors trigger_price=midnight_price * 1.01, expires_at=input.timestamp + pd.Timedelta(hours=24), ) # We do not know the accurage quantity we need to close, # because of occuring slippage, # but we use the close flag below to close the remaining] # amount total_quantity = position.get_pending_quantity() # Fully close 24h after opening position_manager.prepare_take_profit_trades( position, [ (datetime.timedelta(hours=24), -total_quantity, True), ] ) - Parameters:
- position (TradingPosition) – The trading position 
- levels (list[tuple[float | datetime.timedelta | datetime.datetime, decimal.Decimal, bool]]) – - Tuples of (price | time, quantity, full close). - The trigger level may be price or time. - float: US dollar mid price 
- datetime: absolute time 
- timedelta: relative to the opening time of the position 
 - Quantity must be negative when closing spot positions. - The last member is True if the position should be fully closed, False otherwise. 
 
- Returns:
- Prepared trades. - Stored in position.pending_trades. 
- Return type:
 
 - get_pending_redemptions()[source]#
- Get the amount of cash needed to settle the redemptions. - Relevant for ERC-7540: Asynchronous ERC-4626 Tokenized Vaults like Lagoon protocol 
- Vaults do not offer in kind redemption, and the trade executor must need to make enough cash available for the redemption queue 
 - Returns:
- US dollar amount pending redemptions. - If the associated vault protocol does not have redemption queue, always return zero. 
- Return type:
 
 - log(msg, level=20, prefix='{self.timestamp}: ')[source]#
- Log debug info. - Useful to debug the backtesting when it is not making trades. - To log a message from your decide_trade functions: - position_manager = PositionManager(timestamp, strategy_universe, state, pricing_model) # ... some indicator calculation code goes here... position_manager.log(f"RSI current: {current_rsi_values[btc_pair]}, previous: {previous_rsi_values[btc_pair]}") - This will create output like: - INFO:tradeexecutor.strategy.pandas_trader.position_manager:2019-08-20 00:00:00: RSI current: 65.0149379533956, previous: 65.0149379533956 INFO:tradeexecutor.strategy.pandas_trader.position_manager:2019-08-21 00:00:00: RSI current: 57.38598755909552, previous: 57.38598755909552 - To make notebook logging visible you need to pass strategy_logging=True to - tradeexecutor.backtest.backtest_runner.run_backtest_inline():- from tradeexecutor.strategy.cycle import CycleDuration from tradeexecutor.backtest.backtest_runner import run_backtest_inline state, universe, debug_dump = run_backtest_inline( name="RSI multipair", engine_version="0.3", decide_trades=decide_trades, client=client, cycle_duration=CycleDuration.cycle_1d, universe=strategy_universe, initial_deposit=10_000, strategy_logging=True, ) - Note - Any logging output will likely mess up the rendering of the backtest progress bar. - Parameters:
- msg (str) – Message to log 
- level – - Python logging level. - Defaults to info. 
- prefix – - String prefix added to each logged message. - By default shows the strategy timestamp. Can use Python string formatting within PositionManager context. 
 
 
 - calculate_credit_flow_needed(trades, allocation_pct, buffer_pct=0.01, lending_reserve_identifier=None)[source]#
- How much cash we need ton this cycle. - We have a strategy that uses Aave for USDC credit yield, or similar yield farming service 
- We need to know how much new cash we need to release 
 - Note - Only call this after you have set up all the other trades in this cycle. - See also - manage_credit_flow()- Parameters:
- allocation_pct (float) – - How much of the cash we allocate to the portfolio positions. - E.g. if this is 0.95, then 95% goes to open positions, 5% to cash. 
- buffer_pct (float) – Because we do not know the executed reserve quantity released in sell trades, we need to have some safe margin because we might getting a bit less cash from sells we expect. 
- lending_reserve_identifier (TradingPairIdentifier) – Check our open lending position. 
- trades (list[tradeexecutor.state.trade.TradeExecution]) – 
 
- Returns:
- Positive: This much of cash must be released from credit supplied. Negative: This much of cash be deposited to Aave at the end of the cycle. 
- Return type:
 
 - manage_credit_flow(flow, lending_reserve_identifier=None, cash_change_tolerance_usd=50.0)[source]#
- Create trades to adjust cash/credit supply positions. - Parameters:
- flow (float) – - How much credit supply should change. - Positive: This much of cash must be released from credit supplied. Negative: This much of cash be deposited to Aave at the end of the cycle. 
- lending_reserve_identifier (TradingPairIdentifier) – Use this lending protocol. 
- cash_change_tolerance_usd (float) – 
 
- Return type:
 
 - check_enough_cash(trades)[source]#
- Check that we have enough cash to cover buys. - This is a trip wire for a strategy logic not to generate and rebalances 
- This is to check that strategy internal logic is coherent 
 - xz
- For example, too high filtering parameters of alpha model trade generation may cause us not to generate enough trades 
 - Example: - trades = alpha_model.generate_rebalance_trades_and_triggers( position_manager, min_trade_threshold=parameters.rebalance_threshold_usd, # Don't bother with trades under XXXX USD invidiual_rebalance_min_threshold=parameters.individual_rebalance_min_threshold_usd, sell_rebalance_min_threshold=parameters.sell_rebalance_min_threshold_usd, execution_context=input.execution_context, ) position_manager.check_enough_cash(trades) - raise NotEnoughCasForBuys:
- In the case we cannot execute all buy trades. 
 
 - Parameters:
- trades (list[tradeexecutor.state.trade.TradeExecution]) – 
 
 - check_enter_position(trading_pair)[source]#
- Check if we can open a position for a pair. - It will check if the underlying router (swap aggregator, intent service, etc). currently supports a pair we see on chain 
- For documentation see - check_enter_position()
 - Example: - for pair_id in included_pairs: pair = strategy_universe.get_pair_by_id(pair_id) pair_signal = indicators.get_indicator_value("signal", pair=pair) if pair_signal is None: continue weight = pair_signal if weight < 0: continue # Enso hack to see if Enso routing is supported existing_position = position_manager.get_current_position_for_pair(pair) if existing_position is None: position_availability = position_manager.check_enter_position( pair, ) if not position_availability.supported: # Enso does not support routing this token, we cannot open a position continue alpha_model.set_signal( pair, weight, ) - Parameters:
- trading_pair (TradingPairIdentifier) – 
- Return type: