Skip to content

feat(labs): aggregate CVD Binance + OKX (Phase 2 Hook A) - #131

Merged
mashkovd merged 3 commits into
mainfrom
feat/labs-trading-intel-cvd-okx
May 6, 2026
Merged

mashkovd merged 3 commits into
mainfrom
feat/labs-trading-intel-cvd-okx

Conversation

@mashkovd

@mashkovd mashkovd commented May 6, 2026

Copy link
Copy Markdown
Member

Summary

Phase 2 Hook A of labs-trading-intel. Phase 1.6 shipped CVD as single-exchange Binance taker-buy with the explicit cvd_24h.source = "binance_taker_buy_24h" tag and called multi-exchange aggregation Phase 2 work. Hook A delivers the second viable public source — OKX V5 rubik/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

  • New endpoints documented: OKX taker-volume-contract (returns 100 bars × [ts, buyVol, sellVol] in contracts; per period 4H) + OKX public/instruments for ctVal (contract size in base coin — 0.1 ETH for ETH-USDT-SWAP).
  • 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.

Why not Bybit / Bitget?

Documented exhaustively in memory reference_multi_exchange_taker_endpoints.md (probed 2026-05-06):

  • Bybit V5 — no taker_buy_volume in kline; no public historical-trade endpoint; recent-trade?limit=1000 covers minutes, not 24h.
  • Bitget V2 — probed 5 candidate endpoints (buy-sell-volume, taker-volume, long-short-position-ratio, long-short-vol-ratio, both spot+mix), all 404. Has account-long-short but that's account-ratio, not taker volume.

Both go to Phase 2 Hook B alongside the labs-trading-data stateful service (~/.claude/plans/smooth-soaring-candy.md).

OKX validation (live 2026-05-06)

ETH-USDT-SWAP, 4H, last 6 bars (24h window):

  • Sum buy: 2,010,142 contracts × 0.1 ETH × $2349 = $4.72B
  • Net delta: −29,004 ETH = −$68.1M (sellers dominant)
  • Same period Binance: −$36.3M (sellers dominant — aligned in sign)
  • Aggregated: −$104.5M — both venues confirm bearish taker pressure

Units validated against data[0].ctVal from /api/v5/public/instruments; ctValCcy == "ETH" confirmed; volume order-of-magnitude sane for OKX perp ETH market share.

Test plan

  • Live OKX taker-volume probed via throwaway python — units confirmed (contracts × ctVal × close → USD).
  • Skill markdown smoke-greps green (per_exchange, agreement, source string, step 13/14, OKX docs link).
  • generated/skills-values.yaml regenerated via the same PyYAML serializer that wft-openclaw-skill-save uses.
  • Post-merge: ArgoCD reconciles labs-openclaw-skills. Operator runs /eth ETH in Telegram. Output should now show CVD broken into per_exchange + an agreement qualifier (or a cvd source split line in Risks: if the venues disagree on direction).

Notes for reviewers

  • No code change; pure skill-prose + spec extension. The LLM operating on this skill will fan out the new HTTP calls per the documented endpoints.
  • ctVal caching note in anti-patterns: read once, cache long, never per-snapshot. ETH-USDT-SWAP ctVal has been 0.1 since the contract launched; new coin pairs would need their own ctVal lookup.
  • The agreement="split" risks-warning is operator-facing context, not a scoring penalty — score still uses the aggregated net_usd.
  • Cron labs-watch-scan deliberately untouched — its 5th signal is RSI 4h (Phase 1.6), not CVD; adding CVD to cron pre-filter is scope creep for Hook A.

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).
@mashkovd

mashkovd commented May 6, 2026

Copy link
Copy Markdown
Member Author

@codex review

@mashkovd

mashkovd commented May 6, 2026

Copy link
Copy Markdown
Member Author

@copilot review

@chatgpt-codex-connector

Copy link
Copy Markdown

💡 Codex Review

- Per-bar delta_usd = `(buyVol − sellVol) * ctVal * close` (close из oldest-first Bybit 4h kline last bar). Sum 6 баров = 24h OKX CVD.

P2 Badge Price each OKX CVD bar with its matching 4h close

The step computes OKX 24h CVD by multiplying all six buyVol-sellVol bars with a single Bybit 4h kline last bar close, which distorts USD delta whenever price moved during the window. In mixed-flow windows this can change cvd_24h.net_usd enough to alter its sign, and that sign directly drives the +15 long/short CVD score branches later in the spec. Map each OKX bar timestamp to its corresponding 4h close before summing to keep the signal stable.


14. **CVD aggregation (Phase 2 Hook A):** `cvd_24h.net_usd = binance_24h + okx_24h`. Build `cvd_24h.per_exchange = { binance: <usd>, okx: <usd> }`. Determine `cvd_24h.agreement`: `"aligned"` если sign(binance) == sign(okx) И обе non-zero; `"split"` если знаки противоположны; `"binance_only"` / `"okx_only"` если один из источников `null`. На `"split"` — append `risks: ["cvd source split: binance <sign>$<X>M, okx <sign>$<Y>M"]`. Source string: `"binance_taker_buy_24h+okx_rubik_taker_volume_24h"`.

P1 Badge Define agreement output for zero-delta exchange legs

The new agreement rules only define outcomes for same-sign non-zero (aligned), opposite-sign (split), or null-source (binance_only/okx_only) cases. If one venue returns an exact 0 delta and the other is non-zero, none of these predicates match, so cvd_24h.agreement has no valid enum despite this commit requiring it to always exist in snapshot output. Add an explicit zero-handling branch to avoid undefined agreement values and downstream formatting/risk inconsistencies.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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.
@mashkovd

mashkovd commented May 6, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

💡 Codex Review

1. `binance == null` (unreachable) AND `okx != null` → `agreement = "okx_only"`

P1 Badge Remove impossible okx_only fallback when Binance is down

Rule 1 allows agreement = "okx_only" when Binance is unreachable, but the same section now requires pricing each OKX taker-volume bar with the matching Binance 4h close (Per-bar pricing rule earlier in this file). If Binance klines are unavailable, the OKX leg has no defined USD pricing source, so this branch cannot compute a valid okx_24h delta and may emit inconsistent CVD output. Please either define a Binance-independent price source for OKX bars (e.g., OKX candles/mark) or remove the okx_only branch.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".
@mashkovd

mashkovd commented May 6, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

@mashkovd
mashkovd merged commit 8950407 into main May 6, 2026
@mashkovd
mashkovd deleted the feat/labs-trading-intel-cvd-okx branch May 6, 2026 18:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant