Help - Buy signal recognition and trade creation vs execution?
-
from __future__ import (absolute_import, division, print_function, unicode_literals) import datetime # For datetime objects import os.path # To manage paths import sys # To find out the script name (in argv[0]) import matplotlib.pyplot as plt filepath = r'C:\Users\lenovo\Desktop\Scripts\Data\varta20152021.csv' # Import the backtrader platform import backtrader as bt cerebro = bt.Cerebro(stdstats=False, cheat_on_open = True) # cerebro.addobserver(bt.observers.DrawDown) # Create a Stratey class SmaStrategy(bt.Strategy): params = ( ('maperiod', 10), ) def log(self, txt, dt=None): ''' Logging function fot this strategy''' dt = dt or self.datas[0].datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): # Keep a reference to the "close" line in the data[0] dataseries self.dataclose = self.datas[0].close # To keep track of pending orders and buy price/commission self.order = None self.buyprice = None self.buycomm = None # Add a MovingAverageSimple indicator self.sma = bt.indicators.SimpleMovingAverage( self.datas[0], period=self.params.maperiod) # Indicators for the plotting show bt.indicators.ExponentialMovingAverage(self.datas[0], period=25) bt.indicators.WeightedMovingAverage(self.datas[0], period=25, subplot=True) bt.indicators.StochasticSlow(self.datas[0]) bt.indicators.MACDHisto(self.datas[0]) rsi = bt.indicators.RSI(self.datas[0]) bt.indicators.SmoothedMovingAverage(rsi, period=10) bt.indicators.ATR(self.datas[0], plot=False) def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: # Buy/Sell order submitted/accepted to/by broker - 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( '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 else: # Sell self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) self.bar_executed = len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') # Write down: no pending order self.order = None def notify_trade(self, trade): if not trade.isclosed: return self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % (trade.pnl, trade.pnlcomm)) 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, we cannot send a 2nd one if self.order: return # Check if we are in the market if not self.position: # Not yet ... we MIGHT BUY if ... if self.dataclose[0] > self.sma[0]: # BUY, BUY, BUY!!! (with all possible default parameters) self.log('BUY CREATE, %.2f' % self.dataclose[0]) # Keep track of the created order to avoid a 2nd order self.order = self.buy(exectype=bt.Order.StopTrail, trailpercent=0.007) else: if self.dataclose[0] < (self.sma[0]): # SELL, SELL, SELL!!! (with all possible default parameters) self.log('SELL CREATE, %.2f' % self.dataclose[0]) # Keep track of the created order to avoid a 2nd order self.order = self.sell() if __name__ == '__main__': # Create a cerebro entity cerebro = bt.Cerebro() # Add a strategy cerebro.addstrategy(SmaStrategy) cerebro.addanalyzer(bt.analyzers.SharpeRatio) cerebro.addanalyzer(bt.analyzers.DrawDown) cerebro.addanalyzer(bt.analyzers.TradeAnalyzer) cerebro.addanalyzer(bt.analyzers.Returns) cerebro.addanalyzer(bt.analyzers.PyFolio) cerebro.addanalyzer(bt.analyzers.Transactions) cerebro.addanalyzer(bt.analyzers.SQN, _name="sqn") # Datas are in a subfolder of the samples. Need to find where the script is # because it could have been called from anywhere modpath = os.path.dirname(os.path.abspath(sys.argv[0])) datapath = os.path.join(modpath, filepath) # Create a Data Feed data = bt.feeds.YahooFinanceCSVData( dataname=datapath, # Do not pass values before this date fromdate=datetime.datetime(2020,6, 30), # Do not pass values before this date todate=datetime.datetime(2021, 6, 30), # Do not pass values after this date reverse=False) # Add the Data Feed to Cerebro cerebro.adddata(data) # Set our desired cash start cerebro.broker.setcash(1000000.0) # Add a FixedSize sizer according to the stake cerebro.addsizer(bt.sizers.FixedSize, stake=6000) # Set the commission cerebro.broker.setcommission(commission=0.0002) # Print out the starting conditions print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Run over everything res = cerebro.run()[0] print("\n") sharpe_data = res.analyzers.sharperatio.get_analysis() print("=== Sharpe Ratio ===") print("Sharpe: %s" % sharpe_data['sharperatio']) # print("Draw Down: ", res.analyzers.drawdown.get_analysis()) draw_down_data = res.analyzers.drawdown.get_analysis() print("========== Draw Down ==========") print("max drawdown: %s %%" % draw_down_data['max']['drawdown']) print("max money drawdown: %s" % draw_down_data['max']['moneydown']) # print("Trade Analyzer: ", res.analyzers.tradeanalyzer.get_analysis()) trading_data = res.analyzers.tradeanalyzer.get_analysis() print("========== Trading Analysis ==========") print("Winning Trades") print("win ratio: %s" % (trading_data['won']['total'] / float(trading_data['won']['total'] + trading_data['lost']['total']))) print("win_hits: %s" % trading_data['won']['total']) print("win_pnl --> total: %s, average: %s, max: %s" % (trading_data['won']['pnl']['total'], trading_data['won']['pnl']['average'], trading_data['won']['pnl']['max']) ) print("Losing Trades") print("lost_hits:%s" % trading_data['lost']['total']) print("lost_pnl --> total: %s, average: %s, max: %s" % (trading_data['lost']['pnl']['total'], trading_data['lost']['pnl']['average'], trading_data['lost']['pnl']['max']) ) print("Long Trades") print("long_hits: %s" % trading_data['long']['total']) print("long_pnl --> total: %s, average: %s" % (trading_data['long']['pnl']['total'], trading_data['long']['pnl']['average']) ) print("Short Trades") print("short_hits: %s" % trading_data['short']['total']) print("short_pnl --> total: %s, average: %s" % (trading_data['short']['pnl']['total'], trading_data['short']['pnl']['average']) ) transactions_data = res.analyzers.tradeanalyzer.get_analysis() print("========== SQN Analysis ==========") print(dict(res.analyzers.sqn.get_analysis())['sqn']) print('\n') # Print out the final result print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Plot the result cerebro.plot(style='candle')
Testing strategy using VAR1.DE daily data from yahoo finance.
-
Why is the buy creation and execution distanced away by more than 1 day? As I see this happen maybe a couple of times.
-
Why didn't the signal detect a buy order at the start of the data? As you can see, the first buy order is on Aug 2020 but in the chart you can see that before the first buy order, there is another crossover where the close is above the sma10.
Please let me know your thoughts, thanks a lot! Would really appreciate the help especially on the coding part, as I most likely typed something wrong somewhere.. though this is taken from the quickstarter guide. The cheat is not incorporated yet.
-
-
@j63009567 said in Help - Buy signal recognition and trade creation vs execution?:
from __future__ import (absolute_import, division, print_function, unicode_literals) import datetime # For datetime objects import os.path # To manage paths import sys # To find out the script name (in argv[0]) import matplotlib.pyplot as plt filepath = r'C:\Users\lenovo\Desktop\Scripts\Data\varta20152021.csv' # Import the backtrader platform import backtrader as bt cerebro = bt.Cerebro(stdstats=False, cheat_on_open = True) # cerebro.addobserver(bt.observers.DrawDown) # Create a Stratey class SmaStrategy(bt.Strategy): params = ( ('maperiod', 10), ) def log(self, txt, dt=None): ''' Logging function fot this strategy''' dt = dt or self.datas[0].datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): # Keep a reference to the "close" line in the data[0] dataseries self.dataclose = self.datas[0].close # To keep track of pending orders and buy price/commission self.order = None self.buyprice = None self.buycomm = None # Add a MovingAverageSimple indicator self.sma = bt.indicators.SimpleMovingAverage( self.datas[0], period=self.params.maperiod) # Indicators for the plotting show bt.indicators.ExponentialMovingAverage(self.datas[0], period=25) bt.indicators.WeightedMovingAverage(self.datas[0], period=25, subplot=True) bt.indicators.StochasticSlow(self.datas[0]) bt.indicators.MACDHisto(self.datas[0]) rsi = bt.indicators.RSI(self.datas[0]) bt.indicators.SmoothedMovingAverage(rsi, period=10) bt.indicators.ATR(self.datas[0], plot=False) def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: # Buy/Sell order submitted/accepted to/by broker - 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( '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 else: # Sell self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) self.bar_executed = len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') # Write down: no pending order self.order = None def notify_trade(self, trade): if not trade.isclosed: return self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % (trade.pnl, trade.pnlcomm)) 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, we cannot send a 2nd one if self.order: return # Check if we are in the market if not self.position: # Not yet ... we MIGHT BUY if ... if self.dataclose[0] > self.sma[0]: # BUY, BUY, BUY!!! (with all possible default parameters) self.log('BUY CREATE, %.2f' % self.dataclose[0]) # Keep track of the created order to avoid a 2nd order self.order = self.buy(exectype=bt.Order.StopTrail, trailpercent=0.007) else: if self.dataclose[0] < (self.sma[0]): # SELL, SELL, SELL!!! (with all possible default parameters) self.log('SELL CREATE, %.2f' % self.dataclose[0]) # Keep track of the created order to avoid a 2nd order self.order = self.sell() if __name__ == '__main__': # Create a cerebro entity cerebro = bt.Cerebro() # Add a strategy cerebro.addstrategy(SmaStrategy) cerebro.addanalyzer(bt.analyzers.SharpeRatio) cerebro.addanalyzer(bt.analyzers.DrawDown) cerebro.addanalyzer(bt.analyzers.TradeAnalyzer) cerebro.addanalyzer(bt.analyzers.Returns) cerebro.addanalyzer(bt.analyzers.PyFolio) cerebro.addanalyzer(bt.analyzers.Transactions) cerebro.addanalyzer(bt.analyzers.SQN, _name="sqn") # Datas are in a subfolder of the samples. Need to find where the script is # because it could have been called from anywhere modpath = os.path.dirname(os.path.abspath(sys.argv[0])) datapath = os.path.join(modpath, filepath) # Create a Data Feed data = bt.feeds.YahooFinanceCSVData( dataname=datapath, # Do not pass values before this date fromdate=datetime.datetime(2020,6, 30), # Do not pass values before this date todate=datetime.datetime(2021, 6, 30), # Do not pass values after this date reverse=False) # Add the Data Feed to Cerebro cerebro.adddata(data) # Set our desired cash start cerebro.broker.setcash(1000000.0) # Add a FixedSize sizer according to the stake cerebro.addsizer(bt.sizers.FixedSize, stake=6000) # Set the commission cerebro.broker.setcommission(commission=0.0002) # Print out the starting conditions print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Run over everything res = cerebro.run()[0] print("\n") sharpe_data = res.analyzers.sharperatio.get_analysis() print("=== Sharpe Ratio ===") print("Sharpe: %s" % sharpe_data['sharperatio']) # print("Draw Down: ", res.analyzers.drawdown.get_analysis()) draw_down_data = res.analyzers.drawdown.get_analysis() print("========== Draw Down ==========") print("max drawdown: %s %%" % draw_down_data['max']['drawdown']) print("max money drawdown: %s" % draw_down_data['max']['moneydown']) # print("Trade Analyzer: ", res.analyzers.tradeanalyzer.get_analysis()) trading_data = res.analyzers.tradeanalyzer.get_analysis() print("========== Trading Analysis ==========") print("Winning Trades") print("win ratio: %s" % (trading_data['won']['total'] / float(trading_data['won']['total'] + trading_data['lost']['total']))) print("win_hits: %s" % trading_data['won']['total']) print("win_pnl --> total: %s, average: %s, max: %s" % (trading_data['won']['pnl']['total'], trading_data['won']['pnl']['average'], trading_data['won']['pnl']['max']) ) print("Losing Trades") print("lost_hits:%s" % trading_data['lost']['total']) print("lost_pnl --> total: %s, average: %s, max: %s" % (trading_data['lost']['pnl']['total'], trading_data['lost']['pnl']['average'], trading_data['lost']['pnl']['max']) ) print("Long Trades") print("long_hits: %s" % trading_data['long']['total']) print("long_pnl --> total: %s, average: %s" % (trading_data['long']['pnl']['total'], trading_data['long']['pnl']['average']) ) print("Short Trades") print("short_hits: %s" % trading_data['short']['total']) print("short_pnl --> total: %s, average: %s" % (trading_data['short']['pnl']['total'], trading_data['short']['pnl']['average']) ) transactions_data = res.analyzers.tradeanalyzer.get_analysis() print("========== SQN Analysis ==========") print(dict(res.analyzers.sqn.get_analysis())['sqn']) print('\n') # Print out the final result print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Plot the result cerebro.plot(style='candle')
Testing strategy using VAR1.DE daily data from yahoo finance.
-
Why is the buy creation and execution distanced away by more than 1 day? As I see this happen maybe a couple of times.
-
Why didn't the signal detect a buy order at the start of the data? As you can see, the first buy order is on Aug 2020 but in the chart you can see that before the first buy order, there is another crossover where the close is above the sma10.
Please let me know your thoughts, thanks a lot! Would really appreciate the help especially on the coding part, as I most likely typed something wrong somewhere.. though this is taken from the quickstarter guide. The cheat is not incorporated yet.

As you can see the create and execute is randomly distanced by a day. Please help me!
-
-
@j63009567 The answer is because you are using a stop trail order:
# Keep track of the created order to avoid a 2nd order self.order = self.buy(exectype=bt.Order.StopTrail, trailpercent=0.007)
You can read more about how they operate here in the docs
-
I thought the trailing stop loss would automatically execute?
I think there is something error with my code, as the trailing stop loss doesn't seem to be hitting
I added a bracket order, and the limit price is not executing despite the price reaching that target on the graph, as we have a position already?
A sell is only detected when close < sma