Skip to main content

Migrating from zipline

You have an existing zipline pipeline + algorithm and want to run on MTS1B. Here's the mapping.

High-level

ziplineMTS1B
Pipeline factor@register("f_X") function returning (T, A) ndarray
BeforeTradingStartFuncNATS 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.ingestmts1b-datalake.flows.ingest
Quantopian risk modelRiskEnvelope
run_algorithmmts1b-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.universe but 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 Pipeline factor into a @register("f_X") function
  • Build a UniversePanel from your data source
  • Convert handle_data into a strategy spec via mts1b_research.strategies.StrategyRegistry
  • Run mts1b_GPUbacktester.run_single for in-sample validation
  • Run mts1b_quantkit.cv.walk_forward for OOS validation
  • Set up FundConfig + RiskEnvelope
  • Test on paper before live

See also