Quant Python: Architecting Autonomous Trading Systems

Quant Python: Architecting Autonomous Trading Systems

Day 46 — External Ingestion: Feeding Price Data to the MockBroker

Python Quant's avatar
Python Quant
May 07, 2026
∙ Paid

This lesson covers one of the most misunderstood parts of building a trading system: how price data actually gets in. You will learn why the obvious approach fails, how professional systems handle it, and you will build a working version from scratch.


The “REST Polling” Trap

A junior engineer opens the Alpaca docs, sees a clean REST endpoint, and writes this:

import requests, time

while True:
    r = requests.get(
        "https://data.alpaca.markets/v2/stocks/SPY/quotes/latest",
        headers={"APCA-API-KEY-ID": key, "APCA-API-SECRET-KEY": secret}
    )
    price = r.json()["quote"]["ap"]
    broker.update_price("SPY", price)
    time.sleep(1)

This pattern appears in every beginner tutorial. It will ruin a live account. Here is why.


The Failure Mode

Symptom 1 — Rate Limit Collapse. Alpaca’s free tier enforces 200 requests/min per endpoint. That sounds generous — until you are polling 20 symbols at 1-second intervals. You hit the ceiling in 10 seconds. The API returns 429 Too Many Requests. Your loop swallows it silently (no error handling), continues with a stale price, and sends an order at a quote that is now 8 seconds old.

Symptom 2 — Synchronous I/O Blocks Your Event Loop. requests.get() is a blocking call. It holds the GIL for the duration of the network round trip — typically 20–150ms to Alpaca’s servers. While that call is blocking, your order matching logic, risk checks, and P&L recalculation are all frozen. During a volatility spike, when you most need sub-millisecond responsiveness, you are dead in the water.

Symptom 3 — Unbounded Memory Growth. Storing every tick: self.ticks.append(price). For 4 symbols at 10 ticks/second gives 144,000 entries per hour. Over a 6.5-hour session: roughly 936,000 floats. Python’s float is 28 bytes under object model overhead. That is 26MB — manageable today, catastrophic when you scale to 50 symbols.

Symptom 4 — Clock Skew on Staleness Checks. Using datetime.now() for staleness detection breaks under NTP clock adjustments. If your server syncs and the wall clock jumps backward by 50ms, your “5-second stale threshold” logic fires incorrectly. Use time.monotonic() — it is guaranteed to never go backward.

The actual kill shot is that none of these failures throw exceptions. They silently corrupt your price state. An order fills at yesterday’s bid. Your P&L attribution is wrong. You do not know until reconciliation — if you built reconciliation at all.


User's avatar

Continue reading this post for free, courtesy of Python Quant.

Or purchase a paid subscription.
© 2026 Python Quant · Privacy ∙ Terms ∙ Collection notice
Start your SubstackGet the app
Substack is the home for great culture