Pyfolio – AttributeError: ‘Series’ object has no attribute ‘iteritems’ & AttributeError: ‘numpy.int64’ object has no attribute ‘to_pydatetime’

Recently I was following a paper and in the example they used Pyfolio which is an awesome performance and risk analysis library in Python developed by Quantopian Inc when they were still around. Given that Quantopian is no longer around nobody is maintaining this library. I ran into a few errors and figured I would outline the solutions below in case anyone has these issues. But before I dive too deep into modifying this library you may be better off just uninstalling Pyfolio and loading Pyfolio-reloaded.

Also, if you’re interested here is an article on modifying PyFolio to output charts and data to an HTML.

Pyfolio-reloaded

pip uninstall pyfolio
pip install git+https://github.com/stefan-jansen/pyfolio-reloaded.git

First Error

Traceback (most recent call last):
  File "/home/shared/algos/ml4t/pairs_trading_backtest.py", line 512, in <module>
    pf.create_full_tear_sheet(returns,
  File "/opt/anaconda3/envs/ml4t/lib/python3.10/site-packages/pyfolio/tears.py", line 201, in create_full_tear_sheet
    create_returns_tear_sheet(
  File "/opt/anaconda3/envs/ml4t/lib/python3.10/site-packages/pyfolio/plotting.py", line 52, in call_w_context
    return func(*args, **kwargs)
  File "/opt/anaconda3/envs/ml4t/lib/python3.10/site-packages/pyfolio/tears.py", line 496, in create_returns_tear_sheet
    plotting.show_perf_stats(returns, benchmark_rets,
  File "/opt/anaconda3/envs/ml4t/lib/python3.10/site-packages/pyfolio/plotting.py", line 648, in show_perf_stats
    for stat, value in perf_stats[column].iteritems():
  File "/opt/anaconda3/envs/ml4t/lib/python3.10/site-packages/pandas/core/generic.py", line 5989, in __getattr__
    return object.__getattribute__(self, name)
AttributeError: 'Series' object has no attribute 'iteritems'

Process finished with exit code 1

This is the first error I received which was generated by this line of code:


pf.create_full_tear_sheet(returns, 
                          positions=positions, 
                          transactions=transactions, 
                          benchmark_rets=benchmark.loc[returns.index], 
                          estimate_intraday=False)

This can be fixed by modifying the file, /opt/anaconda3/envs/ml4t/lib/python3.10/site-packages/pyfolio/plotting.py

The line of code I’m going to change is as follows:

Existing:
for stat, value in perf_stats[column].iteritems():

New:
for stat, value in perf_stats[column].items():

Second Error:

Traceback (most recent call last):
  File "/home/shared/algos/ml4t/pairs_trading_backtest.py", line 512, in <module>
    pf.create_full_tear_sheet(returns,
  File "/opt/anaconda3/envs/ml4t/lib/python3.10/site-packages/pyfolio/tears.py", line 201, in create_full_tear_sheet
    create_returns_tear_sheet(
  File "/opt/anaconda3/envs/ml4t/lib/python3.10/site-packages/pyfolio/plotting.py", line 52, in call_w_context
    return func(*args, **kwargs)
  File "/opt/anaconda3/envs/ml4t/lib/python3.10/site-packages/pyfolio/tears.py", line 504, in create_returns_tear_sheet
    plotting.show_worst_drawdown_periods(returns)
  File "/opt/anaconda3/envs/ml4t/lib/python3.10/site-packages/pyfolio/plotting.py", line 1664, in show_worst_drawdown_periods
    drawdown_df = timeseries.gen_drawdown_table(returns, top=top)
  File "/opt/anaconda3/envs/ml4t/lib/python3.10/site-packages/pyfolio/timeseries.py", line 1008, in gen_drawdown_table
    df_drawdowns.loc[i, 'Valley date'] = (valley.to_pydatetime()
AttributeError: 'numpy.int64' object has no attribute 'to_pydatetime'

To fix this I modified this file /opt/anaconda3/envs/ml4t/lib/python3.10/site-packages/pyfolio/timeseries.py

The issue is within the function get_max_drawdown_underwater() the code is returning the index position for valley and it needs to be the date not the index position itself. The fixed code is below


def get_max_drawdown_underwater(underwater):
    """
    Determines peak, valley, and recovery dates given an 'underwater'
    DataFrame.

    An underwater DataFrame is a DataFrame that has precomputed
    rolling drawdown.

    Parameters
    ----------
    underwater : pd.Series
       Underwater returns (rolling drawdown) of a strategy.

    Returns
    -------
    peak : datetime
        The maximum drawdown's peak.
    valley : datetime
        The maximum drawdown's valley.
    recovery : datetime
        The maximum drawdown's recovery.
    """

    valley_idx = np.argmin(underwater)  # end of the period, as an index position
    valley_date = underwater.index[valley_idx]  # convert index position to timestamp
    # Find first 0
    peak = underwater[:valley_date][underwater[:valley_date] == 0].index[-1]
    # Find last 0
    try:
        recovery = underwater[valley_date:][underwater[valley_date:] == 0].index[0]
    except IndexError:
        recovery = np.nan  # drawdown not recovered
    logging.info(f'get_max_drawdown_underwater is returning \n {peak} \n {valley_date} \n {recovery}')
    return peak, valley_date, recovery

Leave a Reply

Continue reading

More from the archive

Article Dec 3, 2024 1 min read

YouTube Videos to MP3 and Transcription

I find myself listening to videos on YouTube quite frequently where it would be nice to dump them into an MP3 and take them on the road. This…

Article Sep 24, 2024 40 min read

Analyzing Any Polymarket User’s Trades Using Polygon

Polymarket.com, a prediction market platform, operates on the Ethereum blockchain through the Polygon network, making it possible to analyze user transactions directly from the blockchain. By accessing a…

error

Follow for updates!