fix: honor explicit calibration horizon

This commit is contained in:
Курнат Андрей
2026-07-14 23:58:05 +03:00
parent e1a42a9011
commit 1f2fb011a7
2 changed files with 21 additions and 1 deletions
+9
View File
@@ -8,6 +8,7 @@ from tools.calibrate_torch_thresholds import (
_average_selected_predictions, _average_selected_predictions,
_apply_platt_calibration, _apply_platt_calibration,
_build_torch_model, _build_torch_model,
_calibration_horizon,
_calibration_symbols, _calibration_symbols,
_choose_recommendation, _choose_recommendation,
_full_backtest, _full_backtest,
@@ -78,6 +79,14 @@ def test_calibration_symbols_reject_malformed_artifact_symbols() -> None:
assert _calibration_symbols("", (), {"symbols": []}) == [] assert _calibration_symbols("", (), {"symbols": []}) == []
def test_explicit_calibration_horizon_selects_existing_multi_horizon_output() -> None:
entry = {"target_horizon": 12, "target_horizons": [3, 6, 12, 24]}
assert _calibration_horizon(entry, 24, explicit=True) == 24
assert _calibration_horizon(entry, 20, explicit=True) == 24
assert _calibration_horizon(entry, 24, explicit=False) == 12
def test_calibration_does_not_fallback_to_too_few_trades() -> None: def test_calibration_does_not_fallback_to_too_few_trades() -> None:
selected = _choose_recommendation( selected = _choose_recommendation(
[_result(trades=1, average=2.0, total=2.0, profit_factor=999.0)], [_result(trades=1, average=2.0, total=2.0, profit_factor=999.0)],
+12 -1
View File
@@ -120,6 +120,7 @@ def main() -> None:
trend_candles=trend_candles, trend_candles=trend_candles,
artifact=artifact, artifact=artifact,
horizon=horizon, horizon=horizon,
horizon_is_explicit=args.horizon > 0,
round_trip_cost=round_trip_cost, round_trip_cost=round_trip_cost,
min_candles=max(30, settings.time_series_min_candles), min_candles=max(30, settings.time_series_min_candles),
calibration_window=args.calibration_window, calibration_window=args.calibration_window,
@@ -329,6 +330,15 @@ def _calibration_symbols(
return [str(symbol).strip().upper() for symbol in artifact_symbols if str(symbol).strip()] return [str(symbol).strip().upper() for symbol in artifact_symbols if str(symbol).strip()]
def _calibration_horizon(entry: dict[str, Any], requested: int, *, explicit: bool) -> int:
horizons = _entry_target_horizons(entry)
if explicit and requested > 0:
if horizons:
return min(horizons, key=lambda value: abs(value - requested))
return requested
return _entry_horizon(entry, requested)
def _forecast_records( def _forecast_records(
*, *,
symbol: str, symbol: str,
@@ -337,6 +347,7 @@ def _forecast_records(
trend_candles: list[Candle], trend_candles: list[Candle],
artifact: dict[str, Any], artifact: dict[str, Any],
horizon: int, horizon: int,
horizon_is_explicit: bool,
round_trip_cost: float, round_trip_cost: float,
min_candles: int, min_candles: int,
calibration_window: int, calibration_window: int,
@@ -355,7 +366,7 @@ def _forecast_records(
trend_candles=trend_candles, trend_candles=trend_candles,
) )
closes = [float(candle.close) for candle in candles] closes = [float(candle.close) for candle in candles]
decision_horizon = _entry_horizon(entry, horizon) decision_horizon = _calibration_horizon(entry, horizon, explicit=horizon_is_explicit)
start = max(min_candles, int(float(entry.get("lookback", 64)))) start = max(min_candles, int(float(entry.get("lookback", 64))))
end = len(candles) - decision_horizon - 1 end = len(candles) - decision_horizon - 1
holdout_start_timestamp = int(float(entry.get("holdout_start_timestamp", 0) or 0)) holdout_start_timestamp = int(float(entry.get("holdout_start_timestamp", 0) or 0))