alphax/tests/test_opportunity_lifecycle.py
2026-05-18 00:58:19 +08:00

173 lines
6.2 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 json
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
from app.core.opportunity_lifecycle import apply_entry_quality_gate
from app.services.price_tracker import reconcile_buy_signals_after_gate
from legacy import price_tracker_ws
def test_risk_reward_false_blocks_buy_now():
action, plan, reasons = apply_entry_quality_gate(
action_status='可即刻买入',
entry_plan={
'entry_action': '等回踩',
'entry_price': 0.072,
'current_price': 0.0758,
'risk_reward_ok': False,
'rr1': 0.4,
},
signals=['1H 起爆点↑(强度56×)', '⚠️ 等回踩降权(-3分)'],
current_price=0.0758,
market_context={'change_24h': 9.0},
)
assert action in ('等回踩', '观察')
assert action != '可即刻买入'
assert plan['entry_quality_gate']['blocked_action'] == '可即刻买入'
assert any('risk_reward_ok=false' in r for r in reasons)
def test_buy_now_with_bad_rr_sets_real_pullback_price():
action, plan, reasons = apply_entry_quality_gate(
action_status='可即刻买入',
entry_plan={
'entry_action': '即刻买入',
'entry_price': 0.11455,
'current_price': 0.11455,
'stop_loss': 0.107457,
'tp1': 0.120089,
'risk_reward_ok': False,
'rr1': 0.83,
},
signals=['🟢 15min即刻入场信号', '日线 站稳突破位+19.2%'],
current_price=0.11455,
market_context={'change_24h': 3.1},
)
assert action == '等回踩'
assert plan['entry_price'] < 0.11455
assert round(plan['entry_price'], 6) == 0.113199
assert plan['rr_target_entry'] == plan['entry_price']
assert any('现价不买' in r for r in reasons)
def test_buy_now_requires_current_trigger_and_no_bearish_flow_risk():
action, plan, reasons = apply_entry_quality_gate(
action_status='可即刻买入',
entry_plan={
'entry_action': '即刻买入',
'entry_price': 1.0,
'current_price': 1.0,
'stop_loss': 0.95,
'tp1': 1.12,
'risk_reward_ok': True,
'rr1': 2.4,
},
signals=['1H历史起爆点已过期(12根前)', '⚠️ 1H连续3K空头加速'],
current_price=1.0,
market_context={'change_24h': 2.0},
)
assert action != '可即刻买入'
assert any('缺少当前15min触发' in r for r in reasons)
assert any('空头加速' in r for r in reasons)
def test_structure_watch_pullback_touch_does_not_upgrade_to_buy_now():
action, plan, reasons = apply_entry_quality_gate(
action_status='等回踩',
entry_plan={
'entry_action': '等回踩',
'entry_price': 9.74,
'current_price': 9.74,
'stop_loss': 9.253,
'tp1': 10.5192,
'risk_reward_ok': True,
'rr1': 1.6,
'opportunity_level': 'structure_watch',
'opportunity_level_label': '结构观察',
'max_action': 'wait_pullback',
},
signals=['1H放量(4.4x)但无量价齐飞(量价背离)', '🟢 15min即刻入场信号'],
current_price=9.74,
market_context={'change_24h': 0.3},
)
assert action == '等回踩'
assert action != '可即刻买入'
assert any('不能因到价直接升级' in r for r in reasons)
def test_tracker_gate_downgrade_removes_provisional_buy_signal():
signals = reconcile_buy_signals_after_gate(
[
'🟢 回踩确认完毕!可即刻入场(15min动K确认)',
'其他背景信号',
],
'等回踩',
{'rr_target_entry': 0.11322245, 'entry_price': 0.11322245},
['rr1=0.82 < 1.2,禁止现价买入', '现价不买等回落到0.11322245附近再评估'],
)
assert all('可即刻入场' not in signal for signal in signals)
assert all('回踩确认完毕' not in signal for signal in signals)
assert any('现价不买' in signal and '$0.1132' in signal for signal in signals)
def test_breakout_distance_over_60_forces_observe():
action, plan, reasons = apply_entry_quality_gate(
action_status='可即刻买入',
entry_plan={'entry_action': '即刻买入', 'risk_reward_ok': True, 'rr1': 2.0, 'entry_price': 0.164},
signals=['日线站稳突破位 +66.7%', '日线站稳突破位 +71.7%'],
current_price=0.168,
market_context={'change_24h': 5.0},
)
assert action == '观察'
assert plan['entry_quality_gate']['breakout_distance_pct'] == 71.7
assert any('严禁现价追' in r for r in reasons)
def test_low_static_accumulation_builds_ambush_plan():
action, plan, reasons = apply_entry_quality_gate(
action_status='等回踩',
entry_plan={'entry_action': '等回踩', 'entry_price': 2.393, 'risk_reward_ok': True, 'rr1': 1.6, 'support': 2.2, 'resistance': 3.0},
signals=['4H静K蓄力观察(3静K,量比1.4x)', '大户偏多 62%'],
current_price=2.393,
market_context={'change_24h': 3.0},
derivatives_context={'top_trader_long_pct': 62},
)
assert action == '等回踩'
lifecycle = plan.get('opportunity_lifecycle')
assert lifecycle['stage'] == '低位潜伏'
assert lifecycle['plan_type'] == 'ambush'
assert lifecycle['static_count'] >= 3
def test_ws_tracker_does_not_push_when_gate_downgrades_buy_now():
rec = {
'id': 1,
'symbol': 'WLFI/USDT',
'status': 'active',
'entry_price': 0.0758,
'stop_loss': 0.070,
'tp1': 0.080,
'tp2': 0.085,
'entry_plan': {
'entry_action': '等回踩',
'entry_price': 0.072,
'risk_reward_ok': False,
'rr1': 0.4,
},
'signals': json.dumps(['1H 起爆点↑(强度56×)', '⚠️ 等回踩降权(-3分)'], ensure_ascii=False),
'market_context': {'change_24h': 9.0},
'derivatives_context': {},
'sector_context': {},
'action_status': '持有',
}
trigger = price_tracker_ws.check_triggers('WLFI/USDT', rec, 0.0719)
assert trigger is not None
assert trigger['action_status'] != '可即刻买入'
assert trigger['pushable'] is False