← Back to app
◆ PUBLIC API

Read-only. Free. No signup.

The same data Rotator's own site and Telegram bot read: about 290 crypto assets and tokenized stocks, rescored every 15 minutes, with the numbers behind every score. Also the market backdrop on the TODAY page: central bank rates, bond yields, metals, energy and on-chain activity (below). This page exists so developers and AI agents can query it directly instead of scraping the UI.

All endpoints are standard PostgREST: plain HTTPS GET requests, JSON responses, filterable and sortable with query parameters. Agents: the machine-readable contract is openapi.json.

Public key, no signup Rescored every 15 min Read-only (writes are rejected) OpenAPI 3.1 spec
Authentication
Every request needs the public anon key below, as both the apikey header and a Bearer token. It is the same key Rotator's own frontend ships to every browser, so it is not a secret. It grants read access only: Row Level Security rejects any insert, update or delete, whatever key is used.
apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Ind5dnd5Y2F0Z2V4cGJ1Z3prZGZ3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzU0ODcwNTAsImV4cCI6MjA5MTA2MzA1MH0.msUPOUjd1iZwuG6SxFlhr-0xYPt6fqTUy5iOYnf8Z20 Authorization: Bearer <same value as apikey>
Base URL: https://wyvwycatgexpbugzkdfw.supabase.co/rest/v1/
Start here: the scored universe
Every 15 minutes the scoring engine runs once over the whole universe and writes one run (a header row) and one item per asset. This is the core dataset; everything else on this page is derived from it or recorded alongside it.
Read the newest run that has items, not simply the newest run. The run header is written a moment before its items. A request that lands in that gap gets a run with zero items. Ask for the newest two runs and use the first one that returns items, or use the embedded form below and check that the item list is not empty.
GET /signal_runs
One row per scoring run. The newest is the current state of the market as the engine sees it.
curl "https://wyvwycatgexpbugzkdfw.supabase.co/rest/v1/signal_runs?select=id,as_of,engine_version,cycle_label,universe_size,eligible_count&order=as_of.desc&limit=2" \ -H "apikey: <anon key>" -H "Authorization: Bearer <anon key>"
fieldtypenotes
idbigintrun id; join key for signal_run_items.run_id
as_oftimestamptzwhen the run was scored
engine_versiontextscores from different versions are not directly comparable; see the engine changelog
cycle_labeltextBTC market regime from the Mayer multiple: 'neutral', 'oversold' or 'stretched'. Zone thresholds depend on it.
universe_size / eligible_countintegerassets scored / assets that passed every eligibility check
paramsjsonbevery threshold and input the run used (zone thresholds, macro readings, Fear & Greed, rule tables), so a score can be reproduced
changesjsonbwhat moved since the run ~24h earlier: zone and class transitions, biggest score and rank changes
input_freshnessjsonbage in ms of the price and macro inputs when the run was scored
GET /signal_run_items
One row per asset per run: its score, its label, and the components behind them. About 290 rows per run. The jsonb columns are large, so select only the columns you need.
# the strongest eligible assets in run 1732 curl "https://wyvwycatgexpbugzkdfw.supabase.co/rest/v1/signal_run_items?run_id=eq.1732&eligible=is.true&select=coin_sym,score,strength,zone,candidate_class,p7,p30&order=strength.desc&limit=10" \ -H "apikey: <anon key>" -H "Authorization: Bearer <anon key>" # the newest run and its items in one request curl "https://wyvwycatgexpbugzkdfw.supabase.co/rest/v1/signal_runs?select=id,as_of,signal_run_items(coin_sym,score,zone)&order=as_of.desc&limit=1" \ -H "apikey: <anon key>" -H "Authorization: Bearer <anon key>"
fieldtypenotes
run_idbigintsignal_runs.id
coin_idtextCoinGecko id for crypto; tokenized stocks are bstock_<TICKER>. Use this as the key, not the ticker: tickers are not unique.
coin_symtextdisplay ticker
asset_typetext'crypto' or 'bstock' (Binance tokenized equity certificates; never eligible)
price / mcapnumericUSD at scoring time
p7 / p14 / p30numerictrailing return in percent
r7 / r14 / r30integerrank of that return within the run, 1 = best; 0 = not ranked (incomplete data)
scorenumericcomposite: momentum rank, macro-relative strength, tokenomics (supply and unlocks). Higher = stronger recent relative performance. Not bounded to 0–100; it can go negative.
effective_scorenumericscore after the insight cross-check; this is what sets the zone
zonetext'buy', 'neutral' or 'sell': a band of effective_score, not an instruction. 'buy' is the LOW end (has lagged), 'sell' the HIGH end (has run). Thresholds and hysteresis are in params.zoneRules. See "What the evidence says" below before using it.
strengthnumeric0–100, high = relative strength (second model). Rank on this.
setupnumeric0–100 mean-reversion setup quality; null when there is no setup
eligiblebooleanfalse when any exclusion applies
exclusionstext[]why not eligible: 'equity', 'delisted', 'illiquid', 'no_market_cap', 'incomplete_history', 'monitoring' (Binance monitoring tag), 'unlock_pending' (large token unlock within 30 days)
data_completebooleanfalse = inputs missing; treat the score as unreliable
candidate_classtextmean-reversion classification, see the table below; null when not eligible
rsi / rsi_statenumeric / textdaily RSI(14); state 'oversold' (≤30), 'low' (≤45), 'neutral' (<60), 'elevated' (<70), 'overbought'; null when no candles
breakdownjsonbscore components: layer1 (momentum), layer2 (macro-relative), layer3 (tokenomics), supplyPts, unlockPts, sizeAdj, …
candidatejsonbthe numbers the class was reached from: p24, recentWeek, priorWeek, pace30, flags
insightjsonbtechnical read: label 'STRONG' / 'NEUTRAL' / 'WARN', points, and human-readable signals[]
positioningjsonbderivatives: funding, open interest and its 24h change, long/short and taker ratios; label 'NEUTRAL', 'CROWDED LONG', 'CROWDED SHORT' or 'UNWINDING'. Published at zero weight: it does not move the score.
unlock30dnumericpercent of supply unlocking in the next 30 days. null means no published schedule, not "no unlock due"; roughly 30% of the universe has one.
candidate_classmeaning
CANDIDATEin a pullback, not accelerating down, RSI agrees it is low
STRONGno pullback; a strong asset, not a mean-reversion entry
EXTENDEDalready made an extreme one-day move
COOLDOWNlarge one-day gain, short of extreme
FALLING_KNIFEdecline accelerating, or deep with no sign of stabilising
NOT_OVERSOLDin a pullback, but RSI does not support the setup
UNCONFIRMEDRSI is in use this run but missing for this asset
Published calls
GET /rotation_snapshots
The daily "rotate out of A, into B" pairs, written once a day at 19:07 UTC from the latest run: the five highest scores paired with the five lowest eligible ones. Always filter on source. The table also holds experiments that are recorded for grading and never published (see below); an unfiltered query mixes them in. Calls are graded at 30 days; the pre-graded record is at /track-record.html.
curl "https://wyvwycatgexpbugzkdfw.supabase.co/rest/v1/rotation_snapshots?source=eq.sync-rotation-snapshot&order=snap_date.desc&limit=20" \ -H "apikey: <anon key>" -H "Authorization: Bearer <anon key>"
fieldtypenotes
snap_datedatethe day the call was made
from_id / from_symtextthe "rotate out of" asset
from_price / from_scorenumericprice and score at call time
to_id / to_symtextthe "rotate into" asset
to_price / to_scorenumericprice and score at call time
sourcetextsync-rotation-snapshot = the published calls. Unpublished experiments: -inverted (the same pairs reversed; retired 2026-09-23, 15 rows kept as history), -gold, -gold-30d, -gold-both (a hot asset paired with PAXG), -top20 (within the 20 largest by market cap, lowest scores into highest; from 2026-09-23).
GET /signal_snapshots
Daily single-asset calls, 'bullish' or 'lagging', recorded since 2026-09-07. Each row carries the engine version that made it. The track record grades these against the market median over the same window, from 2026-09-11 on.
curl "https://wyvwycatgexpbugzkdfw.supabase.co/rest/v1/signal_snapshots?snap_date=gte.2026-09-11&order=snap_date.desc" \ -H "apikey: <anon key>" -H "Authorization: Bearer <anon key>"
fieldtypenotes
snap_datedate
coin_id / coin_sym / coin_nametext
signal_typetext'bullish' or 'lagging'
signal_labeltextdisplay label at call time, e.g. 'MOMENTUM', 'LAGGING', 'ROTATE IN'
score / zonenumeric / textat call time
price / p24 / p7 / p30 / mcapnumericat call time
engine_version / sourcetextwhich engine made the call; 'dashboard' or 'bot'
Market backdrop: the TODAY indices
The readings on the TODAY section of the main page: central bank rates and government bond yields, the dollar index, metals, energy, and Bitcoin and DeFi network activity. Each comes from a named public source and is collected by the same sync that feeds the scores. They describe the market around crypto; they are context, not signals, and none of them is a forecast. One request returns all of them.
GET /market_cache?cache_key=eq.world_data
Every TODAY index in one row: the latest value, the date of that reading, its change over six windows, and the daily history the site draws its charts from. Refreshed once a day after the US close; the Treasury and central banks publish on their own calendars, so each item carries its own date.
curl "https://wyvwycatgexpbugzkdfw.supabase.co/rest/v1/market_cache?cache_key=eq.world_data&select=updated_at,data" \ -H "apikey: <anon key>" -H "Authorization: Bearer <anon key>" # the response: data.items.<key> for each index, e.g. the Fed rate # { "v": 3.88, "date": "2026-10-01", "lo": 3.75, "hi": 4, "c30": 0.25, "c365": -0.21, "s": [ … ], … }
field (per item)typenotes
vnumberlatest value, in the unit listed below
datetextthe day of that reading (YYYY-MM-DD); for power the first day of its month
c7 / c30 / c90 / c182 / c365 / c1095numberchange over 7 days, 30 days, 3 months, 6 months, 1 year, 3 years. Percent for prices and activity; points for rates and yields (4.00% → 4.40% is 0.40); dollars for crack. null when there is no reading that far back.
snumber[]about one year of daily values, oldest first (monthly for power)
s3number[]three years, thinned to about 150 points
n7 / n30 / n90 / n182integerhow many points of s fall inside that window; s.slice(-n30) is the 30-day line
lo / hinumberfed only: the target range around the effective rate
lastobjectcentral banks only: the latest rate decision, {from, to, date}
cnobjectoil only: Shanghai crude in dollars, with its own series and its gap to Brent and WTI
gweinumberethFees only: the current gas price
keywhat it isunit of vsource
fed / ecb / bojUS, euro area and Japan central bank policy rates%New York Fed, ECB, Bank of Japan
us3m / us2y / us10yUS Treasury yields, 3 months, 2 and 10 years%U.S. Treasury
jgb10yJapan 10-year government bond yield%Japan Ministry of Finance
dxyUS dollar indexindexICE via Yahoo Finance
gold / silverfutures, front month$ per troy ounceCOMEX via Yahoo Finance
copperfutures, front month$ per poundCOMEX via Yahoo Finance
aluminumfutures, front month$ per tonneCOMEX via Yahoo Finance
oil / brentWTI and Brent crude futures$ per barrelNYMEX via Yahoo Finance (CL=F, BZ=F)
crackdiesel crack spread: heating oil × 42 minus Brent, what refiners earn per barrel$ per barrelcomputed from heating oil (HO=F) and Brent (BZ=F), Yahoo Finance
gasUS natural gas futures$ per MMBtuNYMEX via Yahoo Finance
poweraverage US household electricity price, monthly, about six weeks behind$ per kWhU.S. Bureau of Labor Statistics
hashBitcoin hash rateEH/sBlockchain.com
addractive Bitcoin addresses per daycountBlockchain.com
tvl / stableDeFi value locked across all chains; stablecoin supply$DefiLlama
ethFees / solFeesfees users paid on Ethereum and Solana in a day$ per dayDefiLlama
solDexvalue traded on Solana's exchanges in a day$ per dayDefiLlama
GET /market_cache?cache_key=eq.network_data
The on-chain readings averaged over 7 days, which is what the TODAY tiles show as their headline value: hashrateEh, addrCount, tvlUsd, stableUsd, each with its 7-day change (hashrateP7, addrP7, tvlP7, stableP7), 30-day changes in p30, and a month of daily values in series. Refreshed daily.
curl "https://wyvwycatgexpbugzkdfw.supabase.co/rest/v1/market_cache?cache_key=eq.network_data&select=updated_at,data" \ -H "apikey: <anon key>" -H "Authorization: Bearer <anon key>"
GET /market_cache?cache_key=eq.fear_greed
The Crypto Fear & Greed Index: {value, label, asOf, source}, 0 = extreme fear, 100 = extreme greed. One reading a day, from alternative.me.
curl "https://wyvwycatgexpbugzkdfw.supabase.co/rest/v1/market_cache?cache_key=eq.fear_greed&select=data" \ -H "apikey: <anon key>" -H "Authorization: Bearer <anon key>"
Showing these on another site? A ready-made panel exists: today-embed.html shows every index with its source, in English or Macedonian, light or dark, and can be placed on any page with one <iframe>. Please keep the visible link to Rotator and the source of each reading.
<!-- Rotator · TODAY. Options: lang=mk|en, theme=dark|light (default: the viewer's setting), period=7|30|365 --> <iframe id="rotator-today" src="https://rotatortool.com/today-embed.html?lang=mk&period=30" style="width:100%;height:1400px;border:0;" loading="lazy" title="Rotator · TODAY"></iframe> <script> // optional: size the frame to its content window.addEventListener('message', function (e) { if ((e.origin === 'https://rotatortool.com' || e.origin === 'https://rotatortool-official.github.io') && e.data && e.data.rotatorEmbedHeight) document.getElementById('rotator-today').style.height = e.data.rotatorEmbedHeight + 'px'; }); </script>
Supporting data
GET /coin_events
Technical events detected once a day at 00:45 UTC: 'golden_cross', 'death_cross', 'rsi_overbought', 'rsi_oversold', 'futures_long_crowded'.
curl "https://wyvwycatgexpbugzkdfw.supabase.co/rest/v1/coin_events?select=base_asset,event_date,event_type,value,prev_value&order=event_date.desc&limit=50" \ -H "apikey: <anon key>" -H "Authorization: Bearer <anon key>"
GET /coin_technicals
Per Binance base asset: daily and weekly RSI(14), 60/125-day moving averages, cross state and how many days ago it crossed. Refreshed every 3 hours.
curl "https://wyvwycatgexpbugzkdfw.supabase.co/rest/v1/coin_technicals?base_asset=eq.BTC" \ -H "apikey: <anon key>" -H "Authorization: Bearer <anon key>"
GET /market_cycle
Real 200-day moving average and Mayer multiple (price ÷ MA200) for BTC, ETH, BNB, SOL, XRP and PAXG. Only BTC has calibrated bands: the 2.4× / 0.8× thresholds come from Bitcoin's own history. Treat the other five as raw ratios.
curl "https://wyvwycatgexpbugzkdfw.supabase.co/rest/v1/market_cycle?select=*" \ -H "apikey: <anon key>" -H "Authorization: Bearer <anon key>"
fieldtypenotes
symboltext'BTC','ETH','BNB','SOL','XRP','PAXG'
price / ma200 / mayer_multiplenumericma200 is the average of actual daily closes
sample_sizeintegercloses that went into ma200; a true 200-day average only when this is 200
computed_attimestamptzsynced once a day
GET /unified_market_data
Price, 24h change and market cap for every tracked Binance bStock (tokenized equity certificate, not direct share ownership). Crypto prices are in signal_run_items.
curl "https://wyvwycatgexpbugzkdfw.supabase.co/rest/v1/unified_market_data?asset_type=eq.stock&select=*" \ -H "apikey: <anon key>" -H "Authorization: Bearer <anon key>"
What the evidence says
Measured on 771 days of history (2024-06 to 2026-08, about 115 assets a day), not on live results:
· The score ranks in the right direction. A higher score preceded better 30-day relative performance: rank correlation +0.053. The share of each score decile that beat the market median rose from 45.1% (lowest) to 51.8% (highest). It is a small edge, and it was measured on the history the engine was tuned on.
· So the 'buy' zone is not a prediction of outperformance. It marks the low end of the score, the assets that have lagged. The published rotation pairs (sell the five highest scores, buy the five lowest) had a positive 30-day spread on 46.8% of 3,855 pairs, below the ~50% of two assets picked at random. The pairs are published and graded as a test.
· No live accuracy claim yet. Live calls are graded at 30 days on the track record. It will take months of live data before it can confirm or contradict the figures above.
Rate limits & fair use
No key tiers and no published hard limit yet. This runs on the same infrastructure as the live site, so be reasonable: runs change every 15 minutes, so polling faster buys nothing; cache what you read; select only the columns you need; and do not bulk-scrape in parallel. If you need higher volume or an SLA, get in touch through the CONTACT link on the main site before building against this at scale.
Scope, stated plainly: nothing here is a security audit, a long-term valuation, a usage or TVL metric, or sentiment analysis. The scores measure 7–30 day price momentum, macro-relative strength and, for crypto, supply and unlock mechanics. Nothing else. This is not financial advice; nothing here, machine-readable or not, should be the sole basis for deploying capital.