For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

self.buy(size=1.5) does not work



  • We use the buy method with the params size = 1.5 ,but it does work. I use backtrader in cryptocurrency in btc/usdt market, but does not work, what should I do or how to modify the code so the backtrader support in cryptocurrency market ? thanks


  • administrators

    What doesn't exactly work?



  • For example , I have $10000 or 10000USDT ,and the price of BTC is 6500, so I can buy 1.53 BTC. So for the backtesting , I will buy 1.53 BTC , so in backtrader's buy method, I will set self.order = self.buy(size=1.53) , but doesn't work, the param size only accept the int value , float value doesn't work in backtrader.


  • administrators

    Some extra random details doesn't really show what isn't working.

    • Do you have a working code sample?
    • Do you try to run Market orders with close prices?
    • Do you use cheat-on-close?

    @ramoslin02 said in self.buy(size=1.5) does not work:

    The param size only accept the int value , float value doesn't work in backtrader.

    Can you let us know how you know that the float value doesn't work? Python is a dynamic type language ... you could even pass a string to size. There are no provisions forbidding you from using a float.



  • @backtrader ok , I can send you the code.

    class ThreeDaysBreakoutIndicator(bt.Indicator):
    lines=('up','down',)

    def __init__(self):
        self.addminperiod(4)
        self.plotinfo.plotmaster = self.data
    def next(self):
        self.up[0] = max(max(self.data.open.get(ago=-1,size=3)), max(self.data.close.get(ago=-1,size=3)))
        self.down[0] = min(min(self.data.open.get(ago=-1,size=3)),min(self.data.close.get(ago=-1,size=3)))
    

    class ThreeDaysBreakoutStrategy(bt.Strategy):

    def log(self,txt,dt=None):
        """ Loging function for this Strategy"""
        dt = dt or self.datas[0].datetime.date(0)
        print("%s, %s" % (dt.isoformat(), txt))
    
    def __init__(self):
        self.up_down = ThreeDaysBreakoutIndicator(self.data)
        self.buy_signal = CrossOver(self.data.close,self.up_down.up)
        self.sell_signal = CrossDown(self.data.close,self.up_down.down)
    
    def next(self):
        buy_price = self.data.close[0] * (1+0.002)
        sell_price = self.data.close[0] *(1-0.002) 
        cash = self.broker.get_cash()
        size = cash/buy_price
        # size = 1
        # print("cash = %f , will buy price = %f size = %f" %(cash,buy_price,size))
    
        if not self.position and self.buy_signal == 1:
            self.order = self.buy(size=size,price=buy_price)
    
        if self.getposition().size > 0 and self.sell_signal == 1:
            self.order = self.sell(size=self.getposition().size,price=sell_price)
    
    def notify_order(self,order):
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log("Buy executed = %f, volume = %f , position = %f" % (order.executed.price, order.executed.size,self.getposition().size))
            elif order.issell():
                self.log("Sell executed = %f, volume = %f, position = %f" % (order.executed.price, order.executed.size,self.getposition().size))
    

    it seems that the buy method does work , how can I make sure that my order will be completed with the set price and size. thanks



  • @ramoslin02

    in the next() method, my logic is like this: if I don't have any position , and my buy_signal is equal 1, I will buy the BTC , with the the set price and calculate the size I can buy , but doesn't work, how can I fixt this ? thanks .


  • administrators

    @ramoslin02 said in self.buy(size=1.5) does not work:

    how can I make sure that my order will be completed

    1. Read.
    • For example how to post code (see the top of the forum)

      For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/
      
    • Then the docs: Doc - Order Management and Execution

    1. Explain what doesn't work and why it doesn't or why you believe it doesn't. We have gone from
    • buy doesn't work and doesn't accept a float param

    to

    to

    But there is still not a single explanation as to why you believe it doesn't work. Not a log, not a chart: nothing.

    1. Your problem

    You are not getting matched because you are in all-in strategy.

    @ramoslin02 said in self.buy(size=1.5) does not work:

    if not self.position and self.buy_signal == 1:
        self.order = self.buy(size=size,price=buy_price)
    

    And because you use Market orders for which it doesn't matter which price you set. The market price will be used (that's why they are called Market orders)

    Furthermore

    @ramoslin02 said in self.buy(size=1.5) does not work:

    buy_price = self.data.close[0] * (1+0.002)

    You give yourself a buy_price which is even more expensive than the current close. Even if you use another order type (Limit for example), it is not understandable why you increase the price. You don't have cash enough to buy a more expensive price.

    1. You can use
    • cheat-on-close and use the current close and have an approximation. Worse than the actual default behavior.
    • cheat-on-open to make calculations before the market is open and get matched with the next market price (the opening tick)

    See:



  • @backtrader said in self.buy(size=1.5) does not work:

    Blog - Cheat On Open
    ok, thanks for your reply , but still I still don't solve my problem. Here is my code below.

    
    import backtrader as bt
    import pandas as pd
    from backtrader.indicators import CrossOver
    from backtrader.indicators import CrossDown
    from backtrader.order import Order
    
    pd.set_option('expand_frame_repr',False)
    pd.set_option('display.max_rows',10)
    
    def resample(rule_type='15T'):
        df = pd.read_hdf('/Users/Lins/Python/QuantTrade/BTDemo/program/BTCUSDT_1min_data.h5')
        df['datetime'] = df['open_time']
        df = df.resample(rule=rule_type,on='open_time',base=0,label='left',closed='left').agg({
            'open':'first',
            'close':'last',
            'volume':'sum',
            'high':'max',
            'low':'min',
        })
    
        df['datetime'] = df.index
        df = df[df['volume'] > 0]
        return df
    
    class ThreeDaysBreakoutIndicator(bt.Indicator):
        lines=('up','down',)
    
        def __init__(self):
            self.addminperiod(4)
            self.plotinfo.plotmaster = self.data
        def next(self):
            self.up[0] = max(max(self.data.open.get(ago=-1,size=3)), max(self.data.close.get(ago=-1,size=3)))
            self.down[0] = min(min(self.data.open.get(ago=-1,size=3)),min(self.data.close.get(ago=-1,size=3)))
    
    class ThreeDaysBreakoutStrategy(bt.Strategy):
    
        def log(self,txt,dt=None):
            """ Loging function for this Strategy"""
            dt = dt or self.datas[0].datetime.date(0)
            print("%s, %s" % (dt.isoformat(), txt))
    
        def __init__(self):
            self.up_down = ThreeDaysBreakoutIndicator(self.data)
            self.buy_signal = CrossOver(self.data.close,self.up_down.up)
            self.sell_signal = CrossDown(self.data.close,self.up_down.down)
    
        def next(self):
            # buy_price = self.data.close[0] * (1+0.002)
            # sell_price = self.data.close[0] *(1-0.002)
            # cash = self.broker.get_cash()
            # size = cash/buy_price
            # size = 1
            # print("cash = %f , will buy price = %f size = %f" %(cash,buy_price,size))
    
            if not self.position and self.buy_signal == 1:
                self.order = self.buy()
    
            if self.getposition().size > 0 and self.sell_signal == 1:
                self.order = self.sell()
    
        def notify_order(self,order):
            if order.status in [order.Completed]:
                if order.isbuy():
                    self.log("Buy executed = %f, volume = %f , position = %f" % (order.executed.price, order.executed.size,self.getposition().size))
                elif order.issell():
                    self.log("Sell executed = %f, volume = %f, position = %f" % (order.executed.price, order.executed.size,self.getposition().size))
    
    
    
    if __name__ == "__main__":
        cerebro = bt.Cerebro(cheat_on_open=True)
        cerebro.broker.set_cash(100000)
        df = resample(rule_type='1D')
        df = df[df.index > pd.to_datetime('20180601')]
        data = bt.feeds.PandasData(dataname=df)
        cerebro.broker.setcommission(commission=0.002)
        # cerebro.broker.set_slippage_perc(perc=0.005)
        # cerebro.broker.set_slippage_perc()
        cerebro.adddata(data)
        cerebro.addobserver(bt.observers.TimeReturn)
        cerebro.addstrategy(ThreeDaysBreakoutStrategy)
    
        # cerebro.addwriter(bt.WriterFile,csv=True,out='ThreeDaysBreakoutStrategy.csv')
    
        print("The initial Cash = %.2f" %cerebro.broker.get_cash())
        cerebro.run()
        print("The final Cash = %.2f" % cerebro.broker.get_cash())
    
        cerebro.plot(style='candle')
        # here is the log for executing the code 
        """
          The initial Cash = 100000.00
          2018-06-19, Buy executed = 6711.390000, volume = 1.000000 , position = 1.000000
          2018-06-23, Sell executed = 6045.920000, volume = -1.000000, position = 0.000000
          2018-07-01, Buy executed = 6391.080000, volume = 1.000000 , position = 1.000000
          2018-07-11, Sell executed = 6296.910000, volume = -1.000000, position = 0.000000
          2018-07-17, Buy executed = 6723.330000, volume = 1.000000 , position = 1.000000
          2018-08-01, Sell executed = 7735.670000, volume = -1.000000, position = 0.000000
          2018-08-17, Buy executed = 6316.000000, volume = 1.000000 , position = 1.000000
          2018-08-21, Sell executed = 6251.000000, volume = -1.000000, position = 0.000000
          2018-08-24, Buy executed = 6525.000000, volume = 1.000000 , position = 1.000000
          2018-09-06, Sell executed = 6399.040000, volume = -1.000000, position = 0.000000
          The final Cash = 99930.95
       """
    

    You can see from the log that even if I have $10000, and the executed price = 6711.390000, my strategy only buy 1 BTC , how can I buy 1.49 ( 10000/6711.39 = 1.49BTC) . Thanks and best regards.


  • administrators

    @ramoslin02 said in self.buy(size=1.5) does not work:

    how can I buy 1.49 ( 10000/6711.39 = 1.49BTC) .

    Here is your code

    @ramoslin02 said in self.buy(size=1.5) does not work:

       if not self.position and self.buy_signal == 1:
            self.order = self.buy()
    

    How do you expect the system to know you want to buy 1.49? Artificial Intelligence?

    If you don't specify the size and as quoted in the documentation, the default system sizer will allocate the size for you.



  • @backtrader
    Thanks. And how do I get the market price for I use the following method

    self.order = self.buy()
    
    

    for I need to calculate the size . Or how can I set that I will buy all the size I can.



  • @ramoslin02 Or how can I set or what should I do to make sure that all my money buy all the position. any method or what parameter I need to use in the buy method ?

    self.order = self.buy( some parameter here ?) ## thanks 
    


  • @ramoslin02 in the code posted above you have several commented lines of code which calculate the size. Why don't you use them modified according to @backtrader remarks?

            # buy_price = self.data.close[0] * (1+0.002)
            # sell_price = self.data.close[0] *(1-0.002)
            # cash = self.broker.get_cash()
            # size = cash/buy_price
            # print("cash = %f , will buy price = %f size = %f" %(cash,buy_price,size))
    

    Just use 90% of cash to accommodate potential price change between close and open prices.


  • administrators

    For an All-In strategy, use cheat-on-open (not recommended, but do if, if you really want to go all-in)