"""Tests for scripts.manual_log — derivation logic + vision_schema compatibility.""" from __future__ import annotations import pytest from scripts.manual_log import build_extraction, OUTCOME_TO_BE_MOVED, OUTCOME_TO_MAX_REACHED, ro_to_utc from scripts.vision_schema import M2DExtraction def test_buy_happy_path(): d = build_extraction( data="2026-05-13", ora_ro="17:33", directie="Buy", entry=497.42, sl=496.80, outcome_path="TP0→TP1", ) # Satisfies pydantic M2DExtraction.model_validate(d) assert d["directie"] == "Buy" assert d["entry"] == 497.42 assert d["sl"] == 496.80 # tp0 = entry + 0.4 * 0.62 = 497.42 + 0.248 = 497.668 assert abs(d["tp0"] - 497.668) < 0.01 assert abs(d["tp1"] - 497.792) < 0.01 assert abs(d["tp2"] - 498.04) < 0.01 assert d["max_reached"] == "TP1" assert d["be_moved"] is True def test_sell_happy_path(): d = build_extraction( data="2026-05-13", ora_ro="17:33", directie="Sell", entry=492.47, sl=492.77, outcome_path="TP0→TP1", ) M2DExtraction.model_validate(d) assert d["directie"] == "Sell" # For Sell: tp0 = entry - 0.4 * 0.30 = 492.47 - 0.12 = 492.35 assert abs(d["tp0"] - 492.35) < 0.01 assert abs(d["tp1"] - 492.29) < 0.01 assert abs(d["tp2"] - 492.17) < 0.01 assert d["sl"] > d["entry"] > d["tp0"] > d["tp1"] > d["tp2"] def test_ora_utc_dst_summer(): # May = EEST = UTC+3 d = build_extraction( data="2026-05-13", ora_ro="17:33", directie="Sell", entry=492.47, sl=492.77, outcome_path="pending", ) assert d["ora_utc"] == "14:33" def test_ora_utc_dst_winter(): # January = EET = UTC+2 d = build_extraction( data="2026-01-15", ora_ro="17:00", directie="Buy", entry=400, sl=399, outcome_path="pending", ) assert d["ora_utc"] == "15:00" def test_outcome_sl_max_reached_consistent(): d = build_extraction( data="2026-05-13", ora_ro="17:33", directie="Buy", entry=400, sl=399, outcome_path="SL", ) M2DExtraction.model_validate(d) assert d["max_reached"] == "SL_first" assert d["be_moved"] is False def test_outcome_tp0_pending_max_reached_tp0(): d = build_extraction( data="2026-05-13", ora_ro="17:33", directie="Buy", entry=400, sl=399, outcome_path="TP0→pending", ) M2DExtraction.model_validate(d) assert d["max_reached"] == "TP0" assert d["be_moved"] is True def test_outcome_tp0_sl_be_moved_true(): d = build_extraction( data="2026-05-13", ora_ro="17:33", directie="Buy", entry=400, sl=399, outcome_path="TP0→SL", ) M2DExtraction.model_validate(d) assert d["max_reached"] == "TP0" assert d["be_moved"] is True # rule-enforced def test_explicit_max_reached_override(): d = build_extraction( data="2026-05-13", ora_ro="17:33", directie="Buy", entry=400, sl=399, outcome_path="pending", max_reached="TP0", ) M2DExtraction.model_validate(d) assert d["max_reached"] == "TP0" def test_screenshot_file_generated(): d = build_extraction( data="2026-05-13", ora_ro="17:33", directie="Sell", entry=492.47, sl=492.77, outcome_path="pending", instrument="DIA", ) assert d["screenshot_file"] == "2026-05-13-dia-1733.png" def test_screenshot_file_explicit(): d = build_extraction( data="2026-05-13", ora_ro="17:33", directie="Sell", entry=492.47, sl=492.77, outcome_path="pending", screenshot_file="custom.png", ) assert d["screenshot_file"] == "custom.png" def test_risc_pct_computed(): d = build_extraction( data="2026-05-13", ora_ro="17:33", directie="Sell", entry=500.00, sl=501.00, outcome_path="pending", ) assert abs(d["risc_pct"] - 0.20) < 0.001 # 1/500 = 0.002 = 0.20% def test_entry_equals_sl_raises(): with pytest.raises(ValueError, match="zero risk"): build_extraction( data="2026-05-13", ora_ro="17:33", directie="Buy", entry=500, sl=500, outcome_path="pending", ) def test_buy_inverted_ordering_raises(): with pytest.raises(ValueError, match="Buy"): build_extraction( data="2026-05-13", ora_ro="17:33", directie="Buy", entry=400, sl=401, outcome_path="pending", # sl > entry for Buy ) def test_sell_inverted_ordering_raises(): with pytest.raises(ValueError, match="Sell"): build_extraction( data="2026-05-13", ora_ro="17:33", directie="Sell", entry=400, sl=399, outcome_path="pending", # sl < entry for Sell ) def test_optional_fields_defaults(): d = build_extraction( data="2026-05-13", ora_ro="17:33", directie="Buy", entry=400, sl=399, outcome_path="pending", ) assert d["instrument"] == "DIA" assert d["tf_mare"] == "5min" assert d["tf_mic"] == "1min" assert d["calitate"] == "n/a" assert d["confidence"] == "high" assert d["ambiguities"] == [] assert d["note"] == "" def test_ro_to_utc_helper(): assert ro_to_utc("2026-05-13", "17:33") == "14:33" assert ro_to_utc("2026-01-15", "10:00") == "08:00"