VIOLET OA: partial spec PASS 5 — mock-BingX execution stack (quirks seam-only, deferred)
VIOLET_PART_SPEC_OA_TODO_PASS5.md — the DARK mock-BingX execution stack so the full order lifecycle is buildable/testable with zero keys/risk (V4-live later = swap mock for real client). Five independent units extending contracts_v3 (Order/OrderAck/Fill/OrderStatus/PositionDelta): 20. Execution contracts + QuirkProfile seam registry (no quirk logic). 21. Mock BingX order FSM (legal lifecycle, partials, reject, reduce-only-increase rejection). 22. Mock BingX venue adapter (port-conformant, injectable fill model, quirk hooks INERT by default). 23. Fill→position/PnL reducer (PnL from fill_price ONLY; ×leverage-aware) → PositionDelta. 24. DARK E2E gate: ExecIntent → router/driver → mock venue → fill reducer → PASS-4 ledger. CRITICAL per operator: a prominent ⚠️ section makes explicit that BingX "quirks" (zero-wb WS frames, ownership/foreign-fill collision, bound-price poison, ×leverage notional, settle desync, reduce-only edge, setLeverage race, dead .pro TLS) are EXPLICITLY OUT OF SCOPE for PASS 5 — the mock carries injection SEAMS (QuirkProfile, default OFF) to accommodate them LATER, and a real-key boundary smoke remains MANDATORY before V4-live. Quirks sourced from PINK orphan/reconcile + DITAv2 audit memory. Standing ready to write PASS 6–9 (exec internals/reconcile, V5 selection+slots, V6 bible consumers, economics/observability). Added PASS 5 to the review queue in VIOLET_TODO_CRITICAL.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
192
prod/docs/VIOLET_PART_SPEC_OA_TODO_PASS5.md
Normal file
192
prod/docs/VIOLET_PART_SPEC_OA_TODO_PASS5.md
Normal file
@@ -0,0 +1,192 @@
|
||||
# VIOLET — partial spec for another agent, PASS 5 (OA TODO): MOCK-BINGX EXECUTION STACK
|
||||
|
||||
Date: 2026-06-17. Continues PASS 1–4 (same V0→V6 plan, same independent-unit discipline). PASS 5
|
||||
builds the **mock-BingX execution stack** — the DARK path that lets the ENTIRE order lifecycle
|
||||
(submit → ack → fill/partial/reject → reconcile → position/PnL) be built and bit-tested with
|
||||
**zero keys, zero risk**, so that V4-live later becomes "swap the mock adapter for the real BingX
|
||||
client." This is the largest remaining buildable-while-DARK chunk of the spec.
|
||||
|
||||
**Read first:** the V2 execution work already shipped — `prod/clean_arch/violet/scripted_venue.py`,
|
||||
`exec_driver.py`, `exec_harness.py`, `observe_guard.py`, `synthetic_intents.py`,
|
||||
`exchange_leverage.py`, and PINK's `prod/clean_arch/runtime/pink_direct.py` +
|
||||
`prod/clean_arch/exec/` ExecutionRouter (READ for maker/taker policy conventions; do NOT edit).
|
||||
PASS 5 extends, does not replace, these.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ ⚠️ READ THIS FIRST — EXCHANGE "QUIRKS" ARE EXPLICITLY OUT OF SCOPE FOR PASS 5 ⚠️ ⚠️
|
||||
|
||||
The mock built here implements BingX's **NORMATIVE / documented** semantics only (clean order
|
||||
lifecycle, fills, leverage, reduce-only, maker/taker, partials). BingX has a substantial set of
|
||||
**undocumented / edge "quirks"** that broke PINK in production. They are **NOT to be implemented
|
||||
or worked around during PASS 5.** Two hard requirements instead:
|
||||
|
||||
1. **The mock MUST be structured with explicit INJECTION SEAMS** so each quirk can later be turned
|
||||
on (a `QuirkProfile` config + hook points) to test the reconcile/filter logic against it —
|
||||
WITHOUT rewriting the mock.
|
||||
2. **A real-key smoke at the venue boundary remains MANDATORY before V4-live** — a mock can only
|
||||
validate logic, never undocumented venue reality.
|
||||
|
||||
### Known BingX quirks to ACCOMMODATE-LATER (do NOT implement now; just leave seams + a registry):
|
||||
Source: memory `project_pink_orphan_fixes`, `ditav2_kernel_audit_20260611`, `incident_*`.
|
||||
1. **Zero-wallet-balance WS frames** — BingX transiently pushes account/position frames with
|
||||
`walletBalance=0`; treating them as truth zeroes capital. (Reconcile must ignore zero-wb / use
|
||||
reseed-on-update.) Seam: mock can emit a zero-wb frame on demand.
|
||||
2. **Ownership / foreign-fill collision** — fills/orders for OTHER subaccounts appear on a shared
|
||||
user-data stream (PRODGREEN↔PINK shared-account hazard); must be filtered by ownership. Seam:
|
||||
mock can emit a fill tagged with a foreign `ownership_id`.
|
||||
3. **Bound-price poison** — orders carry a "bound" price; using it for PnL instead of the actual
|
||||
fill price poisons accounting. Seam: mock fill carries both bound and fill price; PnL must use
|
||||
fill price (Task 23).
|
||||
4. **×leverage notional** — BingX reports notional/qty with leverage applied; double-applying
|
||||
leverage corrupts size. Seam: documented in the Fill→position reducer (Task 23).
|
||||
5. **Settle / funding desync** — settlement & funding events arrive desynced from fills; capital
|
||||
deltas must be `event_seq`-ordered (ties to PASS-4 economics ledger). Seam: mock can interleave
|
||||
a settle event out of fill order.
|
||||
6. **Reduce-only edge** — a reduce-only order that would INCREASE the position is rejected by
|
||||
BingX. Implement this ONE as normative (it is documented), but note the partial/zero-qty edge.
|
||||
7. **setLeverage race** — `setLeverage` is a separate call with its own ack; a race vs the order
|
||||
can apply the wrong leverage. Seam: mock `set_leverage` is a distinct, separately-ackable op.
|
||||
8. **Dead `.pro` TLS WS backup** — the `.pro` WS endpoint TLS can die silently (connection-layer).
|
||||
Out of mock scope (connection layer); note for the real-client adapter.
|
||||
|
||||
A new file `prod/clean_arch/violet/exec/bingx_quirks.py` holds ONLY a `QuirkProfile`
|
||||
(StrictModel, all quirks default OFF) + an enum registry of the above — the seam contract. No
|
||||
quirk LOGIC. Tasks below reference `QuirkProfile` at their hook points but implement none.
|
||||
|
||||
---
|
||||
|
||||
## 0. HARD RULES (identical to PASS 1–4 — summarized)
|
||||
- **Never edit shared files** (`prod/nautilus_event_trader.py`, `clean_arch/dita_v2/**`,
|
||||
`dita/decision.py`, `nautilus_dolphin/**`, `blue_parity.py`, `prod/bingx/leverage.py`). READ only.
|
||||
(You MAY read `prod/clean_arch/exec/**` + `pink_direct.py` for router/venue conventions; do not edit.)
|
||||
- **VIOLET DARK** — the mock NEVER touches a real venue, network, or key. No service/HZ control.
|
||||
- **V-TYPES on all new code**; faithful poison-guards only.
|
||||
- **NEW-FILE-ONLY** under a NEW package `prod/clean_arch/violet/exec/` (plus extending
|
||||
`contracts_v3.py`). Do NOT modify in-flight files (the V3.4 sourcing/engine set, `cadence.py`,
|
||||
`clock.py`, `exchange_leverage.py`, `scripted_venue.py`, `exec_driver.py`, `22_violet_decisions.sql`).
|
||||
READ + IMPORT them.
|
||||
|
||||
## 0a. COMMIT / BRANCH POLICY (3 shared-index collisions on 2026-06-16 — non-negotiable)
|
||||
Own `git worktree` (`git worktree add ../vp-oa5 -b agent/oa-violet5`) strongly preferred. Else
|
||||
never `git add -A`; `git commit -F msg -- <files>` with explicit pathspec; verify
|
||||
`git show --stat --format="" HEAD` lists ONLY your files. One commit/task, prefix `VIOLET OA:`,
|
||||
Co-Authored-By trailer. Tests on `/home/dolphin/siloqy_env/bin/python3`. `git grep` only.
|
||||
|
||||
---
|
||||
|
||||
## I. SHARED INTERFACE EXTENSIONS (add to `contracts_v3.py`; never fork a parallel type)
|
||||
Reuse PASS-3/4 types (`VenueTick`, `OpenPositionView`, `ExitDecision`, `ExecIntent`,
|
||||
`CapitalState`). ADD the execution vocabulary (all `StrictModel` / `Annotated` V-TYPES):
|
||||
1. **`OrderType`** = Literal["MAKER","TAKER"]; **`OrderSide`** = Literal["BUY","SELL"];
|
||||
**`OrderStatus`** = Literal["NEW","ACK","PARTIALLY_FILLED","FILLED","CANCELED","REJECTED"].
|
||||
2. **`Order`** — `client_order_id: str`, `asset: Symbol`, `side: OrderSide`, `qty: Qty`,
|
||||
`price: Px` (limit; maker), `order_type: OrderType`, `reduce_only: bool`,
|
||||
`leverage: Annotated[int, Field(ge=1)]`, `ts_ns: MonoNs`.
|
||||
3. **`OrderAck`** — `client_order_id: str`, `venue_order_id: str`, `status: OrderStatus`,
|
||||
`ts_ns: MonoNs`, `reject_reason: str = ""`.
|
||||
4. **`Fill`** — `venue_order_id: str`, `asset: Symbol`, `side: OrderSide`, `fill_qty: Qty`,
|
||||
`fill_price: Px`, `bound_price: Px` (quirk #3 seam — carry it, never use it for PnL),
|
||||
`fee: float (ge=0)`, `is_maker: bool`, `ownership_id: str` (quirk #2 seam),
|
||||
`event_seq: Seq`, `ts_ns: MonoNs`.
|
||||
5. **`PositionDelta`** — `asset: Symbol`, `qty_delta: float`, `realized_pnl_delta: float`,
|
||||
`fee: float (ge=0)`, `event_seq: Seq` — the unit that feeds PASS-4 `EconomicsLedger`.
|
||||
|
||||
If a task needs another field, ADD it here and note it.
|
||||
|
||||
---
|
||||
|
||||
## TASK 20 — Execution contracts + QuirkProfile seam registry
|
||||
**Why.** The shared execution vocabulary + the quirk-seam contract everything else depends on.
|
||||
**Affected files (NEW):** extend `prod/clean_arch/violet/contracts_v3.py` (the §I types);
|
||||
`prod/clean_arch/violet/exec/__init__.py`; `prod/clean_arch/violet/exec/bingx_quirks.py`
|
||||
(`QuirkProfile` StrictModel, all flags default False + the quirk enum registry — NO logic);
|
||||
`prod/clean_arch/violet/exec/test_violet_exec_contracts.py`.
|
||||
**Pass criteria.** All types construct + poison-reject (negative qty, non-finite price, etc.);
|
||||
`QuirkProfile()` defaults every quirk OFF; the enum lists exactly the 8 quirks above. No logic in
|
||||
`bingx_quirks.py`. No edits outside the new/extended files.
|
||||
|
||||
## TASK 21 — Mock BingX order FSM
|
||||
**Why.** The deterministic order lifecycle state machine — the heart of the mock.
|
||||
**Affected files (NEW):** `prod/clean_arch/violet/exec/order_fsm.py`,
|
||||
`prod/clean_arch/violet/exec/test_violet_order_fsm.py`.
|
||||
**Interface/approach.** `OrderFSM` holds per-order state; legal transitions only:
|
||||
NEW→ACK→{PARTIALLY_FILLED*→FILLED | CANCELED | REJECTED}. `submit(order)->OrderAck`,
|
||||
`apply_fill(venue_order_id, fill_qty, fill_price)->(OrderStatus, Fill)`, `cancel(...)`. Illegal
|
||||
transitions raise/reject (never silently). Reduce-only that would increase position → REJECTED
|
||||
(quirk #6, normative). Partial fills accumulate; FILLED only when cumulative == order qty.
|
||||
Monotonic `event_seq`. Pure/in-memory; deterministic (no wall clock — caller passes ts_ns).
|
||||
**Pass criteria.** Full-fill, multi-partial→fill, cancel-after-partial, reject (reduce-only
|
||||
increase), illegal-transition rejection; Hypothesis: cumulative fill ≤ order qty always; event_seq
|
||||
strictly increasing. No edits outside the 2 files.
|
||||
|
||||
## TASK 22 — Mock BingX venue adapter (port-conformant, quirk-seamed)
|
||||
**Why.** The venue itself: a `MockBingxVenue` implementing the execution-venue port so the router
|
||||
/ driver can drive it exactly like the real one — but deterministic + DARK.
|
||||
**Affected files (NEW):** `prod/clean_arch/violet/exec/mock_bingx_venue.py`,
|
||||
`prod/clean_arch/violet/exec/test_violet_mock_bingx_venue.py`.
|
||||
**Interface/approach.** Define `ExecutionVenuePort` (ABC) if one isn't already agreed: `set_leverage(asset,
|
||||
lev)->OrderAck` (quirk #7 seam — separate ackable op), `submit(order)->OrderAck`,
|
||||
`cancel(client_order_id)->OrderAck`, `poll_fills()->list[Fill]`, `close()`. Implement
|
||||
`MockBingxVenue(fill_model, quirks: QuirkProfile = QuirkProfile())` over `OrderFSM`. Fill model is
|
||||
INJECTABLE (`ScriptedFillModel` for tests: immediate full / N-partials / reject / maker-vs-taker).
|
||||
Maker orders fill at limit price; taker at a provided reference (VenueTick.ask/bid). Fee = maker vs
|
||||
taker rate (read the router's rate conventions; pass rates in, don't hardcode a venue-specific
|
||||
number). **Quirk hooks present but inert:** when `quirks.zero_wb`/`foreign_fill`/`settle_desync`
|
||||
are False (default) behave normatively; the hook points exist for a later quirk-injection pass.
|
||||
**Pass criteria.** A `ScriptedFillModel` drives submit→ack→fill→FILLED; partial sequence;
|
||||
reject; maker vs taker fill price + fee differ correctly; `set_leverage` acks independently;
|
||||
with default `QuirkProfile()` NO quirk behaviour occurs. No live network. No edits outside the 2 files.
|
||||
|
||||
## TASK 23 — Fill → position/PnL reducer (fill-price PnL, ×leverage-aware)
|
||||
**Why.** Turn `Fill`s into `PositionDelta`s correctly — the accounting seam where bound-price
|
||||
poison (#3) and ×leverage (#4) would bite. Feeds PASS-4 `EconomicsLedger`.
|
||||
**Affected files (NEW):** `prod/clean_arch/violet/exec/fill_reducer.py`,
|
||||
`prod/clean_arch/violet/exec/test_violet_fill_reducer.py`.
|
||||
**Interface/approach.** `apply_fill(pos: OpenPositionView | None, fill: Fill) ->
|
||||
(OpenPositionView, PositionDelta)`. **PnL uses `fill.fill_price` ONLY — never `bound_price`**
|
||||
(assert/comment quirk #3). Notional/qty handled WITHOUT double-applying leverage (quirk #4 —
|
||||
document the convention explicitly). Realized PnL on reducing fills = signed (entry−fill)×qty for
|
||||
SHORT, etc.; fees subtracted; `event_seq` carried through. Pure function.
|
||||
**Pass criteria.** Open, add, partial-reduce, full-close produce correct qty + realized PnL +
|
||||
fee; a test asserts that a fill with `bound_price != fill_price` yields PnL from `fill_price`;
|
||||
Hypothesis: qty ≥ 0; realized PnL finite. No edits outside the 2 files.
|
||||
|
||||
## TASK 24 — Mock execution integration harness (router + driver + venue, DARK storm)
|
||||
**Why.** Prove the whole stack composes: `ExecIntent` (PASS-4 Task 17) → router/maker-policy →
|
||||
`ExecDeadlineDriver` (V2) → `MockBingxVenue` → `Fill` → `fill_reducer` → `PositionDelta` →
|
||||
`EconomicsLedger` (PASS-4 Task 16). The end-to-end DARK proof.
|
||||
**Affected files (NEW):** `prod/clean_arch/violet/exec/mock_exec_harness.py`,
|
||||
`prod/clean_arch/violet/exec/test_violet_mock_exec_scenarios.py`, gate report →
|
||||
`prod/VIOLET_dev/reports/violet_mock_exec_<UTC>.json`.
|
||||
**Interface/approach.** Wire the components (READ `exec_harness.py`/`exec_driver.py` for the V2
|
||||
storm pattern; reuse, don't fork). Run a seeded scenario matrix: clean entry→fill→exit; partial
|
||||
fills; cancel/requote on TTL; reject; maker_both policy. Assert: every order reaches a terminal
|
||||
state, capital == anchor + Σ deltas (ledger), NO order ever leaves the mock (DARK guard), and the
|
||||
run is deterministic (same seed ⇒ same fills/deltas twice).
|
||||
**Pass criteria (`@pytest.mark.gate`).** ≥ 8 scenarios green; determinism proven; ObserveOnly/DARK
|
||||
guard asserts zero real-venue calls; report archived. No edits outside the new files.
|
||||
|
||||
---
|
||||
|
||||
## Composition map
|
||||
```
|
||||
contracts_v3 (+Order/OrderAck/Fill/OrderStatus/PositionDelta) + exec/bingx_quirks(QuirkProfile)
|
||||
20 contracts + quirk seams
|
||||
21 order_fsm → legal lifecycle, partials, reject
|
||||
22 mock_bingx_venue(fsm, fill_model, quirks=OFF) → OrderAck + Fill stream (quirk hooks inert)
|
||||
23 fill_reducer(pos, fill) → (OpenPositionView, PositionDelta) (fill-price PnL)
|
||||
24 mock_exec_harness: ExecIntent → router/driver → 22 → 23 → PASS-4 EconomicsLedger (DARK E2E)
|
||||
```
|
||||
Integration into the live reactor + the real BingX client swap is the OWNER's job later. The
|
||||
quirk-injection pass (turning `QuirkProfile` flags ON to test reconcile/filter logic) and the
|
||||
mandatory real-key boundary smoke are SEPARATE, LATER work — NOT PASS 5.
|
||||
|
||||
## Recommended order
|
||||
**20 (contracts+quirk seams) → 21 (FSM) → 23 (fill reducer) → 22 (venue) → 24 (harness/gate)**.
|
||||
|
||||
## Still NOT in scope (operator/owner only, or a later pass)
|
||||
- **Quirk LOGIC / reconcile-against-quirks** — later quirk-injection pass (seams only here).
|
||||
- **Real BingX client + real-key smoke** — mandatory before V4-live; operator-gated.
|
||||
- **DARK soak start; HZ-bridge refactor; VIBRISS; the V3.4c parity root-cause (CRITICAL #1).**
|
||||
- Any edit to the in-flight files / shared files in §0.
|
||||
@@ -59,6 +59,11 @@ exits / SL floor / event-restore / slippage / cadence; review when done.
|
||||
**PASS 4**: `VIOLET_PART_SPEC_OA_TODO_PASS4.md` (issued 2026-06-17) — vol gate / V7 exit wrapper /
|
||||
economics ledger / exec-intent / alpha data feed / time exits; review when done.
|
||||
|
||||
**PASS 5**: `VIOLET_PART_SPEC_OA_TODO_PASS5.md` (issued 2026-06-17) — MOCK-BINGX execution stack
|
||||
(exec contracts + QuirkProfile seams / order FSM / mock venue / fill reducer / DARK E2E gate).
|
||||
NOTE: BingX "quirks" are SEAM-ONLY here (default OFF) — a later quirk-injection pass + a mandatory
|
||||
real-key boundary smoke are required before V4-live; review when done.
|
||||
|
||||
**Action:** review each pass for correctness, BLUE-algo compliance, V-TYPES, no-shared-edits,
|
||||
real (non-vacuous) tests. **Owner: Claude (me), later.**
|
||||
|
||||
|
||||
Reference in New Issue
Block a user