123 lines
4.9 KiB
Python
123 lines
4.9 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import builtins
|
||
|
|
|
||
|
|
import numpy as np
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from gpu_feature_parity_contract_v1_1 import deterministic_adversarial_ohlcv
|
||
|
|
from gpu_feature_parity_contract_v1_2 import (
|
||
|
|
ARTIFACT,
|
||
|
|
CALIBRATION_ARTIFACT,
|
||
|
|
ROLE_C_UNVERIFIABLE,
|
||
|
|
UNVERIFIABLE,
|
||
|
|
calibrate_supertrend,
|
||
|
|
calibrate_output,
|
||
|
|
cpu_supertrend_trace,
|
||
|
|
freeze_contract,
|
||
|
|
role_surface,
|
||
|
|
validate_all_frozen_contract,
|
||
|
|
validate_frozen_contract,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def _traces():
|
||
|
|
ohlcv = deterministic_adversarial_ohlcv(length=96, seed=19)
|
||
|
|
expected = cpu_supertrend_trace(ohlcv["close"], ohlcv["high"], ohlcv["low"], 8, 3.0)
|
||
|
|
actual = {name: value.copy() for name, value in expected.items()}
|
||
|
|
return expected, actual
|
||
|
|
|
||
|
|
|
||
|
|
def test_ordered_on_device_seed_matches_historical_left_to_right_seed():
|
||
|
|
torch = pytest.importorskip("torch")
|
||
|
|
from gpu_feature_engine_v1_2 import rma_ordered_seed
|
||
|
|
|
||
|
|
values = torch.tensor([1e16, 1.0, -1e16, 3.0], dtype=torch.float64)
|
||
|
|
result = rma_ordered_seed(values, 4)
|
||
|
|
total = 0.0
|
||
|
|
for value in values.numpy():
|
||
|
|
total += value
|
||
|
|
assert result[-1].item() == total / 4
|
||
|
|
|
||
|
|
|
||
|
|
def test_v1_2_requires_exact_branch_state_before_atr_bounds():
|
||
|
|
expected, actual = _traces()
|
||
|
|
calibration = {"artifact": CALIBRATION_ARTIFACT, "records": [calibrate_supertrend("super", expected, actual)]}
|
||
|
|
contract = freeze_contract(calibration)
|
||
|
|
assert contract["artifact"] == ARTIFACT
|
||
|
|
assert validate_frozen_contract(contract, {"super": (expected, actual)})["passed"]
|
||
|
|
changed = dict(actual)
|
||
|
|
changed["active_long"] = actual["active_long"].copy()
|
||
|
|
changed["active_long"][-1] = ~changed["active_long"][-1]
|
||
|
|
result = validate_frozen_contract(contract, {"super": (expected, changed)})
|
||
|
|
assert not result["passed"]
|
||
|
|
assert result["records"][0]["atr"] is None
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize("mutation", ["shape", "nan_mask"])
|
||
|
|
def test_v1_2_requires_atr_structure_before_measuring_bounds(mutation):
|
||
|
|
expected, actual = _traces()
|
||
|
|
calibration = {"artifact": CALIBRATION_ARTIFACT, "records": [calibrate_supertrend("super", expected, actual)]}
|
||
|
|
contract = freeze_contract(calibration)
|
||
|
|
changed = dict(actual)
|
||
|
|
changed["atr"] = actual["atr"][:-1].copy() if mutation == "shape" else actual["atr"].copy()
|
||
|
|
if mutation == "nan_mask":
|
||
|
|
changed["atr"][-1] = np.nan
|
||
|
|
result = validate_frozen_contract(contract, {"super": (expected, changed)})
|
||
|
|
assert not result["passed"]
|
||
|
|
assert result["records"][0]["atr"] is None
|
||
|
|
assert not result["records"][0]["trace"]["atr_structure_exact"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_unrecorded_batch01_roles_are_unverifiable_and_not_parity_blockers():
|
||
|
|
surface = role_surface([
|
||
|
|
{"request_id": "known", "indicator_id": 19, "period": 10, "p1": 2.0},
|
||
|
|
{"request_id": "unknown", "indicator_id": 17, "period": 999, "p1": 2.0},
|
||
|
|
])
|
||
|
|
unknown = next(item for item in surface["records"] if item["request_id"] == "unknown")
|
||
|
|
assert unknown["classification"] == ROLE_C_UNVERIFIABLE
|
||
|
|
assert unknown["role_status"] == UNVERIFIABLE
|
||
|
|
assert not unknown["parity_blocker"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_role_surface_is_unverifiable_when_recovered_registry_is_absent(monkeypatch):
|
||
|
|
original_import = builtins.__import__
|
||
|
|
|
||
|
|
def missing_registry(name, *args, **kwargs):
|
||
|
|
if name == "control_plane.trading_studio.indicators.registry":
|
||
|
|
raise ModuleNotFoundError(name)
|
||
|
|
return original_import(name, *args, **kwargs)
|
||
|
|
|
||
|
|
monkeypatch.setattr(builtins, "__import__", missing_registry)
|
||
|
|
surface = role_surface([{"request_id": "known", "indicator_id": 19, "period": 10, "p1": 2.0}])
|
||
|
|
|
||
|
|
record = surface["records"][0]
|
||
|
|
assert record["role_status"] == UNVERIFIABLE
|
||
|
|
assert record["reason"] == "control_plane.trading_studio.indicators.registry is unavailable"
|
||
|
|
assert not record["parity_blocker"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_full_batch_contract_keeps_exact_and_calibration_bounded_classes_separate():
|
||
|
|
expected, actual = _traces()
|
||
|
|
values = np.array([np.nan, 2.0, 3.0])
|
||
|
|
calibration = {
|
||
|
|
"artifact": CALIBRATION_ARTIFACT,
|
||
|
|
"records": [
|
||
|
|
calibrate_supertrend("super", expected, actual, atr_limits={"max_absolute_error": 0.0, "mae": 0.0}),
|
||
|
|
calibrate_output("donch", 20, values, values.copy()),
|
||
|
|
calibrate_output("psar", 28, values, values.copy()),
|
||
|
|
calibrate_output("bb", 17, values, values.copy()),
|
||
|
|
calibrate_output("kc", 23, values, values.copy()),
|
||
|
|
],
|
||
|
|
}
|
||
|
|
contract = freeze_contract(calibration)
|
||
|
|
result = validate_all_frozen_contract(
|
||
|
|
contract,
|
||
|
|
{"super": expected["output"], "donch": values, "psar": values, "bb": values, "kc": values},
|
||
|
|
{"super": actual["output"], "donch": values.copy(), "psar": values.copy(), "bb": values.copy(), "kc": values.copy()},
|
||
|
|
{"super": (expected, actual)},
|
||
|
|
)
|
||
|
|
assert result["passed"]
|
||
|
|
assert contract["feature_limits"]["donch"]["role"] == "A_EXACT"
|
||
|
|
assert contract["feature_limits"]["bb"]["role"] == "B_BOUNDED"
|