Files
siloqy/SILOQY_DOLPHIN_Integration_Engineering_Spect_1.0.md

1400 lines
52 KiB
Markdown

SILOQY DOLPHIN Integration Engineering Specification
====================================================
**Document Version:** 1.0
**Date:** August 31, 2025
**Target Audience:** SILOQY Component Developers
**Framework:** Nautilus Trader Integration Architecture
Executive Summary
-----------------
This document provides the complete technical specification for integrating with
the SILOQY DOLPHIN market regime detection system within the Nautilus Trader
framework. It details the message bus architecture, actor lifecycle management,
data flow patterns, and exact implementation requirements for new SILOQY
components.
Table of Contents
-----------------
1. [Architecture Overview](#architecture-overview)
2. [Nautilus Message Bus Communication](#nautilus-message-bus-communication)
3. [Actor Lifecycle and Execution Model](#actor-lifecycle-and-execution-model)
4. [SILOQY Topic Hierarchy and Data
Structures](#siloqy-topic-hierarchy-and-data-structures)
5. [Producer/Consumer Patterns](#producer-consumer-patterns)
6. [Component Integration Patterns](#component-integration-patterns)
7. [Error Handling and Recovery](#error-handling-and-recovery)
8. [Performance Optimization Guidelines](#performance-optimization-guidelines)
9. [Testing and Validation Requirements](#testing-and-validation-requirements)
10. [Code Examples and Templates](#code-examples-and-templates)
Architecture Overview
---------------------
### System Components
The SILOQY DOLPHIN system operates within a single Nautilus TradingNode instance
with four core actors:
1. **SILOQYSymbolDiscoveryActor**: Symbol discovery and candle reconstruction
2. **SILOQYMainActor**: Real-time data ingestion and WebSocket management
3. **DOLPHINRegimeActor**: Market regime detection and analysis
4. **SILOQYNormalizerActor**: Tick normalization and format standardization
### Data Flow Architecture
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
External Market Data → SILOQYMainActor → MessageBus → [DOLPHINRegimeActor, SILOQYNormalizerActor]
Custom SILOQY Components
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Shared Node Pattern
**Critical Design Principle:** New SILOQY components MUST integrate into the
existing TradingNode instance rather than creating separate nodes. This ensures:
- Shared message bus access - Unified actor lifecycle management - Consistent
resource allocation - Optimal performance through single-process architecture
Nautilus Message Bus Communication
----------------------------------
### Message Bus Access Pattern
All SILOQY actors gain access to the Nautilus MessageBus through the standard
Nautilus actor initialization:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class MySILOQYComponent(Actor):
def __init__(self, config: MyComponentConfig):
super().__init__(config)
# MessageBus is available as self.msgbus after Nautilus initialization
def on_start(self) -> None:
# Subscribe to topics ONLY in on_start()
if hasattr(self, 'msgbus') and self.msgbus:
self.msgbus.subscribe("SILOQY.MY.TOPIC", self.handle_my_data)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Message Publishing Protocol
**High-Performance Publishing Pattern:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def publish_siloqy_data(self, topic: str, data: Any) -> None:
"""Standard SILOQY publishing pattern"""
try:
if hasattr(self, 'msgbus') and self.msgbus:
self.msgbus.publish(topic, data)
else:
self.log.error("MessageBus not available for publishing")
except Exception as e:
self.log.error(f"Failed to publish to {topic}: {e}")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Subscription Management
**Thread-Safe Subscription Pattern:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def on_start(self) -> None:
"""Subscribe to required SILOQY topics"""
if hasattr(self, 'msgbus') and self.msgbus:
# Subscribe to core SILOQY data streams
self.msgbus.subscribe(RAW_TOPIC, self.handle_raw_tick)
self.msgbus.subscribe(REGIME_TOPIC, self.handle_regime_update)
self.msgbus.subscribe("SILOQY.CUSTOM.TOPIC", self.handle_custom_data)
self.log.info("Subscribed to SILOQY message bus topics")
else:
self.log.error("MessageBus not available during initialization")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Message Bus Timing Guarantees
- **Publication Latency:** \< 1μs for tuple data
- **Delivery Guarantee:** Synchronous delivery to all subscribers
- **Thread Safety:** Fully thread-safe for concurrent access
- **Memory Management:** Zero-copy for immutable data types
Actor Lifecycle and Execution Model
-----------------------------------
### Nautilus Actor Initialization Sequence
1. **Construction Phase:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def __init__(self, config: ActorConfig):
super().__init__(config) # MUST call super().__init__()
# Initialize component-specific state
# MessageBus NOT available yet
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2. **Registration Phase:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Handled automatically by TradingNode.build()
# Actor registered with Nautilus kernel
# MessageBus reference established
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3. **Startup Phase:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def on_start(self) -> None:
# MessageBus NOW available as self.msgbus
# Subscribe to required topics
# Initialize async tasks using ActorExecutor
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4. **Execution Phase:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Actor receives messages via subscribed handlers
# Actor publishes data via self.msgbus.publish()
# Long-running tasks managed by ActorExecutor
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5. **Shutdown Phase:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def on_stop(self) -> None:
# Clean up component-specific resources
# Nautilus handles ActorExecutor cleanup automatically
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### ActorExecutor Task Management
**Preferred Pattern for Async Operations:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def on_start(self) -> None:
if hasattr(self, '_executor') and self._executor:
self.log.info("Using Nautilus ActorExecutor")
future = self._executor.submit(self.async_initialization())
else:
self.log.warning("No executor available, falling back to asyncio")
asyncio.create_task(self.async_initialization())
async def async_initialization(self):
# Long-running async operations
# Managed by Nautilus ActorExecutor
pass
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Actor State Management
**Thread-Safe State Pattern:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class MySILOQYActor(Actor):
def __init__(self, config):
super().__init__(config)
# Pre-allocated arrays for high-frequency data (DOLPHIN pattern)
self.data_arrays = np.zeros(config.max_items, dtype=np.float64)
self.symbol_mapping = {}
self.active_count = 0
# Thread-safe collections for shared state
self.message_queue = deque(maxlen=10000)
self.state_lock = threading.Lock()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SILOQY Topic Hierarchy and Data Structures
------------------------------------------
### Core SILOQY Topics
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Primary data flow topics
RAW_TOPIC = "SILOQY.RAW.TICKS" # Raw market tick data
STRUCTURED_TOPIC = "SILOQY.STRUCTURED.TICKS" # Normalized SiloqyTradeTick objects
REGIME_TOPIC = "DOLPHIN.REGIME.RESULTS" # Market regime detection results
# Discovery and initialization topics
SYMBOLS_DISCOVERED_TOPIC = "SILOQY.SYMBOLS.DISCOVERED" # Symbol discovery completion
CANDLES_INITIAL_TOPIC = "SILOQY.CANDLES.INITIAL" # Candle reconstruction results
# Custom component topics (examples)
HD_VECTOR_TOPIC = "SILOQY.HD.VECTORS" # Hyperdimensional vector data
TEMPORAL_TOPIC = "SILOQY.TEMPORAL.PATTERNS" # Temporal memory patterns
ANALYSIS_TOPIC = "SILOQY.ANALYSIS.RESULTS" # Custom analysis results
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Topic Naming Convention
**Standard Format:** `SILOQY.{COMPONENT}.{DATA_TYPE}.{VARIANT}`
**Examples:** - `SILOQY.SENTIMENT.ANALYSIS.REALTIME` -
`SILOQY.CORRELATION.MATRIX.UPDATED` - `SILOQY.RISK.METRICS.CALCULATED` -
`SILOQY.ML.PREDICTIONS.GENERATED`
### Data Structure Specifications
#### Raw Tick Data Format (RAW_TOPIC)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Tuple format: (symbol, price, size, ts_event, open_price, candle_open_time)
raw_tick_tuple = (
"BTCUSDT", # str: Symbol identifier
45000.12345678, # float: Current price (8 decimal precision)
1.23456789, # float: Trade quantity (8 decimal precision)
1693489234567, # int: Event timestamp (milliseconds)
44950.87654321, # float: Current candle open price (8 decimal precision)
1693488900000 # int: Candle open time (milliseconds)
)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#### Structured Tick Data Format (STRUCTURED_TOPIC)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# SiloqyTradeTick object with additional SILOQY fields
structured_tick = SiloqyTradeTick(
instrument_id="BTCUSDT.BINANCE", # InstrumentId: Nautilus format
price=Price(45000.12345678, 8), # Price: Nautilus price object
size=Quantity(1.23456789, 8), # Quantity: Nautilus quantity object
ts_event=1693489234567000000, # int: Nanosecond timestamp
open_price=44950.87654321, # float: SILOQY candle open price
candle_open_time=1693488900000, # int: SILOQY candle open time
exchange="BINANCE", # str: SILOQY exchange identifier
tick_side=None, # Optional[str]: Order side
liquidity_flag=None # Optional[str]: Liquidity classification
)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#### Regime Detection Results (REGIME_TOPIC)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Tuple format: (timestamp, regime, bull_ratio, bear_ratio, sideways_ratio, analyzed, total, confidence)
regime_tuple = (
1693489234567, # int: Detection timestamp (milliseconds)
"BULL", # str: Regime type ["BULL", "BEAR", "SIDEWAYS"]
0.67, # float: Bull ratio (0.0-1.0)
0.25, # float: Bear ratio (0.0-1.0)
0.08, # float: Sideways ratio (0.0-1.0)
150, # int: Symbols analyzed
180, # int: Total symbols available
0.82 # float: Confidence score (0.0-1.0)
)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Custom Data Structure Template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@dataclass
class SILOQYCustomData:
"""Template for custom SILOQY data structures"""
component_id: str
timestamp: int
data_type: str
payload: Dict[str, Any]
confidence: float = 1.0
metadata: Dict[str, Any] = field(default_factory=dict)
def to_message_tuple(self) -> Tuple:
"""Convert to message bus tuple format"""
return (
self.component_id,
self.timestamp,
self.data_type,
json.dumps(self.payload),
self.confidence,
json.dumps(self.metadata)
)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Producer/Consumer Patterns
--------------------------
### High-Frequency Data Producer Pattern
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SILOQYHighFrequencyProducer(Actor):
"""Template for high-frequency data producers"""
def __init__(self, config):
super().__init__(config)
self.publish_count = 0
self.last_publish_time = 0
def produce_data_efficiently(self, data: Any, topic: str) -> None:
"""High-performance data publishing"""
try:
# Validate data before publishing
if self._validate_data(data):
self.msgbus.publish(topic, data)
self.publish_count += 1
# Performance monitoring
if self.publish_count % 1000 == 0:
self._log_performance_metrics()
else:
self.log.warning(f"Invalid data rejected for topic {topic}")
except Exception as e:
self.log.error(f"Publishing failed for topic {topic}: {e}")
def _validate_data(self, data: Any) -> bool:
"""Implement component-specific validation"""
# Override in derived classes
return True
def _log_performance_metrics(self) -> None:
"""Log performance metrics"""
current_time = time.time()
if self.last_publish_time > 0:
duration = current_time - self.last_publish_time
rate = 1000 / duration if duration > 0 else 0
self.log.info(f"Publishing rate: {rate:.1f} messages/sec")
self.last_publish_time = current_time
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Data Consumer Pattern
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SILOQYDataConsumer(Actor):
"""Template for SILOQY data consumers"""
def __init__(self, config):
super().__init__(config)
self.processed_count = 0
self.processing_queue = deque(maxlen=10000)
self.batch_size = 100
def on_start(self) -> None:
"""Subscribe to required SILOQY topics"""
if hasattr(self, 'msgbus') and self.msgbus:
# Subscribe to multiple SILOQY data streams
self.msgbus.subscribe(RAW_TOPIC, self.handle_raw_tick)
self.msgbus.subscribe(REGIME_TOPIC, self.handle_regime_update)
self.msgbus.subscribe("SILOQY.CUSTOM.DATA", self.handle_custom_data)
self.log.info("SILOQY consumer subscriptions established")
def handle_raw_tick(self, data: Tuple) -> None:
"""Handle raw tick data with efficient processing"""
try:
# Parse data
symbol, price, size, ts_event, open_price, candle_open_time = data
# Add to processing queue
self.processing_queue.append({
'type': 'raw_tick',
'symbol': symbol,
'price': price,
'size': size,
'timestamp': ts_event,
'open_price': open_price,
'candle_open_time': candle_open_time
})
# Batch processing for efficiency
if len(self.processing_queue) >= self.batch_size:
self._process_batch()
except Exception as e:
self.log.error(f"Raw tick processing error: {e}")
def handle_regime_update(self, data: Tuple) -> None:
"""Handle DOLPHIN regime updates"""
try:
timestamp, regime, bull_ratio, bear_ratio, sideways_ratio, analyzed, total, confidence = data
# Process regime change
self._on_regime_change(regime, bull_ratio, bear_ratio, confidence)
except Exception as e:
self.log.error(f"Regime update processing error: {e}")
def _process_batch(self) -> None:
"""Process queued data in batches for efficiency"""
batch = list(self.processing_queue)
self.processing_queue.clear()
# Process batch with single operation
self._bulk_process_data(batch)
self.processed_count += len(batch)
def _bulk_process_data(self, batch: List[Dict]) -> None:
"""Override in derived classes for bulk processing"""
pass
def _on_regime_change(self, regime: str, bull_ratio: float, bear_ratio: float, confidence: float) -> None:
"""Override in derived classes for regime-based logic"""
pass
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Actor Lifecycle and Execution Model
-----------------------------------
### TradingNode Initialization Sequence
1. **Node Creation:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
trading_config = TradingNodeConfig(
trader_id=TraderId("SILOQY-PRODUCTION"),
actors=[
# All SILOQY actor configurations
symbol_discovery_config,
main_actor_config,
regime_actor_config,
normalizer_config,
custom_component_config # New components added here
]
)
node = TradingNode(config=trading_config)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2. **Build Phase:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
node.build() # Creates all actors, establishes MessageBus
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3. **Startup Phase:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
node.run() # Calls on_start() on all actors in dependency order
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Actor Dependency Management
**Initialization Order (Critical):** 1. `SILOQYSymbolDiscoveryActor` - Must
complete first 2. `SILOQYMainActor` - Depends on symbol discovery 3.
`DOLPHINRegimeActor` - Depends on main actor tick data 4.
`SILOQYNormalizerActor` - Depends on raw tick data 5. **Custom Components** -
Typically depend on normalized data or regime results
### Async Task Management with ActorExecutor
**ActorExecutor Usage Pattern:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def on_start(self) -> None:
# Start long-running operations via ActorExecutor
if hasattr(self, '_executor') and self._executor:
self.log.info("Using Nautilus ActorExecutor for task management")
future = self._executor.submit(self.long_running_operation())
else:
# Fallback for development/testing
asyncio.create_task(self.long_running_operation())
async def long_running_operation(self):
"""Long-running async operation managed by Nautilus"""
while self.is_running:
try:
# Perform periodic operations
await self.process_periodic_task()
await asyncio.sleep(1.0)
except asyncio.CancelledError:
break
except Exception as e:
self.log.error(f"Long-running operation error: {e}")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Actor State Synchronization
**Synchronization Pattern for Actor Dependencies:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class DependentSILOQYActor(Actor):
def __init__(self, config):
super().__init__(config)
self.dependency_ready = asyncio.Event()
self.symbols = []
self.candle_data = {}
def on_start(self) -> None:
# Subscribe to dependency notifications
self.msgbus.subscribe(SYMBOLS_DISCOVERED_TOPIC, self.handle_symbols_ready)
self.msgbus.subscribe(CANDLES_INITIAL_TOPIC, self.handle_candles_ready)
# Start dependent operations
if hasattr(self, '_executor') and self._executor:
future = self._executor.submit(self.wait_for_dependencies())
async def wait_for_dependencies(self):
"""Wait for required data before starting operations"""
await asyncio.wait_for(self.dependency_ready.wait(), timeout=120.0)
# Now safe to start component-specific operations
await self.start_component_operations()
def handle_symbols_ready(self, data):
symbols, timestamp = data
self.symbols = symbols
self._check_dependencies_complete()
def handle_candles_ready(self, data):
candles, timestamp = data
self.candle_data = candles
self._check_dependencies_complete()
def _check_dependencies_complete(self):
if self.symbols and self.candle_data:
self.dependency_ready.set()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component Integration Patterns
------------------------------
### Adding New SILOQY Components
**Step 1: Component Configuration**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class MySILOQYComponentConfig(ActorConfig):
"""Configuration for custom SILOQY component"""
component_name: str = "MyComponent"
update_interval_ms: int = 1000
enable_hd_processing: bool = True
custom_parameters: Dict[str, Any] = field(default_factory=dict)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Step 2: Actor Implementation**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class MySILOQYComponent(Actor):
def __init__(self, config: MySILOQYComponentConfig):
super().__init__(config)
self.component_name = config.component_name
self.update_interval_ms = config.update_interval_ms
self.enable_hd_processing = config.enable_hd_processing
def on_start(self) -> None:
# Subscribe to required SILOQY data streams
self.msgbus.subscribe(STRUCTURED_TOPIC, self.handle_structured_tick)
self.msgbus.subscribe(REGIME_TOPIC, self.handle_regime_update)
# Start component-specific operations
if hasattr(self, '_executor') and self._executor:
future = self._executor.submit(self.start_processing())
def handle_structured_tick(self, tick: SiloqyTradeTick) -> None:
"""Process incoming SILOQY tick data"""
# Component-specific processing
result = self.process_siloqy_tick(tick)
# Publish results to custom topic
if result:
self.msgbus.publish("SILOQY.MYCOMPONENT.RESULTS", result)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Step 3: Registration with TradingNode**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
my_component_config = ImportableActorConfig(
actor_path="my_module:MySILOQYComponent",
config_path="my_module:MySILOQYComponentConfig",
config={
"component_id": "MY-SILOQY-COMPONENT",
"component_name": "CustomAnalyzer",
"update_interval_ms": 500,
"enable_hd_processing": True
}
)
# Add to existing TradingNode configuration
trading_config = TradingNodeConfig(
trader_id=TraderId("SILOQY-EXTENDED"),
actors=[
symbol_discovery_config,
main_actor_config,
regime_actor_config,
normalizer_config,
my_component_config # Add custom component here
]
)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Inter-Component Communication Patterns
**Direct Communication via MessageBus:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Component A publishes analysis results
def publish_analysis_result(self, analysis_data: Dict):
custom_data = {
'component_id': self.id,
'analysis_type': 'correlation_matrix',
'timestamp': int(time.time() * 1000),
'results': analysis_data,
'confidence': 0.95
}
self.msgbus.publish("SILOQY.CORRELATION.ANALYSIS", custom_data)
# Component B consumes analysis results
def on_start(self):
self.msgbus.subscribe("SILOQY.CORRELATION.ANALYSIS", self.handle_correlation_data)
def handle_correlation_data(self, data: Dict):
# Process correlation analysis from other component
pass
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Request/Response Pattern:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Component A requests data
def request_analysis(self, symbol: str, timeframe: str):
request_data = {
'request_id': str(uuid.uuid4()),
'requesting_component': str(self.id),
'symbol': symbol,
'timeframe': timeframe,
'response_topic': f"SILOQY.RESPONSE.{self.id}"
}
self.msgbus.publish("SILOQY.REQUEST.ANALYSIS", request_data)
# Component B responds to requests
def handle_analysis_request(self, request_data: Dict):
# Process request
analysis_result = self.perform_analysis(request_data['symbol'], request_data['timeframe'])
# Send response
response = {
'request_id': request_data['request_id'],
'result': analysis_result,
'timestamp': int(time.time() * 1000)
}
self.msgbus.publish(request_data['response_topic'], response)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Error Handling and Recovery
---------------------------
### Message Processing Error Handling
**Standard Error Handling Pattern:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def handle_siloqy_message(self, data: Any) -> None:
"""Standard SILOQY message handling with error recovery"""
try:
# Validate message structure
if not self._validate_message_structure(data):
self.log.warning(f"Invalid message structure rejected")
self._record_validation_failure("structure")
return
# Process message
result = self._process_message_content(data)
# Publish result if successful
if result:
self.msgbus.publish(self.output_topic, result)
except ValidationError as e:
self.log.warning(f"Message validation failed: {e}")
self._record_validation_failure("validation")
except ProcessingError as e:
self.log.error(f"Message processing failed: {e}")
self._record_processing_failure()
except Exception as e:
self.log.error(f"Unexpected error in message handling: {e}")
self._record_unexpected_failure()
def _record_validation_failure(self, failure_type: str) -> None:
"""Record validation failures for monitoring"""
if not hasattr(self, 'validation_failures'):
self.validation_failures = defaultdict(int)
self.validation_failures[failure_type] += 1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Actor Recovery Patterns
**Graceful Degradation Pattern:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class ResilientSILOQYActor(Actor):
def __init__(self, config):
super().__init__(config)
self.error_count = 0
self.max_errors = 100
self.recovery_mode = False
def handle_processing_error(self, error: Exception) -> None:
"""Handle processing errors with graceful degradation"""
self.error_count += 1
if self.error_count > self.max_errors:
self.log.error("Error threshold exceeded, entering recovery mode")
self.recovery_mode = True
# Reduce processing frequency or disable non-critical features
# Reset error count periodically
if time.time() % 300 == 0: # Every 5 minutes
self.error_count = max(0, self.error_count - 10)
if self.error_count < 10:
self.recovery_mode = False
self.log.info("Exiting recovery mode")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Performance Optimization Guidelines
-----------------------------------
### Zero-Allocation Patterns (DOLPHIN Style)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class HighPerformanceSILOQYActor(Actor):
"""High-performance actor using zero-allocation patterns"""
def __init__(self, config):
super().__init__(config)
# Pre-allocate arrays for high-frequency data
self.max_symbols = config.max_symbols
self.price_data = np.zeros(self.max_symbols, dtype=np.float64)
self.volume_data = np.zeros(self.max_symbols, dtype=np.float64)
self.timestamp_data = np.zeros(self.max_symbols, dtype=np.int64)
# Symbol mapping for O(1) lookups
self.symbol_to_index = {}
self.index_to_symbol = {}
self.active_symbols = 0
def process_tick_zero_allocation(self, symbol: str, price: float, volume: float, timestamp: int):
"""Process tick with zero memory allocation"""
# Get or assign symbol index
if symbol not in self.symbol_to_index:
if self.active_symbols >= self.max_symbols:
self.log.error(f"Symbol capacity exceeded: {self.max_symbols}")
return
idx = self.active_symbols
self.symbol_to_index[symbol] = idx
self.index_to_symbol[idx] = symbol
self.active_symbols += 1
else:
idx = self.symbol_to_index[symbol]
# Update arrays in-place (zero allocation)
self.price_data[idx] = price
self.volume_data[idx] = volume
self.timestamp_data[idx] = timestamp
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Message Bus Performance Optimization
**Efficient Data Serialization:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Prefer tuples over complex objects for high-frequency data
efficient_message = (symbol, price, volume, timestamp) # Fast
inefficient_message = {'symbol': symbol, 'price': price, 'volume': volume} # Slower
# Use pre-allocated buffers for repeated operations
class BufferedSILOQYActor(Actor):
def __init__(self, config):
super().__init__(config)
self.message_buffer = [None] * 1000 # Pre-allocated buffer
self.buffer_index = 0
def publish_efficiently(self, data):
# Reuse buffer slots to minimize garbage collection
self.message_buffer[self.buffer_index] = data
self.msgbus.publish(self.topic, self.message_buffer[self.buffer_index])
self.buffer_index = (self.buffer_index + 1) % 1000
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Testing and Validation Requirements
-----------------------------------
### Unit Test Requirements for SILOQY Components
**Mandatory Test Coverage:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class TestMySILOQYComponent(unittest.TestCase):
"""Required test patterns for all SILOQY components"""
def test_message_bus_integration(self):
"""Test MessageBus subscription and publishing"""
# Verify component can subscribe to required topics
# Verify component can publish to output topics
# Test message handling with valid and invalid data
pass
def test_actor_lifecycle(self):
"""Test complete actor lifecycle"""
# Test initialization with TradingNode
# Test on_start() behavior
# Test on_stop() behavior
# Test resource cleanup
pass
def test_data_validation(self):
"""Test input data validation"""
# Test with valid SILOQY data structures
# Test with malformed data
# Test boundary conditions
# Test error recovery
pass
def test_performance_requirements(self):
"""Test performance under load"""
# Test high-frequency message processing
# Test memory usage stability
# Test latency requirements
pass
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Integration Test Requirements
**MessageBus Integration Test Template:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def test_full_integration_with_dolphin(self):
"""Test integration with existing DOLPHIN system"""
# Create TradingNode with DOLPHIN + custom component
node = self._create_test_node_with_custom_component()
# Verify component receives DOLPHIN data
collector = TestDataCollector()
node.kernel.msgbus.subscribe("SILOQY.CUSTOM.OUTPUT", collector.collect_data)
# Inject test data through DOLPHIN pipeline
test_ticks = self._generate_test_tick_data()
for tick in test_ticks:
node.kernel.msgbus.publish(RAW_TOPIC, tick)
# Verify custom component processed DOLPHIN regime data
time.sleep(2.0)
self.assertGreater(len(collector.collected_data), 0)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Code Examples and Templates
---------------------------
### Complete Component Template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#!/usr/bin/env python3
"""
SILOQY Custom Component Template
Template for integrating new components with SILOQY DOLPHIN system
"""
import time
import asyncio
import numpy as np
from typing import Dict, List, Optional, Any
from collections import deque, defaultdict
from dataclasses import dataclass, field
from nautilus_trader.common.actor import Actor
from nautilus_trader.common.config import ActorConfig
from nautilus_trader.common.component import Logger
# SILOQY imports
from nautilus_actor_test_implementation_5x_modified import (
RAW_TOPIC, STRUCTURED_TOPIC, REGIME_TOPIC,
SiloqyTradeTick, MarketRegime
)
@dataclass
class MySILOQYComponentConfig(ActorConfig):
"""Configuration for custom SILOQY component"""
component_name: str = "CustomComponent"
processing_interval_ms: int = 1000
enable_regime_tracking: bool = True
max_history_size: int = 10000
custom_parameters: Dict[str, Any] = field(default_factory=dict)
class MySILOQYComponent(Actor):
"""Template for custom SILOQY components"""
def __init__(self, config: MySILOQYComponentConfig):
super().__init__(config)
# Component configuration
self.component_name = config.component_name
self.processing_interval_ms = config.processing_interval_ms
self.enable_regime_tracking = config.enable_regime_tracking
self.max_history_size = config.max_history_size
# High-performance data structures
self.tick_history = deque(maxlen=self.max_history_size)
self.regime_history = deque(maxlen=100)
self.current_regime = MarketRegime.SIDEWAYS
# Performance metrics
self.processed_ticks = 0
self.processed_regimes = 0
self.last_performance_log = time.time_ns()
# State management
self.is_processing = False
self.dependency_ready = asyncio.Event()
self.log.info(f"Custom SILOQY component '{self.component_name}' initialized")
def on_start(self) -> None:
"""Start component and subscribe to SILOQY data streams"""
self.log.info(f"Starting SILOQY component: {self.component_name}")
if hasattr(self, 'msgbus') and self.msgbus:
# Subscribe to core SILOQY data streams
self.msgbus.subscribe(STRUCTURED_TOPIC, self.handle_structured_tick)
if self.enable_regime_tracking:
self.msgbus.subscribe(REGIME_TOPIC, self.handle_regime_update)
# Subscribe to custom topics if needed
self.msgbus.subscribe("SILOQY.CUSTOM.INPUT", self.handle_custom_input)
self.log.info("SILOQY MessageBus subscriptions established")
# Start async processing
if hasattr(self, '_executor') and self._executor:
future = self._executor.submit(self.start_async_processing())
else:
asyncio.create_task(self.start_async_processing())
def on_stop(self) -> None:
"""Stop component processing"""
self.log.info(f"Stopping SILOQY component: {self.component_name}")
self.is_processing = False
# Nautilus ActorExecutor handles task cleanup
async def start_async_processing(self):
"""Start component-specific async processing"""
self.is_processing = True
self.log.info("Custom SILOQY component async processing started")
while self.is_processing:
try:
# Perform periodic processing
await self.perform_periodic_analysis()
await asyncio.sleep(self.processing_interval_ms / 1000.0)
except asyncio.CancelledError:
break
except Exception as e:
self.log.error(f"Periodic processing error: {e}")
await asyncio.sleep(1.0)
def handle_structured_tick(self, tick: SiloqyTradeTick) -> None:
"""Handle incoming structured tick data"""
try:
# Add to history
self.tick_history.append({
'symbol': str(tick.instrument_id),
'price': float(tick.price),
'size': float(tick.size),
'timestamp': tick.ts_event,
'open_price': tick.open_price,
'exchange': tick.exchange
})
self.processed_ticks += 1
# Process tick for component-specific logic
result = self.process_tick_data(tick)
# Publish results if any
if result:
self.msgbus.publish(f"SILOQY.{self.component_name.upper()}.RESULTS", result)
# Performance logging
now = time.time_ns()
if now - self.last_performance_log > 10_000_000_000: # Every 10 seconds
self.log.info(f"Component {self.component_name}: processed {self.processed_ticks} ticks")
self.last_performance_log = now
except Exception as e:
self.log.error(f"Structured tick processing error: {e}")
def handle_regime_update(self, data: Tuple) -> None:
"""Handle DOLPHIN regime updates"""
try:
timestamp, regime, bull_ratio, bear_ratio, sideways_ratio, analyzed, total, confidence = data
# Update current regime
old_regime = self.current_regime
self.current_regime = MarketRegime(regime)
# Add to history
self.regime_history.append({
'regime': regime,
'bull_ratio': bull_ratio,
'bear_ratio': bear_ratio,
'confidence': confidence,
'timestamp': timestamp
})
self.processed_regimes += 1
# React to regime changes
if old_regime != self.current_regime:
self.on_regime_change(old_regime, self.current_regime, confidence)
except Exception as e:
self.log.error(f"Regime update processing error: {e}")
def handle_custom_input(self, data: Any) -> None:
"""Handle custom input data"""
# Override in derived classes
pass
def process_tick_data(self, tick: SiloqyTradeTick) -> Optional[Dict]:
"""Override in derived classes for tick processing"""
# Implement component-specific tick processing
return None
async def perform_periodic_analysis(self) -> None:
"""Override in derived classes for periodic analysis"""
# Implement component-specific periodic operations
pass
def on_regime_change(self, old_regime: MarketRegime, new_regime: MarketRegime, confidence: float) -> None:
"""Override in derived classes for regime change handling"""
self.log.info(f"Regime change detected: {old_regime.value} → {new_regime.value} (confidence: {confidence:.1%})")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Component Registration Template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def create_siloqy_trading_node_with_custom_components():
"""Template for creating TradingNode with custom SILOQY components"""
# Core SILOQY components (required)
symbol_discovery_config = ImportableActorConfig(
actor_path="nautilus_actor_test_implementation_5x_modified:SILOQYSymbolDiscoveryActor",
config_path="nautilus_actor_test_implementation_5x_modified:SILOQYSymbolDiscoveryConfig",
config={
"component_id": "SILOQY-SYMBOL-DISCOVERY",
"symbols": [],
"candle_interval_ms": 15 * 60 * 1000,
"throttle_mode": True, # Safe for development
"throttle_rate_limit_seconds": 10.0,
"max_symbols_throttled": 100
}
)
main_actor_config = ImportableActorConfig(
actor_path="nautilus_actor_test_implementation_5x_modified:SILOQYMainActor",
config_path="nautilus_actor_test_implementation_5x_modified:SILOQYMainActorConfig",
config={
"component_id": "SILOQY-MAIN-ACTOR",
"candle_interval_ms": 15 * 60 * 1000,
"throttle_mode": True,
"enable_real_data": False # Set to True for production
}
)
regime_actor_config = ImportableActorConfig(
actor_path="nautilus_actor_test_implementation_5x_modified:DOLPHINRegimeActor",
config_path="nautilus_actor_test_implementation_5x_modified:DOLPHINRegimeActorConfig",
config={
"component_id": "DOLPHIN-REGIME-ACTOR",
"max_symbols": 5000,
"ticks_per_analysis": 1000
}
)
normalizer_config = ImportableActorConfig(
actor_path="nautilus_actor_test_implementation_5x_modified:SILOQYNormalizerActor",
config_path="nautilus_actor_test_implementation_5x_modified:SILOQYNormalizerConfig",
config={
"component_id": "SILOQY-NORMALIZER"
}
)
# Custom SILOQY components (add new components here)
custom_component_config = ImportableActorConfig(
actor_path="my_custom_module:MySILOQYComponent",
config_path="my_custom_module:MySILOQYComponentConfig",
config={
"component_id": "MY-CUSTOM-SILOQY-COMPONENT",
"component_name": "CustomAnalyzer",
"processing_interval_ms": 1000,
"enable_regime_tracking": True,
"max_history_size": 10000
}
)
# Complete TradingNode configuration
trading_config = TradingNodeConfig(
trader_id=TraderId("SILOQY-EXTENDED-SYSTEM"),
actors=[
symbol_discovery_config,
main_actor_config,
regime_actor_config,
normalizer_config,
custom_component_config # Add all custom components here
],
data_clients={}, # External data clients if needed
exec_clients={} # Execution clients if needed
)
# Create and return node
node = TradingNode(config=trading_config)
return node
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Advanced Integration Patterns
-----------------------------
### Custom Data Type Integration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from nautilus_trader.core.data import Data
class SILOQYCustomData(Data):
"""Custom SILOQY data type for Nautilus integration"""
def __init__(self, component_id: str, analysis_data: Dict, timestamp_ns: int):
self.component_id = component_id
self.analysis_data = analysis_data
super().__init__(ts_event=timestamp_ns, ts_init=timestamp_ns)
def __repr__(self) -> str:
return f"SILOQYCustomData(component={self.component_id}, data_keys={list(self.analysis_data.keys())})"
# Usage in component
def publish_custom_analysis(self, analysis_result: Dict):
custom_data = SILOQYCustomData(
component_id=str(self.id),
analysis_data=analysis_result,
timestamp_ns=int(time.time_ns())
)
# Publish as Nautilus Data object
if hasattr(self, 'publish_data'):
self.publish_data(custom_data)
else:
# Fallback to message bus
self.msgbus.publish("SILOQY.CUSTOM.ANALYSIS", custom_data)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Component Coordination Patterns
**Master/Worker Pattern:**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SILOQYMasterComponent(Actor):
"""Master component that coordinates worker components"""
def __init__(self, config):
super().__init__(config)
self.worker_topics = [
"SILOQY.WORKER.CORRELATION",
"SILOQY.WORKER.SENTIMENT",
"SILOQY.WORKER.MOMENTUM"
]
self.worker_results = {}
def distribute_work(self, work_data: Dict):
"""Distribute work to worker components"""
for topic in self.worker_topics:
work_package = {
'master_id': str(self.id),
'work_data': work_data,
'response_topic': f"SILOQY.MASTER.{self.id}.RESULTS"
}
self.msgbus.publish(topic, work_package)
def on_start(self):
# Subscribe to worker responses
self.msgbus.subscribe(f"SILOQY.MASTER.{self.id}.RESULTS", self.handle_worker_result)
self.msgbus.subscribe(REGIME_TOPIC, self.handle_regime_change)
class SILOQYWorkerComponent(Actor):
"""Worker component that processes distributed tasks"""
def on_start(self):
self.msgbus.subscribe("SILOQY.WORKER.CORRELATION", self.handle_work_assignment)
def handle_work_assignment(self, work_package: Dict):
"""Process assigned work and return results"""
try:
result = self.process_work(work_package['work_data'])
response = {
'worker_id': str(self.id),
'result': result,
'timestamp': int(time.time() * 1000)
}
self.msgbus.publish(work_package['response_topic'], response)
except Exception as e:
self.log.error(f"Work processing failed: {e}")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Production Deployment Checklist
-------------------------------
### Pre-Deployment Requirements
**Configuration Validation:** - [ ] `throttle_mode: False` for production
performance - [ ] `enable_real_data: True` for live market data
- [ ] `max_symbols_throttled: 5000+` for full market coverage - [ ]
`ticks_per_analysis: 1000` for stable regime detection
**Component Integration Validation:** - [ ] All custom components pass
integration tests - [ ] MessageBus topic subscriptions verified - [ ] Actor
dependency order confirmed - [ ] Error handling and recovery tested - [ ]
Performance requirements met
**System Resource Validation:** - [ ] Memory allocation sufficient for all
actors - [ ] CPU capacity adequate for real-time processing - [ ] Network
bandwidth adequate for WebSocket streams - [ ] Storage capacity planned (if
using persistent storage)
### Production Configuration Template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def create_production_siloqy_node():
"""Production-ready SILOQY TradingNode configuration"""
# Production symbol discovery
symbol_discovery_config = ImportableActorConfig(
actor_path="nautilus_actor_test_implementation_5x_modified:SILOQYSymbolDiscoveryActor",
config_path="nautilus_actor_test_implementation_5x_modified:SILOQYSymbolDiscoveryConfig",
config={
"component_id": "SILOQY-SYMBOL-DISCOVERY-PROD",
"symbols": [], # Dynamic discovery
"candle_interval_ms": 15 * 60 * 1000,
"throttle_mode": False, # PRODUCTION: Full performance
"throttle_rate_limit_seconds": 2.5, # Standard rate limit
"max_symbols_throttled": 5000 # Full symbol coverage
}
)
# Production main actor with real data
main_actor_config = ImportableActorConfig(
actor_path="nautilus_actor_test_implementation_5x_modified:SILOQYMainActor",
config_path="nautilus_actor_test_implementation_5x_modified:SILOQYMainActorConfig",
config={
"component_id": "SILOQY-MAIN-ACTOR-PROD",
"candle_interval_ms": 15 * 60 * 1000,
"throttle_mode": False, # PRODUCTION: Full performance
"enable_real_data": True # PRODUCTION: Real WebSocket data
}
)
# Production DOLPHIN regime detection
regime_actor_config = ImportableActorConfig(
actor_path="nautilus_actor_test_implementation_5x_modified:DOLPHINRegimeActor",
config_path="nautilus_actor_test_implementation_5x_modified:DOLPHINRegimeActorConfig",
config={
"component_id": "DOLPHIN-REGIME-ACTOR-PROD",
"max_symbols": 5000, # Full capacity
"ticks_per_analysis": 1000 # Stable regime detection
}
)
return TradingNodeConfig(
trader_id=TraderId("SILOQY-PRODUCTION"),
actors=[symbol_discovery_config, main_actor_config, regime_actor_config, normalizer_config],
data_clients={},
exec_clients={}
)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Appendix: Message Bus Topic Reference
-------------------------------------
### Complete Topic Hierarchy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SILOQY Root Topics:
├── SILOQY.RAW.TICKS # Raw market tick data (tuple format)
├── SILOQY.STRUCTURED.TICKS # Normalized SiloqyTradeTick objects
├── SILOQY.SYMBOLS.DISCOVERED # Symbol discovery completion
├── SILOQY.CANDLES.INITIAL # Candle reconstruction results
DOLPHIN Topics:
├── DOLPHIN.REGIME.RESULTS # Market regime detection results
Custom Component Topics (Examples):
├── SILOQY.HD.VECTORS # Hyperdimensional vector data
├── SILOQY.TEMPORAL.PATTERNS # Temporal memory patterns
├── SILOQY.CORRELATION.MATRIX # Symbol correlation analysis
├── SILOQY.SENTIMENT.ANALYSIS # Market sentiment data
├── SILOQY.RISK.METRICS # Risk calculation results
├── SILOQY.ML.PREDICTIONS # Machine learning predictions
├── SILOQY.ANALYSIS.REQUESTS # Analysis request coordination
├── SILOQY.ANALYSIS.RESPONSES # Analysis response delivery
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Performance Characteristics by Topic
Topic
Frequency
Latency Requirement
Data Size
Thread Safety
`RAW_TOPIC`
1000+ msg/sec
\< 5μs
200 bytes
Full
`STRUCTURED_TOPIC`
1000+ msg/sec
\< 10μs
500 bytes
Full
`REGIME_TOPIC`
1-10 msg/sec
\< 100μs
300 bytes
Full
Custom Topics
Variable
\< 1ms
Variable
Full
This document provides the complete technical foundation for integrating new
SILOQY components with the DOLPHIN market regime detection system within the
Nautilus framework. All patterns, data structures, and lifecycle management
approaches are based on the proven implementation that has processed 289+
million ticks in production operation.