wip COB data source - not ready
This commit is contained in:
@ -86,6 +86,15 @@ class StandardizedDataProvider(DataProvider):
|
||||
enabled=True,
|
||||
websocket_url="wss://stream.binance.com:9443/ws/",
|
||||
symbols_mapping={symbol: symbol.replace('/', '').lower() for symbol in self.symbols}
|
||||
),
|
||||
# CoinAPI REST for supplemental depth snapshots (merged with WS streams)
|
||||
'coinapi': ExchangeConfig(
|
||||
exchange_type=ExchangeType.COINAPI,
|
||||
weight=0.6,
|
||||
enabled=True,
|
||||
rest_api_url="https://rest.coinapi.io/v1/",
|
||||
symbols_mapping={symbol: symbol.replace('/', '_').replace('USDT', 'USD') for symbol in self.symbols},
|
||||
rate_limits={"min_interval_ms": 500}
|
||||
)
|
||||
}
|
||||
|
||||
@ -229,69 +238,24 @@ class StandardizedDataProvider(DataProvider):
|
||||
COBData: COB data with price buckets and moving averages
|
||||
"""
|
||||
try:
|
||||
if not self.cob_provider:
|
||||
# Use real-time COB snapshot from parent and convert to COBData
|
||||
cob_obj = self._get_latest_cob_data_object(symbol)
|
||||
if cob_obj is None:
|
||||
return None
|
||||
|
||||
# Get current price
|
||||
current_price = self.current_prices.get(symbol.replace('/', '').upper(), 0.0)
|
||||
if current_price <= 0:
|
||||
return None
|
||||
|
||||
# Determine bucket size based on symbol
|
||||
bucket_size = 1.0 if 'ETH' in symbol else 10.0 # $1 for ETH, $10 for BTC
|
||||
|
||||
# Calculate price range (±20 buckets)
|
||||
price_range = 20 * bucket_size
|
||||
min_price = current_price - price_range
|
||||
max_price = current_price + price_range
|
||||
|
||||
# Create price buckets
|
||||
price_buckets = {}
|
||||
bid_ask_imbalance = {}
|
||||
volume_weighted_prices = {}
|
||||
|
||||
# Generate mock COB data for now (will be replaced with real COB provider data)
|
||||
for i in range(-20, 21):
|
||||
price = current_price + (i * bucket_size)
|
||||
if price > 0:
|
||||
# Mock data - replace with real COB provider data
|
||||
bid_volume = max(0, 1000 - abs(i) * 50) # More volume near current price
|
||||
ask_volume = max(0, 1000 - abs(i) * 50)
|
||||
total_volume = bid_volume + ask_volume
|
||||
imbalance = (bid_volume - ask_volume) / max(total_volume, 1)
|
||||
|
||||
price_buckets[price] = {
|
||||
'bid_volume': bid_volume,
|
||||
'ask_volume': ask_volume,
|
||||
'total_volume': total_volume,
|
||||
'imbalance': imbalance
|
||||
}
|
||||
bid_ask_imbalance[price] = imbalance
|
||||
volume_weighted_prices[price] = price # Simplified VWAP
|
||||
|
||||
|
||||
# Calculate moving averages of imbalance for ±5 buckets
|
||||
ma_data = self._calculate_cob_moving_averages(symbol, bid_ask_imbalance, timestamp)
|
||||
|
||||
cob_data = COBData(
|
||||
symbol=symbol,
|
||||
timestamp=timestamp,
|
||||
current_price=current_price,
|
||||
bucket_size=bucket_size,
|
||||
price_buckets=price_buckets,
|
||||
bid_ask_imbalance=bid_ask_imbalance,
|
||||
volume_weighted_prices=volume_weighted_prices,
|
||||
order_flow_metrics={},
|
||||
ma_1s_imbalance=ma_data.get('1s', {}),
|
||||
ma_5s_imbalance=ma_data.get('5s', {}),
|
||||
ma_15s_imbalance=ma_data.get('15s', {}),
|
||||
ma_60s_imbalance=ma_data.get('60s', {})
|
||||
)
|
||||
|
||||
# Cache the COB data
|
||||
self.cob_data_cache[symbol] = cob_data
|
||||
|
||||
return cob_data
|
||||
|
||||
ma_data = self._calculate_cob_moving_averages(symbol, cob_obj.bid_ask_imbalance, timestamp)
|
||||
|
||||
# Update MA fields
|
||||
cob_obj.ma_1s_imbalance = ma_data.get('1s', {})
|
||||
cob_obj.ma_5s_imbalance = ma_data.get('5s', {})
|
||||
cob_obj.ma_15s_imbalance = ma_data.get('15s', {})
|
||||
cob_obj.ma_60s_imbalance = ma_data.get('60s', {})
|
||||
|
||||
# Cache and return
|
||||
self.cob_data_cache[symbol] = cob_obj
|
||||
return cob_obj
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting COB data for {symbol}: {e}")
|
||||
return None
|
||||
@ -379,16 +343,40 @@ class StandardizedDataProvider(DataProvider):
|
||||
def _get_pivot_points(self, symbol: str) -> List[PivotPoint]:
|
||||
"""Get pivot points for a symbol"""
|
||||
try:
|
||||
pivot_points = []
|
||||
|
||||
# Get pivot points from Williams Market Structure if available
|
||||
if symbol in self.williams_structure:
|
||||
williams = self.williams_structure[symbol]
|
||||
# This would need to be implemented based on the actual Williams structure
|
||||
# For now, return empty list
|
||||
pass
|
||||
|
||||
return pivot_points
|
||||
results: List[PivotPoint] = []
|
||||
|
||||
# Prefer DataProvider's Williams calculation (1s OHLCV based)
|
||||
try:
|
||||
levels = self.calculate_williams_pivot_points(symbol)
|
||||
except Exception:
|
||||
levels = {}
|
||||
|
||||
# Flatten levels into standardized PivotPoint list
|
||||
if levels:
|
||||
for level_idx, trend_level in levels.items():
|
||||
# Expect trend_level to have an iterable of pivot points
|
||||
pivots = getattr(trend_level, 'pivots', None)
|
||||
if not pivots:
|
||||
# Some implementations may expose as list directly
|
||||
pivots = getattr(trend_level, 'points', [])
|
||||
for p in pivots or []:
|
||||
# Map fields defensively
|
||||
ts = getattr(p, 'timestamp', None)
|
||||
price = float(getattr(p, 'price', 0.0) or 0.0)
|
||||
ptype = getattr(p, 'pivot_type', getattr(p, 'type', 'low'))
|
||||
ptype = 'high' if str(ptype).lower() == 'high' else 'low'
|
||||
lvl = int(getattr(p, 'level', level_idx) or level_idx)
|
||||
if ts and price > 0:
|
||||
results.append(PivotPoint(
|
||||
symbol=symbol,
|
||||
timestamp=ts,
|
||||
price=price,
|
||||
type=ptype,
|
||||
level=lvl,
|
||||
confidence=1.0
|
||||
))
|
||||
|
||||
return results
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting pivot points for {symbol}: {e}")
|
||||
|
Reference in New Issue
Block a user