CUCKOOTRADE
Guide

How to mock the Polygon.io API for development and tests

Polygon’s aggregates wire format, served free and keyless — the same paths, the same envelope, real cursor pagination, and request_id values stable enough to assert on.

Any language REST 6 minutes

The base URL swap

Replace https://api.polygon.io with https://cuckootrade.com/api/v1/polygon. Everything after that is Polygon’s own path:

shell — aggregates, no key
curl 'https://cuckootrade.com/api/v1/polygon/v2/aggs/ticker/MSFT/range/1/day/2026-07-01/2026-08-01'
json — the response envelope
{
  "ticker": "MSFT",
  "queryCount": 22,
  "resultsCount": 22,
  "adjusted": true,
  "results": [
    {"v": 24183400, "vw": 431.87, "o": 429.4, "c": 433.12,
     "h": 434.9, "l": 428.1, "t": 1782964800000, "n": 214905}
  ],
  "status": "OK",
  "request_id": "234ee1ae9d085ae58a8d694fac44e7ed",
  "count": 22
}

Polygon’s conventions are preserved down to the awkward details: t is Unix milliseconds rather than an ISO string, and results and count are omitted entirely when nothing matched rather than sent as [] and 0 — which is what the real API does, and a common source of client-side crashes.

request_id is deterministic. It is an md5 of the request, so the same call returns the same id forever. That makes it assertable in a test, which the real API’s random ids are not.

Parameters

Segment / paramAccepted
multiplierAny positive integer, subject to the timespan limits below.
timespanminute (1–59), hour (1–23), day, week, month (1,2,3,4,6,12), quarter (1,2,4), year.
from / toYYYY-MM-DD or Unix milliseconds — both, as Polygon allows.
sortasc (default) or desc.
limitUp to 50,000.
cursorReal cursor pagination, delivered via next_url.
adjustedAccepted and echoed; this surface does not restate.
apiKeyAccepted and ignored. Nothing is ever checked.
seed, generationCuckooTrade extensions — alternate universe, pinned generator.

There is also /v2/aggs/ticker/{ticker}/prev for the previous session’s daily bar.

python — following the cursor
import httpx

url = ("https://cuckootrade.com/api/v1/polygon"
       "/v2/aggs/ticker/MSFT/range/1/day/2026-01-01/2026-08-01?limit=10")

while url:
    payload = httpx.get(url).json()
    for bar in payload.get("results", []):      # absent, not empty, when unmatched
        print(bar["t"], bar["c"])
    url = payload.get("next_url")               # already carries the cursor

Errors keep Polygon’s shape

json — a 4xx
{
  "status": "ERROR",
  "request_id": "9f2c1b0e5d3a47c8b1e6f0a2d7c94b35",
  "error": "timespan=fortnight is not valid. Use minute, hour, day, week, month, quarter or year -- e.g. /v2/aggs/ticker/MSFT/range/1/day/2026-07-01/2026-08-01"
}

The shape matches Polygon; the message deliberately does not. Errors get read at the moment someone is stuck, so every one states the valid grammar and includes a URL that works.

What the real API cannot do

Scenario tickers work on this surface exactly as they do on the others — the engine is shared, so only the wire format differs:

shell — a crash through Polygon’s format
curl 'https://cuckootrade.com/api/v1/polygon/v2/aggs/ticker/CRASH/range/1/day/2026-07-01/2026-08-01'

And fault injection rides the same scenario= parameter, returning Polygon’s error shape at whatever status you name:

shell — fail twice, then work
curl -i 'https://cuckootrade.com/api/v1/polygon/v2/aggs/ticker/MSFT/range/1/day/2026-07-01/2026-08-01?scenario=flap:2'

One world, three formats

All three provider surfaces read from the same deterministic engine, so the same symbol on the same day returns identical OHLCV through each — only the serialisation differs. A cross-provider consistency test enforces this in CI.

That makes this a useful place to test a provider migration: point the same test suite at both surfaces and any difference is your adapter, not the data.

shell — same bar, two wire formats
curl 'https://cuckootrade.com/api/v1/polygon/v2/aggs/ticker/AAPL/range/1/day/2026-07-06/2026-07-06'
curl 'https://cuckootrade.com/api/v1/alpaca/v2/stocks/bars?symbols=AAPL&timeframe=1Day&start=2026-07-06&end=2026-07-06'

Scope and honesty

Aggregates and previous-close are implemented. Reference data, trades, quotes, snapshots, and the Polygon WebSocket are not. Every response carries X-Cuckoo-Synthetic: true.

All data is synthetic. This exists to exercise code paths, not to validate trading strategies. A backtest that profits against generated prices has learned the generator, not the market.

Next