from datetime import datetime, timedelta import pandas as pd from app.core.signal_taxonomy import signal_code from app.services.altcoin_confirm import detect_box_breakout_pullback_1h, detect_box_breakout_pullback_4h def _bar(ts, open_, high, low, close, volume): return { "timestamp": ts, "open": open_, "high": high, "low": low, "close": close, "volume": volume, } def _box_breakout_rows(fail=False): start = datetime(2026, 5, 20) rows = [] for i in range(32): base = 1.03 + (i % 5) * 0.006 rows.append(_bar(start + timedelta(hours=4 * i), base, 1.095 + (i % 3) * 0.002, 0.985 - (i % 2) * 0.002, base + 0.004, 1000 + (i % 4) * 30)) rows.append(_bar(start + timedelta(hours=4 * 32), 1.085, 1.16, 1.08, 1.135, 2600)) if fail: rows.append(_bar(start + timedelta(hours=4 * 33), 1.13, 1.135, 1.00, 1.055, 1800)) else: rows.append(_bar(start + timedelta(hours=4 * 33), 1.13, 1.145, 1.092, 1.118, 1600)) for i in range(12): close = (1.04 + i * 0.002) if fail else (1.12 + i * 0.008) rows.append(_bar(start + timedelta(hours=4 * (34 + i)), close - 0.01, close + 0.018, close - 0.025, close, 1300 + i * 40)) return rows def test_detect_box_breakout_pullback_4h_finds_box_top_retest(): df = pd.DataFrame(_box_breakout_rows()) result = detect_box_breakout_pullback_4h(df) assert result["detected"] is True assert result["score"] >= 7 assert result["quality"] in {"良好", "优质"} assert result["entry_zone"] > 1.08 assert result["stop_level"] < result["entry_zone"] assert "箱体" in result["signals"][0] assert signal_code(result["signals"][0]) == "box_breakout_pullback_4h" def test_detect_box_breakout_pullback_4h_rejects_failed_retest(): df = pd.DataFrame(_box_breakout_rows(fail=True)) result = detect_box_breakout_pullback_4h(df) assert result["detected"] is False def test_detect_box_breakout_pullback_1h_finds_early_retest(): start = datetime(2026, 5, 20) rows = [] for i in range(44): base = 1.0 + (i % 4) * 0.003 rows.append(_bar(start + timedelta(hours=i), base, 1.035 + (i % 3) * 0.001, 0.985 - (i % 2) * 0.001, base + 0.002, 1000 + (i % 5) * 20)) rows.append(_bar(start + timedelta(hours=44), 1.032, 1.085, 1.03, 1.068, 2300)) rows.append(_bar(start + timedelta(hours=45), 1.064, 1.073, 1.034, 1.055, 1700)) for i in range(8): close = 1.058 + i * 0.004 rows.append(_bar(start + timedelta(hours=46 + i), close - 0.006, close + 0.012, close - 0.018, close, 1250 + i * 25)) result = detect_box_breakout_pullback_1h(pd.DataFrame(rows)) assert result["detected"] is True assert result["score"] >= 7 assert result["quality"] in {"良好", "优质"} assert signal_code(result["signals"][0]) == "box_breakout_pullback_1h"