From 1809e75ca6a87f2ca074f2f23ae481c08abc2c11 Mon Sep 17 00:00:00 2001 From: whn <142425816+Whning0513@users.noreply.github.com> Date: Thu, 30 Jul 2026 05:31:25 +0800 Subject: [PATCH 1/3] Preserve source timezone in chart timestamps --- backtesting/_plotting.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/backtesting/_plotting.py b/backtesting/_plotting.py index 340ea646..6818b46b 100644 --- a/backtesting/_plotting.py +++ b/backtesting/_plotting.py @@ -76,6 +76,13 @@ def _windos_safe_filename(filename): return filename + +def _remove_timezone(values): + if isinstance(values, pd.DatetimeIndex): + return values.tz_localize(None) if values.tz is not None else values + if isinstance(values, pd.Series) and isinstance(values.dtype, pd.DatetimeTZDtype): + return values.dt.tz_localize(None) + return values def _bokeh_reset(filename=None): curstate().reset() if filename: @@ -239,7 +246,7 @@ def plot(*, results: pd.Series, resample, df, indicators, equity_data, trades) df.index.name = None # Provides source name @index - df['datetime'] = df.index # Save original, maybe datetime index + df['datetime'] = _remove_timezone(df.index) # Save original, maybe datetime index df = df.reset_index(drop=True) equity_data = equity_data.reset_index(drop=True) index = df.index From 70ab81f3b63cb3347025995edffb717f776f2538 Mon Sep 17 00:00:00 2001 From: whn <142425816+Whning0513@users.noreply.github.com> Date: Thu, 30 Jul 2026 05:33:02 +0800 Subject: [PATCH 2/3] Normalize trade timestamps for Bokeh --- backtesting/_plotting.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backtesting/_plotting.py b/backtesting/_plotting.py index 6818b46b..607acc2d 100644 --- a/backtesting/_plotting.py +++ b/backtesting/_plotting.py @@ -75,14 +75,14 @@ def _windos_safe_filename(filename): return re.sub(r'[^a-zA-Z0-9,_-]', '_', filename.replace('=', '-')) return filename - - def _remove_timezone(values): if isinstance(values, pd.DatetimeIndex): return values.tz_localize(None) if values.tz is not None else values if isinstance(values, pd.Series) and isinstance(values.dtype, pd.DatetimeTZDtype): return values.dt.tz_localize(None) return values + + def _bokeh_reset(filename=None): curstate().reset() if filename: @@ -275,7 +275,7 @@ def plot(*, results: pd.Series, trade_source = ColumnDataSource(dict( index=trades['ExitBar'], - datetime=trades['ExitTime'], + datetime=_remove_timezone(trades['ExitTime']), size=trades['Size'], returns_positive=(trades['ReturnPct'] > 0).astype(int).astype(str), )) From bfe44f19bebc2174883d587f3bd613df2c86ee68 Mon Sep 17 00:00:00 2001 From: whn <142425816+Whning0513@users.noreply.github.com> Date: Thu, 30 Jul 2026 05:33:51 +0800 Subject: [PATCH 3/3] Format timezone helper separation --- backtesting/_plotting.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backtesting/_plotting.py b/backtesting/_plotting.py index 607acc2d..c53a3e3b 100644 --- a/backtesting/_plotting.py +++ b/backtesting/_plotting.py @@ -75,6 +75,7 @@ def _windos_safe_filename(filename): return re.sub(r'[^a-zA-Z0-9,_-]', '_', filename.replace('=', '-')) return filename + def _remove_timezone(values): if isinstance(values, pd.DatetimeIndex): return values.tz_localize(None) if values.tz is not None else values