What still feels familiar
The core strategy shape is the same:- Store persistent strategy state on
context. - Use
handle_datafor per-bar trading logic. - Use
schedule_functionfor periodic rebalances. - Use
recordfor custom metrics. - Use target order helpers for rebalancing.
Quick conversion table
| Classic Zipline pattern | Ziplime pattern |
|---|---|
from zipline.api import symbol | Prefer await context.symbol(...) inside initialize. |
asset = symbol("AAPL") | asset = await context.symbol("AAPL") |
symbols("AAPL", "MSFT") | [await context.symbol(s) for s in ["AAPL", "MSFT"]] |
data.current(asset, "close") | (await data.current(assets=[asset], fields=["close"]))["close"][0] |
data.history(asset, "close", 20, "1d") | await data.history(assets=[asset], fields=["close"], bar_count=20) |
order(asset, 100) | await context.order(asset, 100, style=MarketOrder()) |
order_target_percent(asset, 0.5) | await context.order_target_percent(asset, 0.5, style=MarketOrder()) |
| Pandas results from data access | Polars data frames from data.current and data.history. |
Synchronous handle_data | async def handle_data(...) and await async API calls. |
run_algorithm(...) with in-memory data | run_simulation(...) with loaded Ziplime bundles and services. |
Imports
Classic Zipline algorithms often import many API functions:context calls and import only helper classes:
ziplime.api namespace exists for compatibility, but direct context calls are easier to read in async code:
Lifecycle functions
initialize
Classic Zipline:
initialize to look up assets, set strategy parameters, register scheduled callbacks, attach pipelines, and configure controls.
handle_data
Classic Zipline:
before_trading_start
Classic Zipline used a synchronous before_trading_start. Ziplime currently does the same.
async def in the current Ziplime runtime. Do not place orders in this hook.
analyze
Classic Zipline usually passed a performance DataFrame to analyze. Ziplime also calls analyze synchronously with the final performance table.
Market data differences
Classic Zipline allowed scalar-style calls:Order differences
Classic Zipline often allowed:Symbol lookup
Classic Zipline usually resolved symbols from an asset database with the simulation lookup date. Ziplime resolves symbols through its asset service:mic or use the SYMBOL@MIC form.
For named universes:
Scheduling
Classic Zipline:Portfolio and positions
Classic Zipline commonly used:Recording metrics
This part is close to Zipline:Pipeline migration
Ziplime includes a Zipline-like Pipeline API:initialize:
EquityPricing is the standard path; custom datasets require custom loaders.
Running migrated algorithms
Classic Zipline examples often callrun_algorithm(...) directly with pandas data or bundle names.
Ziplime’s standard flow is:
- Ingest or load data into a Ziplime bundle.
- Load the bundle with
bundle_service.load_bundle(...). - Pass the loaded data source to
run_simulation(...). - Point
algorithm_fileat the migrated.pystrategy file.
Full before and after
Classic Zipline:Migration checklist
- Replace
zipline.apiimports with directcontextcalls and Ziplime helper imports. - Make
initialize,handle_data, and scheduled callbacks async. - Add
awaitto asset lookup, data access, order placement, and order cancellation. - Pass lists to
data.currentanddata.history. - Update pandas assumptions to Polars or call
.to_pandas()explicitly. - Add an execution style such as
MarketOrder()to order calls. - Use
def before_trading_start, notasync def before_trading_start. - Use
def analyze, notasync def analyze. - Replace direct
portfolio.positions[asset]access with portfolio helper methods. - Pass MIC codes for ambiguous symbols.
- Move runner setup to
run_simulation(...)with Ziplime data bundles.