WIP: feat(nautilus): initial integration #1
@@ -36,6 +36,8 @@ STRUCTURED_TOPIC = "SILOQY.STRUCTURED.TICKS"
|
||||
REGIME_TOPIC = "DOLPHIN.REGIME.RESULTS"
|
||||
SYMBOLS_DISCOVERED_TOPIC = "SILOQY.SYMBOLS.DISCOVERED"
|
||||
CANDLES_INITIAL_TOPIC = "SILOQY.CANDLES.INITIAL"
|
||||
# ADDED LINE 18:
|
||||
TICK_SIZES_TOPIC = "SILOQY.TICK.SIZES"
|
||||
|
||||
# Rate limiting constant
|
||||
MIN_INTERVAL = 2.5 # seconds between API batches
|
||||
@@ -351,6 +353,7 @@ class SILOQYSymbolDiscoveryActor(Actor):
|
||||
self.symbols = list(config.symbols) if config.symbols else []
|
||||
self.candle_interval_ms = config.candle_interval_ms
|
||||
self.active_candles = {}
|
||||
self.tick_sizes = {}
|
||||
|
||||
# Process management configuration
|
||||
self.throttle_mode = config.throttle_mode
|
||||
@@ -416,12 +419,38 @@ class SILOQYSymbolDiscoveryActor(Actor):
|
||||
if response.status_code == 200:
|
||||
self.log.info("Successfully received exchange info")
|
||||
data = response.json()
|
||||
# Get all trading symbols (USDT pairs for example)
|
||||
full_symbols = [
|
||||
s['symbol'] for s in data['symbols']
|
||||
if s['status'] == 'TRADING' and s['symbol'].endswith('USDT')
|
||||
]
|
||||
|
||||
# Combined symbol discovery and tick size extraction
|
||||
self.log.info("Processing symbols and extracting tick sizes...")
|
||||
full_symbols = []
|
||||
for symbol_info in data['symbols']:
|
||||
if symbol_info['status'] == 'TRADING' and symbol_info['symbol'].endswith('USDT'):
|
||||
symbol = symbol_info['symbol']
|
||||
full_symbols.append(symbol)
|
||||
|
||||
# Extract tick size while processing # Extract tick size while processing
|
||||
tick_size = None
|
||||
for filter_info in symbol_info['filters']:
|
||||
if filter_info['filterType'] == 'PRICE_FILTER':
|
||||
tick_size = float(filter_info['tickSize'])
|
||||
break
|
||||
|
||||
# If no PRICE_FILTER found, try other filter types
|
||||
if tick_size is None:
|
||||
for filter_info in symbol_info['filters']:
|
||||
if filter_info['filterType'] == 'TICK_SIZE':
|
||||
tick_size = float(filter_info['tickSize'])
|
||||
break
|
||||
|
||||
# Fallback to default if still not found
|
||||
if tick_size is None:
|
||||
tick_size = 1e-8 # Default fallback
|
||||
self.log.warning(f"No tick size found for {symbol}, using fallback {tick_size}")
|
||||
|
||||
self.tick_sizes[symbol] = tick_size
|
||||
|
||||
self.log.info(f"Processed {len(full_symbols)} symbols, extracted {len(self.tick_sizes)} tick sizes")
|
||||
|
||||
# Apply throttle mode symbol limiting
|
||||
if self.throttle_mode:
|
||||
self.symbols = full_symbols[:self.max_symbols_throttled]
|
||||
@@ -574,8 +603,10 @@ class SILOQYSymbolDiscoveryActor(Actor):
|
||||
# Publish symbols and candles as tuples
|
||||
self.msgbus.publish(SYMBOLS_DISCOVERED_TOPIC, (self.symbols, int(time.time_ns())))
|
||||
self.msgbus.publish(CANDLES_INITIAL_TOPIC, (self.active_candles, int(time.time_ns())))
|
||||
self.msgbus.publish(TICK_SIZES_TOPIC, (self.tick_sizes, int(time.time_ns())))
|
||||
|
||||
self.log.info(f"Nautilus ActorExecutor: Published {len(self.symbols)} symbols and {len(self.active_candles)} candles")
|
||||
self.log.info(f"Nautilus ActorExecutor: Published {len(self.tick_sizes)} tick sizes")
|
||||
self.log.info("Nautilus ActorExecutor: Discovery phase complete - other actors can now start processing")
|
||||
else:
|
||||
self.log.warning("Nautilus ActorExecutor: msgbus not available for publishing")
|
||||
@@ -868,6 +899,7 @@ class DOLPHINRegimeActor(Actor):
|
||||
self.low_prices = np.zeros(self.max_symbols, dtype=np.float64)
|
||||
self.volumes = np.zeros(self.max_symbols, dtype=np.float64)
|
||||
self.last_update = np.zeros(self.max_symbols, dtype=np.int64)
|
||||
self.tick_sizes = np.full(self.max_symbols, 1e-8, dtype=np.float64) # Default fallback
|
||||
|
||||
# PRESERVED: All original mapping and state
|
||||
self.symbol_to_idx = {}
|
||||
@@ -904,6 +936,30 @@ class DOLPHINRegimeActor(Actor):
|
||||
self.log.info("Nautilus ActorExecutor: DOLPHINRegimeActor stopping")
|
||||
# Nautilus kernel handles executor shutdown - no manual cleanup needed
|
||||
|
||||
def handle_tick_sizes(self, data):
|
||||
"""Handle tick sizes from discovery actor"""
|
||||
try:
|
||||
tick_sizes, timestamp = data
|
||||
self.log.info(f"Nautilus ActorExecutor: Received {len(tick_sizes)} tick sizes from discovery actor")
|
||||
|
||||
# Update the pre-allocated array with actual tick sizes
|
||||
updated_count = 0
|
||||
for symbol, tick_size in tick_sizes.items():
|
||||
if symbol in self.symbol_to_idx:
|
||||
idx = self.symbol_to_idx[symbol]
|
||||
# Validate tick size
|
||||
if tick_size <= 0 or tick_size > 1.0:
|
||||
self.log.warning(f"Invalid tick size {tick_size} for {symbol}, using fallback")
|
||||
self.tick_sizes[idx] = 1e-8 # Use fallback
|
||||
else:
|
||||
self.tick_sizes[idx] = tick_size
|
||||
updated_count += 1
|
||||
|
||||
self.log.info(f"Nautilus ActorExecutor: Updated {updated_count} tick sizes in pre-allocated array")
|
||||
|
||||
except Exception as e:
|
||||
self.log.error(f"Nautilus ActorExecutor: Error handling tick sizes: {e}")
|
||||
|
||||
def handle_raw_tick(self, data):
|
||||
"""
|
||||
PRESERVED EXACTLY: All original zero-allocation tick processing
|
||||
@@ -1002,12 +1058,15 @@ class DOLPHINRegimeActor(Actor):
|
||||
|
||||
analyzed += 1
|
||||
|
||||
# NEW: Direct price comparison with epsilon for precision
|
||||
EPSILON = 1e-10 # Very small tolerance to capture any meaningful price change
|
||||
|
||||
# NEW: HFT-grade tick-size based comparison
|
||||
tick_size = self.tick_sizes[idx]
|
||||
equality_threshold = tick_size / 2 # Half tick size standard
|
||||
price_diff = abs(close_price - open_price)
|
||||
|
||||
# Check if prices are effectively equal
|
||||
if abs(close_price - open_price) <= EPSILON:
|
||||
# Prices are effectively equal
|
||||
# Check if prices are effectively equal within tick size tolerance
|
||||
if price_diff <= equality_threshold:
|
||||
# Prices are effectively equal (within tick size tolerance)
|
||||
symbol_pattern.append(f"S{close_price:.2f}={open_price:.2f}")
|
||||
elif close_price > open_price:
|
||||
# Bullish: close > open
|
||||
@@ -1241,7 +1300,6 @@ def test_siloqy_actors_with_nautilus_process_management():
|
||||
|
||||
node = TradingNode(config=trading_config)
|
||||
|
||||
|
||||
try:
|
||||
node.build()
|
||||
print("Node built successfully with Nautilus built-in process management")
|
||||
|
||||
Reference in New Issue
Block a user