Skip to content
polysignals.net

Developers

API

Every number on this site comes from a handful of JSON files served over HTTPS with open CORS. Please cache on your side and poll no faster than the data changes. AI assistants can use the MCP server instead.

no key, no sign-up
Free
requests per IP, API and MCP together
50 / 10 s
no uptime guarantee or service level
Best effort
venues, combined signal, confidence score
Version 2
On this page
  1. Endpoints
  2. Example
  3. Limits
  4. Combined reading fields
  5. Venue reading fields
  6. Per coin
  7. History file
  8. Results fields
  9. Results coin file

Endpoints

GET /api/v1/signals.json
Everything: combined and per-venue readings for every coin × timeframe. Written every tick (tick_seconds). Cache 10 s.
GET /api/v1/combined.json
Combined readings only. Written once a minute. Cache 30 s.
GET /api/v1/venues/{venue}.json
One venue’s readings. Venues: polymarket, kalshi, limitless, gemini, binance_options, deribit_options, bybit_options, okx_options. Written once a minute. Cache 30 s.
GET /api/v1/history/{coin}.json
Last 48 h: combined at 1-minute and per-venue at 5-minute resolution. Any coin a venue covers in meta.json (currently at least BTC, ETH, SOL, XRP, DOGE, HYPE, BNB, ZEC, NEAR); a coin with only a regime call has none. Rebuilt every 5 min.
GET /api/v1/results.json
Live backtest: per coin and strategy, what following the calls on Coinbase USD has returned versus buy and hold (net and gross return, fills, trades, win rate, drawdown, open position). Written once a minute. Cache 1 min.
GET /api/v1/results/{coin}.json
One coin’s backtest with its last 100 fills per strategy and its equity curve (every 15 min for 48 h, hourly to 30 days, daily beyond). Written every 5 min. Cache 5 min.
GET /api/v1/meta.json
Coins discovered from the venues, timeframes (5m, 15m, 1h, 4h, 1d), venues with live coverage, thresholds and methodology version.
GET /api/v1/markets.json
Every market on Cryptohopper’s exchanges that receives the daily trend signals: per exchange its name, market count and each coin’s markets. Rewritten daily at 23:00 UTC, an hour before the decision. Cache 10 min.
GET /api/v1/deliveries.json
The signaler’s recent daily trend signals, newest first: the coin, buy or sell, and how many markets accepted, refused or let expire each, and while a decision is still sending, how many it has yet to reach (queued); totals counts every signal since the signaler went live. Rewritten after every send. Cache 1 min.
GET /api/v1/trend-history.json
Each coin’s daily trend call over the latest 90 closes, one letter a day (L long, F flat, - no close) against the list of dates; rewritten after every 00:05 UTC decision. The Trend changes page draws it.
GET /api/v1/live/index.md
Every coin’s overall call and daily trend call as markdown, for AI assistants and tools that do not run JavaScript. Cache 30 s.
GET /api/v1/live/{coin}.md
One coin as markdown: each window, each venue, its daily trend call, the Cryptohopper markets that get its signals and its latest delivery, its backtest and the newest headlines that name it. A lower-case ticker redirects. Cache 30 s.
GET /api/v1/live/trend.md
The daily trend changes as markdown: the coins that turned long (a buy sent to Cryptohopper) or flat (a sell) at each 00:05 UTC decision, and the latest decision even when it changed no call. Cache 5 min.
GET /api/v1/live/trend.xml
The same changes as an Atom feed, one entry per decision. Cache 5 min.
GET /api/v1/live/trend/{coin}.xml
One coin’s trend changes as an Atom feed. Cache 5 min.
GET /api/v1/live/markets.md
Every market that gets the daily trend signals as markdown: the exchanges with their counts, then each exchange’s markets per coin. Cache 1 h.
GET /api/v1/live/markets/{exchange}.md
One exchange’s markets per coin as markdown, by its Cryptohopper key (binance, kraken2, crypto and so on, as in markets.json). Each exchange page links its own. Cache 1 h.
GET /api/v1/live/news.json
The latest crypto headlines from CoinArticle, with the tracked coins each one names. Cache 5 min.
GET /api/v1/openapi.json
OpenAPI 3.1 description of the above.
POST /api/mcp
The MCP server (Streamable HTTP, read-only, no key) for Claude, ChatGPT, Cursor and other AI assistants; setup on the MCP page.

Example

curl -s https://polysignals.net/api/v1/combined.json | jq '.coins.BTC.overall'

