Files
DOLPHIN/prod/docs/NAUTILUS_DOLPHIN_SPEC.md

746 lines
31 KiB
Markdown
Raw Normal View History

# Nautilus-DOLPHIN / Alpha Engine Core — Implementation Specification
**Version:** 1.0
**Date:** 2026-03-22
**Status:** Production-ready (paper trading); live deployment pending exchange integration
**Environment:** siloqy-env (`/home/dolphin/siloqy_env/bin/activate`)
**Stack:** nautilus_trader 1.219.0 · prefect 3.6.22 · hazelcast-python-client 5.6.0 · numba 0.61.2
---
## 1. System Overview
Nautilus-DOLPHIN is a production algorithmic trading system built on the NautilusTrader Rust-core HFT framework. It wraps a 7-layer alpha engine ("NDAlphaEngine") inside a NautilusTrader Strategy primitive ("DolphinActor"), supervised by Prefect for resilience and Hazelcast for distributed system memory.
### 1.1 Performance Specification (Champion — FROZEN)
| Metric | Champion Value |
|---|---|
| ROI (backtest period) | +54.67% |
| Profit Factor | 1.141 |
| Sharpe Ratio | 2.84 |
| Max Drawdown | 15.80% |
| Win Rate | 49.5% |
| Direction | SHORT only (blue deployment) |
| Bar resolution | 5-second |
| Markets | Binance Futures perpetuals (~48 assets) |
These numbers are **invariants**. Any code change that causes a statistically significant deviation must be rejected.
### 1.2 Architecture Summary
```
┌────────────────────────────────────────────────────────────────┐
│ Prefect Supervision Layer │
│ paper_trade_flow.py (00:05 UTC) nautilus_prefect_flow.py │
│ dolphin_nautilus_flow (00:10 UTC) │
└──────────────────────────────┬─────────────────────────────────┘
┌──────────────────────────────▼─────────────────────────────────┐
│ NautilusTrader Execution Kernel │
│ BacktestEngine (paper) / TradingNode (live) │
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ DolphinActor (Strategy) │ │
│ │ on_start() → connect HZ, ACB listener │ │
│ │ on_bar() → step_bar() per 5s tick │ │
│ │ on_stop() → cleanup, HZ shutdown │ │
│ └──────────────────────┬──────────────────┘ │
│ │ │
│ ┌───────────────────────▼──────────────────────────────────┐ │
│ │ NDAlphaEngine │ │
│ │ 7-layer alpha stack (see §4) │ │
│ │ begin_day() / step_bar() / end_day() │ │
│ └───────────────────────────────────────────────────────────┘ │
└──────────────────────────────┬─────────────────────────────────┘
┌──────────────────────────────▼─────────────────────────────────┐
│ Hazelcast "System Memory" │
│ DOLPHIN_SAFETY → posture, Rm (survival stack) │
│ DOLPHIN_FEATURES → ACB boost, beta, eigen scan │
│ DOLPHIN_PNL_BLUE → daily trade results │
│ DOLPHIN_STATE_BLUE→ capital state (continuity) │
│ DOLPHIN_HEARTBEAT → liveness probes │
│ DOLPHIN_FEATURES_SHARD_00..09 → 400-asset feature shards │
└────────────────────────────────────────────────────────────────┘
```
---
## 2. File Map
```
/mnt/dolphinng5_predict/
├── prod/
│ ├── paper_trade_flow.py # Primary daily Prefect flow (NDAlphaEngine direct)
│ ├── nautilus_prefect_flow.py # Nautilus BacktestEngine Prefect flow (NEW)
│ ├── run_nautilus.py # Standalone Nautilus CLI runner
│ ├── configs/
│ │ ├── blue.yml # Champion SHORT config (FROZEN)
│ │ └── green.yml # Bidirectional config (pending LONG validation)
│ └── OBF_SUBSYSTEM.md # OBF architecture reference
├── nautilus_dolphin/
│ └── nautilus_dolphin/
│ └── nautilus/
│ ├── dolphin_actor.py # DolphinActor(Strategy) — Nautilus wrapper
│ ├── esf_alpha_orchestrator.py # NDAlphaEngine — 7-layer core
│ ├── proxy_boost_engine.py # ProxyBoostEngine wrapper (ACBv6 pre-compute)
│ ├── adaptive_circuit_breaker.py # ACBv6 — 3-scale regime sizing
│ ├── strategy.py # DolphinExecutionStrategy (signal-level)
│ ├── strategy_config.py # DolphinStrategyConfig (StrategyConfig subclass)
│ ├── launcher.py # NautilusDolphinLauncher (TradingNode)
│ ├── ob_features.py # OBFeatureEngine — order book intelligence
│ ├── hz_ob_provider.py # HZOBProvider — HZ-backed OB data source
│ └── circuit_breaker.py # CircuitBreakerManager
│ └── tests/
│ ├── test_0_nautilus_bootstrap.py # 11 foundation tests
│ ├── test_dolphin_actor.py # 35 DolphinActor lifecycle tests (NEW)
│ ├── test_strategy.py # DolphinExecutionStrategy filter tests
│ ├── test_adaptive_circuit_breaker.py
│ ├── test_circuit_breaker.py
│ ├── test_volatility_detector.py
│ └── [12 other test files]
└── vbt_cache_klines/ # 5s OHLCV parquet files — daily replay source
└── YYYY-MM-DD.parquet # cols: vel_div, v50/v150/v300/v750, instability_*, 48 assets
```
---
## 3. Champion Parameters (FROZEN)
These parameters are derived from the champion backtest and **must not be altered** without a full re-validation run showing performance preservation.
| Parameter | Value | Description |
|---|---|---|
| `vel_div_threshold` | -0.02 | Primary signal gate: vd must be ≤ this to open a position |
| `vel_div_extreme` | -0.05 | Extreme signal bucket threshold (max leverage tier) |
| `fixed_tp_pct` | 0.0095 | Take-profit at 95 bps from entry (TP sweep 2026-03-06) |
| `max_hold_bars` | 120 | Maximum holding period in 5s bars (= 10 minutes) |
| `fraction` | 0.20 | Base position size fraction of capital |
| `min_leverage` | 0.5 | Floor leverage (applied by AlphaBetSizer) |
| `max_leverage` | 5.0 | Soft leverage ceiling |
| `abs_max_leverage` | 6.0 | Hard leverage ceiling (Rm-scaled by Survival Stack) |
| `leverage_convexity` | 3.0 | Cubic exponent for convex leverage scaling |
| `dc_lookback_bars` | 7 | Direction confirmation lookback window |
| `dc_min_magnitude_bps` | 0.75 | Minimum velocity magnitude for DC trigger |
| `min_irp_alignment` | 0.45 | IRP asset selection threshold |
| `sp_maker_entry_rate` | 0.62 | SmartPlacer: 62% maker fill rate at entry |
| `sp_maker_exit_rate` | 0.50 | SmartPlacer: 50% maker fill rate at exit |
| `seed` | 42 | NumPy / numba RNG seed (reproducibility invariant) |
**Verification:** `nautilus_prefect_flow._CHAMPION_HASH` is computed at import time from these values. Any config drift triggers `ValueError` and aborts the flow.
---
## 4. Alpha Engine — 7-Layer Stack
### Layer 1: Velocity Divergence Signal Gate (`AlphaSignalGenerator`)
**Input:** `vel_div = v50_lambda_max_velocity - v150_lambda_max_velocity`
The primary alpha signal. `v50` is the 50-window eigenvalue velocity; `v150` the 150-window. Negative divergence signals short momentum.
```
Buckets:
0 (extreme): vel_div ≤ -0.075 → max leverage
1 (strong): vel_div ≤ -0.050 → high leverage
2 (moderate): vel_div ≤ -0.035 → normal leverage
3 (weak): vel_div ≤ -0.020 → min leverage
```
Only fires if `vel_div ≤ vel_div_threshold (-0.02)`. Includes direction confirmation (`dc_lookback_bars=7`, `dc_min_magnitude_bps=0.75`).
### Layer 2: Volatility Regime Filter (`VolatilityRegimeDetector`)
Rolling 50-bar standard deviation of BTC returns. Positions are only opened when `dvol > vol_p60` (60th percentile threshold = 0.000099 from 55-day champion calibration). Prevents trading in dead-market microstructure.
### Layer 3: SmartPlacer Fee Model (`AlphaSignalGenerator`)
Models maker vs taker execution costs:
- `sp_maker_entry_rate=0.62`: 62% of entries assumed as maker (0.02% fee)
- `sp_maker_exit_rate=0.50`: 50% of exits as maker
- Remaining fills incur taker fee (+0.04%)
- Net fee per round trip ≈ 0.020.04% depending on fill mix
Fee is charged per trade in `NDAlphaEngine.process_bar()`. No real order routing in paper mode — fee is applied analytically.
### Layer 4: OB Intelligence — 5 Sub-systems (`OBFeatureEngine` / `HZOBProvider`)
Reads from `DOLPHIN_FEATURES_SHARD_{idx}` or `ob_cache/latest_ob_features.json`:
| Sub-system | Key features | Effect |
|---|---|---|
| 1. Placement | `fill_probability`, `depth_quality`, `spread_proxy_bps` | Adjusts maker entry rate; gates entry if `fill_probability < 0.6` |
| 2. Signal | `depth_asymmetry`, `imbalance_persistence`, `withdrawal_velocity` | OB-direction confirmation layer |
| 3. Cross-asset | `agreement_pct`, `cascade_count`, `regime_signal` | Asset selection weighting in IRP |
| 4. Macro | `macro_imbalance`, `macro_spread_bps` | Long-horizon baseline normalization |
| 5. Raw depth | `bid/ask_notional_1-5pct`, `bid/ask_depth_1-5pct` | Notional depth vectors for all 5 levels |
OB edge gate: `ob_edge_bps=5.0`, `ob_confirm_rate=0.40`. Entry only if OB confirms directional signal.
### Layer 5: IRP Asset Selection (`AlphaAssetSelector`)
Inter-asset relative performance (IRP) selects which assets to trade each bar. Only assets where imbalance sign aligns with the directional view, and where `irp_alignment ≥ min_irp_alignment (0.45)`, are traded.
### Layer 6: Dynamic Cubic-Convex Leverage (`AlphaBetSizer`)
```
leverage = min_leverage + (max_leverage - min_leverage) × (signal_strength)^leverage_convexity
signal_strength = (vel_div_threshold - vel_div) / (vel_div_threshold - vel_div_extreme)
clamped to [0, 1]
```
Then scaled by `regime_size_mult` from ACBv6:
```
regime_size_mult = base_boost × (1 + beta × strength_cubic) × mc_scale
```
Final leverage clamped to `[min_leverage, abs_max_leverage × Rm]`.
### Layer 7: Exit Management (`AlphaExitManager`)
Two primary exits (no stop loss in champion):
1. **Fixed TP:** Exit when `price_change_pct ≥ fixed_tp_pct (0.0095)` = 95 bps
2. **Max hold:** Force exit at `max_hold_bars (120)` × 5s = 10 minutes
---
## 5. DolphinActor — Nautilus Strategy Wrapper
**File:** `nautilus_dolphin/nautilus/dolphin_actor.py`
**Base class:** `nautilus_trader.trading.strategy.Strategy`
**Lines:** 338
### 5.1 Initialization
```python
class DolphinActor(Strategy):
def __init__(self, config: dict):
super().__init__() # Nautilus Actor Cython init
self.dolphin_config = config # full YAML config dict
self.engine = None # NDAlphaEngine (created in on_start)
self.hz_client = None # HazelcastClient
self.current_date = None # tracks date boundary
self.posture = 'APEX' # Survival Stack posture
self._processed_dates = set()
self._pending_acb: dict | None = None # pending ACB from HZ listener
self._acb_lock = threading.Lock() # guards _pending_acb
self._stale_state_events = 0
self.last_scan_number = -1
self._day_data = None # (df, asset_columns) for replay mode
self._bar_idx_today = 0
```
### 5.2 on_start() Lifecycle
```
on_start():
1. _connect_hz() → hazelcast.HazelcastClient(cluster_name="dolphin", ...)
2. _read_posture() → reads DOLPHIN_SAFETY (CP atomic ref or map fallback)
3. _setup_acb_listener() → add_entry_listener on DOLPHIN_FEATURES["acb_boost"]
4. create_boost_engine(mode=boost_mode, **engine_kwargs) → NDAlphaEngine
5. MC-Forewarner injection (gold-performance stack — enabled by default):
mc_models_dir = config.get('mc_models_dir', _MC_MODELS_DIR_DEFAULT)
DolphinForewarner(models_dir=mc_models_dir) → engine.set_mc_forewarner(fw, _MC_BASE_CFG)
Graceful: logs warning + continues if models dir missing or import fails.
Disable: set mc_models_dir=None or mc_models_dir='' in config.
```
HZ connection failure is non-fatal: `hz_client = None`, posture defaults to APEX.
MC-Forewarner failure is non-fatal: logs warning, `_day_mc_scale` stays 1.0 (gate disabled).
### 5.3 on_bar() — Hot Loop
```
on_bar(bar: Bar):
① Apply pending ACB (under _acb_lock):
pending = _pending_acb; _pending_acb = None
if pending: engine.update_acb_boost(boost, beta)
② Date boundary detection:
date_str = datetime.fromtimestamp(bar.ts_event / 1e9, UTC).strftime('%Y-%m-%d')
if current_date != date_str:
if current_date: engine.end_day()
current_date = date_str
posture = _read_posture()
_bar_idx_today = 0
engine.begin_day(date_str, posture=posture, direction=±1)
if not live_mode: _load_parquet_data(date_str) → _day_data
③ HIBERNATE guard:
if posture == 'HIBERNATE': return # no position opened
④ Feature extraction (live HZ vs replay parquet):
live_mode=True: _get_latest_hz_scan() → scan dict
staleness check: abs(now_ns - scan_ts_ns) > 10s → warning
dedup: scan_num == last_scan_number → skip
live_mode=False: if _day_data empty → return (no step_bar with zeros)
elif bar_idx >= len(df) → return (end of day)
else: df.iloc[_bar_idx_today] → row
vol_regime_ok = bar_idx >= 100 (warmup)
⑤ Stale-state snapshot (before):
_snap = _GateSnap(acb_boost, acb_beta, posture, mc_gate_open)
⑥ Optional proxy_B pre-update (no-op for baseline engine):
if hasattr(engine, 'pre_bar_proxy_update'): engine.pre_bar_proxy_update(...)
⑦ engine.step_bar(bar_idx, vel_div, prices, v50_vel, v750_vel, vol_regime_ok)
_bar_idx_today += 1
⑧ Stale-state snapshot (after):
_snap_post = _GateSnap(acb_boost, acb_beta, _read_posture(), mc_gate_open)
if _snap != _snap_post:
stale_state_events++
log.warning("[STALE_STATE] ...")
result['stale_state'] = True
⑨ _write_result_to_hz(date_str, result)
```
### 5.4 ACB Thread Safety — Pending-Flag Pattern
```
HZ listener thread:
_on_acb_event(event):
parsed = json.loads(event.value) # parse OUTSIDE lock (pure CPU)
with _acb_lock:
_pending_acb = parsed # atomic assign under lock
on_bar() (Nautilus event thread):
with _acb_lock:
pending = _pending_acb
_pending_acb = None # consume atomically
if pending:
engine.update_acb_boost(...) # apply outside lock
```
This design minimizes lock hold time to a single pointer swap. There is no blocking I/O under the lock.
### 5.5 on_stop()
```python
def on_stop(self):
self._processed_dates.clear() # prevent stale date state on restart
self._stale_state_events = 0
if self.hz_client:
self.hz_client.shutdown()
```
---
## 6. ACBv6 — Adaptive Circuit Breaker
**File:** `nautilus_dolphin/nautilus/adaptive_circuit_breaker.py`
### 6.1 Three-Scale Architecture
```
regime_size_mult = base_boost × (1 + beta × strength_cubic) × mc_scale
Scale 1 — Daily external factors (base_boost):
preloaded from recent 60-day w750 velocity history
p60 threshold determines whether current w750 is "high regime"
base_boost ∈ [0.5, 2.0] typically
Scale 2 — Per-bar meta-boost (beta × strength_cubic):
beta: ACB sensitivity parameter from HZ DOLPHIN_FEATURES
strength_cubic: (|vel_div| / threshold)^3 — convex response to signal strength
Scale 3 — MC-Forewarner scale (mc_scale):
DolphinForewarner ML model predicts MC regime
mc_scale ∈ [0.5, 1.5]
```
### 6.2 HZ Integration
ACBv6 updates are pushed to `DOLPHIN_FEATURES["acb_boost"]` by an external Prefect flow. DolphinActor subscribes via `add_entry_listener` and receives push notifications. Updates are applied at the top of the next `on_bar()` call (pending-flag pattern, §5.4).
### 6.3 Cut-to-Position-Size API
```python
acb.apply_cut_to_position_size(position_size, cut_pct)
# cut_pct in [0.0, 0.15, 0.45, 0.55, 0.75, 0.80]
# Returns position_size × (1 - cut_pct)
```
---
## 7. Survival Stack (5-Sensor Posture)
**HZ map:** `DOLPHIN_SAFETY` (CP atomic reference preferred, map fallback)
```
Rm ∈ [0, 1] — composite risk metric from 5 sensors
Posture Rm threshold Behavior
───────── ──────────── ─────────────────────────────────────────────
APEX Rm ≥ 0.90 Full operation; abs_max_leverage unrestricted
STALKER Rm ≥ 0.75 max_leverage capped to 2.0
TURTLE Rm ≥ 0.50 position sizing reduced via abs_max_leverage × Rm
HIBERNATE Rm < 0.50 on_bar() returns immediately; no new positions
```
Posture is re-read on every date change. In `paper_trade_flow.py`, Rm is applied directly to `engine.abs_max_leverage`:
```python
engine.abs_max_leverage = max(1.0, engine.abs_max_leverage × Rm)
if posture == 'STALKER':
engine.abs_max_leverage = min(engine.abs_max_leverage, 2.0)
```
---
## 8. NDAlphaEngine API
**File:** `nautilus_dolphin/nautilus/esf_alpha_orchestrator.py`
### 8.1 Constructor Parameters
See §3 Champion Parameters. Additional non-champion params:
- `stop_pct=1.0` (effectively disabled — TP exits first)
- `lookback=100` (price history window)
- `use_alpha_layers=True` (enables OB/IRP/SP layers)
- `use_dynamic_leverage=True` (enables cubic-convex sizing)
### 8.2 Day Lifecycle API
```python
engine.begin_day(date_str: str, posture: str, direction: int)
# Sets regime_direction, reads ACB for the day, resets per-day state
for bar in bars:
result = engine.step_bar(
bar_idx=int, # 0-based index within day
vel_div=float, # primary alpha signal
prices=dict, # {symbol: float} current prices
vol_regime_ok=bool, # volatility gate
v50_vel=float, # w50 eigenvalue velocity (raw)
v750_vel=float, # w750 eigenvalue velocity (ACB scale)
) -> dict
result_dict = engine.end_day()
# Returns: {pnl, trades, capital, boost, beta, mc_status, ...}
```
### 8.3 State Fields
| Field | Type | Description |
|---|---|---|
| `capital` | float | Current equity (updated after each trade) |
| `_day_base_boost` | float | ACB base boost for today |
| `_day_beta` | float | ACB beta sensitivity for today |
| `_day_mc_scale` | float | MC-Forewarner scale for today |
| `_global_bar_idx` | int | Lifetime bar counter (persists across days) |
| `_price_histories` | dict | Per-asset price history lists (≤500 values) |
| `position` | NDPosition | Current open position (None if flat) |
| `trade_history` | list | All closed NDTradeRecord objects |
| `regime_size_mult` | float | Current ACBv6 size multiplier |
### 8.4 Setter Methods
```python
engine.set_ob_engine(ob_engine) # inject OBFeatureEngine
engine.set_acb(acb) # inject AdaptiveCircuitBreaker
engine.set_mc_forewarner(fw, base_cfg) # inject DolphinForewarner
engine.update_acb_boost(boost, beta) # called by DolphinActor from HZ events
```
---
## 9. Data Flow — Replay Mode (Paper Trading)
```
vbt_cache_klines/YYYY-MM-DD.parquet
↓ DolphinActor._load_parquet_data()
↓ pd.read_parquet() → DataFrame (1439 rows × ~57 cols)
columns: timestamp, scan_number, vel_div,
v50/v150/v300/v750_lambda_max_velocity,
instability_50, instability_150,
BTCUSDT, ETHUSDT, BNBUSDT, ... (48 assets)
↓ DolphinActor.on_bar() iterates rows via _bar_idx_today
↓ NDAlphaEngine.step_bar(bar_idx, vel_div, prices, ...)
↓ AlphaSignalGenerator → AlphaBetSizer → AlphaExitManager
↓ trade_history.append(NDTradeRecord)
↓ DolphinActor._write_result_to_hz() → DOLPHIN_PNL_BLUE[date]
```
### 9.1 Live Mode Data Flow
```
Binance Futures WS → OBF prefect flow → Hazelcast DOLPHIN_FEATURES_SHARD_*
Eigenvalue scanner → JSON scan files → Hazelcast DOLPHIN_FEATURES["latest_eigen_scan"]
DolphinActor.on_bar():
scan = _get_latest_hz_scan()
vel_div = scan["vel_div"]
prices = scan["asset_prices"]
→ engine.step_bar(...)
```
---
## 10. Hazelcast IMap Schema
| Map name | Key | Value | Writer | Reader |
|---|---|---|---|---|
| `DOLPHIN_SAFETY` | "latest" | JSON `{posture, Rm, ...}` | Survival stack flow | DolphinActor, paper_trade_flow |
| `DOLPHIN_FEATURES` | "acb_boost" | JSON `{boost, beta}` | ACB writer flow | DolphinActor (listener) |
| `DOLPHIN_FEATURES` | "latest_eigen_scan" | JSON `{vel_div, scan_number, asset_prices, ...}` | Eigenvalue scanner | DolphinActor (live mode) |
| `DOLPHIN_PNL_BLUE` | "YYYY-MM-DD" | JSON result dict | paper_trade_flow, DolphinActor | Analytics |
| `DOLPHIN_STATE_BLUE` | "latest" | JSON `{capital, date, pnl, ...}` | paper_trade_flow | paper_trade_flow (restore) |
| `DOLPHIN_STATE_BLUE` | "latest_nautilus" | JSON `{capital, param_hash, ...}` | nautilus_prefect_flow | nautilus_prefect_flow |
| `DOLPHIN_HEARTBEAT` | "nautilus_flow_heartbeat" | JSON `{ts, phase, ...}` | nautilus_prefect_flow | Monitoring |
| `DOLPHIN_FEATURES_SHARD_00..09` | symbol | JSON OB feature dict | OBF prefect flow | HZOBProvider |
**Shard routing:** `shard_idx = sum(ord(c) for c in symbol) % 10` — stable, deterministic, no config needed.
---
## 11. Prefect Integration
### 11.1 paper_trade_flow.py (Primary — 00:05 UTC)
Runs NDAlphaEngine directly (no Nautilus kernel). Tasks:
- `load_config` — YAML config with retries=0
- `load_day_scans` — parquet (preferred) or JSON fallback, retries=2
- `run_engine_day` — NDAlphaEngine.begin_day/step_bar/end_day loop
- `write_hz_state` — HZ persist, retries=3
- `log_pnl` — disk JSONL append
### 11.2 nautilus_prefect_flow.py (Nautilus Supervisor — 00:10 UTC)
Wraps BacktestEngine + DolphinActor. Tasks:
- `hz_probe_task` — verify HZ reachable, retries=3, timeout=30s
- `validate_champion_params` — SHA256 hash check vs `_CHAMPION_PARAMS`, aborts on drift
- `load_bar_data_task` — parquet load with validation, retries=2
- `read_posture_task` — DOLPHIN_SAFETY read, retries=2
- `restore_capital_task` — capital continuity from HZ state
- `run_nautilus_backtest_task` — full BacktestEngine cycle, timeout=600s
- `write_hz_result_task` — persist to DOLPHIN_PNL_BLUE + DOLPHIN_STATE_BLUE, retries=3
- `heartbeat_task` — liveness pulse at flow_start/engine_start/flow_end
### 11.3 Registration
```bash
source /home/dolphin/siloqy_env/bin/activate
PREFECT_API_URL=http://localhost:4200/api
# Primary paper trade (existing):
python prod/paper_trade_flow.py --register
# Nautilus supervisor (new):
python prod/nautilus_prefect_flow.py --register
# → dolphin-nautilus-blue, daily 00:10 UTC, work_pool=dolphin
```
---
## 12. Nautilus Kernel Backends
### 12.1 BacktestEngine (Paper / Replay)
Used in `run_nautilus.py` and `nautilus_prefect_flow.py`. Processes synthetic bars (one bar per date triggers DolphinActor which then iterates over the full parquet day internally). No real exchange connectivity.
```python
engine = BacktestEngine(config=BacktestEngineConfig(trader_id="DOLPHIN-NAUTILUS-001"))
engine.add_strategy(DolphinActor(config=config))
engine.add_venue(Venue("BINANCE"), OmsType.HEDGING, AccountType.MARGIN, ...)
engine.add_instrument(TestInstrumentProvider.default_fx_ccy("BTCUSD", venue))
engine.add_data([synthetic_bar])
engine.run()
```
### 12.2 TradingNode (Live — Future)
`NautilusDolphinLauncher` in `launcher.py` bootstraps a `TradingNode` with `BinanceExecClientConfig`. Requires Binance API keys and live WS data. Not currently active.
```python
from nautilus_dolphin.nautilus.launcher import NautilusDolphinLauncher
launcher = NautilusDolphinLauncher(config_path="prod/configs/blue.yml")
launcher.start() # blocking — runs until SIGTERM
```
### 12.3 Bar Type
```
"BTCUSD.BINANCE-5-SECOND-LAST-EXTERNAL"
```
`EXTERNAL` aggregation type: bars are not synthesized by Nautilus from ticks; they are injected directly. This is the correct type for replay from pre-aggregated parquet.
---
## 13. DolphinStrategyConfig
**File:** `nautilus_dolphin/nautilus/strategy_config.py`
```python
class DolphinStrategyConfig(StrategyConfig, kw_only=True, frozen=True):
vel_div_threshold: float = -0.02
vel_div_extreme: float = -0.05
fixed_tp_pct: float = 0.0095
max_hold_bars: int = 120
fraction: float = 0.20
min_leverage: float = 0.5
max_leverage: float = 5.0
abs_max_leverage: float = 6.0
leverage_convexity: float = 3.0
dc_lookback_bars: int = 7
dc_min_magnitude_bps: float = 0.75
min_irp_alignment: float = 0.45
sp_maker_entry_rate: float = 0.62
sp_maker_exit_rate: float = 0.50
seed: int = 42
# ...
```
Factory methods:
- `create_champion_config()` → excluded_assets=["TUSDUSDT","USDCUSDT"]
- `create_conservative_config()` → reduced leverage/fraction
- `create_growth_config()` → increased leverage
- `create_aggressive_config()` → max leverage stack
---
## 14. Test Suite Summary
| File | Tests | Coverage |
|---|---|---|
| `test_0_nautilus_bootstrap.py` | 11 | Import chain, NautilusKernelConfig, ACB, CircuitBreaker, launcher |
| `test_dolphin_actor.py` | 35 | Champion params, ACB thread-safety, HIBERNATE guard, date change, HZ degradation, replay mode, on_stop, _GateSnap |
| `test_strategy.py` | 4+ | DolphinExecutionStrategy signal filters |
| `test_adaptive_circuit_breaker.py` | ~10 | ACBv6 scale computation, cut-to-size |
| `test_circuit_breaker.py` | ~6 | CircuitBreakerManager is_tripped, can_open, status |
| `test_volatility_detector.py` | ~6 | VolatilityRegimeDetector is_high_regime |
| `test_position_manager.py` | ~5 | PositionManager state |
| `test_smart_exec_algorithm.py` | ~6 | SmartExecAlgorithm routing |
| `test_signal_bridge.py` | ~4 | SignalBridgeActor event handling |
| `test_metrics_monitor.py` | ~4 | MetricsMonitor state |
**Run all:**
```bash
source /home/dolphin/siloqy_env/bin/activate
cd /mnt/dolphinng5_predict
python -m pytest nautilus_dolphin/tests/ -v
```
**Run DolphinActor tests only:**
```bash
python -m pytest nautilus_dolphin/tests/test_dolphin_actor.py -v # 35/35
```
---
## 15. Deployment Procedures
### 15.1 siloqy-env Activation
All production and test commands must run in siloqy-env:
```bash
source /home/dolphin/siloqy_env/bin/activate
# Verify: python -c "import nautilus_trader; print(nautilus_trader.__version__)"
# Expected: 1.219.0
```
### 15.2 Daily Paper Trade (Manual)
```bash
source /home/dolphin/siloqy_env/bin/activate
cd /mnt/dolphinng5_predict
PREFECT_API_URL=http://localhost:4200/api \
python prod/paper_trade_flow.py --config prod/configs/blue.yml --date 2026-03-21
```
### 15.3 Nautilus BacktestEngine Run (Manual)
```bash
source /home/dolphin/siloqy_env/bin/activate
cd /mnt/dolphinng5_predict
python prod/run_nautilus.py --config prod/configs/blue.yml
```
### 15.4 Nautilus Prefect Flow (Manual)
```bash
source /home/dolphin/siloqy_env/bin/activate
cd /mnt/dolphinng5_predict
PREFECT_API_URL=http://localhost:4200/api \
python prod/nautilus_prefect_flow.py --date 2026-03-21
```
### 15.5 Dry Run (Data + Param Validation Only)
```bash
python prod/nautilus_prefect_flow.py --date 2026-03-21 --dry-run
```
### 15.6 Register Prefect Deployments
```bash
PREFECT_API_URL=http://localhost:4200/api \
python prod/paper_trade_flow.py --register # dolphin-paper-blue, 00:05 UTC
PREFECT_API_URL=http://localhost:4200/api \
python prod/nautilus_prefect_flow.py --register # dolphin-nautilus-blue, 00:10 UTC
```
### 15.7 Prefect Worker
```bash
source /home/dolphin/siloqy_env/bin/activate
PREFECT_API_URL=http://localhost:4200/api \
prefect worker start --pool dolphin --type process
```
---
## 16. HZ Sharded Feature Store
**Map pattern:** `DOLPHIN_FEATURES_SHARD_{shard_idx}`
**Shard count:** 10
**Routing:**
```python
shard_idx = sum(ord(c) for c in symbol) % SHARD_COUNT
imap_name = f"DOLPHIN_FEATURES_SHARD_{shard_idx:02d}"
```
The OBF flow writes per-asset OB features to the correct shard. `HZOBProvider` uses dynamic discovery (reads key_set from all 10 shards at startup) to find which assets are present.
---
## 17. Operational Invariants
1. **Champion param hash must match** at every flow start. `_CHAMPION_HASH = "..."` computed from `_CHAMPION_PARAMS` dict. Mismatch → `ValueError` → flow abort.
2. **Seed=42 is mandatory** for reproducibility. numba RNG uses Numba's internal PRNG initialized from seed. NumPy RandomState(42) used in NDAlphaEngine. Any change to seed invalidates backtest comparison.
3. **HIBERNATE is hard** — deliberately tight (Rm < 0.50). When posture=HIBERNATE, `on_bar()` returns immediately, no exceptions, no logging above WARNING.
4. **Stale-state events are logged but not fatal.** `_stale_state_events` counter increments; result dict gets `stale_state=True`. The trade result is written to HZ with a DO-NOT-USE flag in the log. Downstream systems must check this field.
5. **HZ unavailability is non-fatal.** If HZ is unreachable at on_start, `hz_client=None`, posture defaults to APEX. Flow continues with local state only. The `hz_probe_task` retries 3× before giving up with a warning (not an error).
6. **Capital continuity.** Each flow run restores capital from `DOLPHIN_STATE_BLUE["latest_nautilus"]`. If absent, falls back to `initial_capital` from config (25,000 USDT).
7. **Date boundary is ts_event-driven.** The Nautilus bar's `ts_event` nanoseconds are the authoritative source of truth for date detection. Wall clock is not used.
---
## 18. Known Limitations and Future Work
| Item | Status | Notes |
|---|---|---|
| Live TradingNode (Binance) | Pending | launcher.py exists; requires API keys + WS data integration |
| 0.1s (10 Hz) resolution | Blocked | 3 blockers: async HZ push, timeout reduction, lookback recalibration |
| LONG validation (green config) | Pending | green.yml exists; needs backtest sign-off |
| ML-MC Forewarner in Nautilus flow | **Done** | Wired in `DolphinActor.on_start()` — auto-injects for both flows; `_MC_BASE_CFG` frozen constant |
| Full end-to-end Nautilus replay parity | In progress | test_nd_vs_standalone_comparison.py exists; champion param parity confirmed |
---
*Spec version 1.0 — 2026-03-22 — Nautilus-DOLPHIN Alpha Engine Core*