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
def on_trade(self, ctx, market, book, trade):
sign = 1 if trade.side == "BUY" else -1
self.net_flow += sign * float(trade.size)
if ctx.position().shares:
return
if self.net_flow > 2000:
ctx.buy_yes(size="200")
elif self.net_flow < -2000:
ctx.buy_no(size="200")
result = MarketLens().backtest(
strategy=OrderFlowImbalance(),
id="btc-up-or-down-5m",
initial_cash="10000",
)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_book(self, ctx, market, book):
if ctx.position().shares or book.midpoint is None:
return
ref = ctx.reference_price()
if ref is None or market.strike is None:
return
spot, strike = float(ref), float(market.strike)
mid = float(book.midpoint)
# spot 2%+ above strike but YES still cheap
if spot > strike * 1.02 and mid < 0.70:
ctx.buy_yes(size="200")
result = MarketLens().backtest(
strategy=SpotDivergence(),
id="bitcoin-multi-strikes-daily",
initial_cash="20000",
)Inventory-Aware Market Making
on_book · 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 book update, all existing orders are cancelled via cancel_all and replaced. Limit orders expire after 60 seconds using absolute cancel_after timestamps. The queue_position=True flag enables realistic queue priority simulation for passive fills.
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_book(self, ctx, market, book):
ctx.cancel_all()
if book.midpoint is None:
return
mid = float(book.midpoint)
inv = float(ctx.position().shares or "0")
skew = inv * self.SKEW
bid = mid - self.HALF_SPREAD - skew
ask = mid + self.HALF_SPREAD - skew
exp = ctx.time + 60_000
if bid > 0.01:
ctx.buy_yes(size="100", limit_price=f"{bid:.4f}",
cancel_after=exp)
if ask < 0.99:
ctx.sell_yes(size="100", limit_price=f"{ask:.4f}",
cancel_after=exp)
result = MarketLens().backtest(
strategy=AvellanedaStoikov(),
id="eth-up-or-down-5m",
initial_cash="10000",
queue_position=True,
)Cross-Asset Momentum
on_book · 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 on_book(self, ctx, market, book):
if ctx.position(market.id).shares:
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)
elif all(i < -self.THRESHOLD for i in imbalances):
ctx.buy_no(size="100", market_id=market.id)
result = MarketLens().backtest(
strategy=CrossAssetMomentum(),
id=["eth-up-or-down-5m", "sol-up-or-down-5m"],
initial_cash="20000",
)
for sid, m in result.by_series().items():
print(sid, m["total_pnl"])