]> Piment Noir Git Repositories - freqai-strategies.git/commitdiff
fix: validate epoch-ms range before converting int64 date columns
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Fri, 1 May 2026 14:03:12 +0000 (16:03 +0200)
committerJérôme Benoit <jerome.benoit@piment-noir.org>
Fri, 1 May 2026 14:03:12 +0000 (16:03 +0200)
Reject int64 values outside [2010, 2035] epoch-ms range to fail fast
on corrupted data instead of silently producing wrong dates. Catches
nanosecond/microsecond values that would pass the int64 dtype check
but produce garbage timestamps if interpreted as milliseconds.

ReforceXY/user_data/strategies/RLAgentStrategy.py
quickadapter/user_data/strategies/Utils.py

index 38b016ad772dd1544a58ef76b8bcf3d6e561b00a..7cbe10845533d31e936fc873eb1ad1554d5b5e7f 100644 (file)
@@ -19,9 +19,23 @@ logger = logging.getLogger(__name__)
 ACTION_COLUMN: Final = "&-action"
 
 
+_EPOCH_MS_MIN = 1_262_304_000_000  # 2010-01-01T00:00:00Z
+_EPOCH_MS_MAX = 2_051_222_400_000  # 2035-01-01T00:00:00Z
+
+
 def _ensure_datetime_series(series: pd.Series) -> pd.Series:
     """Ensure a date series is datetime64[ms, UTC], following freqtrade's data handler pattern."""
     if pd.api.types.is_integer_dtype(series):
+        sample = series.dropna()
+        if sample.empty:
+            return pd.to_datetime(series, unit="ms", utc=True).dt.as_unit("ms")
+        probe = int(sample.iat[0])
+        if not (_EPOCH_MS_MIN <= probe <= _EPOCH_MS_MAX):
+            raise ValueError(
+                f"Integer date column value {probe} is outside the expected epoch-ms "
+                f"range [{_EPOCH_MS_MIN}, {_EPOCH_MS_MAX}]. "
+                "Data is likely corrupted or uses a different unit."
+            )
         return pd.to_datetime(series, unit="ms", utc=True).dt.as_unit("ms")
     return series.dt.as_unit("ms")
 
index 9ade5af992366416a8f0a102462dd194193d8e10..3050883fe50446814d1925d17af765b534353a1a 100644 (file)
@@ -644,9 +644,23 @@ def get_label_prediction_config(
     )
 
 
+_EPOCH_MS_MIN = 1_262_304_000_000  # 2010-01-01T00:00:00Z
+_EPOCH_MS_MAX = 2_051_222_400_000  # 2035-01-01T00:00:00Z
+
+
 def ensure_datetime_series(series: pd.Series) -> pd.Series:
     """Ensure a date series is datetime64[ms, UTC], following freqtrade's data handler pattern."""
     if pd.api.types.is_integer_dtype(series):
+        sample = series.dropna()
+        if sample.empty:
+            return pd.to_datetime(series, unit="ms", utc=True).dt.as_unit("ms")
+        probe = int(sample.iat[0])
+        if not (_EPOCH_MS_MIN <= probe <= _EPOCH_MS_MAX):
+            raise ValueError(
+                f"Integer date column value {probe} is outside the expected epoch-ms "
+                f"range [{_EPOCH_MS_MIN}, {_EPOCH_MS_MAX}]. "
+                "Data is likely corrupted or uses a different unit."
+            )
         return pd.to_datetime(series, unit="ms", utc=True).dt.as_unit("ms")
     return series.dt.as_unit("ms")