JohnGenetica's picture
Deploy ANE KAN runtime Space
201cf4d verified
"""LRU scenario cache keyed by state hash.
Caches simulation results to avoid recomputing identical
or near-identical market states within the same event window.
"""
from __future__ import annotations
import hashlib
import json
import time
from collections import OrderedDict
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional
@dataclass
class CachedScenario:
"""A cached simulation result."""
state_hash: str
branches: List[List[Dict[str, float]]]
scores: List[float]
expected_value: float
var_95: float
timestamp: float = field(default_factory=time.time)
hit_count: int = 0
class ScenarioCache:
"""LRU cache for simulation results.
Keyed by a hash of the market state vector. Evicts least
recently used entries when capacity is exceeded.
"""
def __init__(self, capacity: int = 1024, ttl_seconds: float = 300.0):
self.capacity = capacity
self.ttl = ttl_seconds
self._cache: OrderedDict[str, CachedScenario] = OrderedDict()
self._hits = 0
self._misses = 0
def state_hash(self, state: Dict[str, Any]) -> str:
"""Compute deterministic hash of a market state."""
serialized = json.dumps(state, sort_keys=True, default=str)
return hashlib.sha256(serialized.encode()).hexdigest()[:16]
def get(self, state: Dict[str, Any]) -> Optional[CachedScenario]:
"""Retrieve cached scenario, or None on miss."""
h = self.state_hash(state)
if h in self._cache:
entry = self._cache[h]
if time.time() - entry.timestamp > self.ttl:
del self._cache[h]
self._misses += 1
return None
self._cache.move_to_end(h)
entry.hit_count += 1
self._hits += 1
return entry
self._misses += 1
return None
def put(self, state: Dict[str, Any], scenario: CachedScenario) -> None:
"""Store a scenario result."""
h = self.state_hash(state)
scenario.state_hash = h
if h in self._cache:
self._cache.move_to_end(h)
self._cache[h] = scenario
while len(self._cache) > self.capacity:
self._cache.popitem(last=False)
@property
def hit_rate(self) -> float:
total = self._hits + self._misses
return self._hits / total if total > 0 else 0.0
def clear(self) -> None:
self._cache.clear()
self._hits = 0
self._misses = 0