wip training

This commit is contained in:
Dobromir Popov
2025-07-27 19:07:34 +03:00
parent e2c495d83c
commit 2a21878ed5
5 changed files with 463 additions and 183 deletions

View File

@ -550,72 +550,318 @@ class DataProvider:
logger.error(f"Error aggregating COB 1s for {symbol}: {e}")
def _add_multi_timeframe_imbalances(self, symbol: str, aggregated_data: Dict, current_second: int) -> Dict:
"""Add 1s, 5s, 15s, and 60s imbalance indicators to the aggregated data"""
"""Add COB-based order book imbalances with configurable price ranges"""
try:
# Get historical aggregated data for calculations
historical_data = list(self.cob_1s_aggregated[symbol])
# Get price range based on symbol
price_range = self._get_price_range_for_symbol(symbol)
# Calculate imbalances for different timeframes
# Get latest COB data for current imbalance calculation
latest_cob = self.get_latest_cob_data(symbol)
current_imbalance = 0.0
if latest_cob:
current_imbalance = self._calculate_cob_imbalance(latest_cob, price_range)
# Get historical COB data for timeframe calculations
historical_cob_data = list(self.cob_raw_ticks[symbol]) if symbol in self.cob_raw_ticks else []
# Calculate imbalances for different timeframes using COB data
imbalances = {
'imbalance_1s': aggregated_data.get('imbalance', 0.0), # Current 1s imbalance
'imbalance_5s': self._calculate_timeframe_imbalance(historical_data, 5),
'imbalance_15s': self._calculate_timeframe_imbalance(historical_data, 15),
'imbalance_60s': self._calculate_timeframe_imbalance(historical_data, 60)
'imbalance_1s': current_imbalance, # Current COB imbalance
'imbalance_5s': self._calculate_timeframe_cob_imbalance(historical_cob_data, 5, price_range),
'imbalance_15s': self._calculate_timeframe_cob_imbalance(historical_cob_data, 15, price_range),
'imbalance_60s': self._calculate_timeframe_cob_imbalance(historical_cob_data, 60, price_range)
}
# Add imbalances to aggregated data
aggregated_data.update(imbalances)
# Add volume-weighted imbalances within price range
volume_imbalances = {
'volume_imbalance_1s': current_imbalance,
'volume_imbalance_5s': self._calculate_volume_weighted_imbalance(historical_cob_data, 5, price_range),
'volume_imbalance_15s': self._calculate_volume_weighted_imbalance(historical_cob_data, 15, price_range),
'volume_imbalance_60s': self._calculate_volume_weighted_imbalance(historical_cob_data, 60, price_range)
}
# Combine all imbalance metrics
all_imbalances = {**imbalances, **volume_imbalances}
# Add to aggregated data
aggregated_data.update(all_imbalances)
# Also add to stats section for compatibility
if 'stats' not in aggregated_data:
aggregated_data['stats'] = {}
aggregated_data['stats'].update(imbalances)
aggregated_data['stats'].update(all_imbalances)
# Add price range information for debugging
aggregated_data['stats']['price_range_used'] = price_range
logger.debug(f"COB imbalances for {symbol} (±${price_range}): {current_imbalance:.4f}")
return aggregated_data
except Exception as e:
logger.error(f"Error calculating multi-timeframe imbalances for {symbol}: {e}")
logger.error(f"Error calculating COB-based imbalances for {symbol}: {e}")
# Return original data with default imbalances
default_imbalances = {
'imbalance_1s': 0.0,
'imbalance_5s': 0.0,
'imbalance_15s': 0.0,
'imbalance_60s': 0.0
'imbalance_1s': 0.0, 'imbalance_5s': 0.0, 'imbalance_15s': 0.0, 'imbalance_60s': 0.0,
'volume_imbalance_1s': 0.0, 'volume_imbalance_5s': 0.0, 'volume_imbalance_15s': 0.0, 'volume_imbalance_60s': 0.0
}
aggregated_data.update(default_imbalances)
return aggregated_data
def _calculate_timeframe_imbalance(self, historical_data: List[Dict], seconds: int) -> float:
"""Calculate average imbalance over the specified number of seconds"""
def _get_price_range_for_symbol(self, symbol: str) -> float:
"""Get configurable price range for order book imbalance calculation"""
# Configurable price ranges per symbol
price_ranges = {
'ETH/USDT': 5.0, # $5 range for ETH
'BTC/USDT': 50.0, # $50 range for BTC
}
return price_ranges.get(symbol, 10.0) # Default $10 range for other symbols
def get_current_cob_imbalance(self, symbol: str) -> Dict[str, float]:
"""Get current COB imbalance metrics for a symbol"""
try:
if not historical_data or len(historical_data) < seconds:
price_range = self._get_price_range_for_symbol(symbol)
latest_cob = self.get_latest_cob_data(symbol)
if not latest_cob:
return {
'imbalance': 0.0,
'price_range': price_range,
'mid_price': 0.0,
'bid_volume_in_range': 0.0,
'ask_volume_in_range': 0.0
}
# Calculate detailed imbalance info
bids = latest_cob.get('bids', [])
asks = latest_cob.get('asks', [])
if not bids or not asks:
return {'imbalance': 0.0, 'price_range': price_range, 'mid_price': 0.0}
# Calculate mid price with proper safety checks
try:
if not bids or not asks or len(bids) == 0 or len(asks) == 0:
return {'imbalance': 0.0, 'price_range': price_range, 'mid_price': 0.0}
best_bid = float(bids[0][0])
best_ask = float(asks[0][0])
mid_price = (best_bid + best_ask) / 2.0
except (IndexError, KeyError, ValueError) as e:
logger.debug(f"Error calculating mid price for {symbol}: {e}")
return {'imbalance': 0.0, 'price_range': price_range, 'mid_price': 0.0, 'error': str(e)}
# Calculate volumes in range with safety checks
price_min = mid_price - price_range
price_max = mid_price + price_range
bid_volume_in_range = 0.0
ask_volume_in_range = 0.0
try:
for price, vol in bids:
price = float(price)
vol = float(vol)
if price_min <= price <= mid_price:
bid_volume_in_range += vol
except (IndexError, KeyError, ValueError) as e:
logger.debug(f"Error processing bid volumes for {symbol}: {e}")
try:
for price, vol in asks:
price = float(price)
vol = float(vol)
if mid_price <= price <= price_max:
ask_volume_in_range += vol
except (IndexError, KeyError, ValueError) as e:
logger.debug(f"Error processing ask volumes for {symbol}: {e}")
total_volume = bid_volume_in_range + ask_volume_in_range
imbalance = (bid_volume_in_range - ask_volume_in_range) / total_volume if total_volume > 0 else 0.0
return {
'imbalance': imbalance,
'price_range': price_range,
'mid_price': mid_price,
'bid_volume_in_range': bid_volume_in_range,
'ask_volume_in_range': ask_volume_in_range,
'total_volume_in_range': total_volume,
'best_bid': best_bid,
'best_ask': best_ask
}
except Exception as e:
logger.error(f"Error getting current COB imbalance for {symbol}: {e}")
return {'imbalance': 0.0, 'price_range': price_range, 'error': str(e)}
def _calculate_cob_imbalance(self, cob_data: Dict, price_range: float) -> float:
"""Calculate order book imbalance within specified price range around mid price"""
try:
bids = cob_data.get('bids', [])
asks = cob_data.get('asks', [])
if not bids or not asks:
return 0.0
# Get the last N seconds of data
recent_data = historical_data[-seconds:]
# Calculate weighted average imbalance
total_volume = 0
weighted_imbalance = 0
for data in recent_data:
imbalance = data.get('imbalance', 0.0)
volume = data.get('total_volume', 1.0) # Use 1.0 as default to avoid division by zero
# Calculate mid price with proper safety checks
try:
if not bids or not asks or len(bids) == 0 or len(asks) == 0:
return 0.0
weighted_imbalance += imbalance * volume
total_volume += volume
best_bid = float(bids[0][0])
best_ask = float(asks[0][0])
if best_bid <= 0 or best_ask <= 0:
return 0.0
mid_price = (best_bid + best_ask) / 2.0
except (IndexError, KeyError, ValueError) as e:
logger.debug(f"Error calculating mid price: {e}")
return 0.0
# Define price range around mid price
price_min = mid_price - price_range
price_max = mid_price + price_range
# Sum volumes within price range
bid_volume_in_range = 0.0
ask_volume_in_range = 0.0
# Sum bid volumes within range with safety checks
try:
for bid_price, bid_volume in bids:
bid_price = float(bid_price)
bid_volume = float(bid_volume)
if price_min <= bid_price <= mid_price:
bid_volume_in_range += bid_volume
except (IndexError, KeyError, ValueError) as e:
logger.debug(f"Error processing bid volumes: {e}")
# Sum ask volumes within range with safety checks
try:
for ask_price, ask_volume in asks:
ask_price = float(ask_price)
ask_volume = float(ask_volume)
if mid_price <= ask_price <= price_max:
ask_volume_in_range += ask_volume
except (IndexError, KeyError, ValueError) as e:
logger.debug(f"Error processing ask volumes: {e}")
# Calculate imbalance: (bid_volume - ask_volume) / (bid_volume + ask_volume)
total_volume = bid_volume_in_range + ask_volume_in_range
if total_volume > 0:
return weighted_imbalance / total_volume
imbalance = (bid_volume_in_range - ask_volume_in_range) / total_volume
return imbalance
else:
# Fallback to simple average
imbalances = [data.get('imbalance', 0.0) for data in recent_data]
return sum(imbalances) / len(imbalances) if imbalances else 0.0
return 0.0
except Exception as e:
logger.error(f"Error calculating {seconds}s imbalance: {e}")
logger.error(f"Error calculating COB imbalance: {e}")
return 0.0
def _calculate_timeframe_cob_imbalance(self, historical_cob_data: List[Dict], seconds: int, price_range: float) -> float:
"""Calculate average COB imbalance over specified timeframe"""
try:
if not historical_cob_data or len(historical_cob_data) == 0:
return 0.0
# Get recent data within timeframe (approximate by using last N ticks)
# Assuming ~100 ticks per second, so N = seconds * 100
max_ticks = seconds * 100
recent_ticks = historical_cob_data[-max_ticks:] if len(historical_cob_data) > max_ticks else historical_cob_data
if not recent_ticks:
return 0.0
# Calculate imbalance for each tick and average
imbalances = []
for tick in recent_ticks:
imbalance = self._calculate_cob_imbalance(tick, price_range)
imbalances.append(imbalance)
if imbalances:
return sum(imbalances) / len(imbalances)
else:
return 0.0
except Exception as e:
logger.error(f"Error calculating {seconds}s COB imbalance: {e}")
return 0.0
def _calculate_volume_weighted_imbalance(self, historical_cob_data: List[Dict], seconds: int, price_range: float) -> float:
"""Calculate volume-weighted average imbalance over timeframe"""
try:
if not historical_cob_data:
return 0.0
# Get recent data within timeframe
max_ticks = seconds * 100 # Approximate ticks per second
recent_ticks = historical_cob_data[-max_ticks:] if len(historical_cob_data) > max_ticks else historical_cob_data
if not recent_ticks:
return 0.0
total_weighted_imbalance = 0.0
total_volume = 0.0
for tick in recent_ticks:
imbalance = self._calculate_cob_imbalance(tick, price_range)
# Calculate total volume in range for weighting
bids = tick.get('bids', [])
asks = tick.get('asks', [])
if bids and asks and len(bids) > 0 and len(asks) > 0:
# Get mid price for this tick with proper safety checks
try:
best_bid = float(bids[0][0])
best_ask = float(asks[0][0])
mid_price = (best_bid + best_ask) / 2.0
except (IndexError, KeyError, ValueError) as e:
logger.debug(f"Skipping tick due to data format issue: {e}")
continue
# Calculate volume in range
price_min = mid_price - price_range
price_max = mid_price + price_range
tick_volume = 0.0
try:
for bid_price, bid_volume in bids:
bid_price = float(bid_price)
bid_volume = float(bid_volume)
if price_min <= bid_price <= mid_price:
tick_volume += bid_volume
except (IndexError, KeyError, ValueError) as e:
logger.debug(f"Error processing bid volumes in weighted calculation: {e}")
try:
for ask_price, ask_volume in asks:
ask_price = float(ask_price)
ask_volume = float(ask_volume)
if mid_price <= ask_price <= price_max:
tick_volume += ask_volume
except (IndexError, KeyError, ValueError) as e:
logger.debug(f"Error processing ask volumes in weighted calculation: {e}")
if tick_volume > 0:
total_weighted_imbalance += imbalance * tick_volume
total_volume += tick_volume
if total_volume > 0:
return total_weighted_imbalance / total_volume
else:
return 0.0
except Exception as e:
logger.error(f"Error calculating volume-weighted {seconds}s imbalance: {e}")
return 0.0
def _create_1s_cob_aggregation(self, symbol: str, ticks: List[Dict], timestamp: int) -> Dict:
"""Create 1s aggregation with $1 price buckets"""
try: