fja05680 / pinkfish

A backtester and spreadsheet library for security analysis.
https://fja05680.github.io/pinkfish
MIT License
264 stars 60 forks source link

Stats error in case of empty tradelog #61

Closed wtld closed 1 year ago

wtld commented 1 year ago

If a tradelog is empty (it happens, for example, when optimizing strategy parameters) the stats function generates an error:

File "/home/witold/miniconda3/lib/python3.9/site-packages/pinkfish/statistics.py", line 827, in stats
    stats['total_net_profit'] = _total_net_profit(tlog)

  File "/home/witold/miniconda3/lib/python3.9/site-packages/pinkfish/statistics.py", line 411, in _total_net_profit
    return tlog.iloc[-1]['cumul_total']

  File "/home/witold/miniconda3/lib/python3.9/site-packages/pandas/core/indexing.py", line 967, in __getitem__
    return self._getitem_axis(maybe_callable, axis=axis)

  File "/home/witold/miniconda3/lib/python3.9/site-packages/pandas/core/indexing.py", line 1520, in _getitem_axis
    self._validate_integer(key, axis)

  File "/home/witold/miniconda3/lib/python3.9/site-packages/pandas/core/indexing.py", line 1452, in _validate_integer
    raise IndexError("single positional indexer is out-of-bounds")

IndexError: single positional indexer is out-of-bounds

I suspect than the problem is in line 411 "return tlog.iloc[-1]['cumul_total']"

Full test code:

import datetime
import pinkfish as pf

symbol = 'SPY'
capital = 10000
start = datetime.datetime(1900, 1, 1)
end = datetime.datetime.now()

# Fetch timeseries, select, finalize.
ts = pf.fetch_timeseries(symbol)
ts = pf.select_tradeperiod(ts, start, end, use_adj=True)
ts, start = pf.finalize_timeseries(ts, start)

# Create tradelog and daily balance objects.
tlog = pf.TradeLog(symbol)
dbal = pf.DailyBal()

pf.TradeLog.cash = capital

# Loop through timeseries.
for i, row in enumerate(ts.itertuples()):
    # no trade here for the test
    date = row.Index.to_pydatetime()
    dbal.append(date, row.high, row.low, row.close)

tlog = tlog.get_log()
dbal = dbal.get_log(tlog)

stats = pf.stats(ts, tlog, dbal, capital)
fja05680 commented 1 year ago

I agree that pinkfish should handle this situation. It may take me several days before I can have a look at it.

fja05680 commented 1 year ago

Thanks for reporting this and also fr providing a complete example!!