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>
15 KiB
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 interfacesprod/clean_arch/adapters/hazelcast_feed.py- Hazelcast adapterprod/clean_arch/core/trading_engine.py- Business logicprod/scan_bridge_service.py- Infrastructure bridgeprod/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
watchdogfor file system events - Parses JSON columns (
assets_json,asset_prices_json) - Handles numpy types in serialization
- Rolls to new day directory automatically
Startup:
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 clusterget_latest_snapshot(symbol)- Get MarketSnapshotsubscribe_snapshots(callback)- Subscribe to updates
Data Structure:
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:
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
# 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:
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():
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:
_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_ordersign + fill_qty - Edge cases: rebates, partials, multiple fills