Commit History
Yesterday
-
fix(quotes): pair a closed-session price by its trade time, not its broadcast time Running
Awannit7a57e8c -
fix(quotes): a closed-session trade without a daily bucket is quoted against its own session's baseline
Awannite3de708
2 days ago
-
fix(quotes): fill a missing prevClose from the baseline, bounded
Awannit0269fbd
3 days ago
-
feat(stream): fills topic for pokes
Awannit9f7f0c5 -
fix(stream): poke body reader settles on every ending; everyone needs a spread and a minute apart
Awannit032a0eb -
feat(stream): poke signed-in sockets when the app writes for them
Awannit74417da
4 days ago
-
feat(stream): admit by feed age and client backlog; slow the update rate as clients grow
Awannitc7d3d86 -
fix(stream): bound queued snapshots per client and across the hub
Awannit6fa0213 -
fix(stream): keep clients through a large snapshot; conflate bar updates in the fan-out
Awannitc7ca669
9 days ago
-
fix(health): answer the Space page's framed address by path
Awannit2f07c83 -
fix(nepse): report the relay's failures by kind on the public health check
Awannit396f362 -
feat(nepse): fail over to the Strix relay when the exchange will not answer
Awannit6dc54d5
11 days ago
-
feat(sentry): error monitoring, preloaded before the app
Awannit2228999
-
feat(nepse): long daily history from Merolagani under the exchange and archive
Awannitb615b41 -
fix(nepse): date a closed-market index read by the board, never the clock
Awannit89764d3 -
feat(nepse): a year of index daily history, quotes dated by the poll, prior board on an open-market start
Awannit113b5d6
-
fix(nepse): read the live market's space-separated timestamps
Awannit7c9610a
-
feat(nepse): relay the exchange's open/closed state in status messages
Awannit1bd6349 -
feat(nepse): live NEPSE feed, one request for the whole market
Awannitb2a48d6
-
feat(history): narrow reads with ?since= for paper trading
AwannitPaper trading judges resting orders on the bars since it last looked, usually a few minutes of 1m bars. The seed path cannot serve that cheaply: on a cache miss it drains the full seed target, which for 1m equities is 10-25 Alpaca pages against the rate limit the live charts share. /history?since=<unixSec> now asks each provider for ONE page from that point forward (Binance startTime, OANDA from, Alpaca start, Yahoo period1), after first trying the chart's seed cache, which costs no upstream call when somebody has the chart open. A 20s cache keyed by the since-minute and the shared in-flight map collapse the same question from several Vercel instances into one request. The OLDEST limit bars are returned, not the newest, so a caller walking forward from a cursor advances without leaving a gap. `since` is echoed in the response so the app can tell this server honoured it; an older server ignores the parameter, and the app filters and rations its requests itself in that case. The legacy…883d1ea
-
Admit non-browser clients: verify token first, Origin only if present
Awannitee87327
-
fix(alerts): drive every tier from here, GitHub is not reliable
AwannitMeasured, not assumed: GitHub's scheduled workflows on this repo are being dropped wholesale. Six consecutive hourly evaluate-watches runs missing, and billing-reconcile (nominally hourly at :23) actually ran at 18:08, 20:14 and 23:46 with an eight-hour overnight gap. GitHub documents scheduled runs as best-effort under load. A daily-tier alert whose only driver is that scheduler is not a monitored alert. So the heartbeat stops requesting tier=live and requests everything, at 15 minutes. This container is a persistent process with a real timer that we keep warm anyway; GitHub drops to a backstop for when it restarts. The daily tier is cheap here because buildMetrics memoises daily metrics for 30 minutes. Spec refresh 180s -> 60s. That window lost a real alert: BTC at ~79,635 with a condition armed at "above 79,630" was invisible here until the next refresh, and price fell back under the level inside it. The window is properly closed on the Vercel side, which now evaluates a condition…9308670 -
feat(alerts): trigger on ticks instead of polling every 2 minutes
AwannitPrice alerts waited up to 120s for a timer to ask Vercel to look. The tick that satisfies the condition was already in this process's memory, so the poll was asking on a schedule about an event being delivered continuously. watch-live.ts pulls the live-tier thresholds from Vercel every few minutes (no user ids, no state), checks them against every tick, and on a local false->true transition asks Vercel to run its normal evaluation pass now. Latency goes from up to 120s to about 2s. It triggers; it does not decide. Edge detection, cooldowns, mute windows, dedupe and the write all stay on Vercel, because a second copy of the firing rules in a second repo is how a user gets notified twice. Being only a trigger means being wrong cheaply, so ambiguous cases err toward poking: a condition mixing live and daily predicates triggers on its live half and Vercel judges the whole thing. Transitions do not send requests, they set a flag, and one debounced request follows. A thousand users watchi…5634d87
-
feat(capacity): admit clients by measured health, not a guessed cap
AwannitAdmission was governed by MAX_CLIENTS, a constant picked by intuition (200). A constant is wrong in both directions: too low and it turns away tabs while the box sits idle, too high and it admits everyone right up until the event loop stalls and *every* connected user loses their feed. Client count was never what determined whether this server could cope. The load that matters is fan-out work (clients x symbols x tick rate), and event-loop delay measures that directly. - load.ts: samples monitorEventLoopDelay + RSS on a 5s reset cycle and reports ok / strained / critical. - Admission keys on that. While healthy there is no client-count ceiling at all. Under strain, anonymous arrivals shed first so signed-in users keep the sessions they have work in. Critical stops new work entirely; existing clients are never dropped for load. - MAX_CLIENTS survives only as a runaway backstop at 20k, far above real load. STRIX_MAX_CLIENTS=0 disables it. Also adds the live-tier alert heartb…d3911cc
-
Add /quotes batch endpoint and opt-in OHLCV to /history
AwannitTwo additive read endpoints over state the engine already holds, plus the freshness rules that make them safe to trust. /quotes?syms= returns latest price + prevClose for up to 50 symbols straight from memory. It never calls getBaseline (which falls through to fetchHistory), so a 50-symbol request cannot fan out into 50 upstream provider calls. This removes ~30 Finnhub /quote calls per Market Intelligence run and up to 50 per portfolio refresh — the two largest consumers of a 60/min shared allowance. Freshness is classified, never synthesised. asOf is the conflated tick-broadcast time (engine.getLatestTickAt, which over-states age by at most one conflation interval and never under-states it) or the 1D bar's own start time. session_close REQUIRES a closed session. A stored daily bar is not a current price while a market is trading — it is that morning's open, and the market has been moving against it ever since. Serving one whenever a tick was merely absent meant the most likely mome…f6456c2
-
Strix V3 — allow strixtrading.com origins for WebSocket upgrades
AwannitALLOWED_ORIGINS is fail-closed: isOriginAllowed() rejects any origin not listed, so the production domain missing from this set would silently break every live price and chart served from it — no error surfaced to the user, just a rejected upgrade. Adds both the apex and www. forms of the current production domain (strixtrading.com), since the browser sends whichever host actually served the page. The legacy strix.technology entries are retained while that domain still resolves, and documented as safe to drop once retired. There is no env override for this set, so shipping it requires this deploy. Verified: tsc --noEmit clean; 36/36 server tests pass.3a87b75
-
Add instrument identity boundary (validFromUtc) — fix SPCX phantom pre-listing candles
Awannit"SPCX" is a recycled ticker: a 2021 SPAC ETF (~$28.85) traded under it before delisting, so raw-ticker history queries returned the old instrument's bars and rendered phantom candles before SpaceX's 2026-06-12 Nasdaq debut. Users could also scroll into that meaningless span (the chart's left edge anchors to bars[0]). - symbols.ts: optional SymbolMeta.validFromUtc (ISO date, parsed as UTC midnight per ECMA-262) — instrument identity boundary, registry-owned; fail-fast authoring tripwires (1990 floor, +10y ceiling); SPCX set to 2026-06-12; getValidFromSec() runtime accessor (epoch sec). - history.ts: central per-branch filter in fetchInitialUncached (upstream of the LRU cache; Alpaca→Yahoo fallback decides on the FILTERED count), floorGuard backfill wrapper (zero-copy fast path, terminates at the boundary, propagates inner errors), per-provider cursor clamps (Alpaca/Yahoo window clamps incl. Yahoo exclusive-period1 -1s slack; Binance/OANDA cursor stops). - engine.ts: aut…069e91a
-
Add SPCX to equity registry, drop dead BRK.B entry, add symbol-cap guard test
AwannitSPCX slots into Alpaca Tier-1 coverage; BRK.B is removed since it had no live feed. New symbol-caps.test.ts guards the Finnhub (50) and Alpaca (30) free-tier WS symbol caps against future registry growth.40b348a
-
Strix Server V2.1.4 — cold-start hardening, memory optimisation, compression test
Awannit +1: Claude Sonnet 4.6Cold-start thundering-herd guard - Add FIFO counting semaphore (SEED_MAX_CONCURRENT=8, env-overridable via STRIX_SEED_MAX_CONCURRENT) in ClientHub.handleSubBars. At market open hundreds of clients subscribe within a second; without this each fires an independent provider REST call. Same-(sym,tf) subs already coalesce via the seeding flag, but the real fan-out (distinct symbols × timeframes) can still produce 429 storms on Alpaca free IEX (~200 req/min). The semaphore caps in-flight fetches to 8 while beginSeed() is called BEFORE acquiring a slot so coalescing still works correctly while a slot waits. try/finally guarantees the slot is released even if fetchHistory() throws. Memory optimisation - MAX_BARS_PER_BUCKET default 1,000,000 → 150,000 bars. This sits above the deepest legitimate single-bucket backfill (BACKFILL_PAGE_SAFETY_LIMIT×~1000 bars/page ≈ 100,000 for a 24/7 market) so no user hit the trim, but drops worst-case per-bucket footprint ~6.7× (≈48 MB → …d1a22ba
-
Strix Server V2.1.3 (Session-open baseline fix, forex tick volume, /history endpoint for Chronos, memory hardening)
AwannitCorresponds to Strix Charts V2.1.3. Baseline / CHG correctness at the session boundary - Fix wrong CHG/CHG% the instant a market opens (watchlist/header showed the move vs the wrong prior session until a page refresh). New session-aware derivePrevClose() (baseline.ts) handles the "session-open lag" window where the provider hasn't emitted today's daily bar yet: when the market is open and the last 1D bar starts before the current session bucket, that last bar IS the previous close. Off-hours/weekend behavior (prevClose = bars[len-2]) preserved. - ClientHub now corrects prevClose instantly and event-driven: detectSessionCross() watches the live tick stream and re-derives + re-pushes the moment a tick crosses into a new daily session (the same instant the chart's 1D bar rolls) — no timer, no network (prior close is already cached). sub_ticker arms the trigger per symbol (seeds 0 when the market is closed so the first tick of the next session fires); only the first su…7d92bb6
-
Corresponds to Strix Charts V2.1.2 commit
Awannit28e0524
-
Corresponds to Strix Charts/Streaming V2.1.2
Awannitf30ccd2 -
Updated Server - Corresponds to Strix Streaming V2.1.1
Awannit9de4cbc
-
Fix Binance 451 Error - Geo restriction
Awannit8ac078e -
Strix Streaming V2.1
Awannit1af30de
-
Strix Streaming - V2
11f6676
-
Deploy latest server updates
4356d4a -
Deploy latest server updates
4ea5acf
-
Deploy latest server updates
d1394d3 -
Deploy latest server updates
927aa39 -
Deploy latest server updates
ad4a28b -
Deploy latest server updates
5863c85 -
Deploy latest server updates
82e6399 -
Deploy latest server updates
5bc4a17 -
Deploy latest server updates
07213aa -
Deploy latest server updates
4e5c23b
-
Deploy latest server updates
64c7275 -
Deploy latest server updates
06b1ab9
-
fix: revert stocks to Finnhub WS, fix baseline routing + retry timing
- Stocks/ETFs back on Finnhub WS (TwelveData 8-symbol limit too restrictive) - TwelveData WS: forex (EUR/USD, GBP/USD) + Gold (XAU/USD) only - Split isTwelveDataWsSymbol (WS routing) from isForexSymbol (baseline routing) - Baseline for stocks: Yahoo Finance (range=1d fix) -> Finnhub /quote fallback - Retry timing: 3s/7s/12s (fits within client 15s DATA UNAVAILABLE timeout) - TwelveData WS: fixed string price parsing (was silently dropping all events)b69c14b -
feat: migrate stocks/ETFs to TwelveData WS for accurate CHG/CHG%
- Stocks/ETFs now stream through TwelveData WS which provides previous_close, change, and percent_change directly in each price event - Client patchTicker accepts authoritative change data instead of computing from potentially stale baseline - Fixed Yahoo range=5d to range=1d (was referencing prevClose from 5 days ago) - OANDA commodities (Silver, Oil) remain on Finnhub WS - TwelveData free-tier: 8 concurrent WS symbols (sufficient for watchlist)c4496c4