From 8defa11f88fdd2069ccc939c3cd7468088beec68 Mon Sep 17 00:00:00 2001 From: Mika Date: Wed, 28 Jan 2026 16:22:42 +0000 Subject: [PATCH] Add python_analysis_script/src/python_analysis_script/core.py --- .../src/python_analysis_script/core.py | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 python_analysis_script/src/python_analysis_script/core.py diff --git a/python_analysis_script/src/python_analysis_script/core.py b/python_analysis_script/src/python_analysis_script/core.py new file mode 100644 index 0000000..ada573d --- /dev/null +++ b/python_analysis_script/src/python_analysis_script/core.py @@ -0,0 +1,64 @@ +from __future__ import annotations +import pandas as pd +from dataclasses import dataclass +from datetime import datetime +from typing import List + + +@dataclass +class DecisionResult: + """Repräsentiert ein einzelnes CI-Entscheidungsresultat.""" + + timestamp: datetime + decision: str + margin: float + flaky_flag: bool + subset_flip_count: int + mischfenster_p95: float + + +def _validate_input_columns(df: pd.DataFrame) -> None: + required_cols = {"margin", "flaky_flag", "subset_flip_count", "mischfenster_p95"} + missing = required_cols - set(df.columns) + assert not missing, f"Missing required columns: {missing}" + + +def _apply_policy(row: pd.Series) -> str: + margin = row.get("margin", 0.0) + flaky = row.get("flaky_flag", False) + # CI-Policy v0.1: einfache Entscheidungslogik + if pd.isna(margin): + return "FAIL" + if flaky: + return "WARN" + if margin >= 0.0: + return "PASS" + elif -0.05 <= margin < 0.0: + return "WARN" + else: + return "FAIL" + + +def analyze_backtest(csv_file: str) -> List[DecisionResult]: + """Analysiert Backtest-Ergebnisse und erstellt eine Liste DecisionResult.""" + assert isinstance(csv_file, str) and csv_file.endswith('.csv'), "csv_file must be a CSV filepath string" + + df = pd.read_csv(csv_file) + _validate_input_columns(df) + + results: List[DecisionResult] = [] + now = datetime.utcnow() + + for _, row in df.iterrows(): + decision = _apply_policy(row) + result = DecisionResult( + timestamp=now, + decision=decision, + margin=float(row.get("margin", 0.0)), + flaky_flag=bool(row.get("flaky_flag", False)), + subset_flip_count=int(row.get("subset_flip_count", 0)), + mischfenster_p95=float(row.get("mischfenster_p95", 0.0)), + ) + results.append(result) + + return results