curl -s https://polysignals.net/api/v1/signals.json | jq '.coins.ETH.timeframes["1h"].combined.current.confidence'

curl -s https://polysignals.net/api/v1/venues/kalshi.json | jq '.coins.SOL["15m"].current.prob_up'

signals.json, trimmed to one coin, one timeframe and one venue:

{
  "version": 2,
  "generated_at": "2026-09-30T20:26:05Z",
  "tick_seconds": 30,
  "venues": ["polymarket", "kalshi", "limitless", "gemini", "binance_options", "deribit_options", "bybit_options", "okx_options"],
  "coins": {
    "BTC": {
      "spot_usd": 83616.4,
      "overall": { "score": 9, "direction": "neutral", "confidence": 71 },
      "timeframes": {
        "1h": {
          "combined": {
            "current": {
              "prob_up": 0.511,
              "score": 2,
              "direction": "neutral",
              "late_window": false,
              "window_start": "2026-09-30T20:00:00Z",
              "window_end": "2026-09-30T21:00:00Z",
              "sources": ["polymarket", "kalshi", "limitless"],
              "merged_options": [],
              "divergence": 0.02,
              "raw_divergence": 0.05,
              "confidence": { "score": 88, "label": "high", "depth": 0.974, "agreement": 0.9, "timing": 1, "sources": 3, "independent_sources": 3, "qualifying_sources": 2, "divergence": 0.02 }
            },
            "next": null
          },
          "venues": {
            "kalshi": {
              "current": {
                "venue": "kalshi", "coin": "BTC", "timeframe": "1h",
                "window_start": "2026-09-30T20:00:00Z", "window_end": "2026-09-30T21:00:00Z",
                "prob_up": 0.51, "score": 2, "direction": "neutral",
                "spread": 0.01, "volume_usd": 333616, "liquidity_usd": null, "depth_usd": 12574,
                "derived": true, "stale": false, "late_window": false,
                "market_url": "https://kalshi.com/markets/kxbtcd/KXBTCD-26SEP3017",
                "confidence": { "score": 72, "label": "high", "quality": 0.72, "timing": 1 }
              },
              "next": null
            }
          }
        }
      }
    }
  }
}

Limits

Up to 50 requests per 10 seconds per IP across /api/ (the JSON, the live markdown and the MCP server together); above that the API answers 429 for 10 seconds. The JSON files are cached at the edge for as long as their Cache-Control says and query strings are ignored, so polling faster than the cache times above returns the same file. Read a coin’s history every 5 minutes, not every tick.

Combined reading fields

prob_up
Quality-weighted mean of venue Up probabilities (0 to 1). null when no source qualifies.
score
(prob_up - 0.5) × 200, rounded. -100 to +100. Mostly a readout of the move since the window opened, not a forecast (see the methodology).
direction
strong_up · up · neutral · down · strong_down.
late_window
true when less than 20% of the window remains.
window_start / window_end
ISO-8601 UTC.
reference_price / reference_source / move_since_open / time_left
The window’s price at the open and its source (venue, collector_spot or candle), price now ÷ that - 1, and the fraction of the window remaining. The reference is null for the next window and for one that opened before a reference was stored.
sources
Venue ids blended into this reading (quality > 0, or every priced venue in the equal-weighted fallback); a merged options reading lists each options venue in it.
merged_options
Options venues merged into one reading before blending: their median prob_up, counted as one source. An options venue more than 0.30 from the median of the others is left out and flagged outlier. Empty when none were merged.
divergence
max - min prob_up among qualifying sources (quality ≥ 0.2); null when fewer than two qualify.
raw_divergence
max - min prob_up across every priced source regardless of quality; null when fewer than two are priced.
confidence
{ score, label, depth, agreement, timing, sources, independent_sources, qualifying_sources, divergence }; score = round(100 × depth × agreement × timing). depth runs over the independent sources (the options venues merged into one). agreement = clamp(1 - divergence / 0.20, 0, 1) with two or more qualifying sources, else 0.7.

Venue reading fields

