This commit is contained in:
Dobromir Popov
2025-06-27 03:30:21 +03:00
parent d791ab8b14
commit 601e44de25
5 changed files with 1025 additions and 346 deletions

View File

@ -2193,135 +2193,24 @@ class DataProvider:
logger.error(f"Error getting BOM matrix for {symbol}: {e}")
return None
def generate_synthetic_bom_features(self, symbol: str) -> List[float]:
def get_real_bom_features(self, symbol: str) -> Optional[List[float]]:
"""
Generate synthetic BOM features when real COB data is not available
Get REAL BOM features from actual market data ONLY
This creates realistic-looking order book features based on current market data
NO SYNTHETIC DATA - Returns None if real data is not available
"""
try:
features = []
# Try to get real COB data from integration
if hasattr(self, 'cob_integration') and self.cob_integration:
return self._extract_real_bom_features(symbol, self.cob_integration)
# Get current price for context
current_price = self.get_current_price(symbol)
if current_price is None:
current_price = 3000.0 # Fallback price
# === 1. CONSOLIDATED ORDER BOOK DATA (40 features) ===
# Top 10 bid levels (price offset + volume)
for i in range(10):
price_offset = -0.001 * (i + 1) * (1 + np.random.normal(0, 0.1)) # Negative for bids
volume_normalized = np.random.exponential(0.5) * (1.0 - i * 0.1) # Decreasing with depth
features.extend([price_offset, volume_normalized])
# Top 10 ask levels (price offset + volume)
for i in range(10):
price_offset = 0.001 * (i + 1) * (1 + np.random.normal(0, 0.1)) # Positive for asks
volume_normalized = np.random.exponential(0.5) * (1.0 - i * 0.1) # Decreasing with depth
features.extend([price_offset, volume_normalized])
# === 2. VOLUME PROFILE FEATURES (30 features) ===
# Top 10 volume levels (buy%, sell%, total volume)
for i in range(10):
buy_percent = 0.3 + np.random.normal(0, 0.2) # Around 30-70% buy
buy_percent = max(0.0, min(1.0, buy_percent))
sell_percent = 1.0 - buy_percent
total_volume = np.random.exponential(1.0) * (1.0 - i * 0.05)
features.extend([buy_percent, sell_percent, total_volume])
# === 3. ORDER FLOW INTENSITY (25 features) ===
# Aggressive order flow
features.extend([
0.5 + np.random.normal(0, 0.1), # Aggressive buy ratio
0.5 + np.random.normal(0, 0.1), # Aggressive sell ratio
0.4 + np.random.normal(0, 0.1), # Buy volume ratio
0.4 + np.random.normal(0, 0.1), # Sell volume ratio
np.random.exponential(100), # Avg aggressive buy size
np.random.exponential(100), # Avg aggressive sell size
])
# Block trade detection
features.extend([
0.1 + np.random.exponential(0.05), # Large trade ratio
0.2 + np.random.exponential(0.1), # Large trade volume ratio
np.random.exponential(1000), # Avg large trade size
])
# Flow velocity metrics
features.extend([
1.0 + np.random.normal(0, 0.2), # Avg time delta
0.1 + np.random.exponential(0.05), # Time velocity variance
0.5 + np.random.normal(0, 0.1), # Trade clustering
])
# Institutional activity indicators
features.extend([
0.05 + np.random.exponential(0.02), # Iceberg detection
0.3 + np.random.normal(0, 0.1), # Hidden order ratio
0.2 + np.random.normal(0, 0.05), # Smart money flow
0.1 + np.random.exponential(0.03), # Algorithmic activity
])
# Market maker behavior
features.extend([
0.6 + np.random.normal(0, 0.1), # MM provision ratio
0.4 + np.random.normal(0, 0.1), # MM take ratio
0.02 + np.random.normal(0, 0.005), # Spread tightening
1.0 + np.random.normal(0, 0.2), # Quote update frequency
0.8 + np.random.normal(0, 0.1), # Quote stability
])
# === 4. MARKET MICROSTRUCTURE SIGNALS (25 features) ===
# Order book pressure
features.extend([
0.5 + np.random.normal(0, 0.1), # Bid pressure
0.5 + np.random.normal(0, 0.1), # Ask pressure
0.0 + np.random.normal(0, 0.05), # Pressure imbalance
1.0 + np.random.normal(0, 0.2), # Pressure intensity
0.5 + np.random.normal(0, 0.1), # Depth stability
])
# Price level concentration
features.extend([
0.3 + np.random.normal(0, 0.1), # Bid concentration
0.3 + np.random.normal(0, 0.1), # Ask concentration
0.8 + np.random.normal(0, 0.1), # Top level dominance
0.2 + np.random.normal(0, 0.05), # Fragmentation index
0.6 + np.random.normal(0, 0.1), # Liquidity clustering
])
# Temporal dynamics
features.extend([
0.1 + np.random.normal(0, 0.02), # Volatility factor
1.0 + np.random.normal(0, 0.1), # Momentum factor
0.0 + np.random.normal(0, 0.05), # Mean reversion
0.5 + np.random.normal(0, 0.1), # Trend alignment
0.8 + np.random.normal(0, 0.1), # Pattern consistency
])
# Exchange-specific patterns
features.extend([
0.4 + np.random.normal(0, 0.1), # Cross-exchange correlation
0.3 + np.random.normal(0, 0.1), # Exchange arbitrage
0.2 + np.random.normal(0, 0.05), # Latency patterns
0.8 + np.random.normal(0, 0.1), # Sync quality
0.6 + np.random.normal(0, 0.1), # Data freshness
])
# Ensure exactly 120 features
if len(features) > 120:
features = features[:120]
elif len(features) < 120:
features.extend([0.0] * (120 - len(features)))
# Clamp all values to reasonable ranges
features = [max(-5.0, min(5.0, f)) for f in features]
return features
# No real data available - return None instead of synthetic
logger.warning(f"No real BOM data available for {symbol} - waiting for real market data")
return None
except Exception as e:
logger.error(f"Error generating synthetic BOM features for {symbol}: {e}")
return [0.0] * 120
logger.error(f"Error getting real BOM features for {symbol}: {e}")
return None
def start_bom_cache_updates(self, cob_integration=None):
"""
@ -2342,17 +2231,14 @@ class DataProvider:
if bom_features:
self.update_bom_cache(symbol, bom_features, cob_integration)
else:
# Fallback to synthetic
synthetic_features = self.generate_synthetic_bom_features(symbol)
self.update_bom_cache(symbol, synthetic_features)
# NO SYNTHETIC FALLBACK - Wait for real data
logger.warning(f"No real BOM features available for {symbol} - waiting for real data")
except Exception as e:
logger.warning(f"Error getting real BOM features for {symbol}: {e}")
synthetic_features = self.generate_synthetic_bom_features(symbol)
self.update_bom_cache(symbol, synthetic_features)
logger.warning(f"Waiting for real data instead of using synthetic")
else:
# Generate synthetic BOM features
synthetic_features = self.generate_synthetic_bom_features(symbol)
self.update_bom_cache(symbol, synthetic_features)
# NO SYNTHETIC FEATURES - Wait for real COB integration
logger.warning(f"No COB integration available for {symbol} - waiting for real data")
time.sleep(1.0) # Update every second
@ -2470,7 +2356,9 @@ class DataProvider:
"""Extract flow and microstructure features"""
try:
# For now, return synthetic features since full implementation would be complex
return self.generate_synthetic_bom_features(symbol)[70:] # Last 50 features
# NO SYNTHETIC DATA - Return None if no real microstructure data
logger.warning(f"No real microstructure data available for {symbol}")
return None
except:
return [0.0] * 50