Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    1. Home
    2. Lammy
    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/
    L
    • Profile
    • Following 0
    • Followers 0
    • Topics 2
    • Posts 6
    • Best 0
    • Groups 0

    Posts made by Lammy

    • RE: Issue with BuySell obverver plot from cerebro.plot(). Disappearing with few data points

      @backtrader

      You are absolutely right, the problem is not with backtrader, but rather with matplotlib. Taking a look at the (excellent) documentation and previous questions have highlighted that for me.

      I will post my workaround as soon as I am done.
      For others who are stuggeling here, take a look at:

      https://www.backtrader.com/docu/observers-reference.html?highlight=buysell#backtrader.observers.BuySell
      https://www.backtrader.com/blog/posts/2016-12-10-buysellarrows/buysellarrows.html
      https://community.backtrader.com/topic/8/change-buysell-to-trade-arrows-in-charts-213/3

      posted in General Code/Help
      L
      Lammy
    • Issue with BuySell obverver plot from cerebro.plot(). Disappearing with few data points

      Hello,

      After a while of trying to trace the source of my missing BuySell indicators, I think the issue is with backtrader.
      Consider the following example:

      class St(bt.Strategy):
      
      	def __init__(self):
      		self.dataclose = self.datas[0].close
      
      	def next(self):
      		if self.dataclose[0] > 2944:
      			self.order = self.sell()
      
      
      data = bt.feeds.BacktraderCSVData(dataname='data.csv')
      
      cerebro = bt.Cerebro()
      cerebro.adddata(data)
      cerebro.addstrategy(St)
      cerebro.run()
      cerebro.plot()
      

      With data.csv

      Date,Open,High,Low,Close,Volume,OpenInterest
      2005-01-03,2952.29,2989.61,2946.80,2970.02,0,0
      2005-01-04,2969.78,2979.88,2961.14,2971.12,0,0
      2005-01-05,2969.00,2969.00,2942.69,2947.19,0,0
      2005-01-06,2947.44,2967.65,2947.44,2966.24,0,0
      2005-01-07,2965.54,2988.99,2964.48,2979.82,0,0
      2005-01-10,2980.30,2986.07,2967.79,2977.21,0,0
      2005-01-11,2977.14,2981.51,2943.42,2949.29,0,0
      2005-01-12,2948.89,2952.79,2914.00,2924.01,0,0
      2005-01-13,2925.60,2943.09,2922.91,2936.32,0,0
      2005-01-14,2933.58,2951.77,2925.13,2948.22,0,0
      2005-01-17,2948.11,2963.22,2948.11,2963.06,0,0
      2005-01-18,2962.28,2965.60,2940.77,2962.50,0,0
      2005-01-19,2963.91,2976.33,2957.21,2959.90,0,0
      2005-01-20,2957.55,2957.55,2929.78,2937.71,0,0
      2005-01-21,2937.27,2944.92,2927.62,2940.87,0,0
      2005-01-24,2939.68,2940.02,2916.08,2937.83,0,0
      2005-01-25,2937.66,2960.90,2932.56,2958.61,0,0
      2005-01-26,2958.31,2967.62,2954.36,2956.43,0,0
      2005-01-27,2956.32,2970.81,2948.55,2970.81,0,0
      2005-01-28,2969.91,2977.99,2950.68,2955.89,0,0
      2005-01-31,2958.07,2987.88,2958.07,2984.75,0,0
      2005-02-01,2984.63,3008.85,2982.06,3008.85,0,0
      2005-02-02,3009.08,3022.87,3008.92,3021.95,0,0
      2005-02-03,3021.94,3023.85,3001.87,3010.39,0,0
      2005-02-04,3011.58,3038.31,3011.58,3037.13,0,0
      

      This yields:

      alt text

      But delete the last 6 dates from data.csv and you will end up with this:

      alt text

      In addition, if my data is on hourly resolution, all BuySell markers disappear, no matter how many hours I include.

      Any idea what to do?

      posted in General Code/Help
      L
      Lammy
    • RE: Dynamically set params and lines attribute of class PandasData

      Big Thanks to @backtrader

      Dynamic subclassing did the job. Absolutely fantastic!

      @Robin-Dhillon

      Thanks for your input. May problem was though that I had a no information about the column names of my data, hence I did not know upfront if there is a e.g. "closed" column.

      posted in General Code/Help
      L
      Lammy
    • RE: Dynamically set params and lines attribute of class PandasData

      @Robin-Dhillon

      Sorry. Edit is not working.

      Can you specify how you initialize a new line in a a strategy based on a column in the existing dataframe?

      posted in General Code/Help
      L
      Lammy
    • RE: Dynamically set params and lines attribute of class PandasData

      Apparently I should have given it a second try when using setattr().
      Adding:

      setattr(BacktraderDataDefintion.params,"col_a",-1)
      

      Seems to work.

      class BacktraderDataDefintion(bt.feeds.PandasData):
            
          lines = ("col_a",)
      
          params = (
              ('datetime', None),
              ('open', -1),
              # ('high', None),
              # ('low', None),
              ('close', -1),
              # ('volume', None),
          )
      
       if __name__ == '__main__':
            
                cerebro = bt.Cerebro()
            
                cerebro.addstrategy(TestStrategy)
            
                cerebro.broker.setcommission(commission=0.001)
            
            
            
                #Add params
            
                setattr(BacktraderDataDefintion.params,"col_a",-1)
            
                # Create a Data Feed
            
                data = BacktraderDataDefintion(dataname=createSampleData())
            
            
            
                cerebro.adddata(data)
            
                cerebro.broker.setcash(10000.0)
            
                print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
            
                cerebro.run()
            
                print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())  
      

      However, I am lost on the "lines" class attribute. Especially because of this:

      dir(BacktraderDataDefintion.lines)
      
      
      prints
      ['__class__',
      '__delattr__',
      ..
      'buflen',
      'close',
      'col_a',
      'datetime',
      'extend',
      ...
      'size',
      'volume']
      
      

      but:

      getattr(BacktraderDataDefintion.lines,"col_a")
      
      ---------------------------------------------------------------------------
      AttributeError                            Traceback (most recent call last)
      ...
      
      AttributeError: 'NoneType' object has no attribute 'lines'
      

      How is this possible?

      @Robin-Dhillon Manipulating the *.csv is not an option.

      posted in General Code/Help
      L
      Lammy
    • Dynamically set params and lines attribute of class PandasData

      Hello,

      I am very new to backtrader and hope to get some advise here.

      Here is what I am trying to do:
      Assuming I get data as pandas dataframe. One or more columns are to be used in the strategy, but I don't know their name. How can I dynamically change the "params" attribute of bt.feeds.PandasData? Note that the resulting complications with the strategy are irrelevant at that piont.

      Consider the following reproducible example:
      import datetime
      import backtrader as bt
      import numpy as np
      import pandas as pd

      class TestStrategy(bt.Strategy):
      	def log(self, txt, dt=None):
      		dt = dt or self.datas[0].datetime.date(0)
      		print('%s, %s' % (dt.isoformat(), txt))
      
      	def __init__(self):
      		self.dataclose = self.datas[0].close
      		self.col_a = self.datas[0].col_a
      		self.order = None
      		self.buyprice = None
      		self.buycomm = None
      		
      	def notify_order(self, order):
      		if order.status in [order.Submitted, order.Accepted]:
      			return
      
      		if order.status in [order.Completed]:
      			if order.isbuy():
      				self.log(
      					'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
      					(order.executed.price,
      					 order.executed.value,
      					 order.executed.comm))
      
      				self.buyprice = order.executed.price
      				self.buycomm = order.executed.comm
      			else:  # Sell
      				self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
      						 (order.executed.price,
      						  order.executed.value,
      						  order.executed.comm))
      
      			self.bar_executed = len(self)
      
      		elif order.status in [order.Canceled, order.Margin, order.Rejected]:
      			self.log('Order Canceled/Margin/Rejected')
      
      		# Write down: no pending order
      		self.order = None
      
      	def notify_trade(self, trade):
      		if not trade.isclosed:
      			return
      
      		self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
      				 (trade.pnl, trade.pnlcomm))
      
      	def next(self):
      		self.log('Close, %.2f' % self.dataclose[0])
      		if self.order:
      			return
      
      		if not self.position:
      			if (self.col_a[0] < 1):
      				self.log('BUY CREATE, %.2f' % self.dataclose[0])
      				self.order = self.buy(size=500)
      
      		else:
      			if (self.col_a[0] > 1):
      				self.log('SELL CREATE, %.2f' % self.dataclose[0])
      				self.order = self.sell(size=500)
      
      class BacktraderDataDefintion(bt.feeds.PandasData):
      	  
      	lines = ("col_a",)
      
      	params = (
      		('datetime', None),
      		('open', -1),
      		# ('high', None),
      		# ('low', None),
      		('close', -1),
      		# ('volume', None),
      		('col_a', -1),
      	)                
      def createSampleData():
      	
      	a = np.random.randint(0,4,size=15)
      	open = np.random.randint(0,10,size=15)
      	close = np.random.randint(0,10,size=15)
      	df = pd.DataFrame({"Open":open,"Close":close,"col_a" if a[0] <= 1 else "col_b":a}, index=pd.date_range('2018-01-01', periods=15, freq='H'))
      	return df
      
      if __name__ == '__main__':
      	cerebro = bt.Cerebro()
      	cerebro.addstrategy(TestStrategy)
      	cerebro.broker.setcommission(commission=0.001)
      
      	# Create a Data Feed
      	data = BacktraderDataDefintion(dataname=createSampleData())
      
      	cerebro.adddata(data)
      	cerebro.broker.setcash(10000.0)
      	print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
      	cerebro.run()
      	print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
      

      As you can see the data sometimes has a column called "col_a" or "col_b". How can I make sure that the attribute tuple "lines" and "params" in class "BacktraderDataDefintion" get adjusted automatically, depending on the pandas DataFrame?

      The expected output would be:

      lines = ("col_a",)
      
      params = (
      	('datetime', None),
      	('open', -1),
      	# ('high', None),
      	# ('low', None),
      	('close', -1),
      	# ('volume', None),
      	('col_a', -1),
      ) 
      

      or

      lines = ("col_b",)
      
      params = (
      	('datetime', None),
      	('open', -1),
      	# ('high', None),
      	# ('low', None),
      	('close', -1),
      	# ('volume', None),
      	('col_b', -1),
      ) 
      

      depending on the columns in dataframe "df".

      Hopefully someone has an idea.

      posted in General Code/Help
      L
      Lammy
    • 1 / 1