From 2393f12b7181c768f71902c12c1e81e3b006b04d Mon Sep 17 00:00:00 2001 From: tiago-hansen Date: Fri, 10 Jul 2026 14:11:41 -0300 Subject: [PATCH] fix: use pandas 2.2+ frequency aliases for pandas 3.0 compatibility pandas 3.0 removed the deprecated single-letter offset aliases, which broke the financial-analysis and data-processing code paths (26 errors in the Flask simulation integration tests on a fresh install, since pip resolves pandas to 3.x with no upper bound). Replace the removed aliases with their 2.2+ equivalents: - freq="T" -> freq="min" (8 date_range call sites) - resample("M") / "M" period literals -> "ME" - freq="H" / resample("1H") -> "h" / "1h" Bump the pandas floor to >=2.2 in pyproject.toml and setup.py, since the "min"/"ME"/"h" aliases require pandas 2.2+. Also add venv/ and .venv/ to .gitignore so a locally-created virtualenv is not tracked. Full fast test suite: 1503 passed, 2 xfailed (was 1477 passed + 26 errored before the fix). Co-Authored-By: Claude Opus 4.8 --- .gitignore | 4 ++++ pyproject.toml | 2 +- quantammsim/core_simulator/windowing_utils.py | 2 +- .../finance/financial_analysis_charting.py | 2 +- .../finance/financial_analysis_functions.py | 14 +++++++------- .../finance/param_financial_calculator.py | 4 ++-- .../utils/data_processing/binance_data_utils.py | 2 +- .../utils/data_processing/historic_data_utils.py | 8 ++++---- .../minute_daily_conversion_utils.py | 2 +- setup.py | 2 +- 10 files changed, 23 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 70ace4c3..c353486d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,10 @@ price-data-new # Ignore frontend build **/**/build +# Ignore virtual environments +venv/ +.venv/ + # Ignore files related to API keys .env diff --git a/pyproject.toml b/pyproject.toml index 413faf9e..36ab9b5f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ dependencies = [ "jax>=0.4.27", "jaxlib", "numpy>=1.21.0", - "pandas>=1.3.6", + "pandas>=2.2", "flask", "flask-jwt-extended", "scipy", diff --git a/quantammsim/core_simulator/windowing_utils.py b/quantammsim/core_simulator/windowing_utils.py index 052a77e0..024e3f1d 100644 --- a/quantammsim/core_simulator/windowing_utils.py +++ b/quantammsim/core_simulator/windowing_utils.py @@ -132,7 +132,7 @@ def raw_trades_to_trade_array(raw_trades, start_date_string, end_date_string, to pd.date_range( start=pd.to_datetime(start_date_string, format="%Y-%m-%d %H:%M:%S"), end=pd.to_datetime(end_date_string, format="%Y-%m-%d %H:%M:%S"), - freq="T", + freq="min", ).astype(int) // 10**6 ) diff --git a/quantammsim/simulator_analysis_tools/finance/financial_analysis_charting.py b/quantammsim/simulator_analysis_tools/finance/financial_analysis_charting.py index 2fd58ba2..87ee5453 100644 --- a/quantammsim/simulator_analysis_tools/finance/financial_analysis_charting.py +++ b/quantammsim/simulator_analysis_tools/finance/financial_analysis_charting.py @@ -50,7 +50,7 @@ def plot_line_chart_from_results( series_dict = {} for result, series in zip(results_list, series_list): result_index = pd.date_range( - start=startDateString, periods=len(result), freq="T" + start=startDateString, periods=len(result), freq="min" ) result_series = pd.Series(result, index=result_index) series_dict[series] = result_series diff --git a/quantammsim/simulator_analysis_tools/finance/financial_analysis_functions.py b/quantammsim/simulator_analysis_tools/finance/financial_analysis_functions.py index fe811fa2..a5fe831b 100644 --- a/quantammsim/simulator_analysis_tools/finance/financial_analysis_functions.py +++ b/quantammsim/simulator_analysis_tools/finance/financial_analysis_functions.py @@ -244,22 +244,22 @@ def calculate_drawdown_statistics(daily_returns, rf_values): weekly_max_drawdown = drawdown_weekly.min() # Monthly maximum drawdown - monthly_returns = daily_returns.resample("M").apply(lambda x: (1 + x).prod() - 1) + monthly_returns = daily_returns.resample("ME").apply(lambda x: (1 + x).prod() - 1) cumulative_monthly_returns = (1 + monthly_returns).cumprod() peak_monthly = cumulative_monthly_returns.cummax() drawdown_monthly = (cumulative_monthly_returns - peak_monthly) / peak_monthly monthly_max_drawdown = drawdown_monthly.min() daily_weekly_avg = calculate_average_daily_drawdown(daily_returns, "W") - daily_monthly_avg = calculate_average_daily_drawdown(daily_returns, "M") + daily_monthly_avg = calculate_average_daily_drawdown(daily_returns, "ME") daily_weekly_max = calculate_max_daily_drawdown(daily_returns, "W") - daily_monthly_max = calculate_max_daily_drawdown(daily_returns, "M") + daily_monthly_max = calculate_max_daily_drawdown(daily_returns, "ME") ulcer_index = calculate_ulcer_index(daily_returns) daily_weekly_ulcer = calcuate_period_ulcer_index(daily_returns, "W") - daily_monthly_ulcer = calcuate_period_ulcer_index(daily_returns, "M") + daily_monthly_ulcer = calcuate_period_ulcer_index(daily_returns, "ME") sterling = calculate_sterling_ratio(daily_returns, rf_values) @@ -267,13 +267,13 @@ def calculate_drawdown_statistics(daily_returns, rf_values): daily_returns, rf_values, "W" ) daily_monthly_sterling = calcuate_period_sterling_index( - daily_returns, rf_values, "M" + daily_returns, rf_values, "ME" ) annualized_cDaR = calculate_cdar(daily_returns) * np.sqrt(365) weekly_cDaR = calculate_monthly_cdar(daily_returns, "W") - monthly_cDaR = calculate_monthly_cdar(daily_returns, "M") + monthly_cDaR = calculate_monthly_cdar(daily_returns, "ME") return { "Daily Returns Maximum Drawdown": abs(daily_max_drawdown), @@ -500,7 +500,7 @@ def calcuate_period_sterling_index(daily_returns, rf_values, period): Parameters: daily_returns (np.array or pd.Series): Daily returns of the portfolio. rf_values (np.array or pd.Series): Daily risk-free rates. - period (str): Period for resampling (e.g., "M" for monthly). + period (str): Period for resampling (e.g., "ME" for monthly). Returns: np.array: Monthly Sterling Ratios. diff --git a/quantammsim/simulator_analysis_tools/finance/param_financial_calculator.py b/quantammsim/simulator_analysis_tools/finance/param_financial_calculator.py index f92f7da3..b7fc80a0 100644 --- a/quantammsim/simulator_analysis_tools/finance/param_financial_calculator.py +++ b/quantammsim/simulator_analysis_tools/finance/param_financial_calculator.py @@ -752,7 +752,7 @@ def fill_missing_values(target_directory, filename, output_filename): def calculate_daily_returns(minute_values, startDateString, name): # Create a pandas Series with minute-level values and a datetime index num_minutes = len(minute_values) - minute_index = pd.date_range(start=startDateString, periods=num_minutes, freq="T") + minute_index = pd.date_range(start=startDateString, periods=num_minutes, freq="min") minute_series = pd.Series(minute_values, index=minute_index) # Resample to daily frequency by taking the last value of each day @@ -968,7 +968,7 @@ def retrieve_mc_param_financial_results(run_fingerprint, params, testEndDateStri minute_index = pd.date_range( start=run_fingerprint["startDateString"], periods=len(portfolio_result["value"]), - freq="T", + freq="min", ) minute_series = pd.Series(portfolio_result["value"], index=minute_index) minute_series.to_csv("./results/portfolio_result_abs.csv") diff --git a/quantammsim/utils/data_processing/binance_data_utils.py b/quantammsim/utils/data_processing/binance_data_utils.py index cd2c8202..fb818ae1 100644 --- a/quantammsim/utils/data_processing/binance_data_utils.py +++ b/quantammsim/utils/data_processing/binance_data_utils.py @@ -199,7 +199,7 @@ def report_gaps(concatenated_df, gaps_output_file=None): pd.date_range( start=pd.to_datetime(start_unix, unit="ms"), end=pd.to_datetime(end_unix, unit="ms"), - freq="T", + freq="min", ).astype(int) // 10**9 ) diff --git a/quantammsim/utils/data_processing/historic_data_utils.py b/quantammsim/utils/data_processing/historic_data_utils.py index 31fb76c3..09ced35e 100644 --- a/quantammsim/utils/data_processing/historic_data_utils.py +++ b/quantammsim/utils/data_processing/historic_data_utils.py @@ -396,7 +396,7 @@ def update_historic_data_old(token, root): pd.date_range( start=pd.to_datetime(csvData.index.min(), unit="ms"), end=pd.to_datetime(csvData.index.max(), unit="ms"), - freq="T", + freq="min", ).astype(int) // 10**6 ) @@ -554,7 +554,7 @@ def update_historic_data_old(token, root): pd.date_range( start=pd.to_datetime(hourly_data.index.min(), unit="ms"), end=pd.to_datetime(hourly_data.index.max(), unit="ms"), - freq="H", + freq="h", ).astype(int) // 10**6 ) @@ -566,7 +566,7 @@ def update_historic_data_old(token, root): pd.date_range( start=pd.to_datetime(hourly_data.index.min(), unit="ms"), end=pd.to_datetime(hourly_data.index.max(), unit="ms"), - freq="T", + freq="min", ).astype(int) // 10**6 ) @@ -987,7 +987,7 @@ def update_historic_data(token, root): agg_dict = {k: v for k, v in agg_dict.items() if k in concated_df_hourly.columns} # Perform resampling - hourly_data = concated_df_hourly.resample("1H").agg(agg_dict).reset_index() + hourly_data = concated_df_hourly.resample("1h").agg(agg_dict).reset_index() # Save hourly data hourly_data.to_csv(hourlyPath, index=False) diff --git a/quantammsim/utils/data_processing/minute_daily_conversion_utils.py b/quantammsim/utils/data_processing/minute_daily_conversion_utils.py index b86c3520..09bf689c 100644 --- a/quantammsim/utils/data_processing/minute_daily_conversion_utils.py +++ b/quantammsim/utils/data_processing/minute_daily_conversion_utils.py @@ -20,7 +20,7 @@ def expand_daily_to_minute_data(daily_data, scale="ms"): # Create a date range with minute frequency minute_range = pd.date_range( - start=daily_data.index.min(), end=daily_data.index.max(), freq="T" + start=daily_data.index.min(), end=daily_data.index.max(), freq="min" ) # Reindex the daily data to the minute range, forward filling the values diff --git a/setup.py b/setup.py index 20eb403f..82813005 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ "jax>=0.4.27", "jaxlib", # Required for JAX to work "numpy>=1.21.0", - "pandas>=1.3.0", + "pandas>=2.2", "flask", "flask-jwt-extended", "scipy",