100 lines
4.6 KiB
Python
100 lines
4.6 KiB
Python
import os
|
||
import sys
|
||
|
||
PROJECT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
||
if PROJECT_DIR not in sys.path:
|
||
sys.path.insert(0, PROJECT_DIR)
|
||
|
||
import altcoin_db
|
||
|
||
|
||
def test_review_stats_contains_strategy_version_summary_and_changelog(monkeypatch):
|
||
monkeypatch.setattr(altcoin_db, "get_strategy_iteration_logs", lambda limit=30: [
|
||
{
|
||
"id": 1,
|
||
"title": "第2轮复盘迭代",
|
||
"strategy_version": "v1.2",
|
||
"version_change_summary": "v1.2:加入静K蓄力旁路 + 板块联动降级保留",
|
||
"changed_rules": [{"type": "learned_rule", "description": "静K旁路"}],
|
||
"config_diff": {"changed": [{"path": "screener.vp_fly"}], "added": [], "removed": []},
|
||
"effect_summary": {"hit_rate_pct": 50.0, "avg_pnl": 0.79},
|
||
}
|
||
])
|
||
monkeypatch.setattr(altcoin_db, "get_strategy_iteration_summary", lambda days=30: {
|
||
"total_logs": 1,
|
||
"version_stats": [
|
||
{"strategy_version": "v1.2", "recommendation_count": 9, "success_count": 5, "failed_count": 1, "pending_count": 3, "success_rate_pct": 55.6, "avg_pnl_pct": 3.2}
|
||
],
|
||
"version_changelog": [
|
||
{"strategy_version": "v1.2", "title": "第2轮复盘迭代", "summary": "加入旁路", "version_change_summary": "v1.2:加入静K蓄力旁路 + 板块联动降级保留"}
|
||
],
|
||
})
|
||
|
||
class DummyConn:
|
||
def execute(self, sql, params=()):
|
||
class Rows(list):
|
||
def fetchall(self_inner):
|
||
return []
|
||
return Rows()
|
||
def close(self):
|
||
pass
|
||
|
||
monkeypatch.setattr(altcoin_db, "get_conn", lambda: DummyConn())
|
||
|
||
data = altcoin_db.get_review_stats()
|
||
|
||
assert data["iteration_summary"]["version_stats"][0]["strategy_version"] == "v1.2"
|
||
assert "静K蓄力旁路" in data["iteration_summary"]["version_changelog"][0]["version_change_summary"]
|
||
assert data["iteration_logs"][0]["strategy_version"] == "v1.2"
|
||
|
||
|
||
def test_strategy_iteration_summary_aggregates_version_stats(monkeypatch):
|
||
class DummyConn:
|
||
def execute(self, sql, params=()):
|
||
sql_norm = " ".join(sql.split())
|
||
if "FROM strategy_iteration_log" in sql_norm:
|
||
class Rows(list):
|
||
def fetchall(self_inner):
|
||
return [
|
||
{
|
||
"id": 1,
|
||
"created_at": "2026-04-30T00:32:05",
|
||
"run_date": "2026-04-30",
|
||
"title": "第2轮复盘迭代",
|
||
"summary": "继续积累样本",
|
||
"changed_rules_json": "[]",
|
||
"metrics_json": "{}",
|
||
"related_symbols_json": "[]",
|
||
"findings_json": "[]",
|
||
"problems_json": "[]",
|
||
"actions_json": "[]",
|
||
"config_diff_json": '{"changed": [{"path": "meta.last_review"}], "added": [], "removed": []}',
|
||
"effect_summary_json": '{"hit_rate_pct": 50.0, "avg_pnl": 0.79}',
|
||
"strategy_version": "v1.2",
|
||
"version_change_summary": "v1.2:加入静K蓄力旁路 + 板块联动降级保留",
|
||
}
|
||
]
|
||
return Rows()
|
||
if "FROM recommendation" in sql_norm:
|
||
class Rows(list):
|
||
def fetchall(self_inner):
|
||
return [
|
||
{"strategy_version": "v1.2", "status": "hit_tp1", "pnl_pct": 8.0, "max_pnl_pct": 12.0, "max_drawdown_pct": -1.0},
|
||
{"strategy_version": "v1.2", "status": "active", "pnl_pct": 2.0, "max_pnl_pct": 6.0, "max_drawdown_pct": -2.0},
|
||
{"strategy_version": "v1.2", "status": "stopped_out", "pnl_pct": -4.0, "max_pnl_pct": 1.0, "max_drawdown_pct": -6.0},
|
||
]
|
||
return Rows()
|
||
raise AssertionError(sql)
|
||
def close(self):
|
||
pass
|
||
|
||
monkeypatch.setattr(altcoin_db, "get_conn", lambda: DummyConn())
|
||
|
||
summary = altcoin_db.get_strategy_iteration_summary(days=30)
|
||
|
||
assert summary["version_stats"][0]["strategy_version"] == "v1.2"
|
||
assert summary["version_stats"][0]["recommendation_count"] == 3
|
||
assert summary["version_stats"][0]["success_count"] == 2
|
||
assert summary["version_stats"][0]["failed_count"] == 1
|
||
assert summary["version_changelog"][0]["strategy_version"] == "v1.2"
|