StrategyParameters#
API documentation for tradeexecutor.strategy.parameters.StrategyParameters Python class in Trading Strategy framework.
- class StrategyParameters[source]#
Bases:
MutableAttributeDict
Strategy parameters.
These parameters may present
Individual constant parameters for the strategy, like indicators threshold levels: rsi_low, rsi_high
Parameters about the backtesting itself: backtest_start, backtest_end
Parameters about strategy execution: cycle_duration.
See
CoreStrategyParameters
for the always present parameters. Due to Python limitations these cannot be automatically type hinted.
The parameters are presented as attributed dict and are accessible using both dotted attribe access and dict access:
value = parameters.rsi_low value = parameters["rsi_low"] # Are equal
Example parameter definition:
from tradeexecutor.strategy.cycle import CycleDuration from tradeexecutor.backtest.backtest_runner import run_backtest_inline class Parameters: cycle_duration = CycleDuration.cycle_1d rsi_bars = 5 # 5 days = 15 8 hour bars eth_btc_rsi_bars = 20 # The length of ETH/BTC RSI rsi_high = 77 # RSI trigger threshold for decision making rsi_low = 60 # RSI trigger threshold for decision making allocation = 0.85 # Allocate 90% of cash to each position lookback_candles = 140 minimum_rebalance_trade_threshold = 500.00 # Don't do trades that would have less than 500 USD value change initial_cash = 10_000 # Start with 10k USD trailing_stop_loss = 0.875 shift = 0 state, universe, debug_dump = run_backtest_inline( name="RSI multipair", engine_version="0.4", decide_trades=decide_trades, client=client, universe=strategy_universe, parameters=Parameters, strategy_logging=False, ) trade_count = len(list(state.portfolio.get_all_trades())) print(f"Backtesting completed, backtested strategy made {trade_count} trades")
You can use StrategyParameters with inline backtest as a dict:
def decide_trades( timestamp: pd.Timestamp, parameters: StrategyParameters, strategy_universe: TradingStrategyUniverse, state: State, pricing_model: PricingModel) -> List[TradeExecution]: assert parameters.test_val == 111 # ... parameters = StrategyParameters({ "test_val": 111, }) # Run the test state, universe, debug_dump = run_backtest_inline( parameters=parameters, )
When dealing with grid search input, every parameter is assumed to be a list of potential grid search combination values. decide_trades function gets called with every single combination of the list.
from tradeexecutor.strategy.cycle import CycleDuration from pathlib import Path from tradeexecutor.backtest.grid_search import prepare_grid_combinations # This is the path where we keep the result files around storage_folder = Path("/tmp/v5-grid-search.ipynb") class StrategyParameters: cycle_duration = CycleDuration.cycle_1d rsi_days = [5, 6, 9, 8, 20] # The length of RSI indicator eth_btc_rsi_days = 60 # The length of ETH/BTC RSI rsi_high = [60, 70, 80] # RSI trigger threshold for decision making rsi_low = [30, 40, 50] # RSI trigger threshold for decision making allocation = 0.9 # Allocate 90% of cash to each position lookback_candles = 120 minimum_rebalance_trade_threshold = 500.00 # Don't do trades that would have less than 500 USD value change combinations = prepare_grid_combinations(StrategyParameters, storage_folder) print(f"We prepared {len(combinations)} grid search combinations") # Then pass the combinations to a grid search from tradeexecutor.backtest.grid_search import perform_grid_search grid_search_results = perform_grid_search( decide_trades, strategy_universe, combinations, max_workers=8, trading_strategy_engine_version="0.4", multiprocess=True, )
When working with optimiser, the optimiser search space must be defined using
skopt.space.Dimension
instances likeskopt.space.Real
,skopt.space.Integer
orskopt.space.Categorial
.from skopt import space class Parameters: stop_loss = space.Real(0.85, 0.99) max_asset_amount = space.Integer(3, 4) regime_filter_type = space.Categorical(["bull", "bull_and_bear"])
- __init__(dictionary, *args, **kwargs)#
Methods
__init__
(dictionary, *args, **kwargs)clear
()from_class
(c[, grid_search])Create parameter dict out from a class object.
from_dict
(other_parameters)Create parameter dict out from another dict.
get
(k[,d])Are these parameters for a grid search.
Are these parameters for a single backtest run.
items
()Iterate over parameter definitions.
keys
()pop
(k[,d])If key is not found, d is returned if given, otherwise KeyError is raised.
popitem
()as a 2-tuple; but raise KeyError if D is empty.
recursive
(value)setdefault
(k[,d])update
([E, ]**F)If E present and has a .keys() method, does: for k in E: D[k] = E[k] If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v In either case, this is followed by: for k, v in F.items(): D[k] = v
Do a basic validation for backtesting parameters.
values
()- is_single_run()[source]#
Are these parameters for a single backtest run.
As opposite to the grid search.
- Return type:
- is_grid_search()[source]#
Are these parameters for a grid search.
Search over multiple values.
- Return type:
- static from_class(c, grid_search=False)[source]#
Create parameter dict out from a class object.
Convert inlined class-style strategy parameter input to dictionary
TODO: Write separate methdods from_class_for_backtest, from_class_for_grid_search, from_class_for_optimiser, as we cannot otherwisde detect all human input errors.
- Parameters:
grid_search –
Make grid-search style parameters.
Every scalar input is converted to a single item list if set.
c (type) –
- Return type: