Skip to content

Commit 90083e9

Browse files
committed
Fixed various deprecation messages related Pandas
1 parent 736f364 commit 90083e9

21 files changed

+156
-129
lines changed

README.md

+16-7
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ https://github.com/cuemacro/finmarketpy/blob/master/INSTALL.md (which includes d
7272

7373
Also take a look at https://github.com/cuemacro/teaching/blob/master/pythoncourse/installation/installing_anaconda_and_pycharm.ipynb
7474
from my Python for finance workshop course, where I keep notes specifically about setting up your Anaconda environment
75-
for data science (including for findatapy/chartpy/finmarketpy), including YAML files etc.
75+
for data science (including for findatapy/chartpy/finmarketpy) etc.
7676

7777
You can install the library using the below (better to get the newest version from repo, as opposed to releases).
7878

@@ -102,12 +102,15 @@ pip install chartpy
102102
pip install findatapy
103103
```
104104

105-
Note that if you use the option pricing/total returns you might need to get the latest FinancePy version from GitHub
106-
https://github.com/domokane/FinancePy/ as opposed to PyPI
105+
FinancePy is an optional dependency for finmarketpy for option pricing. It is recommended
106+
to install it separately from PyPI after installing finmarketpy, and without dependencies
107+
otherwise it can cause clashes with other libraries (because of its strict version
108+
dependencies on libraries like llvmlite, which in practice can be relaxed).
109+
The API changes a lot so it recommended to install the specific version listed below.
107110

108111
```
109-
pip install git+https://github.com/domokane/FinancePy/FinancePy.git
110-
112+
pip install numba numpy scipy llvmlite ipython pandas prettytable
113+
pip install financepy==0.370 --no-deps
111114
```
112115

113116
# Binder and Jupyter - Run finmarketpy in your browser
@@ -158,17 +161,19 @@ You may sometimes experience Numba errors like such as `Failed in nopython mode
158161

159162
One possible way to fix this is to delete the `__pycache__` folders underneath wherever financepy is installed:
160163

161-
Eg. if you are using the `py38class` environment, if you've installed Anaconda in `C:\Anaconda3`, you might find the financepy
164+
Eg. if you are using the `py310class` environment, if you've installed Anaconda in `C:\Anaconda3`, you might find the financepy
162165
folder at the below location
163166

164-
`C:\Anaconda3\envs\py38class\Lib\site-packages\financepy`
167+
`C:\Anaconda3\envs\py310class\Lib\site-packages\financepy`
165168

166169
# finmarketpy examples
167170

168171
In finmarketpy/examples you will find several examples, including some simple trading models
169172

170173
# Release Notes
171174

175+
* 0.11.14 - finmarketpy (08 Mar 2025)
176+
* 0.11.13 - finmarketpy (01 Jan 2024)
172177
* 0.11.12 - finmarketpy (26 Apr 2023)
173178
* 0.11.11 - finmarketpy (07 Oct 2021)
174179
* 0.11.10 - finmarketpy (06 Oct 2021)
@@ -187,6 +192,10 @@ In finmarketpy/examples you will find several examples, including some simple tr
187192

188193
# finmarketpy log
189194

195+
* 08 Mar 2025
196+
* Make FinancePy an optional dependency
197+
* Fixed various deprecation messages related Pandas
198+
* Made Plotly charts look nicer (autoscale with latest ChartPy)
190199
* 07 Mar 2025
191200
* Merge changes for pyproject.toml etc.
192201
* Formatting towards PEP8

finmarketpy/backtest/backtestengine.py

+15-12
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ def calculate_trading_PnL(
187187
# Only allow signals to change on the days when we can trade assets
188188
signal_df = signal_df.mask(
189189
non_trading_days) # fill asset holidays with NaN signals
190-
signal_df = signal_df.fillna(method='ffill') # fill these down
190+
signal_df = signal_df.ffill() # fill these down
191191

192192
# Transaction costs and roll costs
193193
tc = br.spot_tc_bp
@@ -202,8 +202,7 @@ def calculate_trading_PnL(
202202
pnl_cols.append(asset_df_cols[i] + " / " + signal_cols[i])
203203

204204
# Fill down asset holidays (we won't trade on these days)
205-
asset_df = asset_df.fillna(
206-
method='ffill')
205+
asset_df = asset_df.ffill()
207206
returns_df = calculations.calculate_returns(asset_df)
208207

209208
# Apply a stop loss/take profit to every trade if this has been specified
@@ -969,6 +968,7 @@ class TradingModel(object):
969968
HEIGHT = ChartConstants().chartfactory_height
970969
CHART_SOURCE = ChartConstants().chartfactory_source
971970
CHART_STYLE = Style()
971+
AUTO_SCALE = True
972972
PLOTLY_PLOT_MODE = "offline_html_exc_embed_js"
973973

974974
DUMP_CSV = ''
@@ -1428,7 +1428,7 @@ def compare_strategy_vs_benchmark(
14281428
# Only calculate return statistics if this has been specified (note when different frequencies of data
14291429
# might underrepresent vol
14301430
# if calc_stats:
1431-
benchmark_df = benchmark_df.fillna(method='ffill')
1431+
benchmark_df = benchmark_df.ffill()
14321432
benchmark_df = self._filter_by_plot_start_finish_date(benchmark_df,
14331433
br)
14341434

@@ -1440,8 +1440,7 @@ def compare_strategy_vs_benchmark(
14401440

14411441
# Realign strategy & benchmark
14421442
strategy_benchmark_df = strategy_df.join(benchmark_df, how='inner')
1443-
strategy_benchmark_df = strategy_benchmark_df.fillna(
1444-
method='ffill')
1443+
strategy_benchmark_df = strategy_benchmark_df.ffill()
14451444

14461445
strategy_benchmark_df = self._filter_by_plot_start_finish_date(
14471446
strategy_benchmark_df, br)
@@ -1623,7 +1622,7 @@ def _reduce_plot(self,
16231622
if reduce_plot and resample is not None:
16241623
# make plots on every business day (will downsample intraday data)
16251624
data_frame = data_frame.resample(resample).last()
1626-
data_frame = data_frame.fillna(method='pad')
1625+
data_frame = data_frame.ffill(method='pad')
16271626

16281627
return data_frame
16291628
except:
@@ -2017,13 +2016,13 @@ def _plot_ret_stats_helper(self, ret_stats, metric, title, file_tag,
20172016

20182017
for key in keys:
20192018
if metric == "IR":
2020-
ret_metric.append(ret_stats[key].inforatio()[0])
2019+
ret_metric.append(ret_stats[key].inforatio().iloc[0])
20212020
elif metric == "Returns":
2022-
ret_metric.append(ret_stats[key].ann_returns()[0] * 100)
2021+
ret_metric.append(ret_stats[key].ann_returns().iloc[0] * 100)
20232022
elif metric == "Vol":
2024-
ret_metric.append(ret_stats[key].ann_vol()[0] * 100)
2023+
ret_metric.append(ret_stats[key].ann_vol().iloc[0] * 100)
20252024
elif metric == "Drawdowns":
2026-
ret_metric.append(ret_stats[key].drawdowns()[0] * 100)
2025+
ret_metric.append(ret_stats[key].drawdowns().iloc[0] * 100)
20272026

20282027
if strip is not None: keys = [k.replace(strip, '') for k in keys]
20292028

@@ -2113,7 +2112,8 @@ def plot_strategy_group_leverage(
21132112
ret_with_df=ret_with_df,
21142113
split_on_char=split_on_char)
21152114

2116-
###### Plot signals and trades, in terms of units, notionals and contract sizes (eg. for futures)
2115+
###### Plot signals and trades, in terms of units, notionals and
2116+
# contract sizes (eg. for futures)
21172117

21182118
def plot_strategy_all_signals(
21192119
self,
@@ -2483,6 +2483,9 @@ def _create_style(self, title, file_add, reduce_plot=True):
24832483
style.source = self.CHART_SOURCE
24842484
style.silent_display = not (self.SHOW_CHARTS)
24852485
style.plotly_plot_mode = self.PLOTLY_PLOT_MODE # Smaller file sizes
2486+
style.auto_scale = self.AUTO_SCALE
2487+
2488+
print(style.plotly_plot_mode)
24862489

24872490
style.legend_bgcolor = 'rgba(0,0,0,0)'
24882491

finmarketpy/backtest/tradeanalysis.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def __init__(self, engine=ChartConstants().chartfactory_default_engine):
5252

5353
return
5454

55-
def run_strategy_returns_stats(self, trading_model):
55+
def run_strategy_returns_stats(self, trading_model, engine="finmarketpy"):
5656
"""Plots useful statistics for the trading strategy using various backends
5757
5858
Parameters
@@ -335,8 +335,8 @@ def run_arbitrary_sensitivity(self, trading_model, parameter_list=None,
335335

336336
style = Style()
337337

338-
ir = [t.inforatio()[0] for t in ret_stats_list]
339-
rets = [t.ann_returns()[0] for t in ret_stats_list]
338+
ir = [t.inforatio().iloc[0] for t in ret_stats_list]
339+
rets = [t.ann_returns().iloc[0] for t in ret_stats_list]
340340

341341
# if we have too many combinations remove legend and use scaled shaded colour
342342
# if len(port_list) > 10:

finmarketpy/curve/fxoptionscurve.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -792,10 +792,10 @@ def apply_tc_signals_to_total_return_index(self, cross_fx,
792792
total_return_index_df[cross + '-delta.close'].shift(
793793
1)) * spot_tc
794794

795-
total_return_index_df[cross + '-option-return-with-tc.close'][
796-
0] = 0
797-
total_return_index_df[cross + '-delta-pnl-return-with-tc.close'][
798-
0] = 0
795+
total_return_index_df.iloc[0,
796+
total_return_index_df.columns.get_loc(cross + '-option-return-with-tc.close')] = 0
797+
total_return_index_df.iloc[0,
798+
total_return_index_df.columns.get_loc(cross + '-delta-pnl-return-with-tc.close')] = 0
799799
total_return_index_df[
800800
cross + '-option-delta-return-with-tc.close'] = \
801801
total_return_index_df[cross + '-option-return-with-tc.close'] + \

finmarketpy/curve/fxspotcurve.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -260,11 +260,11 @@ def construct_total_return_index(self, cross_fx, market_df,
260260

261261
# Sometimes depo data can be patchy, ok to fill down, given not
262262
# very volatile (don't do this with spot!)
263-
carry = carry.fillna(method='ffill') / 100.0
263+
carry = carry.ffill() / 100.0
264264

265265
# In case there are values missing at start of list (fudge for
266266
# old data!)
267-
carry = carry.fillna(method='bfill')
267+
carry = carry.bfill()
268268

269269
spot = spot[cross + "." + field].to_frame()
270270

@@ -274,11 +274,12 @@ def construct_total_return_index(self, cross_fx, market_df,
274274
terms_deposit_vals = carry[
275275
cross[3:6] + depo_tenor + "." + field].values
276276

277-
# Calculate the time difference between each data point (flooring it to whole days, because carry
277+
# Calculate the time difference between each data point (
278+
# flooring it to whole days, because carry
278279
# is accured when there's a new day)
279280
spot['index_col'] = spot.index.floor('D')
280281
time = spot['index_col'].diff()
281-
spot = spot.drop('index_col', 1)
282+
spot = spot.drop('index_col', axis=1)
282283

283284
time_diff = time.values.astype(
284285
float) / 86400000000000.0 # get time difference in days

finmarketpy/curve/volatility/fxvolsurface.py

+36-36
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
FinFXDeltaMethod
3333
from financepy.market.volatility.fx_vol_surface_plus import vol_function
3434
from financepy.market.volatility.fx_vol_surface_plus import \
35-
VolFunctionTypes
35+
VolFuncTypes
3636

3737
from financepy.utils.global_types import FinSolverTypes
3838
except:
@@ -142,17 +142,17 @@ def __init__(self, market_df=None, asset=None, field="close",
142142
[asset + "10R" + t + field for t in tenors]].values
143143

144144
if vol_function_type == "CLARK":
145-
self._vol_function_type = VolFunctionTypes.CLARK
145+
self._vol_function_type = VolFuncTypes.CLARK
146146
elif vol_function_type == "CLARK5":
147-
self._vol_function_type = VolFunctionTypes.CLARK5
147+
self._vol_function_type = VolFuncTypes.CLARK5
148148
elif vol_function_type == "BBG":
149-
self._vol_function_type = VolFunctionTypes.BBG
149+
self._vol_function_type = VolFuncTypes.BBG
150150

151151
# Note: currently SABR isn"t fully implemented in FinancePy
152152
elif vol_function_type == "SABR":
153-
self._vol_function_type = VolFunctionTypes.SABR
153+
self._vol_function_type = VolFuncTypes.SABR
154154
elif vol_function_type == "SABR3":
155-
self._vol_function_type = VolFunctionTypes.SABR3
155+
self._vol_function_type = VolFuncTypes.SABR3
156156

157157
# What does ATM mean? (for most
158158
if atm_method == "fwd-delta-neutral": # ie. strike such that a straddle would be delta neutral
@@ -246,10 +246,10 @@ def build_vol_surface(self, value_date):
246246
self._risk_reversal10DeltaVols[
247247
date_index][0],
248248
self._alpha,
249-
atmMethod=self._atm_method,
250-
deltaMethod=self._delta_method,
251-
volatility_function_type=self._vol_function_type,
252-
finSolverType=self._solver,
249+
atm_method=self._atm_method,
250+
delta_method=self._delta_method,
251+
vol_func_type=self._vol_function_type,
252+
fin_solver_type=self._solver,
253253
tol=self._tol) # TODO add tol
254254

255255
def calculate_vol_for_strike_expiry(self, K, expiry_date=None, tenor="1M"):
@@ -335,21 +335,21 @@ def extract_vol_surface(self, num_strike_intervals=60, low_K_pc=0.95,
335335

336336
# columns = tenors
337337
df_vol_surface_strike_space = pd.DataFrame(
338-
columns=self._fin_fx_vol_surface._tenors)
338+
columns=self._fin_fx_vol_surface.tenors)
339339
df_vol_surface_delta_space = pd.DataFrame(
340-
columns=self._fin_fx_vol_surface._tenors)
340+
columns=self._fin_fx_vol_surface.tenors)
341341

342342
# columns = tenors
343343
df_vol_surface_implied_pdf = pd.DataFrame(
344-
columns=self._fin_fx_vol_surface._tenors)
344+
columns=self._fin_fx_vol_surface.tenors)
345345

346346
# Conversion between main deltas and strikes
347347
df_deltas_vs_strikes = pd.DataFrame(
348-
columns=self._fin_fx_vol_surface._tenors)
348+
columns=self._fin_fx_vol_surface.tenors)
349349

350350
# ATM, 10d + 25d market strangle and 25d risk reversals
351351
df_vol_surface_quoted_points = pd.DataFrame(
352-
columns=self._fin_fx_vol_surface._tenors)
352+
columns=self._fin_fx_vol_surface.tenors)
353353

354354
# Note, at present we"re not using 10d strikes
355355
quoted_strikes_names = ["ATM", "STR_25D_MS", "RR_25D_P", "STR_10D_MS",
@@ -359,8 +359,8 @@ def extract_vol_surface(self, num_strike_intervals=60, low_K_pc=0.95,
359359
"K_10D_C_MS"]
360360

361361
# Get max/min strikes to interpolate (from the longest dated tenor)
362-
low_K = self._fin_fx_vol_surface._K_25D_P[-1] * low_K_pc
363-
high_K = self._fin_fx_vol_surface._K_25D_C[-1] * high_K_pc
362+
low_K = self._fin_fx_vol_surface.k_25d_p[-1] * low_K_pc
363+
high_K = self._fin_fx_vol_surface.k_25d_c[-1] * high_K_pc
364364

365365
if num_strike_intervals is not None:
366366
# In case using old version of FinancePy
@@ -370,19 +370,19 @@ def extract_vol_surface(self, num_strike_intervals=60, low_K_pc=0.95,
370370
except:
371371
pass
372372

373-
for tenor_index in range(0, self._fin_fx_vol_surface._num_vol_curves):
373+
for tenor_index in range(0, self._fin_fx_vol_surface.num_vol_curves):
374374

375375
# Get the quoted vol points
376-
tenor_label = self._fin_fx_vol_surface._tenors[tenor_index]
376+
tenor_label = self._fin_fx_vol_surface.tenors[tenor_index]
377377

378-
atm_vol = self._fin_fx_vol_surface._atm_vols[tenor_index] * 100
379-
ms_25d_vol = self._fin_fx_vol_surface._mktStrangle25DeltaVols[
378+
atm_vol = self._fin_fx_vol_surface.atm_vols[tenor_index] * 100
379+
ms_25d_vol = self._fin_fx_vol_surface.ms_25_delta_vols[
380380
tenor_index] * 100
381-
rr_25d_vol = self._fin_fx_vol_surface._riskReversal25DeltaVols[
381+
rr_25d_vol = self._fin_fx_vol_surface.rr_25_delta_vols[
382382
tenor_index] * 100
383-
ms_10d_vol = self._fin_fx_vol_surface._mktStrangle10DeltaVols[
383+
ms_10d_vol = self._fin_fx_vol_surface.ms_10_delta_vols[
384384
tenor_index] * 100
385-
rr_10d_vol = self._fin_fx_vol_surface._riskReversal10DeltaVols[
385+
rr_10d_vol = self._fin_fx_vol_surface.rr_10_delta_vols[
386386
tenor_index] * 100
387387

388388
df_vol_surface_quoted_points[tenor_label] = pd.Series(
@@ -416,19 +416,19 @@ def extract_vol_surface(self, num_strike_intervals=60, low_K_pc=0.95,
416416

417417
# Extract strikes for the quoted points (ie. 10d, 25d and ATM)
418418
key_strikes = []
419-
key_strikes.append(self._fin_fx_vol_surface._K_10D_P[tenor_index])
419+
key_strikes.append(self._fin_fx_vol_surface.k_10d_p[tenor_index])
420420
key_strikes.append(
421-
self._fin_fx_vol_surface._K_10D_P_MS[tenor_index])
422-
key_strikes.append(self._fin_fx_vol_surface._K_25D_P[tenor_index])
421+
self._fin_fx_vol_surface.k_10d_p_ms[tenor_index])
422+
key_strikes.append(self._fin_fx_vol_surface.k_25d_p[tenor_index])
423423
key_strikes.append(
424-
self._fin_fx_vol_surface._K_25D_P_MS[tenor_index])
425-
key_strikes.append(self._fin_fx_vol_surface._K_ATM[tenor_index])
426-
key_strikes.append(self._fin_fx_vol_surface._K_25D_C[tenor_index])
424+
self._fin_fx_vol_surface.k_25d_p_ms[tenor_index])
425+
key_strikes.append(self._fin_fx_vol_surface.k_atm[tenor_index])
426+
key_strikes.append(self._fin_fx_vol_surface.k_25d_c[tenor_index])
427427
key_strikes.append(
428-
self._fin_fx_vol_surface._K_25D_C_MS[tenor_index])
429-
key_strikes.append(self._fin_fx_vol_surface._K_10D_C[tenor_index])
428+
self._fin_fx_vol_surface.k_25d_c_ms[tenor_index])
429+
key_strikes.append(self._fin_fx_vol_surface.k_10d_c[tenor_index])
430430
key_strikes.append(
431-
self._fin_fx_vol_surface._K_10D_C_MS[tenor_index])
431+
self._fin_fx_vol_surface.k_10d_c_ms[tenor_index])
432432

433433
df_deltas_vs_strikes[tenor_label] = pd.Series(
434434
index=key_strikes_names, data=key_strikes)
@@ -467,9 +467,9 @@ def get_vol_from_quoted_tenor(self, K, tenor, gaps=None):
467467
if gaps is None:
468468
gaps = np.array([0.1])
469469

470-
params = self._fin_fx_vol_surface._parameters[tenor_index]
471-
t = self._fin_fx_vol_surface._texp[tenor_index]
472-
f = self._fin_fx_vol_surface._F0T[tenor_index]
470+
params = self._fin_fx_vol_surface.parameters[tenor_index]
471+
t = self._fin_fx_vol_surface.t_exp[tenor_index]
472+
f = self._fin_fx_vol_surface.fwd[tenor_index]
473473

474474
return vol_function(self._vol_function_type.value, params,
475475
np.array([K]), gaps, f, K, t)

finmarketpy/economics/seasonality.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def monthly_seasonality(self, data_frame,
149149

150150
if price_index:
151151
data_frame = data_frame.resample(
152-
'BM').mean() # resample into month end
152+
'BME').mean() # resample into month end
153153
data_frame = calculations.calculate_returns(data_frame)
154154

155155
data_frame.index = pandas.to_datetime(data_frame.index)
@@ -209,7 +209,7 @@ def _remove_seasonality(self, series, likely_period=None):
209209
if adjusted is None:
210210
return numpy.nan
211211

212-
return adjusted[-1]
212+
return adjusted.iloc[-1]
213213

214214

215215
if __name__ == '__main__':

0 commit comments

Comments
 (0)