DEV Community

Emily
Emily

Posted on

How to Fix A-Share Backtest Drift Caused by Real-Time API Data Inconsistency

We’ve all been there: an A-share strategy looks stellar in backtesting, then starts throwing random signals as soon as you connect a live feed. In this guide, we’ll walk through how we diagnosed and fixed the root cause—misalignment between historical aggregates and real-time tick synthesis—and how you can build a robust pipeline around your A-share real-time data API.

The Scenario

Our team runs intraday momentum models on A-shares. During backtesting with pre-downloaded minute bars, Sharpe looked great. After switching to a live tick stream, signals shifted by one or two minutes, leading to mistimed entries and exits. The strategy logic was identical. The data wasn’t.

Why Historical and Real-Time Data Diverge

Historical bars come ready-made. Live ticks require you to define bar boundaries. If those boundaries don’t match the historical provider’s rules, you’re effectively trading a different instrument.

Mismatch Consequence
Timestamp formatting Bar sequence jitter
Tick aggregation rules differ Erroneous OHLC values
Adjustment factor handling Discontinuous price series
Field unit discrepancies Miscalibrated indicators

Understanding these differences is the first step to eliminating backtest drift.

Evaluating Real-Time Data Solutions

We compared several approaches:

  • Free public datasets + sporadic tick scrapers: great for offline research, but unreliable for low-latency live aggregation.
  • Broker-specific APIs: functional but tied to trading frontends, with limited flexibility for custom bar engineering.
  • Dedicated market data APIs: services like AllTick provide a clean WebSocket stream with a unified schema, allowing us to bypass normalization scripts and focus on aggregation logic.

The key advantage of a focused API is that it delivers ticks in a predictable format, making it trivial to enforce consistency across your pipeline.

Implementation Guide

1. Unify Time Representation
Convert all timestamps to a common datetime at ingestion.

from datetime import datetime

def convert_time(timestamp):
    return datetime.fromtimestamp(timestamp / 1000)

ts = 1710000000000
trade_time = convert_time(ts)

print(trade_time)
Enter fullscreen mode Exit fullscreen mode

2. Replicate Historical Bar Construction
Implement a minute aggregator that strictly follows natural minute cutoffs. Use the same open/high/low/close extraction logic that your historical dataset employs. This aggregator runs identically for both backtest replay and live processing.

3. Synchronize Adjustment Methods
If your backtest uses forward-adjusted prices, apply the same adjustment factor to live incoming prices before bar synthesis.

4. Insert an Abstraction Layer
Keep your strategy code clean. Build a market data middleware that subscribes to real-time streams, normalizes them, and emits standardized bar events.

import websocket
import json

def on_message(ws, message):
    data = json.loads(message)

    symbol = data.get("symbol")
    price = data.get("price")
    timestamp = data.get("timestamp")

    print(symbol, price, timestamp)

ws = websocket.WebSocketApp(
    "wss://api.alltick.co/stock/websocket",
    on_message=on_message
)

ws.run_forever()
Enter fullscreen mode Exit fullscreen mode

With these four pillars, our strategy’s live simulation finally matched its historical profile. An A-share real-time data API is just the starting point; the real work is building the governance layer that makes your data trustworthy. Invest in the pipeline, and your strategies will reward you.

Top comments (0)