Quick Mode
Chain the full pipeline with a fluent builder. Same power, less ceremony.
Quick Mode gives you two ways to use Horizon with less boilerplate:
hz.pipe()- a fluent builder that chains the full pipeline. Same objects, same power, just easier to compose.hz.quick.backtest()- one-liner backtests for fast exploration.
Neither loses any capability. They both call hz.run() underneath.
The pipe builder
Chain markets, strategies, sizers, and risk into a single expression:
import horizon as hz
from horizon.quant import BollingerMeanRev, TSMomentum
from horizon.portfolio import KellyOptimizer
result = (hz.pipe("AAPL", "MSFT", "NVDA")
.strategy(BollingerMeanRev(window=20))
.strategy(TSMomentum(lookback=20))
.kelly(fraction=0.25)
.stop_loss(pct=0.05)
.drawdown(daily=0.03, weekly=0.08, monthly=0.15)
.run(bars=252, cash=100_000)
)
print(f"Sharpe: {result.sharpe:+.3f}")
Every method returns the builder, so you chain. Every method accepts the real objects from the library, so you keep full control.
What you can chain
Markets
hz.pipe("AAPL", "MSFT") # equities by default
hz.pipe().equities("AAPL", "MSFT") # explicit
hz.pipe().predictions("TRUMP-2028") # prediction markets
hz.pipe().crypto("BTC-PERP", "ETH-PERP") # crypto/perps
hz.pipe().options("AAPL:2026-06:call:200") # options
# Mix asset classes
(hz.pipe()
.equities("AAPL", "MSFT", "NVDA")
.predictions("TRUMP-2028", "FED-CUT")
.crypto("BTC-PERP")
...)
Strategies
.strategy(BollingerMeanRev(window=20)) # pass any Strategy instance
.strategy(TSMomentum(lookback=20)) # chain multiple
.strategy(RSIMeanRev(window=14)) # they all run together
.strategy(MyCustomStrategy()) # your own classes work too
Sizing
.kelly(fraction=0.25) # Kelly with fraction
.kelly(fraction=0.25, max_leverage=1.5, cost_bps=5) # with all params
.carver(vol_target=0.15, buffering=True) # Carver vol targeting
.equal_weight(max_positions=20) # equal weight baseline
.sizer(MyCustomSizer()) # any Sizer instance
.leverage(2.0) # set max leverage separately
Risk
.stop_loss(pct=0.05) # 5% per-position stop
.stop_loss(pct=0.05, trailing=0.08) # with trailing
.drawdown(daily=0.03, weekly=0.08, monthly=0.15) # stacked guards
.moderate_risk() # preset
.conservative_risk() # preset
.risk(my_risk_config) # pass a full RiskConfig
Data
.data(SyntheticRegimes(...)) # custom data source
.data(my_csv_source) # any DataSource
.seed(42) # set random seed
Run
.run() # defaults: 252 bars, $100k
.run(bars=500, cash=200_000) # override
.run(seed=7) # different random path
Multi-asset example
from horizon.quant import BollingerMeanRev, TSMomentum
result = (hz.pipe()
.equities("AAPL", "MSFT", "NVDA", "JPM", "GS")
.predictions("TRUMP-2028", "FED-CUT")
.crypto("BTC-PERP", "ETH-PERP")
.strategy(BollingerMeanRev(window=20))
.strategy(TSMomentum(lookback=20))
.kelly(fraction=0.25, max_leverage=1.5)
.stop_loss(pct=0.06)
.drawdown(daily=0.03, weekly=0.07, monthly=0.12)
.run(bars=500, cash=500_000)
)
Each strategy only sees its declared asset classes. The sizer allocates across everything. The risk engine protects the whole portfolio.
Quick backtest (one-liners)
For even faster exploration, hz.quick lets you skip imports entirely:
# Built-in strategy by name
result = hz.quick.backtest("mean_reversion", tickers=["AAPL", "MSFT"])
# Custom logic as a plain function
result = hz.quick.backtest(
lambda prices: {"AAPL": "buy"} if prices["AAPL"].zscore < -2 else {},
tickers=["AAPL"],
)
# Compare strategies
report = hz.quick.compare(["mean_reversion", "momentum", "rsi"])
print(report.summary())
# Parameter scan
scan = hz.quick.scan("mean_reversion",
params={"window": [10, 20, 30], "entry_z": [1.5, 2.0, 2.5]})
print(f"Best: {scan.best_params}")
Pipe vs Quick vs Full pipeline
hz.pipe() | hz.quick.backtest() | hz.run() | |
|---|---|---|---|
| Strategy | Real objects | String name or function | Real objects |
| Sizer | Real objects or shorthand | String name | Real objects |
| Risk | Chainable or real objects | String name | RiskConfig |
| Asset classes | .equities(), .crypto(), etc. | Auto (equities only) | Explicit list |
| Data | Any DataSource | Auto synthetic | Any DataSource |
| Custom code | Full access | Limited | Full access |
| Chaining | Yes | No | No |
| Best for | Building and iterating | One-line experiments | Production configs |
hz.pipe() is the sweet spot: you get chaining and convenience without giving up any capability.
Dropping down
Every pipe chain has an equivalent hz.run() call. When you need something the builder doesn’t cover (custom executors, lifecycle events, dashboard mode), drop to hz.run() directly.