Files
QuantEngineByItz/tests/parity/test_score_parity_v1.py
T

130 lines
4.2 KiB
Python

from __future__ import annotations
import sys
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from src.quant_engine.exit_decisions import compute_timing_decision
class TestScoreParityV1(unittest.TestCase):
def test_pullback_wait_is_selected_for_borderline_entry_scores(self):
res = compute_timing_decision(
{
"priceStatus": "PRICE_OK",
"atr20": 100.0,
"entryModeGate": "PASS",
"entryMode": "PULLBACK",
"leaderTotal": 3,
"leaderGate": "PASS",
"flowCredit": 0.4,
"acGate": "CAUTION",
"ma20Slope": 1.0,
"disparity": 4.5,
"rsi14": 68.0,
"avgTradeValue5D": 100.0,
"spreadPct": 0.5,
}
)
self.assertEqual(res["action"], "BUY_PULLBACK_WAIT")
self.assertGreaterEqual(res["entry_score"], 60)
self.assertLess(res["entry_score"], 100)
def test_entry_score_boosts_with_leader_flow_and_clear_gate(self):
res = compute_timing_decision(
{
"priceStatus": "PRICE_OK",
"atr20": 100.0,
"entryModeGate": "PASS",
"entryMode": "BREAKOUT",
"leaderTotal": 4,
"leaderGate": "PASS",
"flowCredit": 0.8,
"acGate": "CLEAR",
"ma20Slope": 1.0,
"disparity": 2.0,
"rsi14": 55.0,
"avgTradeValue5D": 100.0,
"spreadPct": 0.5,
}
)
self.assertEqual(res["action"], "BUY_BREAKOUT_PILOT_ONLY")
self.assertGreaterEqual(res["entry_score"], 75)
self.assertLessEqual(res["exit_score"], 20)
def test_exit_review_is_selected_before_forced_exit_threshold(self):
res = compute_timing_decision(
{
"priceStatus": "PRICE_OK",
"atr20": 100.0,
"entryModeGate": "PASS",
"entryMode": "PULLBACK",
"leaderTotal": 3,
"leaderGate": "PASS",
"flowCredit": 0.6,
"acGate": "CAUTION",
"ma20Slope": -1.0,
"disparity": 8.5,
"rsi14": 70.0,
"avgTradeValue5D": 100.0,
"spreadPct": 0.5,
"rwPartial": 2,
}
)
self.assertEqual(res["action"], "EXIT_REVIEW")
self.assertGreaterEqual(res["exit_score"], 50)
self.assertLess(res["exit_score"], 75)
def test_data_missing_short_circuits_timing_action(self):
res = compute_timing_decision(
{
"priceStatus": "PRICE_OK",
"atr20": None,
"entryModeGate": "PASS",
"entryMode": "BREAKOUT",
"leaderTotal": 4,
"leaderGate": "PASS",
"flowCredit": 0.8,
"acGate": "CLEAR",
"ma20Slope": 1.0,
"disparity": 2.0,
"rsi14": 55.0,
"avgTradeValue5D": 100.0,
"spreadPct": 0.5,
}
)
self.assertEqual(res["action"], "OBSERVE_DATA_MISSING")
def test_exit_score_dominates_with_risk_off_and_time_stop(self):
res = compute_timing_decision(
{
"priceStatus": "PRICE_OK",
"atr20": 100.0,
"entryModeGate": "PASS",
"entryMode": "PULLBACK",
"leaderTotal": 3,
"leaderGate": "PASS",
"flowCredit": 0.6,
"acGate": "BLOCK",
"ma20Slope": -1.0,
"disparity": 13.0,
"rsi14": 80.0,
"avgTradeValue5D": 100.0,
"spreadPct": 0.5,
"rwPartial": 4,
"daysToTimeStop": 3,
"profitPct": 12.0,
}
)
self.assertEqual(res["action"], "STOP_OR_TIME_EXIT_READY")
self.assertGreaterEqual(res["exit_score"], 75)
self.assertGreaterEqual(res["entry_score"], 0)
if __name__ == "__main__":
unittest.main()