Buying and Selling with Signals
-
Im trying to code the strategy that works in this way:
- If today is a down candle (open price higher than the closing price), I will go long position. If today is an up candle (closing price is higher than the open price), I will go short position.
- If yesterday I was in a long position, today is an up candle, I will close my long position and start a short position.
- I am using a stop loss and take profit price for each of my position. As such, I am using the bracket order. However, as the exectype is Limit Order and I would like it to be implemented as a Market Order, I change the price into self.data.open[0] with reference to yesterday's signal.
from __future__ import (absolute_import, division, print_function, unicode_literals) import os.path import argparse import datetime import collections import backtrader as bt import backtrader.feeds as btfeeds import backtrader.plot as plt import backtrader.indicators as btinds class Plotter(plt.Plot): def __init__(self): super().__init__(volup='#60cc73') # custom color for volume up bars def show(self): mng = self.mpyplot.get_current_fig_manager() mng.window.state('zoomed') self.mpyplot.show() class St(bt.Strategy): def log(self, txt, dt=None): ''' Logging function fot this strategy''' dt = dt or self.data.datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): self.signal = 0 def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: return if order.status in [order.Completed]: if order.isbuy(): self.signal +=1 self.log( 'BUY EXECUTED, Price: %.5f, Cost: %.5f, Position : %d' % (order.executed.price, order.executed.value,self.signal)) self.buyprice = order.executed.price else: # Sell self.signal -= 1 self.log('SELL EXECUTED, Price: %.5f, Cost: %.5f,Position : %d' % (order.executed.price, order.executed.value,self.signal)) 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 notify_trade(self, trade): if not trade.isclosed: return self.log('OPERATION PROFIT, GROSS %.5f, NET %.5f' % (trade.pnl, trade.pnlcomm)) def next(self): txt = ','.join( ['%04d' % len(self.data), self.data.datetime.date(0).isoformat(), 'Open : %.5f' % self.data.open[0], 'High : %.5f' % self.data.high[0], 'Low : %.5f' % self.data.low[0], 'Close : %.5f' % self.data.close[0], 'Position : %d' % self.signal]) print(txt) if self.signal == 0: if self.data.open[-1] > self.data.close[-1]: self.log('BUY CREATE, %.5f, Limitprice : %.5f, Stopprice : %.5f' % (self.data.open[0],1.01*self.data.open[0],0.99*self.data.open[0])) self.order = self.buy_bracket(limitprice = 1.01*self.data.open[0],price=self.data.open[0],stopprice = 0.99*self.data.open[0]) elif self.data.open[-1] < self.data.close[-1]: self.log('SELL CREATE, %.5f, Limitprice : %.5f, Stopprice : %.5f' % (self.data.open[0],0.99*self.data.open[0],1.01*self.data.open[0])) self.order = self.sell_bracket(limitprice =0.99*self.data.open[0], price = self.data.open[0], stopprice= 1.01*self.data.open[0]) elif self.signal == 1: if self.data.open[-1] > self.data.close[-1]: return elif self.data.open[-1] < self.data.close[-1]: self.log('SELL CREATE, %.5f, Limitprice : %.5f, Stopprice : %.5f' % (self.data.open[0],0.99*self.data.open[0],1.01*self.data.open[0])) self.order = self.sell_bracket(limitprice =0.99*self.data.open[0], price = self.data.open[0], stopprice= 1.01*self.data.open[0],size=2) elif self.signal == -1: if self.data.open[-1] < self.data.close[-1]: return elif self.data.open[-1] > self.data.close[-1]: self.log('BUY CREATE, %.5f, Limitprice : %.5f, Stopprice : %.5f' % (self.data.open[0],1.01*self.data.open[0],0.99*self.data.open[0])) self.order = self.buy_bracket(limitprice = 1.01*self.data.open[0],price=self.data.open[0],stopprice = 0.99*self.data.open[0]) class Plotter(plt.Plot): def __init__(self): super().__init__(volup='#60cc73') # custom color for volume up bars def show(self): mng = self.mpyplot.get_current_fig_manager() mng.window.state('zoomed') self.mpyplot.show() def runstrat(): args = parse_args() cerebro = bt.Cerebro() modpath = 'd:\\I - TradersGPS\\' datapath = os.path.join(modpath, 'GBPUSD_D1_UTC+2_00.csv') data = btfeeds.GenericCSVData(dataname=datapath, timeframe=bt.TimeFrame.Days, fromdate = datetime.datetime(2017,4,10), todate=datetime.datetime(2017,4,20), nullvalue=0.0, dtformat=('%Y.%m.%d'), tmformat=('%H:%M'), datetime=0, time=1, open=2, high=3, low=4, close=5, volume=6, openinterest=-1) cerebro.adddata(data) cerebro.addstrategy(St) cerebro.broker.setcash(100000.0) print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) cerebro.run(stdstats=False) print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue()) #plotter = Plotter() #cerebro.plot(plotter=plotter,subplot=False) def parse_args(): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter, description='Sample for pivot point and cross plotting') parser.add_argument('--data0', default='d:\\I - TradersGPS\\GBPUSD_D1_UTC+2_00.csv', required=False, help='Data0 to read in') parser.add_argument('--data1', default='d:\\I - TradersGPS\\GBPUSD_H1_UTC+2_00.csv', required=False, help='Data1 to read in') parser.add_argument('--fromdate', required=False, default='2001-01-01', help='Date[time] in YYYY-MM-DD[THH:MM:SS] format') parser.add_argument('--todate', required=False, default='2007-01-01', help='Date[time] in YYYY-MM-DD[THH:MM:SS] format') parser.add_argument('--plot', required=False, action='store_true', help=('Plot the result')) return parser.parse_args() if __name__ == '__main__': runstrat()
This is a snippet of my data. It is a daily data with date. time, open, high, low,close,volume.
2017.04.10,00:00,1.23802,1.24286,1.23657,1.24117,196634
2017.04.11,00:00,1.24116,1.24944,1.24035,1.24893,235307
2017.04.12,00:00,1.24891,1.25483,1.24801,1.25387,261157
2017.04.13,00:00,1.2537,1.25742,1.25,1.25008,248594
2017.04.14,00:00,1.25007,1.25346,1.2497,1.25172,161537
2017.04.17,00:00,1.25271,1.25959,1.2524,1.25631,164495
2017.04.18,00:00,1.25638,1.29053,1.25151,1.284,336253
2017.04.19,00:00,1.28398,1.28603,1.27701,1.27772,278525
2017.04.20,00:00,1.27773,1.28444,1.27724,1.28298,114281This is the output from my code:
Starting Portfolio Value: 100000.00 0001,2017-04-10,Open : 1.23802,High : 1.24286,Low : 1.23657,Close : 1.24117,Position : 0 2017-04-10, BUY CREATE, 1.23802, Limitprice : 1.25040, Stopprice : 1.22564 0002,2017-04-11,Open : 1.24116,High : 1.24944,Low : 1.24035,Close : 1.24893,Position : 0 2017-04-11, SELL CREATE, 1.24116, Limitprice : 1.22875, Stopprice : 1.25357 2017-04-12, SELL EXECUTED, Price: 1.24891, Cost: -1.24891,Position : -1 0003,2017-04-12,Open : 1.24891,High : 1.25483,Low : 1.24801,Close : 1.25387,Position : -1 2017-04-13, BUY EXECUTED, Price: 1.25370, Cost: -1.24891, Position : 0 2017-04-13, Order Canceled/Margin/Rejected 2017-04-13, OPERATION PROFIT, GROSS -0.00479, NET -0.00479 0004,2017-04-13,Open : 1.25370,High : 1.25742,Low : 1.25000,Close : 1.25008,Position : 0 2017-04-13, SELL CREATE, 1.25370, Limitprice : 1.24116, Stopprice : 1.26624 0005,2017-04-14,Open : 1.25007,High : 1.25346,Low : 1.24970,Close : 1.25172,Position : 0 2017-04-14, BUY CREATE, 1.25007, Limitprice : 1.26257, Stopprice : 1.23757 2017-04-17, SELL EXECUTED, Price: 1.25370, Cost: -1.25370,Position : -1 0006,2017-04-17,Open : 1.25271,High : 1.25959,Low : 1.25240,Close : 1.25631,Position : -1 2017-04-18, BUY EXECUTED, Price: 1.26624, Cost: -1.25370, Position : 0 2017-04-18, Order Canceled/Margin/Rejected 2017-04-18, OPERATION PROFIT, GROSS -0.01254, NET -0.01254 0007,2017-04-18,Open : 1.25638,High : 1.29053,Low : 1.25151,Close : 1.28400,Position : 0 2017-04-18, SELL CREATE, 1.25638, Limitprice : 1.24382, Stopprice : 1.26894 2017-04-19, SELL EXECUTED, Price: 1.28398, Cost: -1.28398,Position : -1 0008,2017-04-19,Open : 1.28398,High : 1.28603,Low : 1.27701,Close : 1.27772,Position : -1 Final Portfolio Value: 99999.99
I would like to know how to set the limit price and the stop price to be a percentage of the execution price. For now, the execution price is the open price of the next day but the limit and stop price are based on the open price of that day.
I would also like to know why are there buy orders that are not executed (e.g. : 2017-04-10, BUY CREATE, 1.23802)
Thanks a lot :D
-
I tried using the manual bracket order to code the same strategies.
from __future__ import (absolute_import, division, print_function, unicode_literals) import os.path import argparse import datetime import collections import backtrader as bt import backtrader.feeds as btfeeds import backtrader.plot as plt import backtrader.indicators as btinds MAINSIGNALS = collections.OrderedDict( (('longonly',bt.SIGNAL_LONG), ('shortonly',bt.SIGNAL_SHORT), )) class Plotter(plt.Plot): def __init__(self): super().__init__(volup='#60cc73') # custom color for volume up bars def show(self): mng = self.mpyplot.get_current_fig_manager() mng.window.state('zoomed') self.mpyplot.show() class St(bt.Strategy): def log(self, txt, dt=None): ''' Logging function fot this strategy''' dt = dt or self.data.datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): self.signal = 0 def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: return if order.status in [order.Completed]: if order.isbuy(): self.signal +=1 self.log( 'BUY EXECUTED, Price: %.5f, Cost: %.5f, Position : %d' % (order.executed.price, order.executed.value,self.signal)) self.buyprice = order.executed.price else: # Sell self.signal -= 1 self.log('SELL EXECUTED, Price: %.5f, Cost: %.5f,Position : %d' % (order.executed.price, order.executed.value,self.signal)) 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 notify_trade(self, trade): if not trade.isclosed: return self.log('OPERATION PROFIT, GROSS %.5f, NET %.5f' % (trade.pnl, trade.pnlcomm)) def next(self): txt = ','.join( ['%04d' % len(self.data), self.data.datetime.date(0).isoformat(), 'Open : %.5f' % self.data.open[0], 'High : %.5f' % self.data.high[0], 'Low : %.5f' % self.data.low[0], 'Close : %.5f' % self.data.close[0], 'Position : %d' % self.signal]) print(txt) if self.signal == 0: if self.data.open[0] > self.data.close[0]: o1 = self.buy(exectype=bt.Order.Market, transmit=False) print('{}: Oref {} / Buy at {}'.format( self.datetime.date(), o1.ref,self.data.open[1])) o2 = self.sell(exectype=bt.Order.Stop, price=0.99*self.data.open[1], parent=o1, transmit=False) print('{}: Oref {} / Sell Stop at {}'.format( self.datetime.date(), o2.ref,0.99*self.data.open[1])) o3 = self.sell(exectype=bt.Order.Limit, price=1.01*self.data.open[1], parent=o1, transmit=True) print('{}: Oref {} / Sell Limit at {}'.format( self.datetime.date(), o3.ref,1.01*self.data.open[1])) self.orefs = [o1.ref, o2.ref, o3.ref] elif self.data.open[0] < self.data.close[0]: o1 = self.sell(exectype=bt.Order.Market, transmit=False) print('{}: Oref {} / Sell at {}'.format( self.datetime.date(), o1.ref,self.data.open[1])) o2 = self.buy(exectype=bt.Order.Stop, price=1.01*self.data.open[1], parent=o1, transmit=False) print('{}: Oref {} / Buy Stop at {}'.format( self.datetime.date(), o2.ref,1.01*self.data.open[1])) o3 = self.buy(exectype=bt.Order.Limit, price=0.99*self.data.open[1], parent=o1, transmit=True) print('{}: Oref {} / Buy Limit at {}'.format( self.datetime.date(), o3.ref,0.99*self.data.open[1])) self.orefs = [o1.ref, o2.ref, o3.ref] elif self.signal == 1: if self.data.open[0] > self.data.close[0]: return elif self.data.open[0] < self.data.close[0]: o1 = self.sell(exectype=bt.Order.Market, transmit=False,size=2) print('{}: Oref {} / Sell at {}'.format( self.datetime.date(), o1.ref,self.data.open[1])) o2 = self.buy(exectype=bt.Order.Stop, price=1.01*self.data.open[1], parent=o1, transmit=False) print('{}: Oref {} / Buy Stop at {}'.format( self.datetime.date(), o2.ref,1.01*self.data.open[1])) o3 = self.buy(exectype=bt.Order.Limit, price=0.99*self.data.open[1], parent=o1, transmit=True) print('{}: Oref {} / Buy Limit at {}'.format( self.datetime.date(), o3.ref,0.99*self.data.open[1])) self.orefs = [o1.ref, o2.ref, o3.ref] elif self.signal == -1: if self.data.open[0] < self.data.close[0]: return elif self.data.open[0] > self.data.close[0] : o1 = self.sell(exectype=bt.Order.Market,size=2, transmit=False) print('{}: Oref {} / Sell at {}'.format( self.datetime.date(), o1.ref,self.data.open[1])) o2 = self.buy(exectype=bt.Order.Stop, price=1.01*self.data.open[1], parent=o1, transmit=False) print('{}: Oref {} / Buy Stop at {}'.format( self.datetime.date(), o2.ref,1.01*self.data.open[1])) o3 = self.buy(exectype=bt.Order.Limit, price=0.99*self.data.open[1], parent=o1, transmit=True) print('{}: Oref {} / Buy Limit at {}'.format( self.datetime.date(), o3.ref,0.99*self.data.open[1])) self.orefs = [o1.ref, o2.ref, o3.ref] class Plotter(plt.Plot): def __init__(self): super().__init__(volup='#60cc73') # custom color for volume up bars def show(self): mng = self.mpyplot.get_current_fig_manager() mng.window.state('zoomed') self.mpyplot.show() def runstrat(): args = parse_args() cerebro = bt.Cerebro() modpath = 'd:\\I - TradersGPS\\' datapath = os.path.join(modpath, 'GBPUSD_D1_UTC+2_00.csv') data = btfeeds.GenericCSVData(dataname=datapath, timeframe=bt.TimeFrame.Days, fromdate = datetime.datetime(2017,4,10), todate=datetime.datetime(2017,4,20), nullvalue=0.0, dtformat=('%Y.%m.%d'), tmformat=('%H:%M'), datetime=0, time=1, open=2, high=3, low=4, close=5, volume=6, openinterest=-1) cerebro.adddata(data) cerebro.addstrategy(St) cerebro.broker.setcash(100000.0) print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) cerebro.run(stdstats=False) print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue()) #plotter = Plotter() #cerebro.plot(plotter=plotter,subplot=False) def parse_args(): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter, description='Sample for pivot point and cross plotting') parser.add_argument('--data0', default='d:\\I - TradersGPS\\GBPUSD_D1_UTC+2_00.csv', required=False, help='Data0 to read in') parser.add_argument('--data1', default='d:\\I - TradersGPS\\GBPUSD_H1_UTC+2_00.csv', required=False, help='Data1 to read in') parser.add_argument('--fromdate', required=False, default='2001-01-01', help='Date[time] in YYYY-MM-DD[THH:MM:SS] format') parser.add_argument('--todate', required=False, default='2007-01-01', help='Date[time] in YYYY-MM-DD[THH:MM:SS] format') parser.add_argument('--plot', required=False, action='store_true', help=('Plot the result')) return parser.parse_args() if __name__ == '__main__': runstrat()
I got the warning that the array index out of range. Is it because of the [1] ? Thankss :)
File "<ipython-input-11-2905f8945d39>", line 176, in next self.datetime.date(), o1.ref,self.data.open[1])) File "C:\Users\KT\Miniconda3\lib\site-packages\backtrader\linebuffer.py", line 163, in __getitem__ return self.array[self.idx + ago] IndexError: array index out of range
-
@KT said in Buying and Selling with Signals:
I would like to know how to set the limit price and the stop price to be a percentage of the execution price
You cannot with a bracket order. You can do it manually or you can set the bracketing orders to be
StopTrail
orders, where you can set the trailing in percentage mode, but it will not be a percentage of the execution price, because that price is not known in advance.@KT said in Buying and Selling with Signals:
Is it because of the [1]
[1]
is the future and therefore an error can be expected.@KT said in Buying and Selling with Signals:
I tried using the manual bracket
buy_bracket
generates 3 orders. Creating the 3 orders won't also allow you a priori to set things in terms of the execution price because that price is only known after execution and not during order creation. -
Thanks @backtrader for the help :)
May I know how to implement it manually?
-
Once you receive notification of order execution, you use
order.executed.price
as the reference to send the desired orders into the market at a percentage of the execution price. -
Hi @backtrader Can I see the sample implementation using the code above? I am quite confused on how to implement it. Thanks :)
-
There is no such thing as a sample implementation.
- You send an order to the market:
self.buy(price=myprice, exectype=bt.Order.MyPreferredExecutionType)
- The order is completed and notified to
notify_order(order)
order.executed.price
contains the actual execution price- A new order is sent to act as a stop-loss order:
self.sell(price=% of order.executed.price, exectype=probably Stop)
- You send an order to the market: