The problem
Any application that reads market data hits the same four problems the moment you try to test it:
- Credentials. A key has to reach your laptop, your teammates’ laptops, and CI — secrets management for data that is not secret.
- Rate limits. A test suite that fans out across symbols burns a free-tier quota quickly, and then the build is red for a reason that has nothing to do with your code.
- Closed markets. Today’s bars do not exist at 9pm, and Saturday has no bars at all. A demo rehearsed on Sunday behaves differently on Monday.
- Moving data. Real prices change, so an assertion about a specific close is a test with an expiry date.
None of these are problems with Alpaca. They are the consequence of pointing a live production feed at something that is not production. A mock server fixes all four at once.
The one-line change
CuckooTrade serves Alpaca’s market data wire format at
https://cuckootrade.com/api/v1/alpaca.
alpaca-py already supports pointing at a different host
through url_override, so the whole integration is that
argument:
from datetime import datetime
from alpaca.data.historical import StockHistoricalDataClient
from alpaca.data.requests import StockBarsRequest
from alpaca.data.timeframe import TimeFrame
client = StockHistoricalDataClient(
api_key="any", # required by the constructor,
secret_key="any", # never checked by the server
url_override="https://cuckootrade.com/api/v1/alpaca",
)
bars = client.get_stock_bars(StockBarsRequest(
symbol_or_symbols=["AAPL", "MSFT"],
timeframe=TimeFrame.Day,
start=datetime(2026, 7, 1),
end=datetime(2026, 7, 31),
))
for bar in bars["AAPL"]:
print(bar.timestamp.date(), bar.close)
The keys are positional requirements of the constructor, not
authentication. Delete the url_override line and the
same code talks to the real Alpaca again — there is no mocking
library to remove and no code path that exists only in tests.
alpaca-py against the live server as an acceptance test
on every commit, so “the SDK parses it unmodified”
becomes a build failure the moment it stops being true.
Verify it in one command
Before wiring up the SDK, confirm the endpoint from a shell. This works right now, from anywhere, with no setup:
curl -i 'https://cuckootrade.com/api/v1/alpaca/v2/stocks/bars?symbols=AAPL&timeframe=1Day&start=2026-07-01&end=2026-07-31'
The body is Alpaca’s exact shape —
{"bars": {"AAPL": […]}, "next_page_token": null}
with each bar carrying t, o, h, l, c, v, n, vw. Keep
the -i: the response headers say which server answered.
x-cuckoo-synthetic: true x-cuckoo-generation: 1 x-cuckoo-docs: https://cuckootrade.com/docs cache-control: public, max-age=31536000, immutable
The marking rides in headers rather than the JSON body on purpose:
strict SDK parsers reject unknown body fields, so a
"synthetic": true key would have broken the exact
compatibility this page is about.
What matches, and what deliberately does not
| Area | Behavior |
|---|---|
| Bar shape | Identical — t, o, h, l, c, v, n, vw. |
| Paths | Identical after the base URL: /v2/stocks/bars, /v2/stocks/{symbol}/bars, /v2/stocks/bars/latest. |
| Params | symbols, timeframe, start, end, limit, page_token, sort behave as Alpaca documents them, including real cursor pagination. |
| Errors | Alpaca’s {"code", "message"} shape and status codes — but the message states the valid grammar and includes a working example URL. |
| Auth | None. Keys are accepted and ignored rather than rejected, so client code that sends them works. |
| Symbols | Any well-formed string returns bars. ~130 well-known tickers sit at plausible price levels; every other string gets a stable hash-derived personality. |
| Partial bars | Only completed bars are served — no in-progress current day. Determinism requires it. |
| Extended hours | Not modeled. Intraday bars are regular session only, 09:30–16:00 ET. |
feed | Accepted and ignored; there is one synthetic feed, so SIP and IEX return the same data. |
The data follows the real NYSE calendar — no bars on weekends or market holidays — while the API itself stays up regardless of the hour. That combination is what makes a demo behave the same on Sunday night as on Tuesday morning.
Writing tests that do not expire
The reason to prefer a deterministic server over recorded fixtures is that you can assert on values. Every bar is a pure function of symbol, timestamp, generation, and seed, so this holds indefinitely:
import httpx
BASE = "https://cuckootrade.com/api/v1/alpaca"
def test_bars_are_byte_stable():
params = {"symbols": "AAPL", "timeframe": "1Day",
"start": "2026-07-01", "end": "2026-07-31"}
first = httpx.get(f"{BASE}/v2/stocks/bars", params=params).text
second = httpx.get(f"{BASE}/v2/stocks/bars", params=params).text
assert first == second # identical today, identical next year
Two extension parameters give you control over that world:
seed=anything— selects an alternate universe. Same structure and realism, different history. Useful when one test needs a symbol trending up and another needs it trending down.generation=1— pins the generator version. If the engine is ever improved that becomes generation 2, and generation 1 stays queryable forever. Pinning it in fixtures makes the guarantee explicit.
Both are ignored by real Alpaca, so leaving them in a shared code path is harmless.
The part a real API cannot do
Once you are pointed at a mock server you get something the live API structurally cannot offer: market conditions on demand. Reserved ticker symbols return scripted behavior, anchored to the calendar so the pattern appears in any 30-day window.
curl 'https://cuckootrade.com/api/v1/alpaca/v2/stocks/bars?symbols=CRASH,HALTS,GAPPY&timeframe=1Day'
| Ticker | What your code has to survive |
|---|---|
| CRASH | A ~25% drawdown over a few sessions, then a slow recovery. |
| HALTS | Minute bars missing mid-session — gap handling. |
| STALE | Bars arriving on time with the price frozen and v=0 — freshness checks. |
| GAPPY | ±5–15% overnight gaps most days. |
| FLAT | Zero-range bars at exactly $100.00 — naive chart autoscaling divides by zero here. |
| PENNY | ~$0.30 prices with four decimals — float and rounding bugs. |
| SPIKEY | Single-minute wicks that instantly revert. |
| CHOPPY | High volatility with zero net drift. |
Running it yourself
A pipeline that depends on someone else’s server has a new outage mode. The engine is stateless and MIT-licensed, and determinism means a local instance serves byte-identical data to the hosted one for the same generation:
docker run -p 8000:8000 ghcr.io/tj-miller-dev/cuckootrade # then point the SDK at it: # url_override="http://localhost:8000/api/v1/alpaca"
Running locally also removes the 60 requests/minute limit and gives
an exact flap:n failure count, which a multi-replica
hosted deployment cannot promise.
Full CI setup, including a GitHub Actions service container →