Harden trading, training, and monitoring
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
@@ -11,19 +12,25 @@ def main() -> None:
|
||||
args = _parse_args()
|
||||
current = _read_json(args.current_report)
|
||||
candidate = _read_json(args.candidate_report)
|
||||
decision = _decision(
|
||||
current,
|
||||
candidate,
|
||||
min_trades=args.min_trades,
|
||||
min_profit_factor=args.min_profit_factor,
|
||||
min_avg_net_percent=args.min_avg_net_percent,
|
||||
max_score_regression=args.max_score_regression,
|
||||
)
|
||||
candidate_artifact = Path(args.candidate_artifact)
|
||||
candidate_sha256 = _sha256(candidate_artifact)
|
||||
if candidate.get("artifact_sha256") != candidate_sha256:
|
||||
decision = {"accepted": False, "reason": "candidate_report_artifact_hash_mismatch"}
|
||||
else:
|
||||
decision = _decision(
|
||||
current,
|
||||
candidate,
|
||||
min_trades=args.min_trades,
|
||||
min_profit_factor=args.min_profit_factor,
|
||||
min_avg_net_percent=args.min_avg_net_percent,
|
||||
max_score_regression=args.max_score_regression,
|
||||
)
|
||||
payload = {
|
||||
"accepted": decision["accepted"],
|
||||
"reason": decision["reason"],
|
||||
"current": _summary(current),
|
||||
"candidate": _summary(candidate),
|
||||
"candidate_artifact_sha256": candidate_sha256,
|
||||
}
|
||||
if args.report:
|
||||
Path(args.report).write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
@@ -31,7 +38,6 @@ def main() -> None:
|
||||
if not decision["accepted"]:
|
||||
raise SystemExit(2)
|
||||
target = Path(args.target_artifact)
|
||||
candidate_artifact = Path(args.candidate_artifact)
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(candidate_artifact, target)
|
||||
|
||||
@@ -83,6 +89,8 @@ def _validation_passed(report: dict[str, Any]) -> bool:
|
||||
validation = report.get("validation")
|
||||
if not isinstance(validation, dict):
|
||||
return False
|
||||
if validation.get("protocol") != "untouched_model_holdout_with_threshold_walk_forward":
|
||||
return False
|
||||
if "passed" in validation:
|
||||
return bool(validation.get("passed"))
|
||||
return str(validation.get("status", "")).strip().lower() in {"pass", "passed", "ok"}
|
||||
@@ -125,5 +133,13 @@ def _read_json(path: str) -> dict[str, Any]:
|
||||
return data if isinstance(data, dict) else {}
|
||||
|
||||
|
||||
def _sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as source:
|
||||
for chunk in iter(lambda: source.read(1024 * 1024), b""):
|
||||
digest.update(chunk)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user