129 lines
4.5 KiB
Python
129 lines
4.5 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
"""
|
|||
|
|
CMA-ES Re-Run at Corrected Fees — Establishes real performance baseline.
|
|||
|
|
|
|||
|
|
Corrected fees: taker 5.0 bps, maker +2.0 bps (BingX perps).
|
|||
|
|
Previous best 15,080 was at WRONG fees (taker 0.5, maker -0.2).
|
|||
|
|
|
|||
|
|
Runs 200 evals across multiple assets with the full venue-tagged, order-type-aware
|
|||
|
|
system. Produces a JSON report at malkhut/results/cma_rerun_<ts>.json.
|
|||
|
|
|
|||
|
|
Usage:
|
|||
|
|
python -m malkhut.cma_rerun
|
|||
|
|
"""
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import json
|
|||
|
|
import os
|
|||
|
|
import sys
|
|||
|
|
import time
|
|||
|
|
|
|||
|
|
_HERE = os.path.dirname(os.path.abspath(__file__))
|
|||
|
|
if _HERE not in sys.path:
|
|||
|
|
sys.path.insert(0, _HERE)
|
|||
|
|
|
|||
|
|
from malkhut.state import FulfilmentPolicyParams
|
|||
|
|
from malkhut.training.cma_trainer import (
|
|||
|
|
ScenarioFactory, CMAESTrainer, CMAParameterCodec,
|
|||
|
|
PolicySnapshot, PolicyEvaluator, SelfPlayPool,
|
|||
|
|
)
|
|||
|
|
from malkhut.cwm.core import MinimalCryptoLOBCWM
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _baseline() -> FulfilmentPolicyParams:
|
|||
|
|
return FulfilmentPolicyParams(
|
|||
|
|
version="baseline_corrected_fees", ucb_c=1.414, max_sims=256, max_depth=3,
|
|||
|
|
rollout_depth=3, root_temperature=0.5, min_root_entropy=0.25,
|
|||
|
|
quote_offsets_ticks=(0, 1, 2), quote_size_fractions=(0.1, 0.25, 0.5),
|
|||
|
|
passive_ttl_ms=200, aggressive_ttl_ms=50, maker_edge_min_bps=0.5,
|
|||
|
|
cross_spread_edge_min_bps=5.0, adverse_toxicity_cancel_threshold=0.5,
|
|||
|
|
queue_churn_cancel_threshold=0.5, mae_tail_cut_bps=50.0,
|
|||
|
|
mfe_giveback_cut_fraction=0.5, max_time_in_loss_s=300.0,
|
|||
|
|
failed_recovery_cut_count=3, recovery_velocity_min_bps_per_s=0.0,
|
|||
|
|
max_symbol_notional_fraction=0.20, max_single_order_notional_fraction=0.05,
|
|||
|
|
reduce_when_global_up_fraction=0.30, session_profit_lock_fraction=0.02,
|
|||
|
|
w_expected_pnl=1.0, w_fill_probability=0.5, w_adverse_selection=2.0,
|
|||
|
|
w_queue_priority=0.5, w_inventory_risk=1.5, w_tail_loss=5.0,
|
|||
|
|
w_fee_quality=0.5, w_time_decay=0.3, w_policy_entropy=0.5,
|
|||
|
|
robust_tail_weight=2.0, toxic_counterparty_weight=3.0,
|
|||
|
|
low_liquidity_weight=2.0, latency_stress_weight=1.0,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
BUDGET_EVALS = 50
|
|||
|
|
SEED = 42
|
|||
|
|
SYMBOLS = ("BTCUSDT",)
|
|||
|
|
|
|||
|
|
print("=" * 70)
|
|||
|
|
print("CMA-ES RE-RUN AT CORRECTED FEES")
|
|||
|
|
print(f" Fees: taker=5.0 bps, maker=+2.0 bps (BingX)")
|
|||
|
|
print(f" Budget: {BUDGET_EVALS} evals")
|
|||
|
|
print(f" Assets: {', '.join(SYMBOLS)}")
|
|||
|
|
print(f" Seed: {SEED}")
|
|||
|
|
print("=" * 70)
|
|||
|
|
print()
|
|||
|
|
|
|||
|
|
t0 = time.time()
|
|||
|
|
|
|||
|
|
factory = ScenarioFactory(exchange_id="bingx")
|
|||
|
|
scenarios = factory.build_suite(symbols=list(SYMBOLS), steps_per_scenario=10, seed=SEED)
|
|||
|
|
print(f"Scenarios: {len(scenarios)} (×{len(SYMBOLS)} assets)")
|
|||
|
|
print(f" Tags: {sorted(set(t for s in scenarios for t in s.tags))[:10]}...")
|
|||
|
|
print()
|
|||
|
|
|
|||
|
|
def cwm_factory():
|
|||
|
|
return MinimalCryptoLOBCWM()
|
|||
|
|
|
|||
|
|
evaluator = PolicyEvaluator(cwm_factory=cwm_factory, scoring_mode="fast")
|
|||
|
|
codec = CMAParameterCodec()
|
|||
|
|
pool = SelfPlayPool()
|
|||
|
|
trainer = CMAESTrainer(codec=codec, evaluator=evaluator, pool=pool, workers=0)
|
|||
|
|
|
|||
|
|
print("Running CMA-ES optimization...")
|
|||
|
|
best = trainer.train(
|
|||
|
|
incumbent=_baseline(),
|
|||
|
|
scenarios=scenarios,
|
|||
|
|
budget_evals=BUDGET_EVALS,
|
|||
|
|
seed=SEED,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
duration = time.time() - t0
|
|||
|
|
|
|||
|
|
print()
|
|||
|
|
print("=" * 70)
|
|||
|
|
print("RESULTS")
|
|||
|
|
print("=" * 70)
|
|||
|
|
print(f"Duration: {duration:.1f}s ({duration/60:.1f} min)")
|
|||
|
|
print(f"Best score: {best.score:.2f}")
|
|||
|
|
print(f"Previous: 15,080 (pre-fee-fix, WRONG fees)")
|
|||
|
|
print(f"Params: {best.params.version}")
|
|||
|
|
if best.evaluation_summary:
|
|||
|
|
print(f"Mean PnL: {best.evaluation_summary.get('mean_pnl', 'N/A'):.2f} bps")
|
|||
|
|
print(f"Max DD: {best.evaluation_summary.get('max_dd', 'N/A'):.2f} bps")
|
|||
|
|
print(f"Evals: {best.evaluation_summary.get('n', 'N/A')}")
|
|||
|
|
print("=" * 70)
|
|||
|
|
|
|||
|
|
os.makedirs("malkhut/results", exist_ok=True)
|
|||
|
|
report = {
|
|||
|
|
"timestamp_s": int(time.time()),
|
|||
|
|
"duration_s": round(duration, 1),
|
|||
|
|
"budget_evals": BUDGET_EVALS,
|
|||
|
|
"seed": SEED,
|
|||
|
|
"symbols": list(SYMBOLS),
|
|||
|
|
"fees": {"taker_bps": 5.0, "maker_bps": 2.0},
|
|||
|
|
"previous_best": 15080,
|
|||
|
|
"best_score": best.score,
|
|||
|
|
"improvement_pct": round((best.score - 15080) / max(abs(15080), 1) * 100, 1),
|
|||
|
|
"evaluation_summary": best.evaluation_summary,
|
|||
|
|
"n_scenarios": len(scenarios),
|
|||
|
|
}
|
|||
|
|
report_path = f"malkhut/results/cma_rerun_{int(time.time())}.json"
|
|||
|
|
with open(report_path, "w") as f:
|
|||
|
|
json.dump(report, f, indent=2)
|
|||
|
|
print(f"\nReport saved: {report_path}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
main()
|