Skip to content

ValueError: attempt to get argmax of an empty sequence #789

Closed
@samueltg92

Description

@samueltg92

Expected Behavior

I calculated support & resistance and then created a function ("SIGNAL") that returns a list of signals, when I created the indicator "self.signal" on the "init" function, I passed the "SIGNAL" function. But when I tried to get the stats of the backtest, i get the next exception: "ValueError: attempt to get argmax of an empty sequence".

Actual Behavior

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/tmp/ipykernel_6680/2172180610.py in <module>
      5 # --------------------------------Stats--------------------------------
      6 bt = Backtest(df1, S_R_RSI, cash=1000000, margin=1/1, commission = 0.0006, trade_on_close=True, hedging=True)
----> 7 stat = bt.run()
      8 print(stat)
      9 # print(f'Ret/DD Ratio: {retDD_ratio(stat)}')

~/miniconda3/envs/TRADING/lib/python3.9/site-packages/backtesting/backtesting.py in run(self, **kwargs)
   1137         strategy: Strategy = self._strategy(broker, data, kwargs)
   1138 
-> 1139         strategy.init()
   1140         data._update()  # Strategy.init might have changed/added to data.df
   1141 

/tmp/ipykernel_6680/1588484572.py in init(self)
     25         close = self.data.Close
     26 
---> 27         self.signal = self.I(lambda: SIGNAL)
     28         self.rsi = self.I(lambda: ta.rsi(self.data.Close.s, length=self.rsi_window))
     29 

~/miniconda3/envs/TRADING/lib/python3.9/site-packages/backtesting/backtesting.py in I(self, func, name, plot, overlay, color, scatter, *args, **kwargs)
    137 
    138         # Optionally flip the array if the user returned e.g. `df.values`
--> 139         if is_arraylike and np.argmax(value.shape) == 0:
    140             value = value.T
    141 

~/miniconda3/envs/TRADING/lib/python3.9/site-packages/numpy/core/overrides.py in argmax(*args, **kwargs)

