Migrating from zipline
You have an existing zipline pipeline + algorithm and want to run on MTS1B. Here's the mapping.
High-level
| zipline | MTS1B |
|---|---|
Pipeline factor | @register("f_X") function returning (T, A) ndarray |
BeforeTradingStartFunc | NATS subscriber on mts.v1.marketdata.bars.* |
handle_data(context, data) | mts1b-research/live_executor |
context.order_target_percent(...) | Build target weights → mts1b-oms.submit(Order) |
record(...) | mts1b-platform.observability metrics |
bundle.ingest | mts1b-datalake.flows.ingest |
Quantopian risk model | RiskEnvelope |
run_algorithm | mts1b-GPUbacktester.run_single |
Example: SimpleAlgorithm port
In zipline
from zipline.api import order_target_percent, symbol
from zipline.pipeline import Pipeline
from zipline.pipeline.factors import SimpleMovingAverage
def make_pipeline():
sma_20 = SimpleMovingAverage(window_length=20)
sma_50 = SimpleMovingAverage(window_length=50)
return Pipeline(columns={"sma_20": sma_20, "sma_50": sma_50})
def initialize(context):
context.spy = symbol("SPY")
def handle_data(context, data):
df = pipeline_output("my_pipeline")
if df.loc[context.spy, "sma_20"] > df.loc[context.spy, "sma_50"]:
order_target_percent(context.spy, 1.0)
else:
order_target_percent(context.spy, 0.0)
In MTS1B
import numpy as np
from mts1b_quantkit.factors import register, zscore_cross_sectional
from mts1b_foundation.market_data import UniversePanel
@register("f_sma_cross")
def f_sma_cross(panel: UniversePanel, /, fast: int = 20, slow: int = 50) -> np.ndarray:
"""Long when fast SMA > slow SMA, flat otherwise."""
close = panel.close # (T, A)
sma_fast = np.array([close[max(0, t-fast):t].mean(axis=0)
for t in range(len(close))])
sma_slow = np.array([close[max(0, t-slow):t].mean(axis=0)
for t in range(len(close))])
return (sma_fast > sma_slow).astype(float)
# Backtest
from mts1b_GPUbacktester import run_single
from mts1b_quantkit.factors import get
result = run_single(
factor=get("f_sma_cross"),
params={"fast": 20, "slow": 50},
universe=["SPY"], # equivalent to zipline single-symbol
start="2014-01-01", end="2024-01-01",
rebal="daily",
sizing={"method": "fixed_weight", "weights": {"SPY": 1.0}},
cost_bps=10,
)
Key differences
Pipeline vs cross-sectional factor
zipline's Pipeline returns a DataFrame keyed by (date, asset). MTS1B factors return a (T, A) ndarray.
Mapping:
# zipline
df = pipeline_output("my_pipe")
df.loc[asset, "sma_20"] # per-cell access
# MTS1B
panel = lake.build_panel(...)
factor_output = my_factor(panel)
factor_output[-1, panel.symbols.index("SPY")] # equivalent access
order_target_percent → target weights
# zipline
order_target_percent(symbol("AAPL"), 0.10)
# MTS1B: emit a target weight; OMS computes orders
weights = {"AAPL": 0.10} # 10% of NAV
# (live_executor handles the rest)
Quantopian risk model → RiskEnvelope
zipline's Quantopian risk model constrained sector / size / momentum exposure.
In MTS1B:
envelope = RiskEnvelope(
envelope_id="env-1",
fund_id="paper-momentum",
nav_usd=Decimal("100000"),
max_position_pct=0.10,
max_sector_pct=0.30,
max_asset_class_pct=1.0,
daily_loss_halt_pct=0.03,
allowed_brokers=["paper"],
created_at=datetime.now(timezone.utc),
)
For factor-exposure neutralization (beta-neutral, size-neutral), use mts1b-portfolio.multi_sleeve.compose to balance factor sleeves.
Data ingest
# zipline
$ zipline ingest -b quantopian-quandl
# MTS1B
$ mts1b-datalake flow run --name equities_daily_bars
Bundles → Prefect flows. Same idea: pull data from a provider and persist to a local store. MTS1B uses parquet; zipline used HDF5.
What MTS1B does better than zipline
- Cross-sectional factor APIs (not per-symbol)
- GPU acceleration
- Multi-asset (zipline was equities-only)
- Live trading + risk gates (zipline was Quantopian-only)
- Per-repo SemVer + Apache 2.0 (zipline is essentially unmaintained)
What's missing in MTS1B (vs zipline at its peak)
- Quantopian's "Q500US/Q1500US" curated universe definitions (MTS1B has
lake.equities.universebut you build your own filters) - Quantopian's research community knowledge base (we have docs, but not 10k notebooks of community examples)
- Quantopian's specific risk models (we have HRP/BL/Markowitz; not their exact factor-tilt model)
If you need a specific Quantopian factor, port it to MTS1B as a registered f_X function.
Migration checklist
- Convert each
Pipelinefactor into a@register("f_X")function - Build a
UniversePanelfrom your data source - Convert
handle_datainto a strategy spec viamts1b_research.strategies.StrategyRegistry - Run
mts1b_GPUbacktester.run_singlefor in-sample validation - Run
mts1b_quantkit.cv.walk_forwardfor OOS validation - Set up
FundConfig+RiskEnvelope - Test on paper before live