feat(gold): Gold Intelligence v2 — positioning depth, returns, drivers (#3034)

* feat(gold): richer Gold Intelligence panel with positioning, returns, drivers

* fix(gold): restore leveragedFunds fields and derive P/S netPct in legacy fallback

Review catch on PR #3034:

1. seed-cot.mjs stopped emitting leveragedFundsLong/Short during the v2
   refactor, which would zero out the Leveraged Funds bars in the existing
   CotPositioningPanel on the next seed run. Re-read lev_money_* from the
   TFF rows and keep the fields on the output (commodity rows don't have
   this breakdown, stay at 0).
2. get-gold-intelligence legacy fallback hardcoded producerSwap.netPct to 0,
   meaning a pre-v2 COT snapshot rendered a neutral 0% Producer/Swap bar
   on deploy until seed-cot reran. Derive netPct from dealerLong/dealerShort
   (same formula as the v2 seeder). OI share stays 0 because open_interest
   wasn't captured pre-migration; clearly documented now.

Tests: added two regression guards (leveragedFunds preserved for TFF,
commodity rows emit 0 for those fields).

* fix(gold): make enrichment layer monitored and honest about freshness

Review catch on PR #3034:

- seed-commodity-quotes now writes seed-meta:market:gold-extended via
  writeExtraKeyWithMeta on every successful run. Partial / failed fetches
  skip BOTH the data write and the meta bump, so health correctly reports
  STALE_SEED instead of masking a broken Yahoo fetch with a green check.
- Require both gold (core) AND at least one driver/silver before writing,
  so a half-successful run doesn't overwrite healthy prior data with a
  degraded payload.
- Handler no longer stamps updatedAt with new Date() when the enrichment
  key is missing. Emits empty string so the panel's freshness indicator
  shows "Updated —" with a dim dot, matching reality — enrichment is
  missing, not fresh.
- Health: goldExtended entry in STANDALONE_KEYS + SEED_META (maxStaleMin
  30, matching commodity quotes), and seed-health.js advertises the
  domain so upstream monitors pick it up.

The panel already gates session/returns/drivers sections on presence, so
legacy panels without the enrichment layer stay fully functional.
This commit is contained in:
Elie Habib
2026-04-12 22:53:32 +04:00
committed by GitHub
parent d19b32708c
commit ee66b6b5c2
12 changed files with 966 additions and 158 deletions

View File

@@ -10,13 +10,47 @@ message GoldCrossCurrencyPrice {
double price = 3;
}
message GoldSessionRange {
double day_high = 1;
double day_low = 2;
double prev_close = 3;
}
message GoldReturns {
double w1 = 1;
double m1 = 2;
double ytd = 3;
double y1 = 4;
}
message GoldRange52w {
double hi = 1;
double lo = 2;
double position_pct = 3;
}
message GoldCotCategory {
int64 long_positions = 1;
int64 short_positions = 2;
double net_pct = 3;
double oi_share_pct = 4;
int64 wow_net_delta = 5;
}
message GoldCotPositioning {
string report_date = 1;
double managed_money_long = 2;
double managed_money_short = 3;
double net_pct = 4;
double dealer_long = 5;
double dealer_short = 6;
string next_release_date = 2;
int64 open_interest = 3;
GoldCotCategory managed_money = 4;
GoldCotCategory producer_swap = 5;
}
message GoldDriver {
string symbol = 1;
string label = 2;
double value = 3;
double change_pct = 4;
double correlation_30d = 5;
}
message GetGoldIntelligenceRequest {}
@@ -34,4 +68,8 @@ message GetGoldIntelligenceResponse {
GoldCotPositioning cot = 10;
string updated_at = 11;
bool unavailable = 12;
GoldSessionRange session = 13;
GoldReturns returns = 14;
GoldRange52w range_52w = 15;
repeated GoldDriver drivers = 16;
}