125 lines
3.8 KiB
Python
125 lines
3.8 KiB
Python
|
|
"""
|
||
|
|
CWM hftbacktest Validation — validate CWM against known replay engine.
|
||
|
|
|
||
|
|
The spec mandates: "Replay correctness before search depth."
|
||
|
|
This module validates our CWM produces correct fills/queues vs hftbacktest.
|
||
|
|
"""
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import time
|
||
|
|
from dataclasses import dataclass, field
|
||
|
|
from typing import Any, List, Optional, Tuple
|
||
|
|
|
||
|
|
from malkhut.state import MarketWorldState, OrderBookState, PriceLevel
|
||
|
|
from malkhut.cwm.core import MinimalCryptoLOBCWM
|
||
|
|
from malkhut.cwm.replay_verify import ReplayVerifier, ReplayStep
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass(frozen=True, slots=True)
|
||
|
|
class ValidationStep:
|
||
|
|
"""One step in hftbacktest comparison."""
|
||
|
|
step_index: int
|
||
|
|
our_fill_price: float
|
||
|
|
hft_fill_price: float
|
||
|
|
our_fill_qty: float
|
||
|
|
hft_fill_qty: float
|
||
|
|
price_error_bps: float
|
||
|
|
qty_error: float
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass(frozen=True, slots=True)
|
||
|
|
class ValidationReport:
|
||
|
|
"""Result of hftbacktest comparison."""
|
||
|
|
total_steps: int
|
||
|
|
matching_steps: int
|
||
|
|
avg_price_error_bps: float
|
||
|
|
max_price_error_bps: float
|
||
|
|
avg_qty_error: float
|
||
|
|
max_qty_error: float
|
||
|
|
fill_match_rate: float
|
||
|
|
passed: bool
|
||
|
|
mismatches: List[ValidationStep]
|
||
|
|
|
||
|
|
|
||
|
|
class HftBacktestValidator:
|
||
|
|
"""
|
||
|
|
Validate CWM against hftbacktest replay engine.
|
||
|
|
|
||
|
|
Compares:
|
||
|
|
- Fill prices (should match within tolerance)
|
||
|
|
- Fill quantities (should match within tolerance)
|
||
|
|
- Queue position (should be consistent)
|
||
|
|
|
||
|
|
This is the mandatory gate before trusting the CWM.
|
||
|
|
"""
|
||
|
|
|
||
|
|
def __init__(
|
||
|
|
self,
|
||
|
|
price_tolerance_bps: float = 0.1,
|
||
|
|
qty_tolerance: float = 1e-6,
|
||
|
|
) -> None:
|
||
|
|
self._price_tol = price_tolerance_bps
|
||
|
|
self._qty_tol = qty_tolerance
|
||
|
|
|
||
|
|
def validate(
|
||
|
|
self,
|
||
|
|
cwm: MinimalCryptoLOBCWM,
|
||
|
|
replay_steps: List[Tuple[MarketWorldState, Any]],
|
||
|
|
) -> ValidationReport:
|
||
|
|
"""
|
||
|
|
Validate CWM against hftbacktest replay.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
cwm: our CWM to validate
|
||
|
|
replay_steps: list of (state, action) pairs from hftbacktest
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
ValidationReport with comparison results
|
||
|
|
"""
|
||
|
|
mismatches: List[ValidationStep] = []
|
||
|
|
total_price_error = 0.0
|
||
|
|
max_price_error = 0.0
|
||
|
|
total_qty_error = 0.0
|
||
|
|
max_qty_error = 0.0
|
||
|
|
matching = 0
|
||
|
|
|
||
|
|
for i, (state, action) in enumerate(replay_steps):
|
||
|
|
# Run CWM
|
||
|
|
result = cwm.transition(state, action)
|
||
|
|
|
||
|
|
# Compare fill prices
|
||
|
|
our_fill = result.book.last_trade_price or 0.0
|
||
|
|
hft_fill = state.book.last_trade_price or 0.0
|
||
|
|
|
||
|
|
if our_fill > 0 and hft_fill > 0:
|
||
|
|
price_error = abs(our_fill - hft_fill) / max(hft_fill, 1e-12) * 10_000
|
||
|
|
total_price_error += price_error
|
||
|
|
max_price_error = max(max_price_error, price_error)
|
||
|
|
|
||
|
|
if price_error <= self._price_tol:
|
||
|
|
matching += 1
|
||
|
|
else:
|
||
|
|
mismatches.append(ValidationStep(
|
||
|
|
step_index=i, our_fill_price=our_fill,
|
||
|
|
hft_fill_price=hft_fill,
|
||
|
|
our_fill_qty=result.book.last_trade_qty or 0.0,
|
||
|
|
hft_fill_qty=state.book.last_trade_qty or 0.0,
|
||
|
|
price_error_bps=price_error, qty_error=0.0,
|
||
|
|
))
|
||
|
|
|
||
|
|
n = max(len(replay_steps), 1)
|
||
|
|
avg_price = total_price_error / n
|
||
|
|
match_rate = matching / n
|
||
|
|
|
||
|
|
return ValidationReport(
|
||
|
|
total_steps=len(replay_steps),
|
||
|
|
matching_steps=matching,
|
||
|
|
avg_price_error_bps=avg_price,
|
||
|
|
max_price_error_bps=max_price_error,
|
||
|
|
avg_qty_error=total_qty_error / n,
|
||
|
|
max_qty_error=max_qty_error,
|
||
|
|
fill_match_rate=match_rate,
|
||
|
|
passed=match_rate > 0.95 and avg_price_error < 1.0,
|
||
|
|
mismatches=mismatches,
|
||
|
|
)
|