
In real-time forex trading systems, subscribing to multiple currency pairs seems like a simple scalability feature. However, once deployed in production, a subtle but critical issue quickly emerges: data out-of-order delivery.
Especially in high-frequency streaming scenarios—such as simultaneously subscribing to EURUSD, GBPUSD, and USDJPY—you will find that data within the same time window does not arrive in strict chronological order. Instead, it is affected by network latency, server-side parallelism, and client-side scheduling.
At first glance, it looks like a minor sequencing issue. But in trading systems, it can directly impact:
- Incorrect candlestick generation
- Misaligned indicator calculations
- Abnormal quoting behavior in market making strategies
- False risk triggers
At its core, this is not a “data problem”, but a consistency problem in streaming systems.
1. The Nature of Multi-Currency Subscription: One Connection, Multiple Time Streams
In most Forex APIs, real-time WebSocket design follows a “single connection, multiple subscriptions” model:
- One TCP connection
- Multiple symbols subscribed simultaneously
- Server pushes data concurrently for different currency pairs
For example:
- EURUSD: high update frequency
- GBPUSD: volatile and bursty
- USDJPY: liquidity concentrated in specific sessions
These streams are generated in parallel on the server side but merged into a single message stream on the client side.
This creates a fundamental issue:
Multiple independent timelines are forced into a single-threaded message queue.
As a result, data order becomes unreliable.
2. How Does Out-of-Order Data Occur?
Out-of-order delivery typically comes from four layers:
2.1. Network Jitter
TCP guarantees reliability, not business-level ordering.
Packets may:
- Take different routing paths
- Experience varying queue delays
- Be acknowledged in batches
Result: later-generated data may arrive earlier.
2.2. Server-Side Parallel Publishing
Market data servers are typically multi-threaded:
- Symbol A generated in thread 1
- Symbol B generated in thread 2
Publishing is merged into a queue, not strictly time-sorted.
2.3. Client Event Loop Scheduling
In Python/Node.js WebSocket clients:
- IO thread ≠ business thread
- Callback execution is asynchronous
- Processing delays exist
Thus:
Arrival order ≠ generation order ≠ timestamp order
2.4. Shared Buffer Queue Across Symbols
A naive implementation often uses:
All symbols → one on_message → one queue
This destroys structural ordering entirely.
3. Real Impact of Out-of-Order Data
Out-of-order data is not just cosmetic—it breaks trading logic:
3.1. Incorrect Candlestick Formation
For 1-second candles:
- Tick B arrives first
- Tick A arrives later
Result: OHLC values become incorrect.
3.2. Distorted Momentum Signals
Short-term strategies rely on sequence:
- return(t) vs return(t-1)
If order is broken:
Momentum signals become noise-contaminated.
3.3. Abnormal Market Making Quotes
If quote updates are misordered:
- Spread widens artificially
- Mid-price becomes unstable
- Hedging triggers incorrectly
4. Core Solution: Decouple Time from Message Order
The key is not to “prevent disorder”, but to:
Reconstruct deterministic order on the client side.
Three key fields are used:
- timestamp
- seq_id
- symbol
5. Engineering Solution: Three-Layer Reordering Architecture
Layer 1: Separate Streams by Symbol
Never mix all symbols into one queue:
streams = {
"EURUSD": Queue(),
"GBPUSD": Queue(),
"USDJPY": Queue()
}
Each currency pair maintains its own timeline.
Layer 2: Introduce Time Window Buffering
Use a short buffer per symbol:
BUFFER_MS = 200
Logic:
- Receive tick
- Do not consume immediately
- Store in buffer
- Sort by timestamp before output
Layer 3: Monotonic Sequence Validation
If API provides seq_id:
last_seq = {}
def check_order(symbol, tick):
seq = tick["seq"]
if symbol not in last_seq:
last_seq[symbol] = seq
return True
if seq > last_seq[symbol]:
last_seq[symbol] = seq
return True
return False
This filters most replay or delayed packets.
6. Production-Grade WebSocket Subscription Example
A more realistic multi-symbol structure:
import websocket
import json
import uuid
import time
from collections import defaultdict, deque
API_KEY = "YOUR_API_KEY"
WS_URL = f"wss://quote.alltick.co/quote-b-ws-api?token={API_KEY}"
SYMBOLS = ["EURUSD", "GBPUSD", "USDJPY"]
buffers = defaultdict(deque)
last_seq = {}
def subscribe_msg():
return {
"cmd_id": 22004,
"seq_id": int(time.time()),
"trace": str(uuid.uuid4()),
"data": {
"symbol_list": [{"code": s} for s in SYMBOLS]
}
}
def on_open(ws):
ws.send(json.dumps(subscribe_msg()))
def process_tick(symbol, tick):
seq = tick.get("seq")
if seq is not None:
if symbol in last_seq and seq <= last_seq[symbol]:
return
last_seq[symbol] = seq
buffers[symbol].append(tick)
def on_message(ws, message):
msg = json.loads(message)
if msg.get("cmd_id") == 22998:
tick = msg["data"]
symbol = tick["code"]
process_tick(symbol, tick)
def start():
ws = websocket.WebSocketApp(
WS_URL,
on_open=on_open,
on_message=on_message
)
ws.run_forever(ping_interval=10)
if __name__ == "__main__":
start()
7. Why Forex Is More Prone to Out-of-Order Than Crypto
Compared to crypto markets, forex APIs have unique characteristics:
7.1. Distributed liquidity providers
Quotes come from multiple LPs
7.2. Uneven update frequency
EURUSD vs exotic pairs behave very differently
7.3. Session-based volatility
Asian / London / US sessions
Result:
Data behaves like intermittent bursts, not continuous flow.
8. Advanced Direction: From Ordering Fix to Event-Time Systems
Advanced systems go beyond reordering:
Event-time processing
Not arrival-time, but event-time
Watermarking
Allow bounded lateness:
- Accept late ticks within window
- Drop beyond threshold
Symbol-level clock synchronization
Align multiple instruments into a unified time framework
9. When the System Stabilizes
Once ordering issues are properly handled, market data transforms:
- EURUSD stops “jumping”
- GBPUSD stops “spiking randomly”
- USDJPY becomes structurally stable
What emerges is no longer a raw data stream, but a structured temporal system:
- Each symbol has its own rhythm
- Each tick has a deterministic position
- Every movement becomes traceable
On top of this foundation, trading systems—whether market making, arbitrage, or risk control—can operate reliably.
And infrastructures like AllTick API provide not just market data, but an engineering-grade real-time time-stream layer.


