BacktestConfig
Every field of the backtest configuration dataclass
BacktestConfig is a nested dataclass passed to hz.run(mode="backtest", backtest=...). Every field controls some aspect of the simulation.
Import
python
from horizon import BacktestConfig
Full field list
python
@dataclass
class BacktestConfig:
# Time window
start: str = "" # "YYYY-MM-DD"
end: str = ""
initial_cash_usd: float = 100_000.0
# Per-asset-class data sources (optional. when None, use a default)
data_sources: dict[AssetClass, Any] = field(default_factory=dict)
# Fill and fee models
fill_model: Any = field(default_factory=RealisticFill)
fee_model: Any = field(default_factory=TieredFees)
# Tick mechanics
tick_resolution: str = "1s"
warmup_period: str = "60d"
# Output
save_to: str = ""
snapshot_equity_every: str = "1d"
save_signals: bool = True
save_features: bool = False
# Per-venue budget overrides
venue_budgets: dict[str, float] = field(default_factory=dict)
Time window
startstrISO date string (`"2023-01-01"`). Backtest begins from this date.
endstrISO date string. Backtest stops here.
initial_cash_usdfloatStarting equity. The ledger initializes with this cash and P&L accumulates from here. All risk limits and Kelly sizing compound from this base.
Data sources (per asset class)
python
from horizon.asset_classes import Equity, Option, Prediction
from horizon.data import SyntheticGBM
bt = BacktestConfig(
initial_cash_usd=100_000,
data_sources={
Equity: SyntheticGBM(["AAPL", "MSFT"], n_bars=252, seed=42),
# Option: historical_options_source(...),
# Prediction: polymarket_historical_source(...),
},
)
In the current Horizon implementation, you can also pass a single data_source directly to hz.run(): the per-asset-class dict is the future-proof path when mixing multiple asset classes in one backtest.
Fill model
python
@dataclass
class RealisticFill:
latency_ms: int = 200 # simulated order → fill delay
slippage_bps: float = 2.0 # marketable orders pay half-spread + slippage
reject_prob: float = 0.01 # random order rejection probability
partial_fill_prob: float = 0.10 # probability of partial fill on limit orders
spread_as_cost: bool = True # treat the spread as a trading cost
Fee model
python
@dataclass
class TieredFees:
equity: Any = field(default_factory=PerShareFee)
option: Any = field(default_factory=PerContractFee)
prediction: Any = field(default_factory=lambda: PercentageFee(pct=0.02))
perp: Any = field(default_factory=lambda: PercentageFee(pct=0.0005))
Individual fee models:
python
@dataclass
class PerShareFee:
fee_per_share: float = 0.005
min_per_order: float = 1.0
@dataclass
class PerContractFee:
fee_per_contract: float = 0.65
@dataclass
class PercentageFee:
pct: float = 0.02
Defaults reflect approximate retail rates:
- Equity: $0.005/share, $1 minimum (typical for IBKR tiered)
- Option: $0.65/contract (typical for most retail brokers)
- Prediction: 2% (Polymarket)
- Perp: 5 bps (Hyperliquid taker)
Override per asset class:
python
bt = BacktestConfig(
fee_model=TieredFees(
equity=PerShareFee(fee_per_share=0.003), # lower than default
prediction=PercentageFee(pct=0.01), # assume cheaper venue
),
)
Tick mechanics
tick_resolutionstrSimulated clock step. Metadata today; will be enforced in a future version. Common values: `"1s"`, `"1m"`, `"1h"`, `"1d"`.
warmup_periodstrHow much history to preload before the first strategy evaluation. Prevents features from returning NaN for the first `window` bars.
Output controls
save_tostrPath to save results. Empty = no save.
snapshot_equity_everystrHow often to snapshot the equity curve. `"1d"` keeps one point per day; `"1h"` keeps hourly.
save_signalsboolLog every signal emitted during the backtest. Essential for post-hoc IC / feature-importance analysis.
save_featuresboolLog feature values per tick. Larger disk footprint (grows with n_features × n_bars × n_markets). Off by default.
Venue budgets
python
bt = BacktestConfig(
initial_cash_usd=100_000,
venue_budgets={
"alpaca": 60_000,
"ibkr": 40_000,
},
)
Per-venue budgets override the default (which allocates all equity to a single venue). Useful for multi-venue backtests where you want to simulate realistic capital allocation.
Minimal example
python
import horizon as hz
result = hz.run(
mode="backtest",
backtest=hz.BacktestConfig(initial_cash_usd=100_000),
strategies=[...],
data_source=...,
...
)
Full example
python
from horizon import BacktestConfig
from horizon.backtest import RealisticFill, TieredFees, PerShareFee
bt = BacktestConfig(
start="2023-01-01",
end="2024-12-31",
initial_cash_usd=500_000,
fill_model=RealisticFill(
latency_ms=150,
slippage_bps=1.5,
reject_prob=0.005,
),
fee_model=TieredFees(
equity=PerShareFee(fee_per_share=0.003, min_per_order=0.5),
),
tick_resolution="1m",
warmup_period="90d",
save_signals=True,
save_features=True,
venue_budgets={"alpaca": 300_000, "ibkr": 200_000},
)
result = hz.run(mode="backtest", backtest=bt, ...)