Files
atm-backtesting/tests/test_manual_log.py

176 lines
5.1 KiB
Python

"""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"