Repository navigation
feat(labs): aggregate CVD Binance + OKX (Phase 2 Hook A) - #131
Conversation
Phase 1.6 shipped single-exchange Binance taker_buy CVD with the
aggregated framing deferred to Phase 2 because Bybit V5 doesn't expose
taker_buy in kline. Hook A adds the second viable public source — OKX
V5 rubik/stat/taker-volume-contract — bringing CVD coverage to ~75%
of perp ETH volume without paid APIs.
Skill changes (chat snapshot pipeline only — cron pre-filter
unchanged):
- New endpoints: OKX taker-volume-contract (returns 100 × [ts, buyVol,
sellVol] in contracts) + OKX public/instruments for ctVal (contract
size in base coin; ETH-USDT-SWAP currently 0.1 ETH).
- Snapshot pipeline gains step 13 (OKX leg) + step 14 (aggregation
with per_exchange split + agreement classification).
- Normalized cvd_24h shape extended: per_exchange.{binance, okx},
agreement ∈ {aligned, split, binance_only, okx_only}, source string
bumped to binance_taker_buy_24h+okx_rubik_taker_volume_24h.
- Source-agreement rule: when binance and okx deltas have opposite
signs, append a "cvd source split" risks-warning so the operator
sees that directional pressure isn't confirmed across venues.
- OKX leg fail-soft: if rubik or instruments unreachable, append
okx_taker_volume_unreachable to missing_data, fall back to
Binance-only (Phase 1.6 path) without aborting the pipeline.
Bitget remains Phase 2 Hook B work — probed 5 V2 endpoints during
discovery, all 404; needs labs-trading-data stateful service or
auth keys. References updated; reference_multi_exchange_taker_endpoints.md
already captures the rationale.
OKX validated live 2026-05-06: ETH-USDT-SWAP 24h taker delta -$68M
agreed in sign with Binance -$36M, aggregated -$104M — units checked
against $4.7B 24h volume (sane for OKX perp ETH market share).
|
@codex review |
|
@copilot review |
💡 Codex ReviewThe step computes OKX 24h CVD by multiplying all six The new agreement rules only define outcomes for same-sign non-zero ( ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
… P1+P2)
Two findings on Hook A:
1. P2 — Price each OKX CVD bar with its matching 4h close. The original
step said use "last bar" close as a single multiplier across all 6 OKX
buy/sell-vol bars. In a window with material price drift the resulting
USD delta could land with the wrong sign and flip the +15 long/short
CVD score branch downstream. Fix: per-bar matching close by timestamp
bucket (floor(ts / 14_400_000) since both sources are UTC-aligned 4h).
Bars without a Binance counterpart are skipped, not zero-filled.
2. P1 — Define agreement output for zero-delta exchange legs. The four
defined values (aligned, split, binance_only, okx_only) didn't cover
the case where one venue returns exactly 0 and the other is non-zero
— a real outcome on quiet hours / thin coins — leaving cvd_24h.agreement
undefined despite being required to always exist. Replaced with a
first-match cascade of 7 rules covering the full 16-cell space
(binance ∈ {null, <0, 0, >0} × okx same), with new enum values
`partial_zero` and `both_zero`. The both_zero case also gets its own
risks-warning so the operator knows neither venue saw net imbalance.
Skill markdown only; no code change. generated/skills-values.yaml
regenerated.
|
@codex review |
💡 Codex Reviewokx_only fallback when Binance is down
Rule 1 allows ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
…computable (codex P1)
Round 2 codex caught that the previous per-bar pricing rule tied OKX bars
to Binance closes. With Binance unreachable the okx_only branch from the
agreement cascade had no defined USD pricing source — making the rule
unreachable in practice and inconsistent with the requirement that
cvd_24h.agreement always exist.
Fix: OKX leg now fetches its own /api/v5/market/candles (4H) alongside
the existing /rubik/stat/taker-volume-contract + /public/instruments
calls. Per-bar delta_usd uses OKX-native closes, matched to OKX
taker-volume bars by the same UTC-aligned 14_400_000ms timestamp bucket.
The okx_only path is now fully self-sufficient.
Cross-venue price sanity check added: when both Binance and OKX closes
are present at the same bucket and disagree by >2%, append a risks-note
("okx/binance price spread >2% at <ts>: $<okx>, $<binance>") so the
operator sees venue dislocations or stale data without it silently
distorting the CVD numbers. The CVD math itself stays self-sourced
(OKX delta uses OKX closes; Binance delta uses Binance closes).
OKX endpoints all three require a User-Agent header (without one they
403); noted explicitly in the skill so a future implementer doesn't
trip on it.
Pipeline step 13 + the unreachable-handling paragraph in step 14 were
updated in lockstep so the only-Binance-down case has a documented
behavior matching agreement="okx_only".
|
@codex review |
|
Codex Review: Didn't find any major issues. 🎉 ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Summary
Phase 2 Hook A of
labs-trading-intel. Phase 1.6 shipped CVD as single-exchange Binance taker-buy with the explicitcvd_24h.source = "binance_taker_buy_24h"tag and called multi-exchange aggregation Phase 2 work. Hook A delivers the second viable public source — OKX V5rubik/stat/taker-volume-contract— bringing CVD coverage to ~75% of perp ETH volume without paid APIs or stateful services.Skill markdown only — chat snapshot pipeline. Cron pre-filter (
labs-watch-scan) is unchanged because it uses RSI 4h as its 5th binary signal, not CVD.What Hook A does
taker-volume-contract(returns 100 bars ×[ts, buyVol, sellVol]in contracts; per period4H) + OKXpublic/instrumentsforctVal(contract size in base coin —0.1 ETHfor ETH-USDT-SWAP).per_exchangesplit +agreementclassification).cvd_24hshape extended:per_exchange: {binance, okx},agreement ∈ {aligned, split, binance_only, okx_only}, source string bumped tobinance_taker_buy_24h+okx_rubik_taker_volume_24h.cvd source splitrisks-warning so the operator sees that directional pressure isn't confirmed across venues.okx_taker_volume_unreachabletomissing_data, fall back to Binance-only (Phase 1.6 path) without aborting the pipeline.Why not Bybit / Bitget?
Documented exhaustively in memory
reference_multi_exchange_taker_endpoints.md(probed 2026-05-06):taker_buy_volumein kline; no public historical-trade endpoint;recent-trade?limit=1000covers minutes, not 24h.buy-sell-volume,taker-volume,long-short-position-ratio,long-short-vol-ratio, both spot+mix), all 404. Hasaccount-long-shortbut that's account-ratio, not taker volume.Both go to Phase 2 Hook B alongside the
labs-trading-datastateful service (~/.claude/plans/smooth-soaring-candy.md).OKX validation (live 2026-05-06)
ETH-USDT-SWAP, 4H, last 6 bars (24h window):
Units validated against
data[0].ctValfrom/api/v5/public/instruments;ctValCcy == "ETH"confirmed; volume order-of-magnitude sane for OKX perp ETH market share.Test plan
per_exchange,agreement, source string, step 13/14, OKX docs link).generated/skills-values.yamlregenerated via the same PyYAML serializer thatwft-openclaw-skill-saveuses.labs-openclaw-skills. Operator runs/eth ETHin Telegram. Output should now show CVD broken intoper_exchange+ anagreementqualifier (or acvd source splitline inRisks:if the venues disagree on direction).Notes for reviewers
ctValhas been0.1since the contract launched; new coin pairs would need their own ctVal lookup.agreement="split"risks-warning is operator-facing context, not a scoring penalty — score still uses the aggregatednet_usd.labs-watch-scandeliberately untouched — its 5th signal is RSI 4h (Phase 1.6), not CVD; adding CVD to cron pre-filter is scope creep for Hook A.