Horizon

Multi-asset trading pipeline for equities, options, perps, and prediction markets

Horizon is a Python trading framework. You write a strategy that returns opinions about markets. Horizon handles sizing, risk, and execution. The same code runs in backtest, paper, and live.

The idea

Most trading libraries have you write a function that takes prices and returns orders. That works, but it collapses three separate problems into one:

  1. Is my signal right? (do I have edge?)
  2. Am I sizing correctly? (Kelly, vol-target, equal-weight?)
  3. Am I executing well? (slippage, fill quality?)

When a strategy loses money, you can’t tell which part failed. Horizon keeps them apart so you can test each one independently.

How it works

Your strategy looks at features (z-scores, RSI, moving averages, volatility) and returns Signal objects: direction, confidence, expected edge, horizon. That’s it. You never touch order sizes or prices.

From there, the pipeline takes over:

  1. Features compute from rolling price history
  2. Strategy reads features, returns signals
  3. Portfolio sizer converts signals to target dollar amounts (Kelly, Carver, or equal-weight)
  4. Execution translates dollar targets to orders for the right asset class
  5. Risk engine checks every order against 7 layers of protection
  6. Venue receives the order (paper, or a real broker)

Each step is a separate module you can swap or customize.

Quickest taste

python
import horizon as hz
from horizon.quant import BollingerMeanRev
from horizon.portfolio import KellyOptimizer
from horizon.risk import RiskProfile

result = hz.run(
    mode="backtest",
    strategies=[BollingerMeanRev(window=20, entry_z=2.0)],
    portfolio=KellyOptimizer(kelly_fraction=0.25),
    risk=RiskProfile.moderate(),
    # ... universe + data source (see Quickstart)
)

print(f"Sharpe: {result.sharpe:+.3f}")
print(f"Max DD: {result.max_drawdown:.2%}")

Swap BollingerMeanRev for TSMomentum, or your own Strategy subclass. Swap KellyOptimizer for CarverSystematic. Swap RiskProfile.moderate() for a custom RiskConfig. The pipeline stays the same.

What’s included

Where to start