Quickstart
A working backtest in under 5 minutes
Copy, paste, run
python
import horizon as hz
from horizon.asset_classes import AssetClass, Equity
from horizon.data import SyntheticGBM
from horizon.discovery import StaticUniverse
from horizon.discovery.base import Market
from horizon.portfolio import KellyOptimizer
from horizon.quant import BollingerMeanRev
from horizon.risk import RiskProfile
result = hz.run(
mode="backtest",
strategies=[BollingerMeanRev(window=20, entry_z=2.0)],
asset_classes=[Equity],
universe=StaticUniverse([
Market(id=t, asset_class=AssetClass.Equity)
for t in ["AAPL", "MSFT", "NVDA", "GOOGL", "AMZN"]
]),
portfolio=KellyOptimizer(kelly_fraction=0.25, max_gross_leverage=1.0),
risk=RiskProfile.moderate(),
data_source=SyntheticGBM(
market_ids=["AAPL", "MSFT", "NVDA", "GOOGL", "AMZN"],
n_bars=252,
seed=42,
),
backtest=hz.BacktestConfig(initial_cash_usd=100_000),
)
print(f"Sharpe: {result.sharpe:+.3f}")
print(f"Total return: {result.total_return:+.2%}")
print(f"Max drawdown: {result.max_drawdown:.2%}")
print(f"Trades: {result.n_trades}")
Save as first.py and run:
bash
PYTHONPATH=. python3 first.py
That’s a full 252-bar, 5-equity backtest with Kelly sizing, Bollinger z-score signals, and a moderate risk profile. Every layer of the pipeline fired on every tick.
What just happened
On each tick:
SyntheticGBMfed a price bar for each tickerFeatureStoreupdated rolling histories and computed Bollinger z-scoresBollingerMeanRevchecked if any z-score crossed ±2, emitting signals in the opposite directionKellyOptimizersized each signal usingedge / vol², scaled by the 0.25 Kelly fractionEquityExecutorconverted dollar targets to share quantitiesRiskProfile.moderate()checked every order against stops, drawdown guards, and notional caps- The paper venue matched orders, applied fees, and updated positions
Add custom risk controls
Replace RiskProfile.moderate() with explicit config:
python
from horizon.risk import DrawdownGuard, RiskConfig, StopLoss
from horizon.risk.drawdown import DrawdownAction
risk=RiskConfig(
max_gross_leverage=1.0,
stop_loss=StopLoss(per_position_pct=0.05),
drawdown=[
DrawdownGuard(daily_pct=0.05, action=DrawdownAction.HaltNew),
DrawdownGuard(weekly_pct=0.10, action=DrawdownAction.ReduceHalf),
DrawdownGuard(monthly_pct=0.20, action=DrawdownAction.Flatten),
],
)
- 5% stop loss closes positions that lose 5% of cost
- 5% daily drawdown halts new entries
- 10% weekly cuts every position in half
- 20% monthly flattens everything
Compare result.max_drawdown with and without these guards.
Swap strategies
python
from horizon.quant import TSMomentum, MovingAverageCrossStrategy, RSIMeanRev
# Time-series momentum
strategies=[TSMomentum(lookback=20)]
# Moving average crossover
strategies=[MovingAverageCrossStrategy(fast=10, slow=30)]
# RSI mean reversion
strategies=[RSIMeanRev(window=14)]
# Run all at once: the portfolio optimizer sees the combined signal list
strategies=[
TSMomentum(lookback=20),
BollingerMeanRev(window=15),
MovingAverageCrossStrategy(fast=10, slow=30),
RSIMeanRev(window=14),
]
Run a preset instead
bash
PYTHONPATH=. python3 -m horizon.cli run equity_mean_reversion
Zero Python written. See Presets & CLI for how to build your own.