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:

python
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

python
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

python
.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

python
.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

python
.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

python
.data(SyntheticRegimes(...))                # custom data source
.data(my_csv_source)                        # any DataSource
.seed(42)                                   # set random seed

Run

python
.run()                                      # defaults: 252 bars, $100k
.run(bars=500, cash=200_000)                # override
.run(seed=7)                                # different random path

Multi-asset example

python
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:

python
# 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()
StrategyReal objectsString name or functionReal objects
SizerReal objects or shorthandString nameReal objects
RiskChainable or real objectsString nameRiskConfig
Asset classes.equities(), .crypto(), etc.Auto (equities only)Explicit list
DataAny DataSourceAuto syntheticAny DataSource
Custom codeFull accessLimitedFull access
ChainingYesNoNo
Best forBuilding and iteratingOne-line experimentsProduction 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.

Next