Repository navigation
v0.8.2 — Rate limit counts REST submissions + /status hardening
Two fixes bundled. Commit message highlights the risk-layer change; the dashboard backend hardening landed alongside it (was uncommitted since earlier in the same session).
Headline fix — rate limit counts actual REST submissions
pre_trade_check was recording one rate-limit attempt per evaluation (twice per quote tick — bid side + ask side). With the strategy emitting quotes on every books5 message (~10/sec), the binary recorded ~40 attempts/sec → 2,400 in the 60-second window → tripped rate_limit_threshold = 1000 → 10 consecutive REJECTED_RATE → CircuitBreaker consecutive_rejections trigger → halt. Nothing ever reached the exchange.
Root cause: rate limiting was measuring strategy evaluation rate, not exchange-bound traffic. Pre-trade checks are cheap local gates; only orders that survive the requote logic and slot bookkeeping actually become REST calls.
Fix:
RiskManager::pre_trade_checkno longer callsrecord_attempt. The rate-limit branch is READ-ONLY — it trims stale entries and compares the count against the threshold.- New
RiskManager::record_submission()is the only writer of the rate-limit window. Takesmu_, callsrecord_attempt(now). OrderManagercallsrm_.record_submission()immediately before every REST write (place_order,cancel_order,place_market_order). Read-onlyquery_positions/query_open_orders(reconcile, every 300s) are excluded — negligible against the window.config/config.toml:rate_limit_threshold = 1500(safe margin under OKX's ~3,000/min for trade writes).tests/test_risk.cpp::RateLimit: rewritten to populate the window viarecord_submission()and verifypre_trade_checkblocks correctly.
Bundled — /api/v5/status hardening + tests
(Landed in the same commit because the working tree was dirty.)
db.Ping()→db.PingContext(ctx)with a 2-second deadline so a hung Postgres can't stall/statusforever.- Silent error swallow → HTTP 500 with JSON
{"error": "..."}onlastSnapshotTsfailure orpg_pingfailure. Surfaces operational degradation instead of returning stalews_connected=truewith no signal. - New
statusReaderinterface (same optional-capability pattern ashaltedReader/fillStatsReader) so test stubs can inject failures without spinning up Postgres. - New helper
writeStatusError(w, code, msg)next towriteJSON. - Three new Go tests:
TestStatusHappyPath— 200 + JSON shape check +pg_connected: true.TestStatusTsQueryFailure—lastSnapshotTsinjected error → 500 + body containslastSnapshotTs.TestStatusPingFailure—dbPinginjected error → 500 + body containspg_ping.
Tests
- C++: 8/8 pass (
test_orderbook,test_spsc,test_strategy,test_risk,test_execution,test_reporter,test_backtest,test_integration) under-O3 -march=native -Wall -Wextra -Werror. Zero warnings. - Go: 9/9 pass (added
TestStatusHappyPath,TestStatusTsQueryFailure,TestStatusPingFailure).
Known issues in this tag
config/config.tomlwas committed with[backtest].enabled = trueand[testnet].enabled = true— the operator-side toggles from the live OKX demo session leaked into the commit. Production default isfalse. Either flip locally before deploying, or expect achorefollow-up that restores the defaults.- Commit message describes only the rate-limit change — bundled dashboard-backend hardening is real but not reflected in the message.
Expected runtime behavior after this tag
With record_submission only counting actual REST writes:
- Steady-state quote rate: ~10/s strategy evaluations → after
should_requotegating, ~1–2 actual place/cancel cycles per second per side - Per-side requote = 1 cancel + 1 place = 2 REST writes
- Steady-state: ~4 writes/sec = 240/min — comfortably under the 1,500/min threshold
The consecutive_rejections circuit breaker trip on rate-limit should not recur in normal operation.