Defect A (fee sign): bingx_user_stream._normalise_order flipped to
fee = -raw_fee so BingX negative-n costs arrive as positive kernel
costs. k_maker_rebates no longer accumulates phantom rebates.
Defect B (opening fee dropped): fill_qty now falls back to "z"
(cumFilledQty) when "l" (lastFilledQty) is zero/absent, so
apply_predicted_fill computes a non-zero opening-leg fee.
Architectural fix (WARN unfreezes): lib.rs reconcile() now unfreezes
capital_frozen on WARN as well as OK. WARN (0.01-20 USDT delta) is
normal in-flight settlement — only ERROR (≥20, unexplained) should
halt ENTERs. The old keep-state logic trapped the kernel permanently
frozen after the first trade's ENTER predicted-fee phase pushed delta
briefly into ERROR.
Acceptance criterion: |k_capital - bingx_balance| < 1 USDT, frozen=False
after every round-trip trade — verified numerically against T-1/T-2
ground truth from the CRITICAL doc.
Docs: CRITICAL_AGENT-TODO_ACCOUNTING_BUGFIX.md §12-13 (fix record),
CAPITAL_BOOKKEEPING_DESIGN.md §8 (kernel spec), SYSTEM_BIBLE §11.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
386 lines
15 KiB
Markdown
386 lines
15 KiB
Markdown
# DOLPHIN Trading System Bible
|
||
|
||
**Version:** 1.0.0
|
||
**Last Updated:** 2026-03-24
|
||
**Status:** Production Ready - Paper Trading Operational
|
||
|
||
---
|
||
|
||
## 1. System Overview
|
||
|
||
The DOLPHIN Trading System is a production-grade algorithmic trading platform implementing clean hexagonal architecture for high-frequency eigenvalue-based trading strategies.
|
||
|
||
### 1.1 Current Architecture
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────────┐
|
||
│ DOLPHIN TRADING SYSTEM │
|
||
│ Version 1.0.0 │
|
||
├─────────────────────────────────────────────────────────────────────────┤
|
||
│ PRESENTATION LAYER │
|
||
│ ├── Paper Trading CLI (paper_trade.py) │
|
||
│ ├── System Monitor (status.py) │
|
||
│ └── Trading Dashboard (future) │
|
||
├─────────────────────────────────────────────────────────────────────────┤
|
||
│ CORE BUSINESS LOGIC (PORTS) │
|
||
│ ├── DataFeedPort - Abstract market data interface │
|
||
│ ├── TradingPort - Abstract execution interface │
|
||
│ └── StrategyPort - Abstract strategy interface │
|
||
├─────────────────────────────────────────────────────────────────────────┤
|
||
│ ADAPTER LAYER │
|
||
│ ├── HazelcastDataFeed - Live data from DolphinNG6 │
|
||
│ ├── PaperTradeExecutor - Simulated order execution │
|
||
│ └── (Future: BinanceDataFeed, LiveExecutor) │
|
||
├─────────────────────────────────────────────────────────────────────────┤
|
||
│ DOMAIN LOGIC │
|
||
│ ├── TradingEngine - Position sizing, risk management │
|
||
│ ├── SignalProcessor - Eigenvalue signal generation │
|
||
│ ├── PortfolioManager - Position tracking, PnL calculation │
|
||
│ └── ACBIntegration - Adaptive Circuit Breaker │
|
||
└─────────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────────┐
|
||
│ INFRASTRUCTURE │
|
||
│ ├── Hazelcast Cluster - Single Source of Truth (localhost:5701) │
|
||
│ ├── Scan Bridge Service - Arrow file watcher → Hazelcast │
|
||
│ ├── Arrow File Storage - /mnt/ng6_data/arrow_scans/ │
|
||
│ └── Nautilus Trader - Execution framework (future integration) │
|
||
└─────────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 1.2 Key Metrics
|
||
|
||
| Metric | Value |
|
||
|--------|-------|
|
||
| Architecture Pattern | Hexagonal (Clean Architecture) |
|
||
| Data Latency | ~5 seconds (DolphinNG6 pulse) |
|
||
| Assets Tracked | 50 (BTC, ETH, BNB, etc.) |
|
||
| Eigenvalue Windows | 50, 150, 300, 750 periods |
|
||
| Current BTC Price | $71,281.03 |
|
||
| Paper Trade Volume | 0.001 BTC per signal |
|
||
|
||
---
|
||
|
||
## 2. Version History
|
||
|
||
### v1.0.0 (2026-03-24) - CURRENT
|
||
**Codename:** Clean Slate
|
||
|
||
#### Major Features
|
||
- ✅ Clean hexagonal architecture implementation
|
||
- ✅ Hazelcast DataFeed adapter (live data from DolphinNG6)
|
||
- ✅ Scan Bridge Service (Arrow → Hazelcast bridge)
|
||
- ✅ Paper trading engine with PnL tracking
|
||
- ✅ Mean reversion strategy on velocity divergence
|
||
- ✅ 23 round-trip trades executed in testing
|
||
|
||
#### Components Added
|
||
- `prod/clean_arch/ports/data_feed.py` - Port interfaces
|
||
- `prod/clean_arch/adapters/hazelcast_feed.py` - Hazelcast adapter
|
||
- `prod/clean_arch/core/trading_engine.py` - Business logic
|
||
- `prod/scan_bridge_service.py` - Infrastructure bridge
|
||
- `prod/clean_arch/paper_trade.py` - Trading CLI
|
||
|
||
#### Infrastructure
|
||
- Hazelcast cluster at localhost:5701
|
||
- Scan bridge watching /mnt/ng6_data/arrow_scans/
|
||
- 6,500+ Arrow scan files processed
|
||
|
||
---
|
||
|
||
## 3. Architecture Principles
|
||
|
||
### 3.1 Hexagonal Architecture (Ports & Adapters)
|
||
|
||
The system follows strict dependency rules:
|
||
```
|
||
Core (inner) → Adapters (outer)
|
||
↑
|
||
Ports (interfaces)
|
||
```
|
||
|
||
**Rule:** Dependencies only point inward. Core knows nothing about Hazelcast, Arrow files, or Binance.
|
||
|
||
### 3.2 Single Source of Truth
|
||
|
||
All market data comes from Hazelcast `DOLPHIN_FEATURES` map:
|
||
- Price + eigenvalues written atomically by DolphinNG6
|
||
- No synchronization issues
|
||
- Guaranteed consistent timestamps
|
||
|
||
### 3.3 File Timestamp vs Scan Number
|
||
|
||
The Scan Bridge uses **file modification time** (mtime) instead of scan numbers because:
|
||
- DolphinNG6 resets scan counters on restarts
|
||
- mtime always correctly identifies the latest file
|
||
- Handles NG6 crashes and restarts gracefully
|
||
|
||
---
|
||
|
||
## 4. Subsystems
|
||
|
||
### 4.1 Data Flow Architecture
|
||
|
||
```
|
||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||
│ DolphinNG6 │────▶│ Arrow Files │────▶│ Scan Bridge │────▶│ Hazelcast │
|
||
│ (Trading) │ │ (Storage) │ │ (Service) │ │ (SSOT) │
|
||
└─────────────┘ └─────────────┘ └─────────────┘ └──────┬──────┘
|
||
5s pulse │
|
||
▼
|
||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||
│ Binance │◀────│ Nautilus │◀────│ Trading │◀────│ Hazelcast │
|
||
│ (Paper) │ │ Trader │ │ Engine │ │ DataFeed │
|
||
│ │ │ (Future) │ │ (Core) │ │ (Adapter) │
|
||
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
|
||
```
|
||
|
||
### 4.2 Component Details
|
||
|
||
#### Scan Bridge Service
|
||
**File:** `prod/scan_bridge_service.py`
|
||
**Purpose:** Watch Arrow files and push to Hazelcast
|
||
**Key Features:**
|
||
- Uses `watchdog` for file system events
|
||
- Parses JSON columns (`assets_json`, `asset_prices_json`)
|
||
- Handles numpy types in serialization
|
||
- Rolls to new day directory automatically
|
||
|
||
**Startup:**
|
||
```bash
|
||
cd /mnt/dolphinng5_predict/prod
|
||
source /home/dolphin/siloqy_env/bin/activate
|
||
python3 scan_bridge_service.py
|
||
```
|
||
|
||
#### Hazelcast DataFeed Adapter
|
||
**File:** `prod/clean_arch/adapters/hazelcast_feed.py`
|
||
**Purpose:** Implement DataFeedPort using Hazelcast
|
||
**Key Methods:**
|
||
- `connect()` - Connect to Hazelcast cluster
|
||
- `get_latest_snapshot(symbol)` - Get MarketSnapshot
|
||
- `subscribe_snapshots(callback)` - Subscribe to updates
|
||
|
||
**Data Structure:**
|
||
```python
|
||
MarketSnapshot(
|
||
timestamp=datetime,
|
||
symbol="BTCUSDT",
|
||
price=71281.03,
|
||
eigenvalues=[...], # 50 loadings
|
||
velocity_divergence=-0.0058,
|
||
scan_number=7315
|
||
)
|
||
```
|
||
|
||
#### Trading Engine
|
||
**File:** `prod/clean_arch/core/trading_engine.py`
|
||
**Purpose:** Pure business logic, no external dependencies
|
||
**Responsibilities:**
|
||
- Position sizing
|
||
- Signal processing
|
||
- Risk management
|
||
- PnL calculation
|
||
|
||
---
|
||
|
||
## 5. Trading Strategy
|
||
|
||
### 5.1 Current Strategy: Velocity Divergence Mean Reversion
|
||
|
||
**Logic:**
|
||
```python
|
||
if velocity_divergence < BUY_THRESHOLD: # -0.01
|
||
BUY 0.001 BTC
|
||
elif velocity_divergence > SELL_THRESHOLD: # 0.01
|
||
SELL position
|
||
```
|
||
|
||
**Rationale:** Extreme negative velocity divergence suggests oversold conditions.
|
||
|
||
### 5.2 Signal Sources
|
||
|
||
| Signal | Source | Description |
|
||
|--------|--------|-------------|
|
||
| `velocity_divergence` | DolphinNG6 | Rate of change divergence |
|
||
| `instability_composite` | DolphinNG6 | Market instability metric |
|
||
| `w50_lambda_max` | DolphinNG6 | Max eigenvalue (50-period) |
|
||
| `asset_loadings` | DolphinNG6 | Eigenvector components |
|
||
|
||
---
|
||
|
||
## 6. Operations Guide
|
||
|
||
### 6.1 Starting the System
|
||
|
||
```bash
|
||
# 1. Ensure Hazelcast is running
|
||
docker ps | grep hazelcast
|
||
|
||
# 2. Start Scan Bridge
|
||
cd /mnt/dolphinng5_predict/prod
|
||
source /home/dolphin/siloqy_env/bin/activate
|
||
python3 scan_bridge_service.py &
|
||
|
||
# 3. Verify data flow
|
||
python3 clean_arch/status.py
|
||
|
||
# 4. Run paper trading
|
||
python3 clean_arch/paper_trade.py --duration 60
|
||
```
|
||
|
||
### 6.2 Monitoring
|
||
|
||
**Check Status:**
|
||
```bash
|
||
cd /mnt/dolphinng5_predict/prod/clean_arch
|
||
python3 status.py
|
||
```
|
||
|
||
**Expected Output:**
|
||
```
|
||
🐬 DOLPHIN PAPER TRADING STATUS
|
||
⚡ HAZELCAST: CONNECTED
|
||
Scan: #7315
|
||
Assets: 50
|
||
Prices: 50
|
||
BTC Price: $71,281.03
|
||
```
|
||
|
||
### 6.3 Troubleshooting
|
||
|
||
| Issue | Solution |
|
||
|-------|----------|
|
||
| No Hazelcast connection | Check `docker ps`, restart container |
|
||
| No data in Hz | Restart scan bridge, check Arrow files |
|
||
| Scan number mismatch | Normal - bridge uses mtime, not scan # |
|
||
| Zero eigenvalues | Check `asset_loadings` field exists |
|
||
|
||
---
|
||
|
||
## 7. Evolution Roadmap
|
||
|
||
### Phase 1: Hazelcast Feed (COMPLETE - v1.0.0)
|
||
- ✅ Clean architecture
|
||
- ✅ Hazelcast adapter
|
||
- ✅ Paper trading
|
||
- ✅ Scan bridge service
|
||
|
||
### Phase 2: Direct Market Feed (v1.1.0)
|
||
- [ ] Binance WebSocket adapter
|
||
- [ ] Local eigenvalue computation
|
||
- [ ] Reduced latency (<100ms)
|
||
|
||
### Phase 3: Rust Kernel (v2.0.0)
|
||
- [ ] Port core to Rust
|
||
- [ ] Python adapter layer only
|
||
- [ ] Microsecond latency
|
||
|
||
### Phase 4: Live Trading (v3.0.0)
|
||
- [ ] Live order execution
|
||
- [ ] Risk management integration
|
||
- [ ] Production deployment
|
||
|
||
---
|
||
|
||
## 8. File Reference
|
||
|
||
| Path | Purpose | Version Added |
|
||
|------|---------|---------------|
|
||
| `prod/clean_arch/ports/data_feed.py` | Port interfaces | v1.0.0 |
|
||
| `prod/clean_arch/adapters/hazelcast_feed.py` | Hz adapter | v1.0.0 |
|
||
| `prod/clean_arch/core/trading_engine.py` | Business logic | v1.0.0 |
|
||
| `prod/scan_bridge_service.py` | Arrow bridge | v1.0.0 |
|
||
| `prod/clean_arch/paper_trade.py` | Trading CLI | v1.0.0 |
|
||
| `prod/clean_arch/status.py` | Status monitor | v1.0.0 |
|
||
|
||
---
|
||
|
||
## 9. Environment
|
||
|
||
**Python Environment:** `/home/dolphin/siloqy_env`
|
||
**Python Version:** 3.12.12
|
||
**Key Dependencies:**
|
||
- nautilus_trader 1.219.0
|
||
- hazelcast-python-client 5.6.0
|
||
- pyarrow
|
||
- watchdog
|
||
|
||
**Data Locations:**
|
||
- Arrow files: `/mnt/ng6_data/arrow_scans/YYYY-MM-DD/`
|
||
- Hazelcast: `localhost:5701`
|
||
- Logs: `/tmp/scan_bridge.log`
|
||
|
||
---
|
||
|
||
## 10. Team & Ownership
|
||
|
||
**System Architect:** Clean Architecture Pattern
|
||
**Data Source:** DolphinNG6 (Eigenvalue Engine)
|
||
**Infrastructure:** Hazelcast Cluster
|
||
**Trading Engine:** Hexagonal Core
|
||
|
||
---
|
||
|
||
*This document is the single source of truth for the DOLPHIN Trading System architecture and operations. All changes must be documented with version updates.*
|
||
|
||
**Document Version:** 1.0.0
|
||
**Last Modified:** 2026-03-24
|
||
**Next Review:** On Phase 2 completion
|
||
|
||
---
|
||
|
||
## 11. DITAv2 / PINK — Accounting Architecture & Known Fixes
|
||
|
||
### 11.1 Fee Sign Convention (CRITICAL — 2026-06-08)
|
||
|
||
The Rust K-account uses **POSITIVE = cost, NEGATIVE = rebate** for all fee buckets.
|
||
BingX VST uses the **opposite convention**: the `"n"` (commission) field is **NEGATIVE for costs, POSITIVE for rebates**.
|
||
|
||
The sign translation is applied at `bingx_user_stream.py:_normalise_order()`:
|
||
```python
|
||
raw_fee = _safe_float(o.get("n") or 0.0)
|
||
fee = -raw_fee # BingX cost (neg) → kernel cost (pos)
|
||
```
|
||
|
||
**Never apply this translation twice.** The kernel's `apply_fill_settled` / `apply_predicted_fill` always expect kernel convention (positive = cost). If a second boundary layer exists, it must pass fees already in kernel convention.
|
||
|
||
### 11.2 Opening-Fee Settlement (Defect B — fixed 2026-06-08)
|
||
|
||
BingX ENTER fills report filled quantity only in field `"z"` (cumFilledQty), not `"l"` (lastFilledQty). The `_normalise_order` fallback:
|
||
```python
|
||
_last_qty = _safe_float(o.get("l") or 0.0)
|
||
_cum_qty = _safe_float(o.get("z") or o.get("cumFilledQty") or 0.0)
|
||
fill_qty = _last_qty if _last_qty > 0.0 else _cum_qty
|
||
```
|
||
Ensures `apply_predicted_fill` receives non-zero `fill_qty` for ENTER fills, so the opening-leg fee prediction lands in `k_taker_fees`.
|
||
|
||
### 11.3 Reconcile / Capital Freeze Logic
|
||
|
||
The Rust kernel classifies K-vs-E divergence:
|
||
|
||
| `reconcile_status` | delta range | `capital_frozen` |
|
||
|---|---|---|
|
||
| `OK` | < 0.01 USDT | False |
|
||
| `WARN` | 0.01–20 USDT | False (unsettled but tradeable) |
|
||
| `ERROR` | ≥ 20 USDT | True (unexplained gap, HALT ENTERs) |
|
||
|
||
**WARN does NOT freeze.** During a live trade, the ENTER predicted fee temporarily pushes delta into ERROR range (seed balance not yet updated by exchange). The EXIT's realized PnL brings delta back into WARN (< 20), then the `ACCOUNT_UPDATE` event brings it to OK. Freezing on WARN would permanently block all trading after the first trade.
|
||
|
||
Only `ERROR` (≥ 20 USDT, unexplained) warrants a freeze.
|
||
|
||
### 11.4 Acceptance Criterion
|
||
|
||
After every round-trip trade: `|k_capital − bingx_wallet_balance| < 1.0 USDT` and `capital_frozen = False`.
|
||
|
||
Verified numerically against BingX ledger in `test_fee_sign_accounting.py` (34 tests, all green as of 2026-06-08).
|
||
|
||
### 11.5 Test File
|
||
|
||
`prod/clean_arch/dita_v2/test_fee_sign_accounting.py` — 34 tests covering:
|
||
- Prove-Broken: characterises the pre-fix buggy behaviour
|
||
- Prove-Fixed: T-2 and T-1 ground-truth round-trips
|
||
- Boundary layer: BingX `_normalise_order` sign + fill_qty
|
||
- Edge cases: rebates, partials, multiple fills
|