orderflow_backtest/ohlc_processor.py

71 lines
2.8 KiB
Python
Raw Normal View History

2025-09-10 15:39:16 +08:00
import logging
from typing import List, Any, Dict, Tuple
from viz_io import add_ohlc_bar, upsert_ohlc_bar, _atomic_write_json, DEPTH_FILE
from db_interpreter import OrderbookUpdate
from level_parser import normalize_levels, parse_levels_including_zeros
from orderbook_manager import OrderbookManager
from metrics_calculator import MetricsCalculator
class OHLCProcessor:
"""
Processes trade data and orderbook updates into OHLC bars and depth snapshots.
This class aggregates individual trades into time-windowed OHLC (Open, High, Low, Close)
bars and maintains an in-memory orderbook state for depth visualization. It also
calculates Order Book Imbalance (OBI) and Cumulative Volume Delta (CVD) metrics.
The processor uses throttled updates to balance visualization responsiveness with
I/O efficiency, emitting intermediate updates during active windows.
Attributes:
window_seconds: Time window duration for OHLC aggregation
depth_levels_per_side: Number of top price levels to maintain per side
trades_processed: Total number of trades processed
bars_created: Total number of OHLC bars created
cvd_cumulative: Running cumulative volume delta (via metrics calculator)
"""
def __init__(self) -> None:
self.current_bar = None
self.trades_processed = 0
self._orderbook = OrderbookManager()
self._metrics = MetricsCalculator()
@property
def cvd_cumulative(self) -> float:
"""Access cumulative CVD from metrics calculator."""
return self._metrics.cvd_cumulative
def process_trades(self, trades: List[Tuple[Any, ...]]) -> None:
for trade in trades:
trade_id, trade_id_str, price, size, side, timestamp_ms = trade[:6]
timestamp_ms = int(timestamp_ms)
self._metrics.update_cvd_from_trade(side, size)
if not self.current_bar:
self.current_bar = {
'open': float(price),
'high': float(price),
'low': float(price),
'close': float(price)
}
self.current_bar['high'] = max(self.current_bar['high'], float(price))
self.current_bar['low'] = min(self.current_bar['low'], float(price))
self.current_bar['close'] = float(price)
self.current_bar['volume'] += float(size)
def update_orderbook(self, ob_update: OrderbookUpdate) -> None:
bids_updates = parse_levels_including_zeros(ob_update.bids)
asks_updates = parse_levels_including_zeros(ob_update.asks)
self._orderbook.apply_updates(bids_updates, asks_updates)
total_bids, total_asks = self._orderbook.get_total_volume()
self._metrics.update_obi_from_book(total_bids, total_asks)