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

TradeAnalyzer with bracket orders problem?



  • I'm having an issue with TradeAnalyzer giving me strange results when I'm using bracket orders.

    I'm using basic bracket orders like the following, in next():

                        self.buy_bracket(limitprice=1.02,
                                         price=1.00, 
                                         stopprice=0.98)
    

    My code to view TradeAnalyzer results is like so (borrowed from backtest-rookies):

    Instantiated like cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name="ta")

    def printTradeAnalysis(analyzer):
        '''
        Function to print the Technical Analysis results in a nice format.
        '''
        #Get the results we are interested in
        total_open = analyzer.total.open
        total_closed = analyzer.total.closed
        total_won = analyzer.won.total
        total_lost = analyzer.lost.total
        win_streak = analyzer.streak.won.longest
        lose_streak = analyzer.streak.lost.longest
        pnl_net = round(analyzer.pnl.net.total,2)
        strike_rate = (total_won / total_closed) * 100
        #Designate the rows
        h1 = ['Total Open', 'Total Closed', 'Total Won', 'Total Lost']
        h2 = ['Strike Rate','Win Streak', 'Losing Streak', 'PnL Net']
        r1 = [total_open, total_closed,total_won,total_lost]
        r2 = [round(strike_rate, 2), win_streak, lose_streak, pnl_net]
        #Check which set of headers is the longest.
        if len(h1) > len(h2):
            header_length = len(h1)
        else:
            header_length = len(h2)
        #Print the rows
        print_list = [h1,r1,h2,r2]
        row_format ="{:<15}" * (header_length + 1)
        print("Trade Analysis Results:")
        for row in print_list:
            print(row_format.format('',*row))
    

    The trade results are like so, starting cash of $100,000:

    Trade Analysis Results:
                   Total Open     Total Closed   Total Won      Total Lost     
                   1              232            1              85             
                   Strike Rate    Win Streak     Losing Streak  PnL Net        
                   0.43           1              6              120972.3       
    SQN: 2.88
    Final Portfolio Value: $1120972.2971421063
    

    The SQN and the Portfolio Value look accurate, and I've used notify_order() to manually create my own trade log which roughly matches this value, but the Trade Analysis Results are all over the place. The number of won, lost, and closed are all wrong, yet the PnL Net does look to be accurate.

    Any thoughts as to what may be occurring here?

    EDIT:

    It appears the SharpeRatio analyzer does not work either...

    Added like:

    cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name="sharpe")

    When I try to access it later...

    > sharpe
    OrderedDict([('sharperatio', None)])
    

    Do the analyzers not function correctly with bracket orders?


  • administrators

    The TradeAnalyzer doesn't care about orders, it only record things when a Trade is opened or closed. Orders which are not executed don't contribute to a Trade.

    You say that results are all over the place, but the only thing you show is a total of 233 trades of which 1 os open. There is no basis to understand if what you do and calculate is wrong or if the analyzer could be wrong. But again, the analyzer doesn't care about orders.

    The SharpeRatio is an analyzer which only looks at returns which are obviously calculated from the portfolio value.

    @tw00000 said in TradeAnalyzer with bracket orders problem?:

    cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name="Sharpe")
    

    When I try to access it later...

    > sharpe
    OrderedDict([('sharperatio', None)])
    

    If you add with a capital S and later show us a prompt (wherever it comes from, because the analyzer it's not in a variable) with a small S, it's difficult to know what you are doing and where things come from.



  • @backtrader

    Sorry, in my original post I had a typo w.r.t. the SharpeRatio. it's actually being instantiated like: cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name="sharpe") , and later on when I try to access it like so: 0_1530392881605_Screenshot 2018-06-30 22.01.52.png
    It returns nothing.

    You say that results are all over the place, but the only thing you show is a total of 233 trades of which 1 os open. There is no basis to understand if what you do and calculate is wrong or if the analyzer could be wrong. But again, the analyzer doesn't care about orders.

    The results are all over the place in that I cannot make sense of them.

    When I log orders into a CSV file using notify_orders() like so:

    def notify_trade(self, trade):
            date = self.data.datetime.datetime()
            if trade.isclosed:
                print('-'*32,' NOTIFY TRADE ','-'*32)
                print('{}, Close Price: {}, Profit, Gross {}, Net {}'.format(
                                                    date,
                                                    trade.price,
                                                    round(trade.pnl,rounding),
                                                    round(trade.pnlcomm,rounding)))
                print('-'*80)
                
            
                THIS_FOLDER = os.getcwd()
                trade_history_file = os.path.join(THIS_FOLDER, 'completed_trades_log_{}.csv'.format(instrument_name))
                
                trade_history_dict = {}
                trade_history_dict['Date_of_trade_completion'] = date
    
                trade_history_dict['trade_price'] = trade.price
                trade_history_dict['Profit_and_loss_gross'] = round(trade.pnl,rounding)
                trade_history_dict['Profit_and_loss_net'] = round(trade.pnlcomm,rounding)
                # Write the trade_setup
                df_trade_history_dict = pd.DataFrame.from_dict(trade_history_dict, orient='index')
    
                # Write the trade history for checking later
                df_one_trade_history = df_trade_history_dict.T
    
                if os.path.exists(trade_history_file):
                    df_one_trade_history.to_csv(trade_history_file, mode='a', header=False)
                else:
                    df_one_trade_history.to_csv(trade_history_file, mode='w', header=True)
                 
    

    The number of Won and Lost trades is always much higher in the log produced by notify_orders() than is reflected in TradeAnalyzer



  • If anyone happens to find this post in the future, this other backtrader post helped me solve the SharpeRatio problem.

    Basically, if you're using 5 Minute candles (as I am), you'll want code like so:
    cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe', timeframe=bt.TimeFrame.Minutes, compression=5)

    That said, I'm not sure the annualized nature of the SR will be a great number to pay attention to, but I'm not sure how to solve that.

    As for TradeAnalyzer - I never did figure out why it doesn't show the correct number of Won trades and only shows Lost trades.


  • administrators

    @tw00000 said in TradeAnalyzer with bracket orders problem?:

    The number of Won and Lost trades is always much higher in the log produced by notify_orders() than is reflected in TradeAnalyzer

    notify_order has nothing to do with Trade instances (and a trade per se) but with Order instances. An Order will undergo several changes (just like in a normal broker) like: Created, Submitted, Completed, ...

    If you want to look at trades yourself, use notify_trade. Some logs would have cleared it from the very beginning.

    @tw00000 said in TradeAnalyzer with bracket orders problem?:

    Basically, if you're using 5 Minute candles (as I am), you'll want code like so:
    cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe', timeframe=bt.TimeFrame.Minutes, compression=5)

    If you look at the documentation: Docs - Analyzer Reference - Sharpe Ratio, you will see that the default timeframe is Years. This is because this is what people use.

    Again, some context code about what you are doing rather that it doesn't work or things are all over the place can help.



  • @backtrader said in TradeAnalyzer with bracket orders problem?:

    If you look at the documentation: Docs - Analyzer Reference - Sharpe Ratio, you will see that the default timeframe is Years. This is because this is what people use.

    I think w.r.t. SharpeRatio, I need to better understand how people use Sharpe ratios when trading smaller timeframes, or perhaps how to configure the backtrader Sharpe ratio for 5 Minute timeframe candles...