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

Problem with using ATR multiplier as stoploss and printing CASH.



  • Hello, I am new to backtrader. I have several questions, i will post them down below the original code. This is what I wanna do:

    1. Only take long positions.
    2. Use donchian channel's 20 day high as open
    3. Use 4 multipler ATR (14 day period) as stoploss/to exit long position.
    4. Risk

    Here is the original code:

    import backtrader as bt
    import datetime
    import math
    
    class DonchianChannels(bt.Indicator):
        alias = ('DCH', 'DonchianChannel',)
        lines = ('dcm', 'dch', 'dcl',)  # dc middle, dc high, dc low
        params = dict(
            period=   20,
            lookback= -1,  # (-1) = doesnt current bar
        )
        plotinfo = dict(subplot=False)  # plot along with dataa
        plotlines = dict(
            dch=dict(color="black"),  # use same color as prev line (dcm)
            #dcl=dict(_samecolor=False),  # use same color as prev line (dch)
        )
        def __init__(self):
            hi, lo = self.data.high, self.data.low
            if self.p.lookback:  # move backwards as needed
                hi, lo = hi(self.p.lookback), lo(self.p.lookback)
    
            self.l.dch = bt.ind.Highest(hi, period=self.p.period)
            #self.l.dcl = bt.ind.Lowest(lo, period=self.p.period)
    
    class MaxRiskSizer(bt.Sizer):
        '''
        Returns the number of shares rounded down that can be purchased for the
        max rish tolerance
        '''
        params = (('risk', 0.03),)
    
        def __init__(self):
            if self.p.risk > 1 or self.p.risk < 0:
                raise ValueError('The risk parameter is a percentage which must be'
                    'entered as a float. e.g. 0.5')
    
        def _getsizing(self, comminfo, cash, data, isbuy):
            if isbuy:
                size = math.floor((cash * self.p.risk) / data[0])
            else:
                size = math.floor((cash * self.p.risk) / data[0]) * -1
            return size
    
    class TestStrategy(bt.Strategy):
    
        params = dict(
            pfast=20,
            pslow=50,
        )
        def __init__(self):
            # Keep a reference to the "close" line in the data[0] dataseries
            self.dataclose = self.datas[0].close
            #DC
            self.dc = DonchianChannels()
            # To keep track of pending orders and buy price/commission
            self.order = None
            self.buyprice = None
            self.buycomm = None
            # Simple Moving Average
            sma1 = bt.ind.SMA(period=self.p.pfast)  # fast moving average
            sma2 = bt.ind.SMA(period=self.p.pslow)  # slow moving average
            self.crossover = bt.ind.CrossOver(sma1, sma2)  # crossover signal
            #ATR
            pureatr = bt.ind.ATR(period = 14)
            self.my_atr = pureatr
    
        # LOG
        def log(self, txt, dt=None):
            ''' Logging function for this strategy'''
            dt = dt or self.datas[0].datetime.date(0)
            print('%s, %s' % (dt.isoformat(), txt))
    
        # EXECUTED ORDER NOTIFICATIONS
        def notify_order(self,order):
            if order.status in [order.Submitted, order.Accepted]:
                return
            # Check if an order has been completed. Broker could reject if not enough cash
            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
    
                elif order.issell():
                    self.log("SELL EXECUTED,Price: %.2f, Cost: %.2f, Comm %.2f" %
                             (order.executed.price,
                              order.executed.value,
                              order.executed.comm))
    
                self.bar_executed = len(self)
                self.log("Balance :%.2f" % (cerebro.broker.getvalue()))
    
            elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                self.log("Order Cancled/Margin/Rejected")
    
            self.order = None
    
        #Exit Operation Logs
        def notify_trade(self, trade):
            if not trade.isclosed:
                return
    
            self.log("[OPERATION PROFIT] GROSS: %.2f NET: %.2f, BALANCE: %.2f" %
                     (trade.pnl, trade.pnlcomm,cerebro.broker.getvalue()))
            print()
    
        def next(self):
            # Simply log the closing price of the series from the reference
            self.log('Close, %.2f' % self.dataclose[0])
    
            #Check if an order is pending.. if yes, cant send a 2nd order.
            if self.order:
                return
    
            #LONG CONDITION
            if not self.position:
                if self.data[0] > self.dc.dch[0]:
                    self.log('BUY CREATE, %.2f' % self.dataclose[0])
                    self.order = self.buy()
            elif (self.dataclose[1]) > self.dataclose[0]:  # in the market & cross to the downside
                self.log("LONG CLOSED {}".format(self.dataclose[0]))
                self.close()  # close long position
    
    
    #CEREBRO
    cerebro = bt.Cerebro()
    data = bt.feeds.YahooFinanceCSVData(
        dataname="oracle.csv",
        fromdate=datetime.datetime(2000,1,1),
        todate=datetime.datetime(2000,12,29),
        reverse=False)
    cerebro.adddata(data)
    cerebro.broker.set_cash(100000)
    cerebro.broker.setcommission(0.01)
    cerebro.addstrategy(TestStrategy)
    cerebro.addsizer(MaxRiskSizer, risk=0.5)
    
    print("Starting Portfolio :%.2f" % cerebro.broker.getvalue())
    print()
    cerebro.run()
    print()
    print("Final Portfolio Value:%.2f" % cerebro.broker.getvalue())
    cerebro.plot(style="candlestick",barup='green', bardown='red')
    

    1. I am trying to make the system print out its 'Balance/Cash' after
    "2000-03-24, BUY EXECUTED,Price: 38.61, Cost: 49922.73, Comm 499.23"

    so i put "self.log("Balance :%.2f" % (cerebro.broker.getvalue()))" after the buy/sell executed code, but the it printed out :

    Starting Portfolio :100000.00
    2000-03-23, BUY CREATE, 38.64
    2000-03-24, BUY EXECUTED,Price: 38.61, Cost: 49922.73, Comm 499.23
    2000-03-24, Balance :99604.21

    The starting portfolio is 100,000. Why is the balance after buy executed 99604?
    100,000 - 99604.21 = 395.79. Where did 395.79 come from? the Commission issued is 499.23.

    2. I am trying to use ATR as my stoploss / exit long position. Can anyone make ATR into trailing stoploss. and I tried using multipler in the ATR, but it doesn't work

    #ATR
            pureatr = bt.ind.ATR(period = 14)
            self.my_atr = pureatr
    

    then
    into
    CLOSE LONG POSITION when current close crosses/touches previous day's close - 4*ATR
    I modified the elif..... from
    elif (self.dataclose[1]) > self.dataclose[0]:
    to
    elif (self.dataclose[0]) > self.dataclose[1]-(pureatr*4)):
    (but it doesnt work)

    #LONG CONDITION
                     if not self.position:
                         if self.data[0] > self.dc.dch[0]:
                             self.log('BUY CREATE, %.2f' % self.dataclose[0])
                             self.order = self.buy()
                     elif (self.dataclose[0]) > self.dataclose[1]-(pureatr*4)):  
                         self.log("LONG CLOSED {}".format(self.dataclose[0]))
                         self.close()  # close long position
    
    "C:\Users\2200214\PycharmProjects\Trade\venv\Scripts\python.exe C:/Users/2200214/PycharmProjects/Trade/Trader.py
      File "C:/Users/2200214/PycharmProjects/Trade/Trader.py", line 123
        elif (self.dataclose[0]) > self.dataclose[1] - (pureatr * 4)):  # in the market & cross to the downside
        ^
    SyntaxError: invalid syntax
    
    Process finished with exit code 1"
    

    3. Is there anything wrong with my code? if theres anything you can think of improving it please help me



  • @Gleetche said in Problem with using ATR multiplier as stoploss and printing CASH.:

    Where did 395.79 come from?

    Evidently, it comes as an output from the code you written. If you expected something else, than please elaborate what did you expect.

    @Gleetche said in Problem with using ATR multiplier as stoploss and printing CASH.:

    Is there anything wrong with my code?

    Since you are asking, than probably yes. Usually if everything goes well, questions are not raised on this forum. But it is quite hard to understand what is the code which potentially has an error, you may want to repost and make it more clear for other members.



  • @ab_trader

    1 Balance Printing
    Starting Portfolio :100000.00
    2000-03-23, BUY CREATE, 38.64
    2000-03-24, BUY EXECUTED,Price: 38.61, Cost: 49922.73, Comm 499.23
    2000-03-24, Balance :99604.21

    The starting portfolio is 100,000.
    Then I made it print the balance after the "BUY EXECUTED,Price: 38.61, Cost: 49922.73, Comm 499.23"
    The balance prints 99604.21

    Like I said, I am quite new and im trying to experiment with the tutorial. I am expecting either of these to be printed

    1. Portfolio - (Cost + Comm), which is 100,000- (49922.73 +499.23) = 49578.04
    2. Portfolio - Cost, which is 100,000 - 49922.73 = 50077.27
    3. Portfolio - Cost which is 99500.77
      ( I don't really expect number 3. to be printed but its the closest with the number printed)

    But the balance prints 99604.21 , why?



  • Documentation says the following:

    get_value(datas=None, mkt=False, lever=False)

    Returns the portfolio value of the given datas (if datas is None, then the total portfolio value will be returned (alias: getvalue)

    Evidently, that item 1 and item 2 shows the cash and cash considering no commission. Really not sure why do you expect cash to be printed with the call of cerebro.broker.getvalue(). Seems it is wrong.

    Item 3 seems equal item 2 by formula, why do you have different number?

    The number99604.21 from the original post is the value of the broker account, which includes cash and position value.



  • @ab_trader

    Sorry it was typo.

    It should be

    1. Portfolio - (Cost + Comm), which is 100,000- (49922.73 +499.23) = 49578.04
    2. Portfolio - Cost, which is 100,000 - 49922.73 = 50077.27
    3. Portfolio - Commission 100,000 - 499.23 which is 99500.77

    "The number 99604.21 from the original post is the value of the broker account, which includes cash and position value."

    I apologize, but I still do not get it. Then can you show me the calculation on how do you get 99604.21 .

    and so,

    How do I get the number "49578.04" (CASH - (Cost + Comm)) printed out?
    The process goes like this right:

    1. Long Signal
    2. "BUY CREATE"
    3. "BUY EXECUTED"
      -->>How do I Print Cash Here (Portfolio - (Cost + Comm))<<--
    4. Long Exit Signal
    5. "LONG EXIT CREATE" (it's "Long Closed" on the original post)
    6. "SELL EXECUTED"


  • @Gleetche said in Problem with using ATR multiplier as stoploss and printing CASH.:

    Then can you show me the calculation on how do you get 99604.21

    Should be CASH LEFT + CLOSE x NUMBER OF SHARES = 99604.21

    @Gleetche said in Problem with using ATR multiplier as stoploss and printing CASH.:

    How do I get the number "49578.04" (CASH - (Cost + Comm)) printed out?

    Docs - Broker - get_cash()


Log in to reply
 

});