Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
samueltg92 opened this issue Oct 24, 2022 · 0 comments
Closed

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

samueltg92 opened this issue Oct 24, 2022 · 0 comments
Labels
bug Something isn't working

Comments

@samueltg92
Copy link

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
@kernc kernc closed this as completed in 3bccbd9 Dec 12, 2022
@kernc kernc added the bug Something isn't working label Dec 13, 2022
Goblincomet pushed a commit to Goblincomet/forex-trading-backtest that referenced this issue Jul 5, 2023
Avoids computing argmax on an empty sequence.

Fixes kernc/backtesting.py#789
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants