Backtesting
Examples
Complete strategy implementations on different market structures. Each example targets a distinct microstructure effect and demonstrates different SDK features.
Order Flow Imbalance
on_trade · on_market_startNet signed order flow, the cumulative difference between buyer and seller initiated volume, predicts short horizon price movement in limit order markets. Informed traders cluster on one side of the book before prices adjust, creating a measurable directional signal.
This strategy accumulates taker initiated volume per 5 minute market via on_trade, resetting at each new market. When net flow exceeds a directional threshold, it enters in the direction of the imbalance. A single position constraint prevents overexposure.
Cont, R., Kukanov, A. & Stoikov, S. The Price Impact of Order Book Events. Journal of Financial Econometrics 12(1), 2014.
from marketlens import MarketLens, Strategy
class OrderFlowImbalance(Strategy):
def on_market_start(self, ctx, market, book):
self.net_flow = 0.0
self._entered = False
def on_trade(self, ctx, market, book, trade):
sign = 1 if trade.side == "BUY" else -1
self.net_flow += sign * trade.size
if self._entered:
return
if self.net_flow > 2000:
ctx.buy_yes(size=200)
self._entered = True
elif self.net_flow < -2000:
ctx.buy_no(size=200)
self._entered = True
result = MarketLens().backtest(
strategy=OrderFlowImbalance(),
id="btc-up-or-down-5m",
initial_cash=10_000,
after="2026-04-15T01:45:00Z",
before="2026-04-15T01:50:00Z",
)Spot-Implied Divergence
on_book · reference_pricePrice discovery across venues creates persistent lead lag relationships. Centralized exchange spot prices update faster than prediction market order books, producing temporary mispricings in structured markets where the outcome is defined by a strike level.
This strategy compares the CEX reference price via reference_price against the market's strike. When spot already exceeds the strike by 2% but the implied probability remains below 0.70, it buys YES on the expected convergence.
Hasbrouck, J. One Security, Many Markets: Determining the Contributions to Price Discovery. The Journal of Finance 50(4), 1995.
from marketlens import MarketLens, Strategy
class SpotDivergence(Strategy):
def on_market_start(self, ctx, market, book):
self._entered = False
def on_book(self, ctx, market, book):
if self._entered:
return
# spot 2%+ above strike but YES still cheap
if ctx.reference_price() > market.strike * 1.02 and book.midpoint < 0.70:
ctx.buy_yes(size=200)
self._entered = True
result = MarketLens().backtest(
strategy=SpotDivergence(),
id="bitcoin-multi-strikes-hourly",
initial_cash=20_000,
after="2026-04-24T02:30:00Z",
before="2026-04-24T04:00:00Z",
)Inventory-Aware Market Making
on_trade · limit orders · cancel_afterThe Avellaneda Stoikov framework derives optimal bid and ask quotes for a market maker facing inventory risk. Quotes are placed symmetrically around the midpoint and skewed linearly by current inventory to penalize adverse accumulation.
On each trade, all existing orders are cancelled via cancel_all and replaced. Limit orders expire after 60 seconds using absolute cancel_after timestamps.
Avellaneda, M. & Stoikov, S. High Frequency Trading in a Limit Order Book. Quantitative Finance 8(3), 2008.
from marketlens import MarketLens, Strategy
class AvellanedaStoikov(Strategy):
HALF_SPREAD = 0.02
SKEW = 0.005
def on_trade(self, ctx, market, book, trade):
ctx.cancel_all()
inv = ctx.position().shares
skew = inv * self.SKEW
bid = book.midpoint - self.HALF_SPREAD - skew
ask = book.midpoint + self.HALF_SPREAD - skew
exp = ctx.time + 60_000
if bid > 0.01:
ctx.buy_yes(size=100, limit_price=bid, cancel_after=exp)
if ask < 0.99 and inv >= 100:
ctx.sell_yes(size=100, limit_price=ask, cancel_after=exp)
result = MarketLens().backtest(
strategy=AvellanedaStoikov(),
id="eth-up-or-down-5m",
initial_cash=10_000,
after="2026-04-15T01:45:00Z",
before="2026-04-15T01:50:00Z",
)Cross-Asset Momentum
on_trade · ctx.books · by_seriesTime series momentum persists across asset classes and strengthens when correlated assets move in unison. In prediction markets, synchronized order book pressure across related underlyings such as ETH and SOL filters noise and isolates regime level directional signals.
This strategy reads all active books via ctx.books and computes 5 level imbalance for each. It enters only when every book agrees on direction, reducing false positives from idiosyncratic flow. Results are disaggregated via by_series.
Moskowitz, T.J., Ooi, Y.H. & Pedersen, L.H. Time Series Momentum. Journal of Financial Economics 104(2), 2012.
from marketlens import MarketLens, Strategy
class CrossAssetMomentum(Strategy):
THRESHOLD = 0.3
def __init__(self):
self._entered: set[str] = set()
def on_trade(self, ctx, market, book, trade):
if market.id in self._entered:
return
imbalances = [
b.imbalance(5) for b in ctx.books.values()
if b.imbalance(5) is not None
]
if len(imbalances) < 2:
return
if all(i > self.THRESHOLD for i in imbalances):
ctx.buy_yes(size=100, market_id=market.id)
self._entered.add(market.id)
elif all(i < -self.THRESHOLD for i in imbalances):
ctx.buy_no(size=100, market_id=market.id)
self._entered.add(market.id)
result = MarketLens().backtest(
strategy=CrossAssetMomentum(),
id=["eth-up-or-down-5m", "sol-up-or-down-5m"],
initial_cash=20_000,
after="2026-04-15T01:45:00Z",
before="2026-04-15T01:50:00Z",
)
for sid, m in result.by_series().items():
print(sid, m["total_pnl"])