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.45k stars 1.06k forks source link

taLib not being able to use backtesting array during next in strategy #409

Closed alizain5693 closed 3 years ago

alizain5693 commented 3 years ago

Expected Behavior

I wanted to use the data of the latest candle within the next method to see if it conformed to a particular bullish/bearish pattern. I'm using the talib library. I expected to get true or false answers.

Actual Behavior

I'm getting an error saying: expected numpy ndarray got numpy float64. I just typecasted but that doesn't seem to work.

Steps to Reproduce

  1. Get talib library for python
  2. define any basic strategy
  3. in next() function try to use the data to use talib.CDLHANGINGMAN(open,high,low,close)

Additional info

I'm new to using python libs, any feedback or help is appreciated.

kernc commented 3 years ago

I'm getting an error saying: expected numpy ndarray got numpy float64.

A full stack trace would be nice.

  1. in next() function try to use the data to use talib.CDLHANGINGMAN(open,high,low,close)

Can you show a code example how you're using it?

alizain5693 commented 3 years ago

Thanks for responding

Traceback (most recent call last):
  File "C:\Users\aliza\Documents\CexTrading\bybit-heikin-ashi\testingback.py", line 138, in <module>
    stats = bt.run()
  File "C:\Users\aliza\AppData\Local\Programs\Python\Python39\lib\site-packages\backtesting\backtesting.py", line 1165, in run
    strategy.next()
  File "C:\Users\aliza\Documents\CexTrading\bybit-heikin-ashi\testingback.py", line 130, in next
    if(bearish(self.data.Open[-1],self.data.High[-1],self.data.Low[-1],self.data.Close[-1])):
  File "C:\Users\aliza\Documents\CexTrading\bybit-heikin-ashi\testingback.py", line 78, in bearish
    if(talib.CDLHANGINGMAN(o,h,l,c)):
  File "C:\Users\aliza\AppData\Local\Programs\Python\Python39\lib\site-packages\talib\__init__.py", line 27, in wrapper       
    return func(*args, **kwargs)
TypeError: Argument 'open' has incorrect type (expected numpy.ndarray, got numpy.float64)
class EMAcross(Strategy):
    a = 9
    profit = 2
    loss = 1

    def init(self):
        self.ema1 = self.I(EMA, self.data.Close, self.a)

    def next(self):
        if crossover(self.data.Close, self.ema1):
            success = self.data.Close * (1+(self.profit)/100)
            fail = self.data.Close * (1-(self.loss)/100)
            self.position.close()
            print('Checking Bullish: ',self.data.Open[-1],self.data.High[-1],self.data.Low[-1],self.data.Close[-1])
            if(bullish(self.data.Open[-1],self.data.High[-1],self.data.Low[-1],self.data.Close[-1])):
                self.buy(sl = fail, tp = success)

        # long trades, and sell the asset
        elif crossover(self.ema1, self.data.Close):
            success = self.data.Close * (1-(self.profit)/100)
            fail = self.data.Close * (1+(self.loss)/100)
            self.position.close()
            if(bearish(self.data.Open[-1],self.data.High[-1],self.data.Low[-1],self.data.Close[-1])):
                self.sell(sl = fail, tp = success)
kernc commented 3 years ago
Argument 'open' has incorrect type (expected numpy.ndarray, got numpy.float64)

This refers to the argument o being a single float64 rather than an array of floats. self.data.Open[-1] is a single numeric value and talib.CDLHANGINGMAN() seems to expect whole arrays.

alizain5693 commented 3 years ago

That's what I thought. I tested it separately with hard coded single numeric values and it worked fine.

alizain5693 commented 3 years ago

I made a bunch of changes. but for some reason, it's not doing any trades. sorry if I'm missing something obvious.

# strategy
class EMAcross(Strategy):
    profit = 2
    loss = 1

    def init(self):
        self.bullish = self.I(bullish, self.data.Open,self.data.High,self.data.Low,self.data.Close)
        self.bearish = self.I(bearish, self.data.Open,self.data.High,self.data.Low,self.data.Close)

    def next(self):
        if(self.bullish>0):
            success = self.data.Close * (1+(self.profit)/100)
            fail = self.data.Close * (1-(self.loss)/100)
            self.position.close()
            self.buy(sl = fail, tp = success)
            print("BUY")

        elif(self.bearish<0):   
            success = self.data.Close * (1-(self.profit)/100)
            fail = self.data.Close * (1+(self.loss)/100)
            self.position.close()
            self.sell(sl = fail, tp = success)
            print("SELL")

It prints when the buy and sell signals come but doesn't do any trades. bullish and bearish are lists calculated in the init method so no talib issues. bullish can be 0 or 100 and bearish can be 0 or -100.

INITIAL STATS
Start                                     0.0
End                                   47017.0
Duration                              47017.0
Exposure Time [%]                         0.0
Equity Final [$]                       1000.0
Equity Peak [$]                        1000.0
Return [%]                                0.0
Buy & Hold Return [%]               90.018874
Return (Ann.) [%]                         NaN
Volatility (Ann.) [%]                     NaN
Sharpe Ratio                              NaN
Sortino Ratio                             NaN
Calmar Ratio                              NaN
Max. Drawdown [%]                        -0.0
Avg. Drawdown [%]                         NaN
Max. Drawdown Duration                    NaN
Avg. Drawdown Duration                    NaN
# Trades                                  0.0
Win Rate [%]                              NaN
Best Trade [%]                            NaN
Worst Trade [%]                           NaN
Avg. Trade [%]                            NaN
Max. Trade Duration                       NaN
Avg. Trade Duration                       NaN
Profit Factor                             NaN
Expectancy [%]                            NaN
SQN                                       NaN
_strategy                            EMAcross
_equity_curve                    Equity  D...
_trades                   Empty DataFrame
alizain5693 commented 3 years ago
# strategy
class EMAcross(Strategy):
    a = 9
    profit = 2
    loss = 1

    def init(self):
        self.ema1 = self.I(EMA, self.data.Close, self.a)
        # self.bullish = self.I(bullish, self.data.Open,self.data.High,self.data.Low,self.data.Close)
        # self.bearish = self.I(bearish, self.data.Open,self.data.High,self.data.Low,self.data.Close)

    def next(self):
        # If sma1 crosses above sma2, close any existing
        # short trades, and buy the asset
        if crossover(self.data.Close, self.ema1):
            if((self.data.Hammer>0) or (self.data.InvertedHammer>0) or (self.data.Engulfing>0) or (self.data.Piercing>0) or(self.data.MorningStar>0) or (self.data.WhiteSoldiers>0) ):
            # if(self.data.Hammer>0):
                success = self.data.Close * (1+(self.profit)/100)
                fail = self.data.Close * (1-(self.loss)/100)
                self.position.close()
                self.buy(sl = fail, tp = success)   
                print("BUY")
            else:
                pass

        # Else, if sma1 crosses below sma2, close any existing
        # long trades, and sell the asset
        elif crossover(self.ema1, self.data.Close):
            if((self.data.HangingMan<0) or (self.data.ShootingStar<0) or (self.data.Engulfing<0) or (self.data.EveningStar<0) or (self.data.BlackCrows<0) or (self.data.DarkCloudCover<0)):   
            # if(self.data.HangingMan<0):
                success = self.data.Close * (1-(self.profit)/100)
                fail = self.data.Close * (1+(self.loss)/100)
                self.position.close()
                self.sell(sl = fail, tp = success)
                print("SELL")
            else:
                pass

Every indicator is now in the dataframe but still not making any trades. it is printing when it sees buy and sell signals.