Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    1. Home
    2. Zhangjt9317
    3. Posts
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/
    • Profile
    • Following 0
    • Followers 0
    • Topics 2
    • Posts 3
    • Best 0
    • Groups 0

    Posts made by Zhangjt9317

    • RE: extending data feed ==> list index out of range issue

      thank you all for the response, I solve the problem by following the documentation, just make sure you count the column number correctly (start from 0) and follow the extending data section in doc

      posted in General Code/Help
      Zhangjt9317
      Zhangjt9317
    • help on a customized strategy

      Hi, I am new to bt and the algo trading, and I really need help with a strategy I am building.

      I have 1-min BTC data OHLCV + (day-based) forecast price predicted using the model. I am trying to run a backtest using 1min data. The data looks like this:

      ,date,time,open,high,low,close,volume,close_time,average,Forecast
      0,2017-08-17,2017-08-17 04:00:00,4261.48,4261.48,4261.48,4261.48,1.7751830000000002,1502942459999,4308.1725,4303.864329999999
      1,2017-08-17,2017-08-17 04:01:00,4261.48,4261.48,4261.48,4261.48,0.0,1502942519999,4308.1725,4303.864329999999
      2,2017-08-17,2017-08-17 04:02:00,4280.56,4280.56,4280.56,4280.56,0.261074,1502942579999,4308.1725,4303.864329999999
      3,2017-08-17,2017-08-17 04:03:00,4261.48,4261.48,4261.48,4261.48,0.012008,1502942639999,4308.1725,4303.864329999999
      4,2017-08-17,2017-08-17 04:04:00,4261.48,4261.48,4261.48,4261.48,0.140796,1502942699999,4308.1725,4303.864329999999
      5,2017-08-17,2017-08-17 04:05:00,4261.48,4261.48,4261.48,4261.48,0.0,1502942759999,4308.1725,4303.864329999999
      6,2017-08-17,2017-08-17 04:06:00,4261.48,4261.48,4261.48,4261.48,0.0,1502942819999,4308.1725,4303.864329999999
      7,2017-08-17,2017-08-17 04:07:00,4261.48,4261.48,4261.48,4261.48,0.0,1502942879999,4308.1725,4303.864329999999
      8,2017-08-17,2017-08-17 04:08:00,4261.48,4261.48,4261.48,4261.48,0.0,1502942939999,4308.1725,4303.864329999999
      9,2017-08-17,2017-08-17 04:09:00,4261.48,4261.48,4261.48,4261.48,0.0,1502942999999,4308.1725,4303.864329999999
      
      

      The forecast price varies by days, and I am trying to do backtest on minutes, that's why they look the same

      The strategy is:

      • Open trade at the daily open price.
      • Long if forecast > open price, short if forecast < open price.
      • Close trade at forecast price or at stop-loss (potential gain == potential loss), whichever reaches first.

      I have $10000 cash and trying to buy BTC as much as I can every time (not sure if this is called all-in)

      and I am trying to set the stop loss condition to just when the trade reaches back to the forecast price

      class Data_Extend(GenericCSVData):
          lines = ('Forecast',)  # add a 'Forecast' line to the inherited ones from the base class
          params = (('Forecast', 7),) # forecast column location
      
      # using a signal strategy here 
      class FStrategy(bt.SignalStrategy):
          params = dict(
              stake=1,
              printout=True,
              csvcross=True,
              period=7,
              startcash=10000,
              target_perc=1.0,
          )
      
          def log(self, txt, dt=None):
              if self.p.printout:
                  dt = dt or self.data.datetime[0]
                  dt = bt.num2date(dt)
                  print('%s, %s' % (dt.isoformat(), txt))
      
          def notify_order(self, order):
              if order.status in [bt.Order.Submitted, bt.Order.Accepted]:
                  return  # Await further notifications
      
              if order.status == order.Completed:
                  if order.isbuy():
                      buytxt = 'BUY COMPLETE, %.2f' % order.executed.price
                      self.log(buytxt, order.executed.dt)
      
                  else:
                      selltxt = 'SELL COMPLETE, %.2f' % order.executed.price
                      self.log(selltxt, order.executed.dt)
      
              elif order.status in [order.Expired, order.Canceled]:
                  self.log('%s ,' % order.Status[order.status])
                  pass  # Simply log
      
              # Allow new orders
              self.orderid = None
      
          def __init__(self):
              self.orderid = None
      
              # there is only 1 data feed, so it is the same anyway
              self.dataclose = self.datas[0].close
              self.dataopen = self.datas[0].open
              self.dataforecast = self.datas[0].Forecast
      
              # long condition (with exit)T
              self.signal_long = self.dataforecast > self.dataopen
              # multi head signal 1 ==> long when forecast > open
              self.signal_add(bt.SIGNAL_LONG, self.signal_long)
              # LONGEXIT: short indications are taken to exit long positions
              self.long_exit = self.dataforecast <= self.dataopen
              self.signal_add(bt.SIGNAL_LONGEXIT, self.long_exit)
      
              # short condition (with exit)
              self.signal_short = self.dataforecast < self.dataopen
              self.signal_add(bt.SIGNAL_SHORT, self.signal_short)
              # SHORTEXIT: long indications are taken to exit short positions
              self.short_exit = self.dataforecast <= self.dataopen
              self.signal_add(bt.SIGNAL_SHORTEXIT, self.short_exit)
      
          def next(self):
              if self.orderid:
                  return  # if an order is active, no new orders are allowed
      
              if not self.position:  # not yet in market
                  sizer = self.broker.get_cash() / self.datas[0].open[0]
                  if self.signal_long:  # cross upwards
                      self.log('BUY CREATE @CLOSE , %.2f, OPEN %.2f, FORECAST %.2f' % (self.data.close[0], self.data.open[0], self.dataforecast[0]))
                      print('Position Size: %.2f BTC' % sizer)
                      self.order = self.buy(size=sizer)
                  elif self.long_exit:
                      self.log('CLOSE LONG , %.2f, OPEN %.2f, FORECAST %.2f' % (self.data.close[0], self.data.open[0], self.dataforecast[0]))
                      self.order = self.close(size=sizer)
      
              else:  # in the market
                  sizer = self.broker.getposition(data=self.datas[0]).size
                  if self.signal_short:  # short signal
                      self.log('SELL CREATE @CLOSE , %.2f, OPEN %.2f, FORECAST %.2f' % (self.data.close[0], self.data.open[0], self.dataforecast[0]))
                      print('Position Size: %.2f BTC' % sizer)
                      self.order = self.sell(size=sizer)
                  elif self.short_exit:
                      self.log('CLOSE SHORT , %.2f, OPEN %.2f, FORECAST %.2f' % (self.data.close[0], self.data.open[0], self.dataforecast[0]))
                      self.order = self.close(size=sizer)
      
      
          def stop(self):
              print('==================================================')
              print('Starting Value - %.2f' % self.broker.startingcash)
              print('Ending   Value - %.2f' % self.broker.getvalue())
              print('==================================================')
      

      In the next and init I log some info I want, and when I run using the data, the log looks like this:

      2019-01-01T23:59:59.999989, BUY CREATE @CLOSE , 3797.14, OPEN 3701.23, FORECAST 3728.05
      Position Size: 2.70 BTC
      2019-01-01T23:59:59.999989, BUY COMPLETE, 3797.14
      2019-01-02T23:59:59.999989, SELL CREATE @CLOSE , 3858.56, OPEN 3796.45, FORECAST 3742.63
      Position Size: 2.63 BTC
      2019-01-02T23:59:59.999989, SELL COMPLETE, 3858.56
      2019-01-03T23:59:59.999989, BUY CREATE @CLOSE , 3766.78, OPEN 3857.57, FORECAST 3863.28
      Position Size: 2.63 BTC
      2019-01-03T23:59:59.999989, BUY COMPLETE, 3766.78
      2019-01-05T23:59:59.999989, SELL CREATE @CLOSE , 3770.96, OPEN 3790.09, FORECAST 3770.63
      Position Size: 2.70 BTC
      2019-01-05T23:59:59.999989, SELL COMPLETE, 3770.96
      2019-01-06T23:59:59.999989, BUY CREATE @CLOSE , 3987.60, OPEN 3771.12, FORECAST 3797.46
      Position Size: 2.70 BTC
      2019-01-06T23:59:59.999989, BUY COMPLETE, 3987.60
      2019-01-07T23:59:59.999989, SELL CREATE @CLOSE , 3975.45, OPEN 3987.62, FORECAST 3925.53
      Position Size: 2.55 BTC
      2019-01-07T23:59:59.999989, SELL COMPLETE, 3975.45
      2019-01-08T23:59:59.999989, BUY CREATE @CLOSE , 3955.13, OPEN 3976.76, FORECAST 4001.77
      Position Size: 2.55 BTC
      2019-01-08T23:59:59.999989, BUY COMPLETE, 3955.13
      2019-01-10T23:59:59.999989, SELL CREATE @CLOSE , 3585.88, OPEN 3966.06, FORECAST 3965.74
      Position Size: 2.56 BTC
      2019-01-10T23:59:59.999989, SELL COMPLETE, 3585.88
      2019-01-11T23:59:59.999989, BUY CREATE @CLOSE , 3601.31, OPEN 3585.88, FORECAST 3670.85
      Position Size: 2.56 BTC
      2019-01-11T23:59:59.999989, BUY COMPLETE, 3601.31
      2019-01-12T23:59:59.999989, SELL CREATE @CLOSE , 3583.13, OPEN 3601.31, FORECAST 3528.85
      Position Size: 2.55 BTC
      2019-01-12T23:59:59.999989, SELL COMPLETE, 3583.13
      2019-01-13T23:59:59.999989, BUY CREATE @CLOSE , 3476.81, OPEN 3584.10, FORECAST 3611.51
      Position Size: 2.55 BTC
      2019-01-13T23:59:59.999989, BUY COMPLETE, 3476.81
      2019-01-15T23:59:59.999989, SELL CREATE @CLOSE , 3553.06, OPEN 3626.08, FORECAST 3600.16
      Position Size: 2.63 BTC
      2019-01-15T23:59:59.999989, SELL COMPLETE, 3553.06
      2019-01-16T23:59:59.999989, BUY CREATE @CLOSE , 3591.84, OPEN 3553.06, FORECAST 3578.68
      Position Size: 2.63 BTC
      2019-01-16T23:59:59.999989, BUY COMPLETE, 3591.84
      2019-01-17T23:59:59.999989, SELL CREATE @CLOSE , 3616.21, OPEN 3591.84, FORECAST 3585.79
      Position Size: 2.60 BTC
      2019-01-17T23:59:59.999989, SELL COMPLETE, 3616.21
      2019-01-18T23:59:59.999989, CLOSE LONG , 3594.87, OPEN 3613.32, FORECAST 3597.20
      2019-01-19T23:59:59.999989, BUY CREATE @CLOSE , 3665.30, OPEN 3594.87, FORECAST 3599.16
      Position Size: 2.62 BTC
      2019-01-19T23:59:59.999989, BUY COMPLETE, 3665.30
      
      Position Size: 1.71 BTC
      2019-12-29T23:59:59.999989, BUY COMPLETE, 7388.24
      ==================================================
      Starting Value - 10000.00
      Ending   Value - 12191.66
      ==================================================
      ===============================================================================
      TimeReturn:
        - 2019-01-31 00:00:00: -0.10192223974656367
        - 2019-02-28 00:00:00: 0.12747463642130064
        - 2019-03-31 00:00:00: 0.07017082291549426
        - 2019-04-30 00:00:00: -0.032682599108764476
        - 2019-05-31 00:00:00: 0.10385189267487394
        - 2019-06-30 00:00:00: 0.10896888494902579
        - 2019-07-31 00:00:00: -0.002396698888080584
        - 2019-08-31 00:00:00: -0.020199229864290236
        - 2019-09-30 00:00:00: 0.024766766780242477
        - 2019-10-31 00:00:00: 0.056789760260889555
        - 2019-11-30 00:00:00: -0.10789694777986258
        - 2019-12-31 00:00:00: 0.006156163558002525
      ===============================================================================
      SharpeRatio:
        - sharperatio: 0.24941200165758853
      ===============================================================================
      SQN:
        - sqn: 0.5616557528887063
        - trades: 126
      

      b66c9eaf-e27f-4d35-86ba-324f62787cef-image.png

      I do not really know if this is working well, I am especially confused with 3 things

      • size ==> is the size correct
      if not self.position:  # not yet in market
                  sizer = self.broker.get_cash() / self.datas[0].open[0]
      else:  # in the market
                  sizer = self.broker.getposition(data=self.datas[0]).size
      
      • close ==> is my way the right way to do it? I close both positions when
                  elif self.long_exit:
                      self.log('CLOSE LONG , %.2f, OPEN %.2f, FORECAST %.2f' % (self.data.close[0], self.data.open[0], self.dataforecast[0]))
                      self.order = self.close(size=sizer)
                  elif self.short_exit:
                      self.log('CLOSE LONG , %.2f, OPEN %.2f, FORECAST %.2f' % (self.data.close[0], self.data.open[0], self.dataforecast[0]))
                      self.order = self.close(size=sizer)
      
      • result ==> does the result look correct? I read many blogs, just wanna check

      Thank you if anybody can help.

      posted in Indicators/Strategies/Analyzers
      Zhangjt9317
      Zhangjt9317
    • extending data feed ==> list index out of range issue

      Hi, I am new to backtrader, and I have a minute-based OHLCV dataset for BTC price, but with an extra 'Forecast' column. I read the extending data feeds post and made my own datafeed class as shown below:

      class datafeed(GenericCSVData):
          lines = ('Forecast',)  # add a 'Forecast' line to the inherited ones from the base class
          params = (
              ('nullvalue', float('NaN')),
              ('dtformat', '%Y-%m-%d %H:%M:%S'),
              ('tmformat', '%H:%M:%S'),
              ('datetime', 1),
              ('open', 2),
              ('high', 3),
              ('low', 4),
              ('close', 5),
              ('volume', 6),
              ('Forecast', 11) # 11th col
          )
      

      and I am trying to compare the open price and forecast price as a signal

          def __init__(self):
              # To control operation entries
              self.orderid = None
      
              # Create a CrossOver Signal from close an moving average
              self.signal = self.data.Forecast - self.data.open
      

      But I have the error:

      Traceback (most recent call last):
        File "D:/DailyTradeForecast.py", line 228, in <module>
          runstrategy()
        File "D:/DailyTradeForecast.py", line 159, in runstrategy
          cerebro.run()
        File "C:\Users\anaconda3\lib\site-packages\backtrader\cerebro.py", line 1127, in run
          runstrat = self.runstrategies(iterstrat)
        File "C:\Users\anaconda3\lib\site-packages\backtrader\cerebro.py", line 1212, in runstrategies
          data.preload()
        File "C:\Users\anaconda3\lib\site-packages\backtrader\feed.py", line 688, in preload
          while self.load():
        File "C:\Users\anaconda3\lib\site-packages\backtrader\feed.py", line 479, in load
          _loadret = self._load()
        File "C:\Users\anaconda3\lib\site-packages\backtrader\feed.py", line 710, in _load
          return self._loadline(linetokens)
        File "C:\Users\anaconda3\lib\site-packages\backtrader\feeds\csvgeneric.py", line 148, in _loadline
          csvfield = linetokens[csvidx]
      IndexError: list index out of range
      
      Process finished with exit code 1
      

      I am not so sure what is wrong with my datafeed, or it is the error from the signal, can someone help?

      posted in General Code/Help
      Zhangjt9317
      Zhangjt9317
    • 1 / 1