Warm Start Guide¶
AKQuant provides a powerful Warm Start workflow that lets you save current backtest state (snapshot) and resume later. This is useful for long-horizon segmented backtests, rolling workflows, and production-like continuation runs.
1. What Is Warm Start?¶
In a traditional event-driven backtest, each run is a cold start, and all state (positions, cash, indicator history) is rebuilt from scratch.
With warm start, you can:
- Save (Snapshot): Serialize in-memory engine and strategy state (positions, open orders, strategy attributes, indicator state) to disk.
- Resume: Load the snapshot and continue with new data as if execution was not interrupted.
2. Basic Usage¶
2.1 Save Snapshot (Phase 1)¶
At the end of phase 1 (or at any strategy checkpoint), save state with save_checkpoint.
from akquant.checkpoint import save_checkpoint
# Run phase 1
result1 = run_backtest(data=data_phase1, strategy=MyStrategy, ...)
# Save snapshot file
checkpoint_file = "checkpoint_phase1.pkl"
save_checkpoint(result1.engine, result1.strategy, checkpoint_file)
print(f"Snapshot saved to {checkpoint_file}")
2.2 Resume and Continue (Phase 2)¶
Use run_from_checkpoint with the snapshot path and phase-2 data.
Important: snapshots only store dynamic runtime state (Portfolio, Orders, strategy attributes). Static configuration (Instrument, MarketModel) is not persisted and must be reconfigured on resume.
import akquant as aq
# Prepare phase-2 data
data_phase2 = ...
config = aq.BacktestConfig(
strategy_config=aq.StrategyConfig(
strategy_id="alpha",
strategies_by_slot={"beta": BetaStrategy},
strategy_max_order_size={"alpha": 10, "beta": 20},
)
)
# Resume from snapshot and continue
result2 = aq.run_from_checkpoint(
checkpoint_path="checkpoint_phase1.pkl",
data=data_phase2,
symbols="AAPL",
commission_rate=0.0003,
stamp_tax_rate=0.001,
transfer_fee_rate=0.00001,
config=config,
t_plus_one=True,
)
3. Strategy Adaptation¶
To support warm start correctly, strategy code should separate initialization from restoration behavior.
3.1 Lifecycle Hooks¶
AKQuant provides two startup hooks:
on_start(): Called for both cold start and warm start.on_resume(): Called only in warm start, beforeon_start().
3.2 Avoid Overwriting Restored State¶
A common mistake is unconditional indicator reinitialization in on_start, which overwrites restored indicator state.
Incorrect:
Correct:
def on_start(self):
if not self.is_restored:
self.sma = SMA(30)
else:
self.log("Resumed from snapshot. Indicators retained.")
self.register_precomputed_indicator("sma", self.sma)
self.subscribe(self.symbol)
3.3 Indicator Serialization¶
Built-in indicators (SMA, EMA, etc.) support pickle serialization. For custom indicators or third-party objects (for example TA-Lib wrappers), ensure they are pickle-compatible or implement state handling explicitly. For the full custom-indicator workflow, see the Custom Indicator Guide.
4. Notes¶
- Instrument re-registration:
run_from_checkpointauto-registers default instrument info for symbols in new data. If your strategy depends on customlot_sizeormultiplier, verify and override inon_start. Note: if asymbolswhitelist is passed, data for symbols outside it is never loaded at all, so no default instrument registration happens for them either —symbolsmeans "only run these symbols", and anything not in it simply does not exist in this resumed run. - MarketModel reset: Fee settings and trading rules (for example T+1) are not persisted in snapshots. Re-pass them via explicit args or
config.strategy_configon resume, includingcommission_policy/commission_rate, taxes, and transfer-fee settings. - Initial cash display:
result2.metrics.initial_cashis adjusted to resumed-phase starting cash, so phase-2 return metrics remain interpretable. - Data continuity: Keep phase-1 end and phase-2 start continuous to avoid indicator jumps.
get_history()continuity: New snapshots also persist the history buffer, soget_history()andget_history_map()resume with the phase-1 rolling window intact. In the normal warm-start path you no longer need to manually prepend extra lookback bars.- Runtime config injection: Use
strategy_runtime_configinrun_from_checkpointto override runtime behavior at resume. - Strategy-level risk state continuity: Strategy limits, strategy cashflow, daily-loss baseline, drawdown peak, and reduce-only activation state are persisted and restored.
- Default timezone: If
timezoneis not explicitly provided torun_from_checkpoint, default isAsia/Shanghai.
5. Full Example¶
See 21_warm_start_demo.py for a complete runnable example.
class MyStrategy(Strategy):
def on_start(self):
if not self.is_restored:
self.sma = SMA(10)
self.register_precomputed_indicator("sma", self.sma)
# ... run phase 1 ...
save_checkpoint(engine, strategy, "checkpoint.pkl")
# ... run phase 2 ...
run_from_checkpoint("checkpoint.pkl", data_new, ...)
5.x Merging Multi-Phase Results (merge_results)¶
Each segment's BacktestResult only covers its own window. Use merge_results
to stitch multiple segments into one continuous result instead of hand-rolling a
concatenation loop:
import akquant as aq
r1 = aq.run_backtest(data=phase1, strategy=MyStrategy, symbols="X", initial_cash=1e6)
aq.save_checkpoint(r1.engine, r1.strategy, "ckpt.pkl")
r2 = aq.run_from_checkpoint("ckpt.pkl", data=phase2, symbols="X")
merged = aq.merge_results(r1, r2)
print(merged.equity_curve) # full curve across both segments
print(merged.metrics.total_return_pct)
returns = merged.to_quantstats() # feed quantstats for reporting
Notes:
- Segments must be time-ordered and non-overlapping (gaps allowed);
overlapping segments raise
ValueError. dedupe_boundary=True(default) drops duplicated boundary timestamps between adjacent segments.drop_expired_instruments=True(default) removes expired-instrument position rows using each segment's instrument-snapshotexpiry_date, preventing asset blow-up over long ranges.merged.metricsis a core subset (total_return / max_drawdown / sharpe / sortino / calmar / win_rate / profit_factor, matching the single-run definitions). Engine-internal-state metrics are not provided on merged results; read the full 60-field metrics from a single-runBacktestResult.
6. Further Reading¶
- API reference for
run_from_checkpoint: API Reference - Runtime behavior overrides during resume: Runtime Config Guide
- Multi-slot continuity and strategy-level risk mapping: Multi-Strategy Guide