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
TradeExecution
objects.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.Decimal
about 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=0.017, trading_pair_cache=Cache({}, maxsize=50000, currsize=0))[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 –
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()
.
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.
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])Estimate the trading/LP fees for a trading pair.
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.
log
(msg[, level, prefix])Log debug info.
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=0.017, trading_pair_cache=Cache({}, maxsize=50000, currsize=0))[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 –
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()
.
- 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:
- 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)[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.
- 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 sizeclose_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_tolerance
if 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)[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.
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.
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
None
if not selling.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_tolerance
if 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
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_tolerance
if 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()[source]#
Close all open 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)[source]#
Move reserve currency to a credit supply position.
- adjust_credit_supply_position(position, new_value, 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:
- 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()
andadjust_credit_supply_position()
, so we do not need to know if we have an existing credit supply openCannot 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 usageThe 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:
- 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.