Artifex/control_plane/trading_studio/indicators/batch01_native_parity.py
2026-08-18 02:00:53 +07:00

307 lines
13 KiB
Python

"""Offline exact-parity gate for the frozen Batch01 band/channel oracle."""
from __future__ import annotations
import csv
import hashlib
import json
from pathlib import Path
from typing import Any
import numpy as np
from .historical_band_channel import OBSERVED_BAND_CHANNEL_PARAMS, evaluate_band_channel
from .parity_harness_v1 import (
ComparisonRecord,
FeatureVersion,
ParityStatus,
compare_array,
compare_float64_ulp,
recompute_coverage,
)
ROOT = Path(__file__).resolve().parents[3]
BATCH01_REQUEST = ROOT / "batch01_oracle_request.json"
BATCH01_RESULT = ROOT / "batch01_oracle_result.json"
BATCH01_OUTPUTS = ROOT / "batch01_oracle_outputs.npz"
CANONICAL_CSV = ROOT / "hs22_oracle_v1" / "binance_btcusdt_spot_2m_180d.csv"
BOLLINGER_RESOLUTION = ROOT / "batch01_bollinger_parity_resolution_v1.json"
BOLLINGER_ROOT_REPORT = ROOT / "batch01_native_mismatch_report.json"
_DIGESTS = {
"batch01_oracle_request.json": (
"7ca0c8578dd81c3ae60898d83e6e73f9bf8889a39a873b451c7cdaf036cbaf24"
),
"batch01_oracle_result.json": (
"7c1d5dbdcb183aa2d872baa45c4d02fe2d59cccabe9022f8797237b3776c8e96"
),
"batch01_oracle_outputs.npz": (
"e1f2268b634e50eb65b9b5175ea369e52bf0a2039b18049030849948a45fd149"
),
"hs22_oracle_v1/binance_btcusdt_spot_2m_180d.csv": (
"7fb56bb05b0edc2348407765cd693efadf334307c25877dfb52acfe4221e5d00"
),
}
class FrozenBatch01ArtifactError(ValueError):
"""Raised when a parity input is not the pinned local oracle artifact."""
def _digest(path: Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
def _canonical_bytes(value: object) -> bytes:
return json.dumps(value, sort_keys=True, separators=(",", ":"), allow_nan=False).encode("utf-8")
def _array_digest(values: np.ndarray) -> str:
values = np.ascontiguousarray(values)
header = _canonical_bytes({"dtype": values.dtype.str, "shape": values.shape})
return hashlib.sha256(header + b"\0" + values.tobytes()).hexdigest()
def batch01_native_parity_manifest() -> dict[str, object]:
"""Return the reproducible exact-comparison contract for all 97 variants."""
return {
"schema_version": 1,
"artifact": "BATCH01_NATIVE_PARITY_MANIFEST_V1",
"engine_revision": "code-5056feb",
"frozen_inputs": {
name: {"path": name, "sha256": digest} for name, digest in _DIGESTS.items()
},
"input_columns": ["close", "high", "low", "volume"],
"variant_count": 97,
"comparison": {"dtype": "exact", "shape": "exact", "nan_mask": "exact", "values": "exact"},
"documented_exception": {
"path": BOLLINGER_RESOLUTION.name,
"scope": "float64 one-ULP cases listed for indicator IDs 17 and 18 only",
"global_tolerance": "forbidden",
},
"derived_state_transitions": {
"indicator_ids": [19, 28],
"state": "1 when close is greater than output, otherwise -1; warmup NaN is 0",
"transitions": "state differs from the preceding bar",
},
}
def batch01_native_parity_manifest_bytes() -> bytes:
return _canonical_bytes(batch01_native_parity_manifest()) + b"\n"
def write_batch01_native_parity_manifest(path: Path) -> None:
path.write_bytes(batch01_native_parity_manifest_bytes())
def _require_frozen_artifacts() -> tuple[dict[str, Any], dict[str, Any]]:
paths = {
"batch01_oracle_request.json": BATCH01_REQUEST,
"batch01_oracle_result.json": BATCH01_RESULT,
"batch01_oracle_outputs.npz": BATCH01_OUTPUTS,
"hs22_oracle_v1/binance_btcusdt_spot_2m_180d.csv": CANONICAL_CSV,
}
for name, path in paths.items():
if _digest(path) != _DIGESTS[name]:
raise FrozenBatch01ArtifactError(f"{name} digest does not match the frozen artifact")
request = json.loads(BATCH01_REQUEST.read_text(encoding="utf-8"))
result = json.loads(BATCH01_RESULT.read_text(encoding="utf-8"))
if request.get("artifact") != "HISTORICAL_FEATURE_ORACLE_V1_REQUEST":
raise FrozenBatch01ArtifactError("invalid Batch01 request artifact")
if result.get("artifact") != "HISTORICAL_FEATURE_ORACLE_V1_RESULT":
raise FrozenBatch01ArtifactError("invalid Batch01 result artifact")
if result.get("request_sha256") != _DIGESTS["batch01_oracle_request.json"]:
raise FrozenBatch01ArtifactError("result is not linked to the frozen request")
csv_digest = _DIGESTS["hs22_oracle_v1/binance_btcusdt_spot_2m_180d.csv"]
if result.get("input_csv_sha256") != csv_digest:
raise FrozenBatch01ArtifactError("result is not linked to the canonical CSV")
if result.get("outputs_npz", {}).get("sha256") != _DIGESTS["batch01_oracle_outputs.npz"]:
raise FrozenBatch01ArtifactError("result is not linked to the frozen NPZ")
return request, result
def _bollinger_resolution() -> dict[str, tuple[dict[str, Any], ...]]:
resolution = json.loads(BOLLINGER_RESOLUTION.read_text(encoding="utf-8"))
report = json.loads(BOLLINGER_ROOT_REPORT.read_text(encoding="utf-8"))
source = resolution.get("source_report", {})
exception = resolution.get("exception", {})
if (
resolution.get("artifact") != "BATCH01_BOLLINGER_PARITY_RESOLUTION_V1"
or resolution.get("schema_version") != 1
or source.get("artifact") != report.get("artifact")
or source.get("classification") != report.get("classification")
or source.get("failed_value_count") != report.get("failed_value_count")
or exception != {
"indicator_ids": [17, 18],
"dtype": "float64",
"max_ulps": 1,
"unlisted_mismatch_policy": "fail",
"all_other_indicators_policy": "exact",
"shape_policy": "exact",
"nan_mask_policy": "exact",
}
):
raise FrozenBatch01ArtifactError("invalid Bollinger parity resolution")
report_cases = {
(item["request_id"], int(detail["index"])): {
"indicator_id": item["indicator_id"],
"signed_ulp": detail["ulp"]["signed"],
"threshold_sensitivity": {
key: detail["threshold_sensitivity"][key]
for key in (
"oracle_close_above_band",
"native_close_above_band",
"decision_changed",
"close_to_oracle_band_ulps",
"close_to_native_band_ulps",
)
},
}
for item in report["variants"]
for detail in item["mismatches"]
}
accepted = resolution.get("accepted_cases")
if not isinstance(accepted, list) or len(accepted) != 8:
raise FrozenBatch01ArtifactError("resolution must list all eight accepted cases")
resolution_cases = {
(item["request_id"], int(item["index"])): {
"indicator_id": item["indicator_id"],
"signed_ulp": item["signed_ulp"],
"threshold_sensitivity": item["threshold_sensitivity"],
}
for item in accepted
}
if resolution_cases != report_cases or any(
int(item["indicator_id"]) not in {17, 18}
or item["threshold_sensitivity"]["decision_changed"]
for item in accepted
):
raise FrozenBatch01ArtifactError("resolution does not match the root-cause evidence")
grouped: dict[str, list[dict[str, Any]]] = {}
for item in accepted:
grouped.setdefault(item["request_id"], []).append(item)
return {request_id: tuple(cases) for request_id, cases in grouped.items()}
def _load_ohlcv() -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
with CANONICAL_CSV.open(newline="", encoding="utf-8") as handle:
rows = list(csv.DictReader(handle))
return tuple(
np.asarray([float(row[name]) for row in rows], dtype=np.float64)
for name in ("close", "high", "low", "volume")
) # type: ignore[return-value]
def _state_and_transitions(close: np.ndarray, output: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
state = np.zeros(output.shape, dtype=np.int8)
valid = ~np.isnan(output)
state[valid] = np.where(close[valid] > output[valid], 1, -1)
transitions = np.zeros(output.shape, dtype=np.bool_)
transitions[1:] = state[1:] != state[:-1]
return state, transitions
def _record_artifact(record: ComparisonRecord) -> dict[str, object]:
return record.artifact()
def batch01_native_acceptance_manifest(report: dict[str, object]) -> dict[str, object]:
"""Summarize the resolved Batch01 gate and recompute its submitted coverage."""
variants = [item for item in report["records"] if ":" not in item["name"]]
feature_versions = [
FeatureVersion(
feature_version=item["name"],
primitive_key=item["name"],
engineering_family="band_channel",
usage_slots=1,
status=ParityStatus(item["status"]),
)
for item in variants
]
accepted = [
item for item in variants if item["reason"] == "accepted_documented_float64_ulp_drift"
]
return {
"schema_version": 1,
"artifact": "BATCH01_NATIVE_ACCEPTANCE_MANIFEST_V1",
"parity_manifest": batch01_native_parity_manifest(),
"status": "accepted" if report["passed"] else "rejected",
"accepted_documented_ulp_variant_count": len(accepted),
"accepted_documented_ulp_value_count": sum(item["value_mismatches"] for item in accepted),
"coverage": recompute_coverage(feature_versions),
}
def write_batch01_native_acceptance_manifest(path: Path) -> None:
report = evaluate_batch01_native_parity()
path.write_bytes(_canonical_bytes(batch01_native_acceptance_manifest(report)) + b"\n")
def evaluate_batch01_native_parity() -> dict[str, object]:
"""Evaluate native Batch01 functions against the immutable oracle NPZ exactly."""
request, result = _require_frozen_artifacts()
accepted_cases = _bollinger_resolution()
requests = request["requests"]
result_requests = {item["request_id"]: item for item in result["requests"]}
requested_params = {
(int(item["indicator_id"]), int(item["period"]), float(item["p1"])) for item in requests
}
if requested_params != OBSERVED_BAND_CHANNEL_PARAMS or len(requests) != 97:
raise FrozenBatch01ArtifactError("request variants do not match the Batch01 native surface")
if set(result_requests) != {item["request_id"] for item in requests}:
raise FrozenBatch01ArtifactError("result request records do not match the frozen request")
close, high, low, volume = _load_ohlcv()
records: list[ComparisonRecord] = []
with np.load(BATCH01_OUTPUTS) as expected_outputs:
if set(expected_outputs.files) != set(result_requests):
raise FrozenBatch01ArtifactError("NPZ output keys do not match result request records")
for item in requests:
request_id = item["request_id"]
expected = expected_outputs[request_id]
metadata = result_requests[request_id]
if expected.dtype.str != metadata["dtype"] or list(expected.shape) != metadata["shape"]:
raise FrozenBatch01ArtifactError(f"NPZ metadata mismatch for {request_id}")
if _array_digest(expected) != metadata["sha256"]:
raise FrozenBatch01ArtifactError(f"NPZ value digest mismatch for {request_id}")
actual = evaluate_band_channel(
int(item["indicator_id"]),
close,
high,
low,
volume,
int(item["period"]),
float(item["p1"]),
)
indicator_id = int(item["indicator_id"])
cases = accepted_cases.get(request_id, ())
records.append(
compare_float64_ulp(
request_id,
expected,
actual,
max_ulps=1,
allowed_indexes=frozenset(int(case["index"]) for case in cases),
)
if indicator_id in {17, 18}
else compare_array(request_id, expected, actual)
)
if indicator_id in {19, 28}:
expected_state, expected_transitions = _state_and_transitions(close, expected)
actual_state, actual_transitions = _state_and_transitions(close, actual)
records.append(compare_array(f"{request_id}:state", expected_state, actual_state))
records.append(
compare_array(
f"{request_id}:transitions", expected_transitions, actual_transitions
)
)
failures = [record for record in records if not record.passed]
report = {
"manifest": batch01_native_parity_manifest(),
"records": [_record_artifact(record) for record in records],
"passed": not failures,
"failure_count": len(failures),
"failures": [_record_artifact(record) for record in failures],
}
report["acceptance_manifest"] = batch01_native_acceptance_manifest(report)
return report