Repository navigation
Releases
Releases · moremeds/argon
v0.13.38
Fixed
- The watchlist page no longer throws a React hydration error (#418). The server formats card times in its own zone (UTC in Docker) and the browser in the reader's, so the text differed and React threw the tree away and re-rendered it on the client. The
suppressHydrationWarningflag sat one element too high to cover the text.TickerCardnow renders the UTC string during hydration and switches to local time right after (useSyncExternalStore). - The API opens one connection pool, not one per racing first request.
get_pool()was a barelru_cache, which runs the factory once for each thread that misses at the same time; each extra pool opened connections and threads, was dropped, and its__del__later failed with "cannot join current thread". A lock now serializes the first call. - The spot feed stays on xenon when IB Gateway is logged out but Futu is up. xenon v0.15.0 serves US stocks from Futu during RTH (
?quotes=futu-first), and its status frame reportsproviders.futu. The handshake used to fail over to massive onib_connected: falsealone, so an IB logout also dropped Futu. It now fails over only when both are down. Indexes still need IB.
v0.13.37
Changed
- Watchlist and stock-page spots are pushed to the browser instead of polled. The page used to poll
/api/watchlist/spotsevery 2.5 s on top of a 1 s WS flush, so a price change reached the screen up to ~3.6 s late. Now the WS writer sends a PostgresNOTIFYinside each flush transaction; oneLISTENconnection per API process re-reads the spots and pushes only the changed tickers over Server-Sent Events atGET /api/watchlist/spots/stream(api/live_spots.py);LiveSpotsProvideropens oneEventSourceper page. The flush interval default drops from 1 s to 0.25 s (MASSIVE_WS_FLUSH_INTERVAL_SECONDS). Measured on a local stack through the Next proxy: an event every ~0.25 s, and 3.4 ms median (6.3 ms max) from the DB commit to the browser. The stream sendsCache-Control: no-transform, because Next's rewrite proxy otherwise gzips it for any browser that accepts gzip and holds every event in the gzip buffer. The API pings every 2 s and the page reopens a stream that is silent for 5 s or closed for good: when the API restarts, the Next proxy can leave the browser's half of the stream open and silent. uvicorn gets--timeout-graceful-shutdownindev.sh(1 s) anddocker-compose.yml(3 s), because an open stream otherwise blocks a reload forever. The mini runs its own copy of the compose file, so there the stop stays bounded by Docker's 10 s SIGKILL until that copy is synced.GET /api/watchlist/spotsstays for other readers.
v0.13.36
Fixed
- The SPX GEX scan runs again; it had been stuck on 2026-10-03. Since 2026-10-05 UW answers
/stock/SPX/stock-statewith HTTP 422 ("not available for index ticker SPX") and returnsclose: nullin the SPX iv-rank row, soscanners/gex.runhad no spot and aborted every 2 minutes. The other 11 tickers succeeded, so the job never failed and the Regime GEX tab kept showing the last SPX snapshot. The scan now takes the spot from the live WS quote inintraday_quote(xenon primary; SPX is always subscribed viaREGIME_WS_SYMBOLS) when UW has none, tagsspot_sourcewith the feed, and setstape_timeto the quote time. A quote older than 24 h means the feed is down, and the scan still aborts. Intraday SPX snapshots from 2026-10-05 until this deploy are lost; the first good scan refillsgreek_exposure_dailyfor SPX, because UW's aggregate endpoint returns the full daily series.
v0.13.35
Fixed
- The spot WS consumer now authenticates to xenon's realtime relay. xenon v0.9.0 rejects a WebSocket upgrade from a service client unless it carries
X-API-Keyand noOriginheader.XenonWsClient(the live session and the fallback probe) now sendsX-API-Key: $XENON_QUERY_API_KEYon the upgrade when the key is set, and never anOrigin. Older relays ignore the header. websockets logs every upgrade header and frame at DEBUG, so the client hands it a logger that renders each record (message, args, exception, stack) to text and prints the key as***; the consumer's own failover and probe logs name only the exception type and, for a rejected upgrade, its HTTP status, because a rejection response can echo the key. Without the key, xenon v0.9.0 answers 401 and the consumer fails over to massive, so the mini's argon.envmust carryXENON_QUERY_API_KEY(the same key the REST greeks API needs) and the WS consumer must restart to pick up a rotated key.
v0.13.34
Changed
- The nightly gold factor reads its prices from the livewire lake, not xenon.
gold_factor_computenow reads XAUUSD (bronze/asset_class=cmdty) and the six dollar-index pairs (bronze/asset_class=fx_ib) as IB 1-day MIDPOINT closes from the lake that livewire writes at ~17:20 New York, and moves from 17:40 to 17:50 ET. It no longer stores raw prices: thesource='IB'rows inmacro_series_dailystay but stop growing, andfetch_ib_legs/xenon_query.fetch_ib_daily_midpointsare deleted. Only completed bars are used (a bar dated D closes 17:00 New York on D); xenon returned the bar still forming, so prod stored partial days (dxy_synthetic_daily2026-10-14 = 102.116 from a mid-session bar, 102.528 from the final one). When a leg's last lake bar is older than the last completed NYSE session the job still computes, then fails naming the legs, so a missed livewire run reachesjob_failures. The lake also carries sessions the old chunked xenon seed dropped at its window seams (around Feb 1), adding 11 factor rows; recomputed on prod data the fitted slopes move by at most 0.35 (b_s) over the whole history and 0.022 since 2025, and the latest rows are identical.gold_factor_dailyanddxy_synthetic_dailyjoin the data-freshness monitor.
v0.13.33
Added
- Treasuries tab (02): gold real-yield sensitivity, honest model attribution, per-series data dates. The
ratesmacro tab gains a "Gold · real-yield sensitivity" panel beside the decompositions — the gold factor's real-yield slope with its 95% interval, live only (/api/gold/factortakes noas_of, so it hides under replay) and carrying "Describes the past, not a forecast · the direction test (Phase 3) failed".RatesDecompositionAttributiongainsmodel_vintage_changed: when both window ends read the same monthly Cleveland vintage the five model columns print—("no new monthly model value in this window") instead of a misleading+0.0, and the 1M read names the vintage rather than "accounts for 0.0bps".RatesSourceFreshnessgainsfirst_seen_at, and a compact "Data dates" table inside the curve panel lists each yield series' observation date and argon first-storage time in New York; the caption states that FRED's own publish time is not stored.
Fixed
- Macro desk charts rendered their text at 9–23px instead of the designed px.
.board .chart svg { width: 100%; height: auto }stretches a fixed viewBox's coordinate system — text included — so the gold-factor charts, the DXY panels,usd-gold-month, the gold-flow minis, the Fedpathschart, the dealer-path and SEP dot-plot charts and the yield curve drew on 300/620/760/1200-unit frames that a ~1590px single-column panel magnified and a narrow column shrank. The newlib/useChartWidthhook measures each chart's rendered width (ResizeObserver + initialgetBoundingClientRect, disconnect on unmount; the fallback width stands under jsdom/SSR) and those charts now drawviewBoxequal to the measured width, so one user unit is one CSS pixel and 10px labels render at 10px at any viewport.
v0.13.32
Fixed
- The nightly gold factor job failed on its first xenon leg. xenon answers 503 when its idle IB data socket was reset, and reconnects on that same request; XAUUSD is fetched first, so it took the 503 and the other six legs passed (
job_failureson prod: 2 consecutive failures, the last at 17:46 ET on 2026-10-13, no success yet).fetch_ib_legsnow retries a leg once, 5 s after aSourceUnavailable. The factor compute still ran on those nights on stored prices; only the XAUUSD refresh was missed.
v0.13.31
Added
- Macro desk redesign, design v3: the gold factor model on the overview, gold and USD tabs. The overview's first zone now shows state changes, market moves for the week and gold's sensitivity from the factor model. The new "What moved gold" section follows it, and the chain rail's gold node prints "3 factors explain N%". The 60-day gold–real-yield correlation panel and its gauge fetch are gone. The market-moves panel gains a "Dollar index (DXY)" row (after the three yields) and drops the weekly Fed broad index. The gold tab (live) opens with the research result (sensitivities with 95% intervals, explained share against its two thresholds), then the breakdown (window waterfall 1W/1M/YTD, year to date, each year as "3 factors vs rest" by default or all five parts, slope history), flows and holdings, and an attribution review (drift vs gold this year, the regrouping, the yearly table). The live gold tab no longer shows the GLD 60-day Compass panels; replay and
/gold/replay/<date>keep them. The USD tab (live) opens with the synthetic DXY (level, 1W/1M/YTD moves), its move split by currency, gold's dollar sensitivity with its interval, and this month's gold move against its dollar part; the Fed broad index stays below as reference. Every research panel carries "Describes the past, not a forecast · the direction test (Phase 3) failed". Flow panels draw only series argon stores history for: China's reported reserves (quarterly), CFTC managed-money net as % of open interest (weekly) and the LBMA vault (monthly); SGE withdrawals and the Shanghai premium have no ingest and no panel. - Synthetic ICE dollar index, stored as a result.
gold_factor_computenow also writesdxy_synthetic_daily(migration 163): the index from the six IB FX closes it already fetches (50.14348112 × EURUSD^-0.576 × USDJPY^0.136 × GBPUSD^-0.119 × USDCAD^0.091 × USDSEK^0.042 × USDCHF^0.036), its daily log change, and each currency's part, which add up to that change exactly.GET /api/macro/dxy?from=serves it (default last 5 years; 404 until the job has run).GET /api/gold/flowsserves the three stored flow histories. The table is enrolled in the gap-healer registry as freshness-only (61 entries). Enginemacro/gold_factor.py::dxy_daily. - Treasuries page plan (
docs/superpowers/plans/2026-10-13-macro-treasuries-page-plan.md): gold's real-yield sensitivity beside the 10-year split, the "model accounts for 0.0bp" row (the monthly model has no new vintage inside the window), and data and release dates on each yield. Plan only.
v0.13.30
Added
- Gold factor model, computed by argon. A port of the signal-lab gold study: a rolling 252-day fit of gold's daily move (XAUUSD) on the 10-year real yield (DFII10), a synthetic ICE dollar index and a safe-haven spread, with coefficients lagged two rows. It produces the 95% intervals, the 63-day explained share and its label, and each day's move split into real-yield, dollar, safe-haven, last-year's-pace and unexplained parts. It is a historical description, not a forecast: the study's direction test failed. Engine
macro/gold_factor.py. Results go togold_factor_daily(migration 162). The newgold_factor_computejob (17:40 ET Mon–Fri, massive-0) fetches the last month of IB 1-day MIDPOINT closes through xenonPOST /historical/bars, stores them inmacro_series_daily(sourceIB), then recomputes and upserts the whole history. The IB fetch runs only whenXENON_QUERY_API_KEYis set, and needs xenon PR #174 deployed.GET /api/gold/factorserves daily points and yearly sums. The Gold tab opens with a "What moved gold" band of six charts.scripts/backfill/gold_factor_seed.pyseeds the history: IB closes through xenon in overlapping 6-year windows (one call of 17 years or more outruns IB's 60 s timeout), plus FRED DFII10/DGS10 from 2010 run through the real FRED job.scripts/research/gold_factor_parity.pychecks the port: from the study's own IB closes, argon matches the study exactly on inputs, coefficients, intervals, parts and labels; with--xenon, the same run on closes pulled through xenon matches it exactly too, on all 4079 rows (docs/research/2026-10-10-gold-factor-parity.json).statsmodels(already installed viaarch) is now declared.
v0.13.29
Added
- Budgeted backfill of dark-pool and lit print history. Before v0.13.28 the nightly capture kept at most 500 prints per ticker, day and source, so busy names lost most of each session. The new
dark_lit_backfilljob (daily 22:30 ET, uw-0,UW_SCAN_DARK_LIT_BACKFILL_ENABLED, default off) re-pages every active-watchlist ticker-day that was cut (500 or more prints in either source) or is missing, oldest first, from UW's earliest available date through 2026-10-05. It writes through the samecapture_dark_lit_foras the nightly capture. Each run spends at most one UW budget day's cap (UTC day;UW_SCAN_DARK_LIT_BACKFILL_WEEKDAY_MAX_CALLS15,000,_SATURDAY_60,000,_SUNDAY_60,000), counted from its own rows inexternal_api_requests, and also stops when the research-pool governor says no. Progress is stored per ticker-day indark_lit_backfill_progress, so a restart resumes where it stopped; dates UW refuses as outside its 730-trading-day window are recorded as unavailable and skipped. Each run writes its calls, finished ticker-days, remaining count and stop reason todark_lit_backfill_runs(migration 161).