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 like skopt.space.Real, skopt.space.Integer or skopt.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)#
Parameters:
  • dictionary (Dict[TKey, TValue]) –

  • args (Any) –

  • kwargs (Any) –

Return type:

None

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])

is_grid_search()

Are these parameters for a grid search.

is_single_run()

Are these parameters for a single backtest run.

items()

iterate_parameters()

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

validate_backtest()

Do a basic validation for backtesting parameters.

values()

iterate_parameters()[source]#

Iterate over parameter definitions.

Return type:

Iterable[Tuple[str, any]]

is_single_run()[source]#

Are these parameters for a single backtest run.

As opposite to the grid search.

Return type:

bool

Are these parameters for a grid search.

Search over multiple values.

Return type:

bool

validate_backtest()[source]#

Do a basic validation for backtesting parameters.

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:

StrategyParameters

static from_dict(other_parameters)[source]#

Create parameter dict out from another dict.

  • Convert scikit-optimizer parameteres to astrategy parameter input to dictionary

Parameters:

other_parameters (dict | web3.datastructures.MutableAttributeDict) –

Return type:

StrategyParameters