~/miniconda3/envs/TRADING/lib/python3.9/site-packages/numpy/core/fromnumeric.py in argmax(a, axis, out, keepdims)
   1214     """
   1215     kwds = {'keepdims': keepdims} if keepdims is not np._NoValue else {}
-> 1216     return _wrapfunc(a, 'argmax', axis=axis, out=out, **kwds)
   1217 
   1218 

~/miniconda3/envs/TRADING/lib/python3.9/site-packages/numpy/core/fromnumeric.py in _wrapfunc(obj, method, *args, **kwds)
     52     bound = getattr(obj, method, None)
     53     if bound is None:
---> 54         return _wrapit(obj, method, *args, **kwds)
     55 
     56     try:

~/miniconda3/envs/TRADING/lib/python3.9/site-packages/numpy/core/fromnumeric.py in _wrapit(obj, method, *args, **kwds)
     41     except AttributeError:
     42         wrap = None
---> 43     result = getattr(asarray(obj), method)(*args, **kwds)
     44     if wrap:
     45         if not isinstance(result, mu.ndarray):

ValueError: attempt to get argmax of an empty sequence

Steps to Reproduce

import warnings
warnings.simplefilter(action='ignore', category=RuntimeWarning)
warnings.simplefilter(action='ignore', category=FutureWarning)
import pandas_ta as ta 
import pandas as pd
from binance.client import Client
from dotenv import load_dotenv
import os
from datetime import datetime, date, timedelta
import matplotlib.pyplot as plt
from backtesting import Strategy, Backtest
import numpy as np
from binance.enums import HistoricalKlinesType
import pandas_montecarlo

# Data
load_dotenv()

public = os.getenv('PUBLIC1')
private = os.getenv('SECRET1')

def save_data(symbol,interval,start_date,end_date):
    
    
    client = Client(public,private)

    history = client.get_historical_klines_generator(symbol = symbol, interval = interval, start_str = start_date, end_str=end_date,klines_type=HistoricalKlinesType.FUTURES)
    df = pd.DataFrame(data = history)
    clean_df = df.drop(columns=[0,7,8,9,10,11])
    clean_df.columns = ['Open','High','Low','Close','Volume','time']
    clean_df['time'] = pd.to_datetime(clean_df['time'], unit='ms')
    dict_cols = {'Open':float, 'High':float, 'Low':float, 'Close':float,'Volume':float}
    newdf = clean_df.astype(dict_cols)
    newdf.set_index('time', inplace=True)
    
    return newdf

df = save_data(symbol='BTCUSDT',interval='1h',start_date='31 Jan, 2020',end_date='17 Oct, 2022')
df1 = save_data(symbol='BTCUSDT',interval='1h',start_date='31 Jan, 2020',end_date='17 Feb, 2022')

# S&R and signal calculation 
def support(data, l, n1, n2): #n1 n2 before and after candle l
    for i in range(l - n1 + 1, l + 1):
        if(data.Low[i] > data.Low[i - 1]):
            return 0
    for i in range(l + 1, l + n2 + 1):
        if(data.Low[i] < data.Low[i - 1]):
            return 0
    return 1

def resistance(data, l, n1, n2): #n1 n2 before and after candle l
    for i in range(l - n1 + 1, l + 1):
        if(data.High[i] < data.High[i - 1]):
            return 0
    for i in range(l + 1, l + n2 + 1):
        if(data.High[i] > data.High[i - 1]):
            return 0
    return 1

def closeResistance(l,levels,lim):
    if len(levels)==0:
        return 0
    c1 = abs(df.High[l]-min(levels, key=lambda x:abs(x-df.High[l])))<=lim
    c2 = abs(max(df.Open[l],df.Close[l])-min(levels, key=lambda x:abs(x-df.High[l])))<=lim
    c3 = min(df.Open[l],df.Close[l])<min(levels, key=lambda x:abs(x-df.High[l]))
    c4 = df.Low[l]<min(levels, key=lambda x:abs(x-df.High[l]))
    if( (c1 or c2) and c3 and c4 ):
        return 1
    else:
        return 0
    
def closeSupport(l,levels,lim):
    if len(levels)==0:
        return 0
    c1 = abs(df.Low[l]-min(levels, key=lambda x:abs(x-df.Low[l])))<=lim
    c2 = abs(min(df.Open[l],df.Close[l])-min(levels, key=lambda x:abs(x-df.Low[l])))<=lim
    c3 = max(df.Open[l],df.Close[l])>min(levels, key=lambda x:abs(x-df.Low[l]))
    c4 = df.High[l]>min(levels, key=lambda x:abs(x-df.Low[l]))
    if( (c1 or c2) and c3 and c4 ):
        return 1
    else:
        return 0

n1 = 2
n2 = 2
backcandles = 30
close = df.Close[-1]
signal = [0] * len(df)

for row in range(backcandles, len(df)-n2):
    ss = []
    rr = []
    for subrow in range(row-backcandles+n1, row+1):
        if support(df, subrow, n1, n2):
            ss.append(df.Low[subrow])
        if resistance(df, subrow, n1, n2):
            rr.append(df.High[subrow])
            
    if close <= closeSupport(row,ss,0.1):
        signal[row] = 1
    elif close >= closeResistance(row,rr,0.1):
        signal[row] = 2
    else:
        signal[row] = 0

df['signal'] = signal
df

def SIGNAL():
    return df.signal

# Strategy
class S_R_RSI(Strategy):
    
    riskpct = 0.01
    rsi_window = 14
    ob = 70
    os = 30
    sl_buy = 0.97
    sl_sell = 1.03
    tp_buy = 1.005
    tp_sell = 0.995
      
    n1 = 2
    n2 = 2
    
    def init(self):
        super().init()
        high = self.data.High
        low = self.data.Low
        close = self.data.Close

        self.signal = self.I(lambda: SIGNAL)
        self.rsi = self.I(lambda: ta.rsi(self.data.Close.s, length=self.rsi_window))
        
        
    def next(self):
        super().next()
        price = self.data.Close[-1]

        
        if self.position:
            self.position.close()


        if self.signal == 1 and self.rsi < self.os: 
            self.position.close()       
            
            self.buy(sl = self.sl_buy * price, tp = self.tp_buy * price, size = self.riskpct)
            
        elif self.signal == 2 and self.rsi > self.ob:
            self.position.close()

            self.sell(sl = self.sl_sell*price, tp = self.tp_sell * price, size=self.riskpct)

# Results
bt = Backtest(df1, S_R_RSI, cash=1000000, margin=1/1, commission = 0.0006, trade_on_close=True, hedging=True)
stat = bt.run()
print(stat)

Additional info

  • Backtesting version: 0.0.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions