137 lines
4.8 KiB
Python
137 lines
4.8 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""
|
||
|
|
CLEAN ARCHITECTURE - DOLPHIN PAPER TRADER
|
||
|
|
==========================================
|
||
|
|
|
||
|
|
🙏 God bless clean code and synchronized data 🙏
|
||
|
|
|
||
|
|
Architecture:
|
||
|
|
┌──────────────────────────────────────────────┐
|
||
|
|
│ CORE: TradingEngine (pure Python) │
|
||
|
|
│ - Business logic only │
|
||
|
|
│ - No external dependencies │
|
||
|
|
│ - Ready for Rust rewrite │
|
||
|
|
└──────────────────┬───────────────────────────┘
|
||
|
|
│ uses PORT
|
||
|
|
↓
|
||
|
|
┌──────────────────────────────────────────────┐
|
||
|
|
│ PORT: DataFeedPort (interface) │
|
||
|
|
│ - Abstract interface │
|
||
|
|
│ - Easy to swap implementations │
|
||
|
|
└──────────────────┬───────────────────────────┘
|
||
|
|
│ implemented by
|
||
|
|
↓
|
||
|
|
┌──────────────────────────────────────────────┐
|
||
|
|
│ ADAPTER: HazelcastDataFeed │
|
||
|
|
│ - Current implementation │
|
||
|
|
│ - Single source: DolphinNG6 → Hazelcast │
|
||
|
|
│ - No sync issues │
|
||
|
|
└──────────────────────────────────────────────┘
|
||
|
|
|
||
|
|
Evolution Path:
|
||
|
|
Phase 1 (NOW): HazelcastDataFeed (this file)
|
||
|
|
Phase 2: BinanceWebsocketFeed (direct connection)
|
||
|
|
Phase 3: RustKernelFeed (in-kernel, zero-copy)
|
||
|
|
|
||
|
|
Usage:
|
||
|
|
python clean_arch/main.py
|
||
|
|
"""
|
||
|
|
|
||
|
|
import asyncio
|
||
|
|
import sys
|
||
|
|
import logging
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
# Setup paths
|
||
|
|
PROJECT_ROOT = Path(__file__).parent.parent
|
||
|
|
sys.path.insert(0, str(PROJECT_ROOT / 'nautilus_dolphin'))
|
||
|
|
sys.path.insert(0, str(PROJECT_ROOT))
|
||
|
|
sys.path.insert(0, str(Path(__file__).parent))
|
||
|
|
|
||
|
|
# Logging
|
||
|
|
logging.basicConfig(
|
||
|
|
level=logging.INFO,
|
||
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||
|
|
)
|
||
|
|
logger = logging.getLogger("DOLPHIN-CLEAN-ARCH")
|
||
|
|
|
||
|
|
# Import clean architecture components
|
||
|
|
from adapters.hazelcast_feed import HazelcastDataFeed
|
||
|
|
from core.trading_engine import TradingEngine
|
||
|
|
|
||
|
|
|
||
|
|
# =============================================================================
|
||
|
|
# CONFIGURATION
|
||
|
|
# =============================================================================
|
||
|
|
|
||
|
|
CONFIG = {
|
||
|
|
'trader_id': 'DOLPHIN-CLEAN-01',
|
||
|
|
'venue': 'BINANCE_FUTURES',
|
||
|
|
|
||
|
|
# Hazelcast configuration (current adapter)
|
||
|
|
'hazelcast': {
|
||
|
|
'cluster': 'dolphin',
|
||
|
|
'host': 'localhost:5701',
|
||
|
|
},
|
||
|
|
|
||
|
|
# Trading parameters
|
||
|
|
'initial_capital': 25000.0,
|
||
|
|
'max_leverage': 5.0,
|
||
|
|
'capital_fraction': 0.20,
|
||
|
|
'min_irp_alignment': 0.45,
|
||
|
|
'vel_div_threshold': -0.02,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
async def main():
|
||
|
|
"""
|
||
|
|
Main entry point - wires clean architecture together.
|
||
|
|
"""
|
||
|
|
logger.info("=" * 70)
|
||
|
|
logger.info("🐬 DOLPHIN CLEAN ARCHITECTURE")
|
||
|
|
logger.info("=" * 70)
|
||
|
|
logger.info(f"Trader ID: {CONFIG['trader_id']}")
|
||
|
|
logger.info(f"Venue: {CONFIG['venue']}")
|
||
|
|
logger.info(f"Data Feed: Hazelcast (DolphinNG6)")
|
||
|
|
logger.info(f"Architecture: Clean / Hexagonal")
|
||
|
|
logger.info(f"Evolution Ready: Yes (in-kernel future)")
|
||
|
|
logger.info("=" * 70)
|
||
|
|
|
||
|
|
# =================================================================
|
||
|
|
# WIRE COMPONENTS
|
||
|
|
# =================================================================
|
||
|
|
|
||
|
|
# 1. Create Data Feed Adapter (ADAPTER layer)
|
||
|
|
# - Currently: Hazelcast
|
||
|
|
# - Future: Can swap to BinanceWebsocket or RustKernel
|
||
|
|
logger.info("[1/3] Creating data feed adapter...")
|
||
|
|
data_feed = HazelcastDataFeed(CONFIG)
|
||
|
|
logger.info(" ✓ Hazelcast adapter created")
|
||
|
|
|
||
|
|
# 2. Create Trading Engine (CORE layer)
|
||
|
|
# - Pure business logic
|
||
|
|
# - No knowledge of Hazelcast
|
||
|
|
# - Works with ANY DataFeedPort implementation
|
||
|
|
logger.info("[2/3] Creating trading engine...")
|
||
|
|
engine = TradingEngine(data_feed, CONFIG)
|
||
|
|
logger.info(" ✓ Trading engine created")
|
||
|
|
logger.info(" ✓ Core is adapter-agnostic")
|
||
|
|
|
||
|
|
# 3. Start system
|
||
|
|
logger.info("[3/3] Starting system...")
|
||
|
|
logger.info("=" * 70)
|
||
|
|
|
||
|
|
try:
|
||
|
|
await engine.start()
|
||
|
|
except KeyboardInterrupt:
|
||
|
|
logger.info("\nShutdown requested...")
|
||
|
|
await engine.stop()
|
||
|
|
except Exception as e:
|
||
|
|
logger.error(f"Fatal error: {e}")
|
||
|
|
await engine.stop()
|
||
|
|
raise
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
asyncio.run(main())
|