prob_up / score / direction
As above, for this venue alone.
spread
Best ask - best bid of the Up share. null for AMM venues.
volume_usd
Volume as the venue’s own site reports it, refreshed every tick (Kalshi counts contracts, each paying $1).
depth_usd
Resting order size within 0.05 of the mid, both sides, in USD, from data the venue already returns: Polymarket full book, Kalshi top of book; null for Limitless, Gemini and the options venues.
liquidity_usd
Pool liquidity for AMM venues, else null.
derived
true when interpolated from a strike ladder (Kalshi hourly, all options readings).
stale
true when the quote could not be refreshed and the previous value is shown (quality 0).
market_url
The market on the venue’s site.
bid / ask / options
The Up share’s best bid and ask where the venue quotes the window directly (null for ladders and options). Options venues add options: { p_at_spot, atm_iv, rr25, forward_usd, basis, method }, each null where the venue gives no input; method says whether prob_up and p_at_spot come from the implied vol (iv) or the call price differences (curve).
flags
Present only on a reading that is published but never blended: outlier (an options venue more than 0.30 from the median of the other options venues on its window) or degenerate_curve (the option ladder’s implied probabilities span less than 0.50, so prob_up is null).
confidence
{ score, label, quality, timing }; score = round(100 × quality × timing).

Per coin

overall is the confidence-weighted mean of the combined current scores of the 1h, 4h and 1d timeframes, with its own confidence; venue_overall.{venue} is the same computed from one venue’s readings (also returned as overall in venues/{venue}.json); spot_usd is a display-only spot price from Coinbase.

regime (signals.json only) is the daily regime strategy’s call, decided once a day at 00:05 UTC on the Coinbase close of the day that just ended, from no venue data: { as_of, call, close, sma50, sigma20, upper, lower, distance_sigmas, days_in_state, next_decision_at, intraday }. call turns long once the close is above upper = sma50 × (1 + sigma20) and flat once it is below lower = sma50 × (1 - sigma20). null for a coin with fewer than 200 daily closes or without that day’s close. intraday: { call, as_of } is the four-hour paper variant (strategy regime_4h, not relayed): the live Coinbase Exchange price against the same band at every 4-hour UTC boundary, starting from the daily call; null before its first check. The rule is in the methodology.

When no source clears the quality bar (typically a thin window with zero reported volume), the combined reading is still filled from the available prices, equal-weighted, with confidence.score 0, so every priced window shows a direction, and the confidence tells you how much to trust it.

History file

{ coin, generated_at, resolution: { combined: "1m", venues: "5m" }, range_hours: 48, timeframes: { "1h": { combined: [{ t, prob_up, score, confidence }], venues: { kalshi: [ … ] } } } }. Minutes with no usable reading are simply absent.

Results fields

results.json carries, per coin and strategy (5m, 15m, 1h, 4h, 1d, overall, regime, regime_4h), what following the calls on the coin’s Coinbase USD market has returned, long-only. A call read in one minute fills 1 minute later at the Coinbase Exchange best ask (buy) or bid (sell); equity is marked at the last trade price. Fractions throughout. This is results version 2: it restarted the simulation from scratch and the earlier numbers were dropped. meta.json thresholds.results carries fee, fillDelayMin and altFee (0.001), the cheaper fee the Results page also shows the same fills at: (1 + gross_return) × (1 - altFee)^fills - 1.

return
Equity now ÷ starting capital - 1, net of a 0.006 fee per fill. buy_hold.return: bought at started_at’s ask with one fee and held.
gross_return
The same fills without fees: equity ÷ starting capital - 1 before fees (the bid/ask spread still paid).
fills
Fills so far, buys plus sells; each paid the fee.
trades
Completed round trips (a buy followed by a sell). win_rate and avg_trade are over those; null without one.
max_drawdown
Largest peak-to-trough fall of the equity.
time_in_market
Share of priced minutes spent holding the coin.
fees_paid
Fees paid so far, in units of the starting capital.
position / since / entry_price
The open position: coin since since at entry_price, or usd.
call
The call the strategy holds right now (buy, sell or hold).
results_version
The simulation’s rules ("2"); when they change the simulation restarts from scratch.
methodology_version
The methodology the calls are read by ("5").

Results coin file

results/{coin}.json is the coin’s block from results.json plus trades (per strategy, the last 100 fills, oldest first: { side, t, price, equity, return? }, price being the ask for a buy and the bid for a sell) and curve, whose columns are t, spot, 5m, 15m, 1h, 4h, 1d, overall, regime, regime_4h, buy_hold, 5m_gross, 15m_gross, 1h_gross, 4h_gross, 1d_gross, overall_gross, regime_gross, regime_4h_gross: the net equity per strategy, buy & hold, then each strategy’s gross (fee-free) equity. Rows come every 15 minutes for the last 48 hours, hourly up to 30 days, daily beyond.

Not financial advice. Not affiliated with Polymarket, Kalshi, Limitless, Gemini, Binance, Deribit, Bybit or OKX. The feed can change or stop without notice. Use is subject to the terms.