One number for the mood of the gold market, recompiled every 60 seconds from news in every language we can reach. Built for trading systems to poll directly.
Create a key at /keys. Send it any of three ways:
curl -H "Authorization: Bearer gri_live_xxx" https://evandersignal.com/api/v1/index curl -H "X-API-Key: gri_live_xxx" https://evandersignal.com/api/v1/index curl "https://evandersignal.com/api/v1/index?key=gri_live_xxx"
Default limit 120 requests/minute per key. The index only
changes once a minute, so polling faster returns the same value — check
age_seconds rather than hammering it.
{
"index": 6.26, // 1 = sell, 5 = undecided, 10 = buy
"verdict": "BUY MOOD",
"raw": 0.129, // -1..+1 before the 1-10 mapping
"coverage": 0.76, // 0..1 how much evidence is behind it
"stories": 982, // weighted stories in the window
"as_of": 1784528400,
"as_of_iso": "2026-07-20T06:20:00Z",
"age_seconds": 12
}
{
"current": 6.26,
"regime": "building_bullish", // stable | building_* | fading_* | drifting
"momentum": { "1h": 0.04, "6h": 0.21, "24h": -0.10 },
"volatility_24h": 0.18,
"pressure": {
"last_hour_polarity": 0.31, // net gold-pull of the newest stories
"last_hour_stories": 47,
"baseline_24h_polarity": 0.14,
"divergence": 0.17 // positive = incoming news more bullish
}, // than what's already priced
"projection": [
{ "horizon_h": 1, "if_no_new_news": 6.24, "low": 6.0, "high": 6.5 },
{ "horizon_h": 6, "if_no_new_news": 6.11, "low": 5.6, "high": 6.7 },
{ "horizon_h": 12, "if_no_new_news": 5.98, "low": 5.3, "high": 6.7 }
],
"emerging_channels": [ ... ] // what's heating up right now
}
if_no_new_news actually is.
Every story's weight halves every 18 hours. So tomorrow's index is already
partly determined by today's book — that path is computed exactly, not
guessed. pressure.divergence is the leading part: fresh stories
are barely represented in the current value yet, so their net polarity tells
you which way the number is about to be pulled. Bands are realised index
volatility scaled by √time.
{ "channels": [
{ "channel": "geopolitics", "label": "Geopolitical risk",
"polarity": 0.45, "weight": 3.21, "stories": 260, "beta": 0.75,
"note": "War, escalation, strikes, blockades, sanctions." }, ... ] }
?hours=24 (max 2160 = 90 days).{ "hours": 24, "count": 1440,
"ticks": [ { "ts": 1784528400, "index": 6.26, "raw": 0.129,
"coverage": 0.76, "stories": 982 }, ... ] }
?limit=50 (max 200).{ "count": 50, "items": [
{ "title": "...", "url": "...", "language": "zh",
"channel": "monetary_policy", "polarity": -0.55, "intensity": 0.6,
"confidence": 0.7, "scored_by": "lexicon", "rationale": "" }, ... ] }
| Code | Meaning |
|---|---|
401 | Missing, unknown, or revoked key |
429 | Over the key's per-minute limit |
503 | No index computed yet (cold start) |
import requests, time
H = {"Authorization": "Bearer gri_live_xxx"}
URL = "https://evandersignal.com/api/v1"
while True:
d = requests.get(f"{URL}/index", headers=H, timeout=10).json()
# Only act on a reading with real evidence behind it.
if d["coverage"] >= 0.5:
if d["index"] >= 7.0:
print("bullish gold mood", d["index"])
elif d["index"] <= 3.0:
print("bearish gold mood", d["index"])
time.sleep(60)