Skip to content

Commit fd7e411

Browse files
author
asbestos22
committed
feat(v10): Stablecoin Risk Radar defensive rotation overlay
NRI was offense-only through v9. v10 closes the loop: - stablecoin_risk.py: 5-bucket SRR model (Peg+Flow+Reserves+Liquidity+Contagion), 15-stable universe - backtest.py: SRR overlay, DEFENSIVE_ROTATION trigger when RISK_OFF + top conviction < 30 - live_demo.py: live CMC stable metrics, SRR ranking + target in JSON output - 3 historical scenarios: BASELINE_2026, USDC_SVB_2023, UST_DEATH_2022 — all validate correct historical verdicts - skill.yaml + README bumped to v10.0
1 parent d678912 commit fd7e411

5 files changed

Lines changed: 599 additions & 10 deletions

File tree

README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,31 @@
22

33
[![python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
44
[![chain](https://img.shields.io/badge/chain-BNB%20Chain%20%2B%20Multichain-F0B90B.svg)](https://www.bnbchain.org/)
5-
[![version](https://img.shields.io/badge/version-9.0-F0B90B.svg)](https://github.com/asbestos22/narrative-rotation-index)
5+
[![version](https://img.shields.io/badge/version-10.0-F0B90B.svg)](https://github.com/asbestos22/narrative-rotation-index)
66
[![license](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
77
[![mcp](https://img.shields.io/badge/MCP-compatible-purple.svg)](https://modelcontextprotocol.io/)
88
[![tests](https://github.com/asbestos22/narrative-rotation-index/actions/workflows/tests.yml/badge.svg)](https://github.com/asbestos22/narrative-rotation-index/actions/workflows/tests.yml)
99
[![live](https://img.shields.io/badge/live-nri.realdo.org-F0B90B.svg)](https://nri.realdo.org/)
1010

1111
A CMC-native AI-agent skill that ranks crypto narratives by relative strength, liquidity expansion, attention velocity, and macro regime — then outputs backtestable portfolio weights with structured confidence explanations and optional BNB Chain (BSC) Trust Wallet execution payloads.
1212

13+
**v10.0** adds the **Stablecoin Risk Radar (SRR)** defensive rotation overlay: NRI scores narratives for offense, SRR scores stablecoins for defense. When regime flips RISK_OFF and top narrative conviction drops below 30, capital rotates to the safest-scoring stable.
14+
1315
Built for the **CMC AI Agent Hub** with native **BNBAgent SDK** and **Trust Wallet Agent Kit** integration. Exposed as an **MCP server** so any MCP-aware client can call it.
1416

1517
**Live dashboard:** [nri.realdo.org](https://nri.realdo.org/)
1618

19+
## v10.0 — Stablecoin Risk Radar (defensive rotation)
20+
21+
NRI was offense-only through v9. v10 closes the loop with a defensive layer:
22+
23+
- **5-bucket SRR model:** `SRR = 0.30×Peg + 0.25×Flow + 0.20×Reserves + 0.15×Liquidity + 0.10×Contagion`
24+
- **9 live-tracked stables:** USDT, USDC, FDUSD, USDe, DAI, FRAX, TUSD, USDD, lisUSD (15-stable universe in `stablecoin_risk.py`, all BNB Hack-eligible)
25+
- **Verdict bands:** SAFE 0–25 · WATCH 26–50 · EXIT 51–75 · EMERGENCY 76–100
26+
- **Defensive trigger:** RISK_OFF regime + top narrative conviction < 30 → rotation to safest stable with BSC contract address surfaced
27+
- **Backtest scenarios:** BASELINE_2026 (calm), USDC_SVB_2023 (banking crisis), UST_DEATH_2022 (algorithmic stable collapse) — all validate historical accuracy
28+
- **Live overlay:** SRR pulls real CMC data on every refresh, scores all 9 stables, surfaces the rotation target on the dashboard
29+
1730
## v9.0 — Multichain Narrative Coverage
1831

1932
- **10 narratives** (was 5): AI Tokens, AI Agents, RWA, DePIN, Meme, Privacy, DeFi Blue, L1/L2, Gaming/NFT, BNB Chain
@@ -29,6 +42,8 @@ Built for the **CMC AI Agent Hub** with native **BNBAgent SDK** and **Trust Wall
2942
$ python live_demo.py # live CMC scoring
3043
$ python mcp_server.py # MCP stdio server (Claude Desktop, CMC Hub, agents)
3144
$ python backtest.py # 90-day historical basket simulation
45+
$ python stablecoin_risk.py # SRR baseline scenario
46+
$ python stablecoin_risk.py USDC_SVB_2023 # historical depeg replay
3247
$ python -m unittest tests # 15 unit tests
3348
```
3449

@@ -50,7 +65,7 @@ python live_demo.py
5065

5166
## What is NRI
5267

53-
> A backtestable strategy skill that scans 10 crypto narratives, detects market regime, ranks by relative strength and liquidity expansion, penalizes crowded late-cycle moves, and outputs portfolio weights plus an optional BNB Chain (BSC) Trust Wallet execution payload.
68+
> A backtestable strategy skill that scans 10 crypto narratives + 9 stablecoins, detects market regime, ranks by relative strength and liquidity expansion, penalizes crowded late-cycle moves, scores stablecoin defensive rotation targets, and outputs portfolio weights plus an optional BNB Chain (BSC) Trust Wallet execution payload.
5469
5570
## Narrative Exhaustion Detector — The Original Moat
5671

backtest.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,40 @@ def global_scan(regime="TRANSITION"):
10591059
else:
10601060
rotation = f"DEFENSIVE — increase stablecoin allocation. Lowest: {bottom[0]}"
10611061

1062+
# ---- v10: Stablecoin Risk Radar (SRR) overlay ----
1063+
# NRI scores narratives for offense; SRR picks the safest defensive target.
1064+
# Trigger DEFENSIVE_ROTATION when regime is RISK_OFF or top conviction < 30.
1065+
try:
1066+
from stablecoin_risk import rank_stables, rotation_target, SCENARIOS
1067+
srr_scenario = "USDC_SVB_2023" if regime == "RISK_OFF" else "BASELINE_2026"
1068+
srr_scores = rank_stables(SCENARIOS[srr_scenario])
1069+
srr_target = rotation_target(srr_scores)
1070+
srr_payload = {
1071+
"scenario": srr_scenario,
1072+
"rankings": [
1073+
{"symbol": s.symbol, "verdict": s.verdict, "score": s.score,
1074+
"issuer": s.issuer, "type": s.type}
1075+
for s in srr_scores
1076+
],
1077+
"target": (
1078+
{"symbol": srr_target.symbol, "verdict": srr_target.verdict,
1079+
"score": srr_target.score, "bsc_address":
1080+
__import__("stablecoin_risk").STABLE_UNIVERSE.get(srr_target.symbol, {}).get("bsc")}
1081+
if srr_target else None
1082+
),
1083+
}
1084+
1085+
# Defensive override: if regime is RISK_OFF AND top conviction < 30,
1086+
# rotate capital to safest stable (if any).
1087+
if regime == "RISK_OFF" and top[1]["conviction"] < 30 and srr_target:
1088+
rotation = (
1089+
f"DEFENSIVE_ROTATION → {srr_target.symbol} ({srr_target.verdict}, "
1090+
f"SRR {srr_target.score}). Top narrative {top[0]} conviction "
1091+
f"{top[1]['conviction']} below threshold."
1092+
)
1093+
except Exception as e: # pragma: no cover — overlay must never break NRI
1094+
srr_payload = {"error": f"SRR overlay unavailable: {e}"}
1095+
10621096
# Build risks list from bottom performers
10631097
top_narrative = top[0]
10641098
top_result = top[1]
@@ -1081,6 +1115,7 @@ def global_scan(regime="TRANSITION"):
10811115
"top_verdict": top_result["verdict"],
10821116
"top_conviction": top_result["conviction"],
10831117
"risks": risks,
1118+
"stablecoin_risk": srr_payload,
10841119
}
10851120

10861121

@@ -1294,7 +1329,7 @@ def run_backtest(narrative, days=90, initial_capital=10000.0):
12941329
# ==============================================================================
12951330
def main():
12961331
print("=" * 80)
1297-
print("CMC Narrative Rotation Index (NRI) Skill v8.1")
1332+
print("CMC Narrative Rotation Index (NRI) Skill v10.0 — multichain + stablecoin risk radar")
12981333
print("BNBAgent SDK + Trust Wallet Agent Kit + x402 + Kaito SoFi")
12991334
print("=" * 80)
13001335
time.sleep(0.2)
@@ -1395,7 +1430,7 @@ def main():
13951430
sizing_pct = 5 * REGIME_SIZING[regime]
13961431
confidence_output = {
13971432
"skill": "narrative-rotation-index",
1398-
"version": "8.1",
1433+
"version": "10.0",
13991434
"regime": regime,
14001435
"top_narrative": top_n,
14011436
"verdict": top_d["verdict"],
@@ -1461,7 +1496,7 @@ def main():
14611496
print(f"\n{'='*80}")
14621497
print("SUMMARY")
14631498
print(f"{'='*80}")
1464-
print(f" Skill: CMC Narrative Rotation Index (NRI) v8.1")
1499+
print(f" Skill: CMC Narrative Rotation Index (NRI) v10.0")
14651500
print(f" Regime: {regime} (cap: {cap}/100)")
14661501
print(f" Top Narrative: {top_n} ({top_d['verdict']}, {top_d['conviction']}/{cap})")
14671502
print(f" Exhaustion: {top_d['exhaustion_score']}/100")

live_demo.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,42 @@ def fetch_fear_greed(api_key: str) -> int:
8282
return 50
8383

8484

85+
# ---------------------------------------------------------------------------
86+
# v10: Stablecoin Risk Radar — live metrics from CMC
87+
# ---------------------------------------------------------------------------
88+
STABLES_TO_TRACK = ["USDT", "USDC", "FDUSD", "USDe", "DAI", "FRAX", "TUSD", "USDD", "lisUSD"]
89+
90+
91+
def fetch_stable_metrics(api_key: str) -> list:
92+
"""Fetch live stablecoin metrics, return list[StableMetrics]."""
93+
from stablecoin_risk import StableMetrics
94+
95+
try:
96+
quotes = fetch_quotes(STABLES_TO_TRACK, api_key)
97+
except RuntimeError:
98+
return []
99+
100+
metrics = []
101+
for sym in STABLES_TO_TRACK:
102+
if sym not in quotes:
103+
continue
104+
v = quotes[sym]
105+
q = (v[0] if isinstance(v, list) else v).get("quote", {}).get("USD", {})
106+
price = q.get("price")
107+
peg_pct = (price - 1.0) * 100 if price else None
108+
metrics.append(StableMetrics(
109+
symbol=sym,
110+
peg_deviation_pct=peg_pct,
111+
peg_deviation_24h_max_pct=peg_pct, # CMC doesn't expose intraday max, use spot
112+
market_cap_usd=q.get("market_cap"),
113+
market_cap_change_7d_pct=q.get("percent_change_7d"),
114+
market_cap_change_24h_pct=q.get("percent_change_24h"),
115+
volume_24h_usd=q.get("volume_24h"),
116+
volume_change_24h_pct=q.get("volume_change_24h"),
117+
))
118+
return metrics
119+
120+
85121
def transform_to_scoring_schema(
86122
narrative: str,
87123
quotes: dict[str, Any],
@@ -310,6 +346,56 @@ def run_live(narrative: str | None, output_json: bool) -> int:
310346

311347
output["narratives"][n] = narrative_out
312348

349+
# ---- v10: Stablecoin Risk Radar overlay ----
350+
try:
351+
from stablecoin_risk import rank_stables, rotation_target, STABLE_UNIVERSE
352+
live_stables = fetch_stable_metrics(api_key) if api_key else []
353+
if live_stables:
354+
srr_scores = rank_stables(live_stables)
355+
srr_target = rotation_target(srr_scores)
356+
output["stablecoin_risk"] = {
357+
"source": "cmc_live",
358+
"rankings": [
359+
{
360+
"symbol": s.symbol,
361+
"verdict": s.verdict,
362+
"score": s.score,
363+
"issuer": s.issuer,
364+
"type": s.type,
365+
"bucket_scores": s.bucket_scores,
366+
"reasons": s.reasons[:3],
367+
"risks": s.risks[:3],
368+
"bsc_address": STABLE_UNIVERSE.get(s.symbol, {}).get("bsc"),
369+
}
370+
for s in srr_scores
371+
],
372+
"target": (
373+
{
374+
"symbol": srr_target.symbol,
375+
"verdict": srr_target.verdict,
376+
"score": srr_target.score,
377+
"bsc_address": STABLE_UNIVERSE.get(srr_target.symbol, {}).get("bsc"),
378+
}
379+
if srr_target else None
380+
),
381+
}
382+
383+
# Defensive rotation override on the macro signal
384+
top_score = max(
385+
(d["conviction"] for d in output["narratives"].values()),
386+
default=0,
387+
)
388+
if regime == "RISK_OFF" and top_score < 30 and srr_target:
389+
output["macro"]["defensive_rotation"] = {
390+
"trigger": "RISK_OFF + top conviction < 30",
391+
"target_symbol": srr_target.symbol,
392+
"target_verdict": srr_target.verdict,
393+
"target_score": srr_target.score,
394+
"target_bsc_address": STABLE_UNIVERSE.get(srr_target.symbol, {}).get("bsc"),
395+
}
396+
except Exception as e:
397+
output["stablecoin_risk"] = {"error": str(e)}
398+
313399
if output_json:
314400
print(json.dumps(output, indent=2))
315401
else:

skill.yaml

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
name: narrative-rotation-index
2-
version: "9.0"
2+
version: "10.0"
33
description: >
44
A CMC-native Narrative Rotation Index (NRI) skill with multichain narrative coverage
5-
aligned to the BNB Hack 149-token whitelist. Dynamic token discovery, Kaito (SoFi)
6-
social intelligence, 5-bucket scoring, narrative exhaustion detection, auto-execute
7-
toggle, and optional Trust Wallet execution payloads. v9.0: 10 narratives, 48 curated
8-
tokens with verified BSC contracts (Binance-Peg BEP-20 wrappers for ETH/SOL-native).
5+
aligned to the BNB Hack 149-token whitelist + Stablecoin Risk Radar (SRR) defensive
6+
rotation overlay. NRI scores narratives for offense; SRR scores stablecoins for defense.
7+
When regime flips RISK_OFF and top narrative conviction < 30, capital rotates to the
8+
safest-scoring stable. v10.0: 10 narratives + 9 stablecoins, dual 5-bucket model,
9+
defensive rotation triggers, historical depeg backtests (USDC SVB 2023, UST 2022).
910
author: ASBESTOS19
1011
tags:
1112
- narrative-rotation
1213
- regime-detection
1314
- exhaustion-detector
15+
- stablecoin-risk-radar
16+
- defensive-rotation
1417
- quant-strategy
1518
- x402-enforced
1619
- bnbagent-sdk
@@ -31,6 +34,19 @@ supported_narratives:
3134
- Gaming/NFT # AXS, SAND, MANA, GALA, IMX
3235
- BNB Chain # BNB, CAKE, BAKE, XVS, ALPACA
3336

37+
stablecoin_risk_radar:
38+
description: >
39+
Defensive rotation overlay. SRR_score = 0.30×Peg + 0.25×Flow + 0.20×Reserves
40+
+ 0.15×Liquidity + 0.10×Contagion. Verdicts: SAFE 0-25, WATCH 26-50, EXIT 51-75,
41+
EMERGENCY 76-100. Trigger: RISK_OFF regime + top narrative conviction < 30 →
42+
rotate to safest-scoring stable.
43+
coverage:
44+
- USDT, USDC, FDUSD, USD1, USDe, DAI, FRAX, FRXUSD, TUSD, USDD, lisUSD, USDF, EURI, XUSD, FF
45+
backtest_scenarios:
46+
- BASELINE_2026
47+
- USDC_SVB_2023
48+
- UST_DEATH_2022
49+
3450
scoring_model:
3551
description: >
3652
5-bucket weighted scoring with narrative-specific fundamental customization.

0 commit comments

Comments
 (0)