alphax/tests/test_strategy_revision_marker.py
2026-05-13 22:32:50 +08:00

145 lines
4.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import sys
from datetime import datetime, timedelta
import pytest
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
import review_engine
import config_loader
@pytest.fixture
def temp_db_and_rules(monkeypatch, tmp_path):
db_path = tmp_path / "altcoin_monitor.db"
rules_path = tmp_path / "rules.yaml"
monkeypatch.setattr(altcoin_db, "DB_PATH", str(db_path))
monkeypatch.setattr(config_loader, "RULES_PATH", str(rules_path))
monkeypatch.setattr(review_engine, "get_conn", altcoin_db.get_conn)
config_loader._cache = None
config_loader._cache_mtime = None
rules_path.write_text(
"""
strategy:
mode: long_only
direction: 多头启动
allow_short: false
screener: {}
confirm: {}
tracker: {}
signal_weights: {}
review:
hit_threshold_pct: 5.0
fail_threshold_pct: -3.0
missed_explosion_pct: 20.0
reverse_analysis: {}
learned_rules: []
meta:
version: 1
strategy_version: v_next
strategy_revision_started_at: '2026-04-30T10:00:00'
strategy_revision_note: '静K蓄力改版开始'
""".strip(),
encoding="utf-8",
)
altcoin_db.init_db()
return db_path, rules_path
def _insert_recommendation(conn, rec_id, symbol, rec_time):
conn.execute(
"""
INSERT INTO recommendation (
id, symbol, rec_time, rec_state, rec_score, entry_price,
stop_loss, tp1, tp2, sector, signals, is_meme, status,
current_price, max_price, min_price, pnl_pct, max_pnl_pct,
max_drawdown_pct, hit_tp1_time, hit_tp2_time, stopped_out_time,
expired_time, last_track_time, entry_plan_json, action_status, direction
) VALUES (?, ?, ?, '加速', 8, 1.0, 0, 0, 0, '', '[]', 0, 'active', 1.0, 1.0, 1.0, 0, 0, 0, '', '', '', '', ?, '{}', '持有', '多头启动')
""",
(rec_id, symbol, rec_time, rec_time),
)
def _insert_review(conn, rec_id, symbol, review_time, outcome, pnl_48h):
conn.execute(
"""
INSERT INTO review_log (
rec_id, symbol, review_time, outcome, pnl_48h, max_pnl_48h,
triggered_signals, hit_signals, miss_signals, lesson
) VALUES (?, ?, ?, ?, ?, ?, '[]', '[]', '[]', '')
""",
(rec_id, symbol, review_time, outcome, pnl_48h, pnl_48h),
)
def _insert_missed(conn, symbol, detect_time, gain_pct):
conn.execute(
"""
INSERT INTO missed_explosions (
symbol, detect_time, price_at_detect, price_before, gain_pct,
reason_missed, features_detected, lesson
) VALUES (?, ?, 1.0, 0.8, ?, '粗筛未过', '[]', '')
""",
(symbol, detect_time, gain_pct),
)
def test_revision_marker_filters_effect_summary(temp_db_and_rules):
conn = altcoin_db.get_conn()
_insert_recommendation(conn, 1, 'OLD/USDT', '2026-04-29T09:00:00')
_insert_recommendation(conn, 2, 'NEW/USDT', '2026-04-30T11:00:00')
_insert_review(conn, 1, 'OLD/USDT', '2026-04-29T12:00:00', '失败', -6.0)
_insert_review(conn, 2, 'NEW/USDT', '2026-04-30T12:00:00', '爆发', 12.0)
conn.commit()
conn.close()
now = datetime.fromisoformat('2026-04-30T13:00:00')
summary = review_engine._compute_effect_summary(now, lookback_days=7)
assert summary['review_count_window'] == 1
assert summary['hit_rate_pct'] == 100.0
assert summary['fail_rate_pct'] == 0.0
assert summary['avg_pnl'] == 12.0
def test_revision_marker_filters_reviewable_recommendations(temp_db_and_rules):
conn = altcoin_db.get_conn()
_insert_recommendation(conn, 1, 'OLD/USDT', '2026-04-29T09:00:00')
_insert_recommendation(conn, 2, 'NEW/USDT', '2026-04-30T11:00:00')
conn.commit()
conn.close()
reviewable = review_engine._get_reviewable_recommendations(datetime.fromisoformat('2026-05-01T13:00:00'))
symbols = [row['symbol'] for row in reviewable]
assert symbols == ['NEW/USDT']
def test_revision_marker_filters_review_stats_and_missed_explosions(temp_db_and_rules):
conn = altcoin_db.get_conn()
_insert_review(conn, 1, 'OLD/USDT', '2026-04-29T12:00:00', '失败', -6.0)
_insert_review(conn, 2, 'NEW/USDT', '2026-04-30T12:00:00', '爆发', 12.0)
_insert_missed(conn, 'OLDMISS/USDT', '2026-04-29T15:00:00', 35.0)
_insert_missed(conn, 'NEWMISS/USDT', '2026-04-30T15:00:00', 28.0)
conn.commit()
conn.close()
stats = altcoin_db.get_review_stats()
review_symbols = [item['symbol'] for item in stats['reviews']]
missed_symbols = [item['symbol'] for item in stats['missed_explosions']]
# get_review_stats() 不再按 revision_started_at 过滤 review_log
# 页面展示需要累积全部复盘数据。revision marker 的过滤只在
# review_engine._get_reviewable_recommendations() 中生效。
assert set(review_symbols) == {'NEW/USDT', 'OLD/USDT'}
assert set(missed_symbols) == {'NEWMISS/USDT', 'OLDMISS/USDT'}