7. Backtesting, live trading, and optimization: a unified entry point and different modes

7.1. 1. 统一入口

Users trigger execution via **qt.run(op, mode=…, kwargs). Internally, it will:

  • Merge kwargs with the global configuration into config (ConfigDict).

  • Call op.run(config, datasource, logger), passing in qteasy’s default datasource and logger.

mode determines which branch to take:

  • mode=0: Live trading mode; enters the Trader workflow (scheduled triggers, fetching real-time data, generating signals, placing orders, and recording).

  • mode=1: Backtest mode; builds a Backtester, runs the Operator step by step according to group_timing_table, simulates fills, and outputs the equity curve and performance.

  • mode=2: optimization mode. The Optimizer searches the parameter space; each parameter set runs one backtest, and results are aggregated according to the objective function.

  • mode=3/4: modes such as tracking and forecasting; see the documentation and API.

Therefore, the same Operator reuses the same mechanism of “running the strategy by time step and mixing signals” under different modes; the only differences are the data source and how results are handled.

7.2. 2. 配置(config)的作用

config includes the asset universe, backtest period, cost parameters, capital plan, etc.; backtesting/live trading/optimization share the same configuration structure. For example:

  • Asset pool, asset types, and the backtest start/end dates;

  • Trading costs (fee rates, minimum fees, etc.);

  • Capital allocation plan (invest_cash_amounts, etc.);

  • Live-trading related (account, Broker type, etc.; used when mode=0).

config is obtained by merging **qt.run(…, kwargs) with the global QT_CONFIG, and is passed into op.run(config, …); Backtester, Trader, and Optimizer each read the fields they need.

7.3. 3. 回测模式(mode=1)

  1. Prepare historical data: based on the asset universe, backtest period in config, and the data_types and window_length of all strategies within the Operator, call check_and_prepare_backtest_data and the like to pull and assemble the required historical data from the DataSource (including sufficient lookback history to cover the start of the period).

  2. Build the Backtester: pass in the Operator, asset list, capital plan, trading price data, cost parameters, etc. to create a Backtester instance.

  3. Branch selection: if op.check_dynamic_data() is False (the strategy does not depend on process data), take the static branch: generate all signals at once, then run a Numba-vectorized backtest; if True (the strategy uses get_data('proc.xxx') or legacy dynamic data types), take the dynamic branch: generate signals step by step, simulate fills step by step, and update process data for the strategy to use in the next step. See Process Data (proc.*) and Dynamic Backtesting for details.

  4. Run step by step: for each time step in group_timing_table, call op.run_strategies(steps) (or an equivalent interface) to get (signal_type, signal) for each step.

  5. Parse and simulate fills: parse signals by signal_type (PT/PS/VS) into buy/sell intents, then use logic such as backtest_step to update positions, cash, and the settlement queue, producing the daily equity curve and trade records.

  6. Evaluation and output: evaluate performance on the equity curve and trade records (e.g., Sharpe ratio, drawdown, etc.), return results to the user, and optionally generate reports and charts.

7.4. 4. 实盘模式(mode=0)

  1. Trader holds the Operator and config, and triggers tasks at specified times within trading days according to run_freq, run_timing, and the trading calendar.

  2. Get data for the current time: based on the strategy declarations, fetch the data window required for the current step from the DataSource (or a real-time interface).

  3. Run the Operator: at this step, call the Operator to generate signals (the same run_strategy flow as in backtesting).

  4. Parse and place orders: parse signals into orders, hand them to the Broker for execution (simulated or a live broker interface), and record fills and positions.

7.5. 5. 优化模式(mode=2)

  1. The Optimizer determines the parameter space (e.g., grid search, random sampling, genetic algorithms, etc.) based on the strategy’s Parameter definitions.

  2. For each parameter set: write the parameters into the Operator via set_parameter and the like, then run one backtest (i.e., the mode=1 workflow).

  3. Compute the objective function (e.g., Sharpe ratio, return-to-drawdown ratio, etc.) from the backtest results, and aggregate the results of all parameter combinations.

  4. It outputs better parameter combinations and the corresponding backtest results for users to choose from.

7.6. 6. 小结

Backtesting, live trading, and optimization share the “Operator + step-by-step execution over time” mechanism: they all prepare data and config first, then call the strategy step by step according to group_timing_table and mix signals. The only differences are: backtesting uses historical data and the Backtester to simulate fills; live trading uses real-time data and the Trader/Broker to execute orders; optimization runs backtests multiple times and compares the objective function. For more parameters and usage, see the “User Guide”, “Backtest and Evaluate Trading Strategies”, “Optimize Trading Strategies”, and the API reference.