80 lines
3.6 KiB
Python
80 lines
3.6 KiB
Python
from datetime import datetime, timezone
|
|
import os
|
|
import unittest
|
|
|
|
os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://user:pass@localhost:5432/ai_ict_test")
|
|
|
|
from src.services.trust import ModelTrustService
|
|
from src.services.trust.model_trust_service import build_model_buckets
|
|
|
|
|
|
class ModelTrustServiceTests(unittest.TestCase):
|
|
def test_build_summary_classifies_models(self) -> None:
|
|
service = ModelTrustService(
|
|
backtest_repository=_BacktestRepo(
|
|
[
|
|
{
|
|
"model_code": "OSOK",
|
|
"candidate_model_code": "OSOK",
|
|
"summary": {
|
|
"quality_gate": {"passed": True},
|
|
"executed_expectancy_r": 0.6,
|
|
"session_performance": {
|
|
"LONDON": {"executed_expectancy_r": 0.8, "framework_execution_rate": 0.9, "risk_violation_count": 0}
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"model_code": "REAL_TRADE_IMPORT",
|
|
"candidate_model_code": "REAL_TRADE_IMPORT",
|
|
"summary": {"quality_gate": {"passed": False}, "executed_expectancy_r": -0.2},
|
|
},
|
|
]
|
|
),
|
|
journal_repository=_JournalRepo(
|
|
[
|
|
{"model_code": "OSOK", "framework_execution": True, "out_of_model_trade": False, "risk_violation": False, "real_trade_detected": True},
|
|
{"model_code": "OSOK", "framework_execution": True, "out_of_model_trade": False, "risk_violation": False, "real_trade_detected": True},
|
|
{"model_code": "OSOK", "framework_execution": True, "out_of_model_trade": False, "risk_violation": False, "real_trade_detected": True},
|
|
{"model_code": "OSOK", "framework_execution": True, "out_of_model_trade": False, "risk_violation": False, "real_trade_detected": True},
|
|
{"model_code": "OSOK", "framework_execution": False, "out_of_model_trade": False, "risk_violation": False, "real_trade_detected": True},
|
|
{"model_code": "REAL_TRADE_IMPORT", "framework_execution": False, "out_of_model_trade": True, "risk_violation": True, "real_trade_detected": True},
|
|
]
|
|
),
|
|
)
|
|
|
|
payload = service.build_summary(instrument_id=1)
|
|
|
|
self.assertIn("OSOK", payload["whitelist"])
|
|
self.assertIn("REAL_TRADE_IMPORT", payload["blacklist"])
|
|
self.assertTrue(payload["models"][0]["score"] >= payload["models"][1]["score"])
|
|
|
|
def test_build_model_buckets_creates_observe_bucket_when_samples_are_small(self) -> None:
|
|
buckets = build_model_buckets(
|
|
backtest_runs=[{"model_code": "OSOK", "candidate_model_code": "OSOK", "summary": {"quality_gate": {"passed": True}, "executed_expectancy_r": 0.2}}],
|
|
journal_entries=[{"model_code": "OSOK", "framework_execution": True, "out_of_model_trade": False, "risk_violation": False, "real_trade_detected": False}],
|
|
)
|
|
|
|
self.assertEqual(buckets["OSOK"].classification, "observe")
|
|
self.assertIn("sample_size_small", buckets["OSOK"].reasons)
|
|
|
|
|
|
class _BacktestRepo:
|
|
def __init__(self, rows):
|
|
self.rows = rows
|
|
|
|
def fetch_recent_backtest_run_rows(self, instrument_id: int, limit: int = 20):
|
|
return list(self.rows)
|
|
|
|
|
|
class _JournalRepo:
|
|
def __init__(self, rows):
|
|
self.rows = rows
|
|
|
|
def fetch_weekly_journal_entries(self, **kwargs):
|
|
return list(self.rows)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|