81 lines
2.5 KiB
Python
81 lines
2.5 KiB
Python
|
|
"""
|
||
|
|
ClickHouse persistence — store, retrieve, table creation.
|
||
|
|
"""
|
||
|
|
import json
|
||
|
|
import time
|
||
|
|
import pytest
|
||
|
|
from malkhut.storage.ch_store import MalkhutCHStore
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture(scope="module")
|
||
|
|
def store():
|
||
|
|
s = MalkhutCHStore()
|
||
|
|
s.ensure_tables()
|
||
|
|
return s
|
||
|
|
|
||
|
|
|
||
|
|
class TestClickHouseTables:
|
||
|
|
def test_tables_exist(self, store):
|
||
|
|
result = store.query("SHOW TABLES")
|
||
|
|
tables = result.strip().split("\n")
|
||
|
|
assert "replay_steps" in tables
|
||
|
|
assert "fulfilment_decisions" in tables
|
||
|
|
assert "self_play_episodes" in tables
|
||
|
|
assert "policy_snapshots" in tables
|
||
|
|
assert "live_discrepancies" in tables
|
||
|
|
|
||
|
|
def test_table_idempotent(self, store):
|
||
|
|
store.ensure_tables()
|
||
|
|
store.ensure_tables()
|
||
|
|
result = store.query("SHOW TABLES")
|
||
|
|
assert "replay_steps" in result
|
||
|
|
|
||
|
|
|
||
|
|
class TestClickHouseInsert:
|
||
|
|
def test_store_fulfilment_decision(self, store):
|
||
|
|
store.store_fulfilment_decision(
|
||
|
|
ts_ns=time.time_ns(), exchange="bingx", symbol="BTCUSDT",
|
||
|
|
intent_id="test_intent", state_hash="abc123",
|
||
|
|
selected_action="PLACE", root_distribution="[0.5, 0.5]",
|
||
|
|
risk_decision="True:approved", policy_version="v0.1",
|
||
|
|
latency_ms=5.0,
|
||
|
|
)
|
||
|
|
|
||
|
|
def test_store_episode(self, store):
|
||
|
|
store.store_episode(
|
||
|
|
policy_version="v0.1", scenario_id="test_scenario",
|
||
|
|
seed=42, pnl_bps=10.0, max_drawdown_bps=-5.0,
|
||
|
|
fill_ratio=0.8, adverse_fill_ratio=0.1,
|
||
|
|
avg_slippage_bps=1.5, liq_near_misses=0,
|
||
|
|
cancel_count=3, diagnostics="{}",
|
||
|
|
)
|
||
|
|
|
||
|
|
def test_store_policy_snapshot(self, store):
|
||
|
|
store.store_policy_snapshot(
|
||
|
|
version="v0.1_test", score=5.0,
|
||
|
|
params_str="test_params", evaluation_summary="{}",
|
||
|
|
)
|
||
|
|
|
||
|
|
def test_store_discrepancy(self, store):
|
||
|
|
store.store_discrepancy(
|
||
|
|
ts_ns=time.time_ns(), exchange="bingx", symbol="BTCUSDT",
|
||
|
|
predicted="PLACE", actual="FILL", severity="warning",
|
||
|
|
)
|
||
|
|
|
||
|
|
def test_store_replay_step(self, store):
|
||
|
|
store.store_replay_step(
|
||
|
|
symbol="BTCUSDT", ts_ns=time.time_ns(), step_index=0,
|
||
|
|
before="{}", action="{}", after="{}",
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
class TestClickHouseQuery:
|
||
|
|
def test_query_returns_string(self, store):
|
||
|
|
result = store.query("SELECT 1")
|
||
|
|
assert result.strip() == "1"
|
||
|
|
|
||
|
|
def test_query_with_format(self, store):
|
||
|
|
result = store.query("SELECT 1 AS val FORMAT JSONEachRow")
|
||
|
|
row = json.loads(result.strip())
|
||
|
|
assert row["val"] == 1
|