kernc / backtesting.py

:mag_right: :chart_with_upwards_trend: :snake: :moneybag: Backtest trading strategies in Python.
https://kernc.github.io/backtesting.py/
GNU Affero General Public License v3.0
5.44k stars 1.06k forks source link

'Empty dataframe' when using a dataframe that has been imported from a file #116

Closed AlgoQ closed 4 years ago

AlgoQ commented 4 years ago

When I'm using another dataframe from a file an try out the backtesting Quick Start strategy I get the message at the parameter '_trades' that the Dataframe empty is, although it isn't. Can someone help me out?

Code:

import numpy as np
import pandas as pd
import json

from backtesting import Strategy, Backtest
from backtesting.test import GOOG
from backtesting.lib import crossover

# Define ohlcv
with open('E:/Work/histCryptoDatafeed/ohlcv_binanceF_BTCUSDT_14days.json') as json_file:
    data = json.load(json_file)

ohlcv = pd.DataFrame(data, columns=['Date', 'Open', 'High', 'Low', 'Close', 'Volume'])
ohlcv['Date'] = pd.to_datetime(ohlcv['Date'], unit='ms')
ohlcv = ohlcv.set_index('Date')

def SMA(values, n):
    """
    Return simple moving average of `values`, at
    each step taking into account `n` previous values.
    """
    return pd.Series(values).rolling(n).mean()

class SmaCross(Strategy):
    # Define the two MA lags as *class variables*
    # for later optimization
    n1 = 5
    n2 = 10

    def init(self):
        # Precompute the two moving averages
        self.sma1 = self.I(SMA, self.data.Close, self.n1)
        self.sma2 = self.I(SMA, self.data.Close, self.n2)

    def next(self):
        # If sma1 crosses above sma2, close any existing
        # short trades, and buy the asset
        if crossover(self.sma1, self.sma2):
            self.position.close()
            self.buy()

        # Else, if sma1 crosses below sma2, close any existing
        # long trades, and sell the asset
        elif crossover(self.sma2, self.sma1):
            self.position.close()
            self.sell()
print(ohlcv)
bt = Backtest(ohlcv, SmaCross, cash=1000, commission=.0003)

stats = bt.run()

print(stats)

Output:

                        Open     High      Low    Close  Volume
Date
2020-07-09 08:16:00  9400.80  9400.81  9399.45  9399.77  20.350
2020-07-09 08:17:00  9399.78  9400.46  9398.36  9398.62  41.819
2020-07-09 08:18:00  9398.94  9399.87  9398.26  9399.87  24.911
2020-07-09 08:19:00  9399.87  9399.87  9398.31  9398.31  13.406
2020-07-09 08:20:00  9398.32  9399.80  9398.00  9398.20  86.632
...                      ...      ...      ...      ...     ...
2020-07-23 05:31:00  9480.73  9482.37  9480.00  9482.36  49.347
2020-07-23 05:32:00  9482.37  9482.50  9482.00  9482.01  11.154
2020-07-23 05:33:00  9482.01  9482.01  9480.90  9481.46   9.794
2020-07-23 05:34:00  9481.45  9482.00  9478.64  9479.04  67.269
2020-07-23 05:35:00  9479.03  9479.04  9478.33  9479.01  20.141

[20000 rows x 5 columns]
Start                     2020-07-09 08:16:00
End                       2020-07-23 05:35:00
Duration                     13 days 21:19:00
Exposure Time [%]                           0
Equity Final [$]                         1000
Equity Peak [$]                          1000
Return [%]                                  0
Buy & Hold Return [%]                0.842999
Max. Drawdown [%]                          -0
Avg. Drawdown [%]                         NaN
Max. Drawdown Duration                    NaN
Avg. Drawdown Duration                    NaN
# Trades                                    0
Best Trade [%]                            NaN
Worst Trade [%]                           NaN
Avg. Trade [%]                            NaN
Max. Trade Duration                       NaN
Avg. Trade Duration                       NaN
Profit Factor                             NaN
Expectancy [%]                            NaN
SQN                                       NaN
Sharpe Ratio                              NaN
Sortino Ratio                             NaN
Calmar Ratio                              NaN
_strategy                            SmaCross
_equity_curve                             ...
_trades                   Empty DataFrame
...
dtype: object

Zipped data file: ohlcv_binanceF_BTCUSDT_14days.zip

kernc commented 4 years ago

Initial cash is 1000; prices are over 9000. Not a single unit can be bought.

AlgoQ commented 4 years ago

Oow okay, I thought it would buy smaller parts of a single unit. Good to know.

kernc commented 4 years ago

Yeah, few asset classes allow fractional ownership. And buying size=0.1 of something in Backtesting.py already means "spend 10% of available equity". For crypto like Bitcoin, you need to trade in fractional units, e.g. satoshis.