For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/
Best way to issue an ATR based trail order?
-
Hi, my strategy buys when some condition is met, it will set a stop loss say 2 ATR below the buy price.
I want to trail the price if it goes up without using a fixed percentage or amount value, basically by using 3 ATR of a bar and recalculating what the trail level should be.
What is the best way I can do this? Where I only issue an order when the close price is crossed below a level that is 3 ATRs below that close price? Currently I am trying to issue the order if I am in position and those conditions are met. But I am facing some challenge in using this. I am sharing my code below:
class bo(bt.Strategy): params = (('fma', 20), ('sma', 50), ('trail', 0.08),) def __init__(self): self.vix = self.datas[2].close self.inds = {} for d in self.datas[:2]: self.inds[d] = {} self.inds[d]['open'] = d.open self.inds[d]['close'] = d.close self.inds[d]['high'] = d.high self.inds[d]['low'] = d.low self.inds[d]['atr'] = bt.talib.ATR(self.inds[d]['high'], self.inds[d]['low'], self.inds[d]['close'], timeperiod = 14) self.inds[d]['maxatr'] = d.close - (self.inds[d]['atr'] * 3) # self.inds[d]['atrema'] = bt.talib.EMA(self.inds[d]['atr'], timeperiod = 30) self.inds[d]['highest'] = bt.indicators.Highest(self.inds[d]['high'], period = 20) self.inds[d]['lowest'] = bt.indicators.Lowest(self.inds[d]['low'], period = 20) self.trigger_price = [] self.buy_exec = 0 self.daily_atrs = {} self.daily_atrs[d] = [] self.orders = {} self.sellprice = {} self.execprice = {} def log(self, txt, dt=None): dt = self.datas[0].datetime.date() print(f'Date: {dt}, {txt}') def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: return if order.status in [order.Completed]: if order.isbuy(): self.execprice[order.data] = order.executed.price self.totalcost = order.executed.value self.buy_exec = len(self) self.log(f'NAME: {order.data._name}, BUY EXECUTED: {self.execprice[order.data]}, Cost: {self.totalcost}') elif order.issell(): self.sellprice[order.data] = order.executed.price self.sellcost = order.executed.value self.log(f'NAME: {order.data._name}, SELL EXECUTED: {self.sellprice[order.data]}, COST: {self.sellcost}') elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') order_name = ['Main', 'Stop', 'Limit', 'Close'] if not order.alive(): dorders = self.orders[order.data] # print(f'DORDERS: {dorders}') idx_orders = dorders.index(order) # print(f'IDX OF ORDER: {idx_orders}') dorders[idx_orders] = None # print(f'REMAINING ORDERS: {dorders}') self.log('-- No longer alive {} Order'.format(order_name[idx_orders])) if all(x is None for x in dorders): dorders[:] = [] def notify_trade(self, trade): if trade.isopen: return else: self.log(f'OPERATION PROFIT: GROSS {trade.pnl}, NET {trade.pnlcomm}, Trade PnL: {trade.pnlcomm/self.totalcost}') self.log(f'Updated Account Balance: {cerebro.broker.getcash()}') def next(self): for d in self.datas[:2]: name = d._name pos = self.getposition(d).size atr = self.inds[d]['atr'][0] self.log(f'NAME: {name}, CLOSE: {d.close[0]}, POS: {pos}') if not pos: if self.inds[d]['close'][0] > self.inds[d]['highest'][-1]: # if not np.isnan(self.inds[d]['atrema'][0]): buy_execprice = self.inds[d]['open'][1] o1 = self.buy(data = d) o2 = self.sell(data = d, exectype=bt.Order.Stop, price = (buy_execprice - (atr * 2))) self.log(f'{name}, BUY CREATED: {o1.created.price}, STOP: {o2.created.price}, SIZE: {o1.created.size}, ATR: {atr}') self.orders[d] = [o1, o2] else: if pos > 0: atr_stop = self.inds[d]['maxatr'][0] self.daily_atrs[d].append(atr_stop) self.log(f'ATRS: {self.daily_atrs}') if self.inds[d]['close'][0] <= atr_stop: o3 = self.sell(data = d, oco = self.orders[d][1]) self.orders[d].append(o3) cerebro = bt.Cerebro() cerebro.broker.set_cash(200000) print(f'Starting Portfolio Value: {cerebro.broker.getvalue()}') for n in range(len(df)): dataset = list(zip(df, names)) data = bt.feeds.PandasData(dataname=dataset[n][0], datetime=None, open=-1, high=-1, low=-1, close=-1, volume=-1) cerebro.adddata(data, name = dataset[n][1]) data1 = bt.feeds.PandasData(dataname=vix, datetime=None, open=-1, high=-1, low=-1, close=-1, volume=-1) cerebro.adddata(data1, name = 'vix') cerebro.addstrategy(bo) cerebro.addsizer(bt.sizers.FixedSize, stake = 10) cerebro.addanalyzer(trades_list, _name = 'listrades') strat = cerebro.run(tradehistory = True) strats = strat[0].analyzers.listrades.get_analysis() listrades = pd.DataFrame(strats) # cerebro.run() print(f'Final Portfolio Value: {cerebro.broker.getvalue()}')