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/

    Execution gives many 'Canceled/Margin/Rejected' orders

    General Code/Help
    2
    3
    488
    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.
    • ?
      A Former User last edited by

      When executing an optimization I'm getting many 'Canceled/Margin/Rejected' orders. There must be something wrong with my strategy but I can't figure out what it is.

      Also the output that I'm expecting is around 10% and it should look like this:
      Excel Heatmap

      But right now I'm getting a maximum of 7.7% and the output looks too uniform which makes me think something is wrong:
      Python Heatmap

      1 Reply Last reply Reply Quote 1
      • ?
        A Former User last edited by

        I forgot to copy the code:
        main.py

        from __future__ import (absolute_import, division, print_function,
                                unicode_literals)
        
        import datetime
        import os.path
        import sys
        
        import backtrader as bt
        
        from strategies.strategies import *
        from sizers import MaxRiskSizer
        from commissions import DegiroCommission
        from heatmap import my_heatmap
        
        STARTING_CASH = 1700
        
        
        if __name__ == '__main__':
            cerebro = bt.Cerebro(optreturn=False)
            cerebro.addanalyzer(bt.analyzers.AnnualReturn, _name='annual_return')
            #cerebro.optstrategy(EMAcrossover, fast=range(5, 7), slow=range(10,12))
            #cerebro.optstrategy(EMAcrossover, fast=range(5, 55, 5), slow=range(60, 300, 10))
            cerebro.optstrategy(EMAcrossover, fast=range(8, 26), slow=range(38, 51))
            cerebro.broker.set_cash(STARTING_CASH)
            cerebro.broker.set_coc(True)
        
            modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
            datapath = os.path.join(modpath, 'data/SPY.csv')
            data = bt.feeds.YahooFinanceCSVData(
                dataname=datapath,
                reverse=False
            )
            cerebro.adddata(data)
        
            cerebro.addsizer(MaxRiskSizer)
            comminfo = DegiroCommission()
            cerebro.broker.addcommissioninfo(comminfo)
        
            optimized_runs = cerebro.run()
        
            final_results_list = []
            for run in optimized_runs:
                for strategy in run:
                    PnL = round(strategy.broker.get_value() - STARTING_CASH, 2)
                    my_dict = strategy.analyzers.annual_return.get_analysis()
                    annual_returns = [v for _, v in my_dict.items() if v != 0]
                    average_annual_return = sum(annual_returns) / len(annual_returns)
                    final_results_list.append([strategy.params.fast,
                    strategy.params.slow, PnL, round(average_annual_return*100, 2)])
        
            my_heatmap(final_results_list)
        

        commissions.py

        import backtrader as bt
        
        class DegiroCommission(bt.CommInfoBase):
            params = (('per_share', 0.004), ('flat', 0.5),)
        
            def _getcommission(self, size, price, pseudoexec):
                return self.p.flat + size * self.p.per_share
        

        sizers.py

        import backtrader as bt
        
        class MaxRiskSizer(bt.Sizer):
            params = (('risk', 0.98),)
        
            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):
                position = self.broker.getposition(data)
        
                if not position:
                    size = comminfo.getsize(data.close[0], cash * self.p.risk)
                else:
                    size = position.size
        
                return size
        

        strategies.py

        import backtrader as bt
        
        class EMAcrossover(bt.Strategy):
            params = (('fast', 20), ('slow', 50),)
        
            def log(self, txt, dt=None):
                dt = dt or self.datas[0].datetime.date(0)
                print(f'{dt.isoformat()} {txt}') # Comment this line when running optimization
        
            def __init__(self):
                self.dataclose = self.datas[0].close
        
                fast_ema, slow_ema = bt.ind.EMA(period=self.p.fast), bt.ind.EMA(period=self.p.slow)
                self.crossover = bt.indicators.CrossOver(fast_ema, slow_ema)
                #self.signal_add(bt.SIGNAL_LONGSHORT, bt.ind.CrossOver(ema1, ema2))
        
                self.order = None
                self.buyprice = None
                self.buycomm = None
        
            def notify_trade(self, trade):
                if not trade.isclosed:
                    return
        
                self.log(f'OPERATION GROSS {trade.pnl:.2f}, NET {trade.pnlcomm:.2f}')
        
            def notify_order(self, order):
                if order.status in [order.Submitted, order.Accepted]:
                    # An active Buy/Sell order has been submitted/accepted - Nothing to do
                    return
        
                # Check if an order has been completed
                # Attention: broker could reject order if not enough cash
                if order.status in [order.Completed]:
                    if order.isbuy():
                        self.log(f'BUY EXECUTED, '
                                 f'Price: {order.executed.price:.2f}, '
                                 f'Cost: {order.executed.value:.2f}, '
                                 f'Commission: {order.executed.comm:.2f}')
                        self.buyprice = order.executed.price
                        self.buycomm = order.executed.comm
                    elif order.issell():
                        self.log(f'SELL EXECUTED, '
                                 f'Price: {order.executed.price:.2f}, '
                                 f'Cost: {order.executed.value:.2f}, '
                                 f'Commission: {order.executed.comm:.2f}')
        
                    self.bar_executed = len(self)
        
                elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                    self.log('Order Canceled/Margin/Rejected')
        
                self.order = None
        
            def next(self):
                if self.order:
                    return
        
                if self.crossover > 0:
                    self.log(f'BUY CREATE {self.dataclose[0]:.2f}')
                    self.order = self.buy()
                elif self.crossover < 0:
                    self.log(f'SELL CREATE {self.dataclose[0]:.2f}')
        

        heatmap.py

        import datetime
        import os.path
        import sys
        import pandas as pd
        import matplotlib.pyplot as plt
        import seaborn as sns
        import numpy as np
        
        from matplotlib.colors import LinearSegmentedColormap
        from matplotlib.patches import Rectangle
        
        
        def my_heatmap(data):
            data = np.array(data)
            xs = np.unique(data[:, 1].astype(int))
            ys = np.unique(data[:, 0].astype(int))
            vals = data[:, 3].reshape(len(ys), len(xs))
            min_val_ndx = np.unravel_index(np.argmin(vals, axis=None), vals.shape)
            max_val_ndx = np.unravel_index(np.argmax(vals, axis=None), vals.shape)
        
            cmap = LinearSegmentedColormap.from_list('', ['red', 'orange', 'yellow', 'chartreuse', 'limegreen'])
            ax = sns.heatmap(vals, xticklabels=xs, yticklabels=ys, cmap=cmap, annot=True, fmt='.2f')
        
            ax.add_patch(Rectangle(min_val_ndx[::-1], 1, 1, fill=False, edgecolor='blue', lw=3, clip_on=False))
            ax.add_patch(Rectangle(max_val_ndx[::-1], 1, 1, fill=False, edgecolor='blue', lw=3, clip_on=False))
        
            plt.tight_layout()
            plt.show()
        
        hghhgghdf dfdf 1 Reply Last reply Reply Quote 1
        • hghhgghdf dfdf
          hghhgghdf dfdf @Guest last edited by

          @quake004 said in Execution gives many 'Canceled/Margin/Rejected' orders:

              if self.crossover > 0:
                  self.log(f'BUY CREATE {self.dataclose[0]:.2f}')
                  self.order = self.buy()
              elif self.crossover < 0:
                  self.log(f'SELL CREATE {self.dataclose[0]:.2f}')
          

          Did you forget to copy the last line where the sell order is created or not? Other than that, I can't quickly spot something wrong with your code.

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