VIOLET OA: partial spec PASS 4 — next plan units (entry gate, exits, accounting, exec-intent, feed)
VIOLET_PART_SPEC_OA_TODO_PASS4.md — six plan-derived independent units continuing from PASS 3, extending the shared contracts_v3 vocabulary (adds ExecIntent / CapitalState / VolGateResult / AlphaBar): 14. Volatility regime gate (faithful vol_ok — the entry precondition). 15. AlphaExitEngineV7 wrapper (V3a deferred — wrap BLUE's exit engine as-is, discretionary pri 2). 16. Capital/economics provenance ledger (capital = anchor + Σ deltas, event_seq, exactly-one-row). 17. Execution-intent emitter, DARK (V4 boundary — ShadowDecision → ExecIntent, log-only sink). 18. Alpha-side reactor data feed (V2 NT Binance DATA spike → AlphaDataFeedPort, data-only). 19. MAX_HOLD + MEAN_REVERSION scan-driven exit timers. Each ships + tests standalone; composition map + recommended order (14→16→15→19→17→18) + the same HARD RULES + commit/branch policy. VIBRISS/adaptive-TP explicitly excluded. Also: added PASS 3 + PASS 4 to the review queue in VIOLET_TODO_CRITICAL.md §2. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
204
prod/docs/VIOLET_PART_SPEC_OA_TODO_PASS4.md
Normal file
204
prod/docs/VIOLET_PART_SPEC_OA_TODO_PASS4.md
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
# VIOLET — partial spec for another agent, PASS 4 (OA TODO)
|
||||||
|
|
||||||
|
Date: 2026-06-17. Continues PASS 3 (same V0→V6 plan, same independent-unit discipline). PASS 3
|
||||||
|
delivered the venue-feed / mechanical-exit / restore / slippage / cadence layer; PASS 4 adds the
|
||||||
|
ENTRY GATE, the EXIT KERNELS (V7 + time-based), the ACCOUNTING ledger, the EXECUTION-INTENT
|
||||||
|
boundary, and the ALPHA-SIDE data feed. Drawn strictly from `VIOLET_DEV_SPEC_AND_PLAN.md` —
|
||||||
|
nothing invented. Each task is an independent, separately-testable unit; the ONLY coupling is the
|
||||||
|
shared `contracts_v3.py` vocabulary (extended in §I).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. HARD RULES (identical to PASS 1/2/3 — 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.
|
||||||
|
- **VIOLET DARK** — no orders, no execution, no keys, no service/HZ control, no PROGREEN.
|
||||||
|
- **V-TYPES on all new code**; faithful poison-guards only.
|
||||||
|
- **NEW-FILE-ONLY**; do NOT modify in-flight files (`live_blue_source.py`,
|
||||||
|
`shadow_live_factors.py`, `live_factor_source.py`, `live_factors.py`, `decision_engine.py`,
|
||||||
|
`sizing.py`, `shadow_journal.py`, `cadence.py`, `clock.py`, `divergence.py`,
|
||||||
|
`alpha_wrappers.py`, `exchange_leverage.py`, `22_violet_decisions.sql`). READ + IMPORT them.
|
||||||
|
- **VIBRISS stays DARK** — do NOT build adaptive-TP / VIBRISS-governable mechanisms here.
|
||||||
|
|
||||||
|
## 0a. COMMIT / BRANCH POLICY (3 shared-index collisions on 2026-06-16 — non-negotiable)
|
||||||
|
Own `git worktree` (`git worktree add ../vp-oa4 -b agent/oa-violet4`) 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 -m pytest -q`. `git grep`
|
||||||
|
only (recursive grep/find time out on CIFS).
|
||||||
|
|
||||||
|
## 0b. ClickHouse (read-only): `http://localhost:8123`, user `dolphin`/key `dolphin_ch_2026`;
|
||||||
|
VIOLET db `dolphin_violet`, BLUE db `dolphin`. NEVER write/alter production tables.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## I. SHARED INTERFACE EXTENSIONS (add to `contracts_v3.py` from PASS 3; never fork a parallel type)
|
||||||
|
Reuse PASS-3 `VenueTick`, `OpenPositionView`, `ExitDecision`. ADD:
|
||||||
|
1. **`ExecIntent`** (StrictModel) — a DARK would-be order: `asset: Symbol`, `side: str`,
|
||||||
|
`qty: Qty`, `exchange_leverage: Annotated[int, Field(ge=1)]`, `maker_policy: str`,
|
||||||
|
`target_notional: float`, `ts_ns: MonoNs`, `reason: str` ("ENTRY"/"EXIT"). NEVER sent.
|
||||||
|
2. **`CapitalState`** (StrictModel) — `capital: float (ge=0, finite)`, `anchor: float`,
|
||||||
|
`delta_sum: float`, `event_seq: Seq`, `pnl_source: str`, `capital_source: str`. Capital is
|
||||||
|
ALWAYS anchor + Σ deltas (never a last-value snapshot — the zombie-trade lesson).
|
||||||
|
3. **`VolGateResult`** (StrictModel) — `vol_ok: bool`, `metric: float`, `threshold: float`.
|
||||||
|
|
||||||
|
If a task needs a field not listed, ADD it to `contracts_v3.py` and note it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TASK 14 — Volatility regime gate [plan: entry precondition `vol_ok` / vol_p60_threshold]
|
||||||
|
|
||||||
|
**Why.** BLUE gates entries on a volatility regime check (`vol_ok`, `vol_p60_threshold`);
|
||||||
|
`VioletDecisionEngine.decide(... vol_ok=...)` already takes it as a param but nothing computes it
|
||||||
|
faithfully. This unit computes `vol_ok` the way BLUE does so the entry gate is real, not assumed.
|
||||||
|
|
||||||
|
**Affected files (NEW only):** `prod/clean_arch/violet/vol_gate.py`,
|
||||||
|
`prod/clean_arch/violet/test_violet_vol_gate.py`. (imports `contracts_v3`.)
|
||||||
|
|
||||||
|
**Interface/approach.** First READ how BLUE computes the vol gate (search the orchestrator / the
|
||||||
|
engine for `vol_regime_ok` / `vol_p60` / the percentile threshold; transcribe the EXACT formula).
|
||||||
|
Define `compute_vol_gate(price_histories: dict[str, list[float]], *, threshold: float) ->
|
||||||
|
VolGateResult` (`@typed`) reproducing BLUE's metric + comparison. Pure function.
|
||||||
|
|
||||||
|
**Tests / pass criteria.** Parity: hand-built histories where BLUE's formula gives a known
|
||||||
|
vol_ok; assert match. Boundary: at/just-below/just-above threshold. Hypothesis: result finite,
|
||||||
|
vol_ok bool. DONE when the formula is transcribed from live BLUE (cite file:line in a docstring),
|
||||||
|
tests pass, no edits outside the 2 files.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TASK 15 — AlphaExitEngineV7 wrapper [plan: V3a deferred — "run exit-v7 as-is first, refactor later"]
|
||||||
|
|
||||||
|
**Why.** The plan wraps BLUE's live multi-leg exit engine `AlphaExitEngineV7` behind a V-TYPES
|
||||||
|
boundary and runs it AS-IS. Its outputs are DISCRETIONARY exits (priority 2) that, per the exit
|
||||||
|
doctrine, can NEVER override the mechanical TP/SL (PASS-3 Task 9).
|
||||||
|
|
||||||
|
**Affected files (NEW only):** `prod/clean_arch/violet/exit_v7_wrapper.py`,
|
||||||
|
`prod/clean_arch/violet/test_violet_exit_v7_wrapper.py`. (imports `contracts_v3`.)
|
||||||
|
|
||||||
|
**Interface/approach.** WRAP, don't reimplement: import
|
||||||
|
`nautilus_dolphin.nautilus.alpha_exit_v7_engine.AlphaExitEngineV7`; build its context
|
||||||
|
(`make_context`) and call `evaluate` over an `OpenPositionView` + market state; map its result to
|
||||||
|
an `ExitDecision(reason=…, priority=2)`. Refined domain types in/out. The wrapper must NOT change
|
||||||
|
V7's logic. Document any state V7 needs.
|
||||||
|
|
||||||
|
**Tests / pass criteria.** For crafted inputs, the wrapper's `ExitDecision` matches what
|
||||||
|
`AlphaExitEngineV7.evaluate` returns (same exit/hold + reason), priority always 2. DONE when wrap
|
||||||
|
parity tests pass, no edits outside the 2 files.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TASK 16 — Capital / economics provenance ledger [plan: V1 inheritance — capital = anchor + Σ deltas]
|
||||||
|
|
||||||
|
**Why.** Binding VIOLET doctrine (from the zombie-trade incident + malformed-open audit): capital
|
||||||
|
is ALWAYS anchor + Σ signed per-trade deltas, NEVER a last-value snapshot; every row carries
|
||||||
|
`pnl_source`/`capital_source` provenance + `event_seq`; exactly-one-row-per-event. Per-trade sizer
|
||||||
|
feedback uses trade-realized PnL, never capital deltas (shared-account foreign-fill immunity).
|
||||||
|
|
||||||
|
**Affected files (NEW only):** `prod/clean_arch/violet/economics_ledger.py`,
|
||||||
|
`prod/clean_arch/violet/test_violet_economics_ledger.py`. (emits `CapitalState`.)
|
||||||
|
|
||||||
|
**Interface/approach.** `EconomicsLedger(anchor: float)` with `apply(delta: float, *, event_seq:
|
||||||
|
int, pnl_source: str) -> CapitalState` (monotonic event_seq; rejects out-of-order / duplicate
|
||||||
|
seq; capital = anchor + Σ deltas). `capital()` returns the derived value, never a stored snapshot.
|
||||||
|
Reject NaN/inf deltas. No CH writes (pure in-memory ledger + a `to_row()` for a future sink).
|
||||||
|
|
||||||
|
**Tests / pass criteria.** Σ-delta correctness over a sequence; duplicate/out-of-order event_seq
|
||||||
|
rejected; capital never goes negative below a floor guard; Hypothesis: capital == anchor + sum of
|
||||||
|
accepted deltas, always. DONE when tests pass, no edits outside the 2 files.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TASK 17 — Execution-intent emitter (DARK) [plan: V4 prep — feeds the ExecDeadlineDriver]
|
||||||
|
|
||||||
|
**Why.** V2 built the `ExecDeadlineDriver` + synthetic intents; V4 will turn decisions into real
|
||||||
|
orders. This unit is the DARK boundary that converts a decision into an `ExecIntent` (a would-be
|
||||||
|
order) — shadow-logged, NEVER sent — so V4 only has to flip the sink from log to venue.
|
||||||
|
|
||||||
|
**Affected files (NEW only):** `prod/clean_arch/violet/exec_intent.py`,
|
||||||
|
`prod/clean_arch/violet/test_violet_exec_intent.py`. (imports `contracts_v3`; composes PASS-2
|
||||||
|
`tradeability.py` if present, else recompute via `exchange_leverage.py`.)
|
||||||
|
|
||||||
|
**Interface/approach.** `to_exec_intent(decision: ShadowDecision, *, capital: float, maker_policy:
|
||||||
|
str = "maker_both") -> ExecIntent` — derive qty from notional/price, exchange_leverage from the L3
|
||||||
|
mapping, attach maker policy. Pure projection; an `IntentSink` protocol with a default
|
||||||
|
`LoggingIntentSink` (shadow-logs, never sends). Hard guard: this module imports NOTHING that can
|
||||||
|
place an order; assert no venue/order symbol is importable here (a test enforces it).
|
||||||
|
|
||||||
|
**Tests / pass criteria.** Intent fields correct vs the decision + L3 mapping; `LoggingIntentSink`
|
||||||
|
records, never sends; a test asserts the module has no order-placing dependency. DONE when tests
|
||||||
|
pass, no edits outside the 2 files.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TASK 18 — Alpha-side reactor data-feed adapter [plan: V2 NT Binance DATA client spike → feed]
|
||||||
|
|
||||||
|
**Why.** The V2 spike GO-qualified the Nautilus Binance DATA client as VIOLET's alpha-side feed
|
||||||
|
(separate feed process recommended; public-data only; dummy keys for the factory). This unit
|
||||||
|
delivers that feed behind a clean port so the reactor consumes normalized bars without coupling to
|
||||||
|
NT internals.
|
||||||
|
|
||||||
|
**Affected files (NEW only):** `prod/clean_arch/violet/alpha_data_feed.py`,
|
||||||
|
`prod/clean_arch/violet/test_violet_alpha_data_feed.py`.
|
||||||
|
|
||||||
|
**Interface/approach.** Define `AlphaDataFeedPort` (ABC): `start()`, `latest_bar(asset)`,
|
||||||
|
`stop()`, yielding a normalized bar type (`AlphaBar` — add to `contracts_v3`: asset, open/high/low/
|
||||||
|
close > 0, volume ≥ 0, ts_ns, source). Implement `NautilusBinanceDataFeed` (READ the V2 spike
|
||||||
|
notes / `dolphin_actor*.py` / `live_price_feed.py` for the NT data-client wiring; public-data,
|
||||||
|
dummy keys, NO execution). Implement `MockDataFeed` (deterministic). NO orders, data-only.
|
||||||
|
|
||||||
|
**Tests / pass criteria.** Mock feed yields valid `AlphaBar`s; poison bars rejected; the NT adapter
|
||||||
|
parses a recorded bar message into a correct `AlphaBar` (captured-frame fixture, no live
|
||||||
|
connection in the unit test). DONE when contract finalized + parse-tested, no live feed in unit
|
||||||
|
tests, no edits outside the 2 files.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TASK 19 — MAX_HOLD + MEAN_REVERSION scan-driven exit timers [plan: scan-driven exits, V6 bible]
|
||||||
|
|
||||||
|
**Why.** The plan keeps MAX_HOLD and MEAN_REVERSION as SCAN-driven exits (champion params are
|
||||||
|
5s-bar-denominated; re-timing requires VBT re-cert). They are mechanical/time-based exits that
|
||||||
|
compose with the exit framework (PASS-3 Task 9) at the right priority.
|
||||||
|
|
||||||
|
**Affected files (NEW only):** `prod/clean_arch/violet/time_exits.py`,
|
||||||
|
`prod/clean_arch/violet/test_violet_time_exits.py`. (imports `contracts_v3`.)
|
||||||
|
|
||||||
|
**Interface/approach.** READ BLUE's exit manager for the EXACT MAX_HOLD (`max_hold_bars`) and
|
||||||
|
mean-reversion rules (`AlphaExitManager` / the orchestrator). Define
|
||||||
|
`evaluate_time_exits(pos: OpenPositionView, *, bars_held: int, vel_div: float) -> ExitDecision` —
|
||||||
|
`bars_held >= max_hold_bars` → `ExitDecision(EXIT, "MAX_HOLD")`; mean-reversion condition →
|
||||||
|
`ExitDecision(EXIT, "MEAN_REVERSION")`; else HOLD. Scan-cadence (no sub-second). Priority below
|
||||||
|
mechanical SL/TP, above pure discretionary (document the chosen priority vs Task 9/15).
|
||||||
|
|
||||||
|
**Tests / pass criteria.** MAX_HOLD fires exactly at the bar threshold; mean-reversion fires on the
|
||||||
|
BLUE condition (transcribed, cited); neither fires early. DONE when tests pass with the rule cited
|
||||||
|
from live BLUE, no edits outside the 2 files.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Composition map
|
||||||
|
```
|
||||||
|
contracts_v3 (VenueTick, OpenPositionView, ExitDecision, ExecIntent, CapitalState, VolGateResult, AlphaBar)
|
||||||
|
├── 14 vol_gate(histories) → VolGateResult (entry gate; feeds decide vol_ok)
|
||||||
|
├── 18 alpha_data_feed → AlphaBar stream (alpha-side reactor feed)
|
||||||
|
├── 15 exit_v7_wrapper(pos, state) → ExitDecision(pri 2) ┐
|
||||||
|
├── 19 time_exits(pos, bars, veldiv) → ExitDecision ├─ exit stack, ranked by priority,
|
||||||
|
│ (PASS-3 9 mechanical = pri 0/1; 10 SL floor = pri 0) ┘ mechanical always wins
|
||||||
|
├── 16 economics_ledger(anchor,Δ…) → CapitalState (accounting; never last-value)
|
||||||
|
└── 17 exec_intent(decision,capital) → ExecIntent (DARK) (V4 boundary; log-only sink)
|
||||||
|
```
|
||||||
|
Integration (ranking the exit stack, wiring the feed into the reactor, the ledger into the
|
||||||
|
journal, the intent sink into the driver) is the OWNER's job later — NOT part of these units.
|
||||||
|
|
||||||
|
## Recommended order
|
||||||
|
**14 (vol gate) → 16 (ledger) → 15 (V7 wrap) → 19 (time exits) → 17 (exec intent) → 18 (data
|
||||||
|
feed)**. 14/16 are small + foundational; 18 is the heaviest (NT adapter).
|
||||||
|
|
||||||
|
## Pass/sprint nomenclature (re-asked) — see `VIOLET_TODO_CRITICAL.md` §3
|
||||||
|
"pass" = a sub-sprint work-package (a batch of self-contained tasks for one agent); a V-stage
|
||||||
|
(V0…V6) = the project's "Sprint N" / epic. Renaming passes to "sprints" over-claims scope. The
|
||||||
|
later REVIEW + INTEGRATE + E2E of all passes is Claude's queued work.
|
||||||
|
|
||||||
|
## Still NOT in scope (operator/owner only)
|
||||||
|
DARK soak start; V4 live order placement / BingX ExecutionClient; HZ-bridge refactor; VIBRISS /
|
||||||
|
adaptive-TP; the V3.4c parity root-cause (CRITICAL #1); any edit to the in-flight files in §0.
|
||||||
@@ -53,7 +53,11 @@ The parallel agent reports these DONE; none reviewed for correctness / BLUE-comp
|
|||||||
- `test_violet_v3_decision_latency_gate.py` (Task 5) → report `violet_v3_decision_latency_2026...`
|
- `test_violet_v3_decision_latency_gate.py` (Task 5) → report `violet_v3_decision_latency_2026...`
|
||||||
- `test_violet_replay_determinism_gate.py` (Task 7) → report `violet_replay_determinism_2026...`
|
- `test_violet_replay_determinism_gate.py` (Task 7) → report `violet_replay_determinism_2026...`
|
||||||
|
|
||||||
**PASS 3**: `VIOLET_PART_SPEC_OA_TODO_PASS3.md` (issued 2026-06-17) — items below; review when done.
|
**PASS 3**: `VIOLET_PART_SPEC_OA_TODO_PASS3.md` (issued 2026-06-17) — venue feed / mechanical
|
||||||
|
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.
|
||||||
|
|
||||||
**Action:** review each pass for correctness, BLUE-algo compliance, V-TYPES, no-shared-edits,
|
**Action:** review each pass for correctness, BLUE-algo compliance, V-TYPES, no-shared-edits,
|
||||||
real (non-vacuous) tests. **Owner: Claude (me), later.**
|
real (non-vacuous) tests. **Owner: Claude (me), later.**
|
||||||
|
|||||||
Reference in New Issue
Block a user