Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

    Mismatch between Analysers and Observers

    Indicators/Strategies/Analyzers
    2
    5
    507
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • J
      jwsmith last edited by

      Hi there,

      In my code I make use of the standard Observers and Analysers. Below is some simplified code:

              cerebro.addobserver(bt.observers.Broker)
              cerebro.addobserver(bt.observers.Trades)
      ...
      
              # Add a strategy,data,sizers etc.
      
              # Add the analyzers we are interested in
              cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name="TradeAnalyzer")
      
              # Run over everything
              results = cerebro.run()
              strategy_results = results[0]
      
              TA=strategy_results.analyzers.TradeAnalyzer.get_analysis()
      
              # PNL
              print(round(TA.pnl.net.total,2))
              #Strike rate
              print(round((TA.won.total/TA.total.closed)*100,2))
      ...
      

      This will print a PNL that is correct, and a Strike rate that isn't correct.
      For example, in the attached sanity check plot, there isn't a single unprofitable trade, which is also in agreement with the output in the strategy (I can attach if needed).
      However, according to the Trades observer, strike rate from TA is reported as 62.5%. (won=5/lost=3).
      So then this makes me question my Sharpe and SQN analysers as well.

      Any help is appreciated!
      Josh

      Here's the full output of TA if that helps.

      AutoOrderedDict([('total', AutoOrderedDict([('total', 8), ('open', 0), ('closed', 8)])), ('streak', AutoOrderedDict([('won', AutoOrderedDict([('current', 1), ('longest', 4)])), ('lost', AutoOrderedDict([('current', 0), ('longest', 2)]))])), ('pnl', AutoOrderedDict([('gross', AutoOrderedDict([('total', 480.4899999999998), ('average', 60.06124999999997)])), ('net', AutoOrderedDict([('total', 320.5035299999998), ('average', 40.06294124999997)]))])), ('won', AutoOrderedDict([('total', 5), ('pnl', AutoOrderedDict([('total', 340.37375999999966), ('average', 68.07475199999993), ('max', 140.4145000000004)]))])), ('lost', AutoOrderedDict([('total', 3), ('pnl', AutoOrderedDict([('total', -19.870229999999886), ('average', -6.623409999999962), ('max', -13.243230000000224)]))])), ('long', AutoOrderedDict([('total', 8), ('pnl', AutoOrderedDict([('total', 320.5035299999998), ('average', 40.06294124999997), ('won', AutoOrderedDict([('total', 340.37375999999966), ('average', 68.07475199999993), ('max', 140.4145000000004)])), ('lost', AutoOrderedDict([('total', -19.870229999999886), ('average', -6.623409999999962), ('max', -13.243230000000224)]))])), ('won', 5), ('lost', 3)])), ('short', AutoOrderedDict([('total', 0), ('pnl', AutoOrderedDict([('total', 0.0), ('average', 0.0), ('won', AutoOrderedDict([('total', 0.0), ('average', 0.0), ('max', 0.0)])), ('lost', AutoOrderedDict([('total', 0.0), ('average', 0.0), ('max', 0.0)]))])), ('won', 0), ('lost', 0)])), ('len', AutoOrderedDict([('total', 23), ('average', 2.875), ('max', 6), ('min', 1), ('won', AutoOrderedDict([('total', 20), ('average', 4.0), ('max', 6), ('min', 1)])), ('lost', AutoOrderedDict([('total', 3), ('average', 1.0), ('max', 1), ('min', 1)])), ('long', AutoOrderedDict([('total', 23), ('average', 2.875), ('max', 6), ('min', 1), ('won', AutoOrderedDict([('total', 20), ('average', 4.0), ('max', 6), ('min', 1)])), ('lost', AutoOrderedDict([('total', 3), ('average', 1.0), ('max', 1), ('min', 1)]))])), ('short', AutoOrderedDict([('total', 0), ('average', 0.0), ('max', 0), ('min', 9223372036854775807), ('won', AutoOrderedDict([('total', 0), ('average', 0.0), ('max', 0), ('min', 9223372036854775807)])), ('lost', AutoOrderedDict([('total', 0), ('average', 0.0), ('max', 0), ('min', 9223372036854775807)]))]))]))])
       2019-04-24 12:48:13 INFO [backtest.py:119] | Final Portfolio Value: 10320.50
      

      0_1556103667308_AAPL_60min_60min_CheatStrategy.png

      1 Reply Last reply Reply Quote 0
      • J
        jwsmith last edited by

        I should mention that I have self.set_coc(True) in the Strategy, which explains why the first trade is profitable: Buys at 3rd bar close, and sells at 4th close.
        I.e., shift red and green arrows 1 to the left.

        1 Reply Last reply Reply Quote 0
        • B
          backtrader administrators last edited by backtrader

          One of the major problems:

          • A user reports something he/she believes to be a problem (it may or may not be)
          • The user posts half-cooked code which cannot of course be used for anything
          • No sample data is provided to reproduce the problem
          • No logging information is provided
          • A chart is the proof of all sins

          Let's use the chart then ...

          0_1556138826884_a867a6d4-de38-49a4-b7eb-870d1750823d-image.png

          That should say everything, because unless David Copperfield, this mere mortal needs something reliable and reproducible to work with.

          1 Reply Last reply Reply Quote 0
          • J
            jwsmith last edited by

            Fair point.
            Full minimal example below.
            It seems the issue(?) is with commission. The TA Analyser seems to take it into account, the Observers (specifically Trades) does not.
            You can test this by enabling and disabling commission. With commission=0%, the Observer and Analyser StrikeRate match, with commision!=0%, they do not.

            So then the question: Is there an easy way to get Observers (or is it just the Trades one where this happens?) to take into account commission?

            import backtrader as bt
            from datetime import datetime
            
            
            class firstStrategy(bt.Strategy):
            
            
                def __init__(self):
                    self.rsi = bt.indicators.RSI_SMA(self.data.close, period=20)
                    self.broker.set_coc(True)
            
                def next(self):
                    if not self.position:
                        # Some bogus values to get some trades
                        if self.rsi[0] < 30:
                            self.buy(size=5)
                    else:
                        if self.rsi[0] > 20:
                            self.close()
            
            
            #Variable for our starting cash
            startcash = 10000
            
            cerebro = bt.Cerebro()
            cerebro.addstrategy(firstStrategy)
            # File is one of the txt files in datas dir, just with most of entries removed for simplicity.
            data = bt.feeds.YahooFinanceCSVData(dataname="yhoo.txt")
            cerebro.adddata(data)
            
            # Set our desired cash start
            cerebro.broker.setcash(startcash)
            cerebro.broker.setcommission(commission=0.01)
            
            # Add the analyzers we are interested in
            cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name="TradeAnalyzer")
            # Run over everything
            results = cerebro.run()
            strategy_results = results[0]
            
            TA=strategy_results.analyzers.TradeAnalyzer.get_analysis()
            print(TA)
            final_portfolio_values=dict()
            final_portfolio_values["StrikeRate"]=round((TA.won.total/TA.total.closed)*100,2)
            #Get final portfolio Value
            portvalue = cerebro.broker.getvalue()
            pnl = portvalue - startcash
            print('Final Portfolio Value: ${}'.format(portvalue))
            print('P/L: ${}'.format(pnl))
            print("StrikeRate = ",final_portfolio_values["StrikeRate"])
            #... And plot
            cerebro.plot(style='candlestick')
            
            

            Cheers,
            Josh

            1 Reply Last reply Reply Quote 0
            • B
              backtrader administrators last edited by

              See: Community - Release 1.9.72.122

              1 Reply Last reply Reply Quote 0
              • 1 / 1
              • First post
                Last post
              Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors