For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/
Pair Trading Problem
-
Hi to my lovely Community ,
Where is the error in the code please for implementing the Pair Trading Strategy ?
Thank you very much
from __future__ import (absolute_import, division, print_function, unicode_literals) import argparse import backtrader as bt import backtrader.analyzers as btanalyzers import backtrader.feeds as btfeeds import backtrader.indicators as btind import datetime import pandas as pd import matplotlib import pandas as pd import quantstats class PairsTradingStrategy(bt.Strategy) : params = dict( period = 10, stake = 10, qty1 = 0, qty2 = 0, printout = True, upper = 2.1, lower = -2.1, up_medium = 0.5, low_medium = -0.5, upper_level = 2.1, lower_level = -2.1, status = 0, portfolio_value=10000, ) def log(self,txt,dt=None) : if self.p.printout : dt = dt or self.data.datetime[0] dt = bt.num2date(dt) print('%s,%s' % (dt.isoformat(),txt)) def notify_order(self,order) : if order.status in [bt.Order.Submitted,bt.Order.Accepted] : return if order.status == order.Completed : if order.isbuy(): buytxt = 'BUY COMPLETE,%2f' % order.executed.price self.log(buytxt,order.executed.dt) else: selltxt = 'SELL COMPLETE,%.2f' % order.executed.price self.log(selltxt,order.executed.dt) elif order.status in [order.Expired,order.Canceled,order.Margin]: self.log('%s,'% order.Status[order.status]) pass self.orderid = None def __init__(self): self.orderid = None self.qty1 = self.p.qty1 self.qty2 = self.p.qty2 self.upper_limit = self.p.upper self.lower_limit = self.p.lower self.up_medium = self.p.up_medium self.low_medium = self.p.low_medium self.status = self.p.status self.portfolio_value = self.p.portfolio_value self.transform = btind.OLS_TransformationN(self.data0,self.data1,period=self.p.period) self.zscore = self.transform.zscore def next(self) : if self.orderid : return if self.p.printout: print('Self len:', len(self)) print('Data0 len:', len(self.data0)) print('Data1 len:', len(self.data1)) print('Data0 len == Data1 len:', len(self.data0) == len(self.data1)) print('Data0 dt:', self.data0.datetime.datetime()) print('Data1 dt:', self.data1.datetime.datetime()) print('status is', self.status) print('zscore is', self.zscore[0]) # Step 2: Check conditions for SHORT & place the order # Checking the condition for SHORT if (self.zscore[0] > self.upper_limit) and (self.status != 1): # Calculating the number of shares for each stock value = 0.5 * self.portfolio_value # Divide the cash equally x = int(value / (self.data0.close)) # Find the number of shares for Stock1 y = int(value / (self.data1.close)) # Find the number of shares for Stock2 print('x + self.qty1 is', x + self.qty1) print('y + self.qty2 is', y + self.qty2) # Placing the order self.log('SELL CREATE %s, price = %.2f, qty = %d' % ("AACQW", self.data0.close[0], x + self.qty1)) self.sell(data=self.data0, size=(x + self.qty1)) # Place an order for buying y + qty2 shares self.log('BUY CREATE %s, price = %.2f, qty = %d' % ("AAME", self.data1.close[0], y + self.qty2)) self.buy(data=self.data1, size=(y + self.qty2)) # Place an order for selling x + qty1 shares # Updating the counters with new value self.qty1 = x # The new open position quantity for Stock1 is x shares self.qty2 = y # The new open position quantity for Stock2 is y shares self.status = 1 # The current status is "short the spread" # Step 3: Check conditions for LONG & place the order # Checking the condition for LONG elif (self.zscore[0] < self.lower_limit) and (self.status != 2): # Calculating the number of shares for each stock value = 0.5 * self.portfolio_value # Divide the cash equally x = int(value / (self.data0.close)) # Find the number of shares for Stock1 y = int(value / (self.data1.close)) # Find the number of shares for Stock2 print('x + self.qty1 is', x + self.qty1) print('y + self.qty2 is', y + self.qty2) # Place the order self.log('BUY CREATE %s, price = %.2f, qty = %d' % ("AACQW", self.data0.close[0], x + self.qty1)) self.buy(data=self.data0, size=(x + self.qty1)) # Place an order for buying x + qty1 shares self.log('SELL CREATE %s, price = %.2f, qty = %d' % ("AAME", self.data1.close[0], y + self.qty2)) self.sell(data=self.data1, size=(y + self.qty2)) # Place an order for selling y + qty2 shares # Updating the counters with new value self.qty1 = x # The new open position quantity for Stock1 is x shares self.qty2 = y # The new open position quantity for Stock2 is y shares self.status = 2 # The current status is "long the spread" # Step 4: Check conditions for No Trade # If the z-score is within the two bounds, close all elif (self.zscore[0] < self.up_medium and self.zscore[0] > self.low_medium): self.log('CLOSE LONG %s, price = %.2f' % ("AACQW", self.data0.close[0])) self.close(self.data0) self.log('CLOSE LONG %s, price = %.2f' % ("AAME", self.data1.close[0])) self.close(self.data1) def stop(self): print('==================================================') print('Starting Value - %.2f' % self.broker.startingcash) print('Ending Value - %.2f' % self.broker.getvalue()) print('==================================================') def parse_args(): parser = argparse.ArgumentParser(description='MultiData Strategy') parser.add_argument('--data0', '-d0', default='/Users/bibani/Desktop/AACQW.csv', help='1st data into the system') parser.add_argument('--data1', '-d1', default='/Users/bibani/Desktop/AAME.csv', help='2nd data into the system') parser.add_argument('--fromdate', '-f', default='2018-01-02', help='Starting date in YYYY-MM-DD format') parser.add_argument('--todate', '-t', default='2021-01-15', help='Starting date in YYYY-MM-DD format') parser.add_argument('--period', default=10, type=int, help='Period to apply to the Simple Moving Average') parser.add_argument('--cash', default=100000, type=int, help='Starting Cash') parser.add_argument('--runnext', action='store_true', help='Use next by next instead of runonce') parser.add_argument('--nopreload', action='store_true', help='Do not preload the data') parser.add_argument('--oldsync', action='store_true', help='Use old data synchronization method') parser.add_argument('--commperc', default=0.005, type=float, help='Percentage commission (0.005 is 0.5%%') parser.add_argument('--stake', default=10, type=int, help='Stake to apply in each operation') parser.add_argument('--plot', '-p', default=True, action='store_true', help='Plot the read data') parser.add_argument('--numfigs', '-n', default=1, help='Plot using numfigs figures') return parser.parse_args() def runstrategy(): args = parse_args() # Create a cerebro cerebro = bt.Cerebro() # Get the dates from the args fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d') todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d') # Create the 1st data data0 = btfeeds.GenericCSVData( dataname=args.data0, dtformat = ('%Y-%m-%d'), fromdate=fromdate, todate=todate, datetime=0, high=-1, low=-1, open=-1, close=1, volume=-1, openinterest=-1 ) # Add the 1st data to cerebro cerebro.adddata(data0) # Create the 2nd data data1 = btfeeds.GenericCSVData( dataname=args.data1, dtformat = ('%Y-%m-%d'), fromdate=fromdate, todate=todate, datetime=0, high=-1, low=-1, open=-1, close=1, volume=-1, openinterest=-1 ) # Add the 2nd data to cerebro cerebro.adddata(data1) # Add the strategy cerebro.addstrategy(PairsTradingStrategy, period=args.period, stake=args.stake) cerebro.broker.setcash(args.cash) # Add the commission - only stocks like a for each operation cerebro.broker.setcommission(commission=args.commperc) # And run it results = cerebro.run(runonce=not args.runnext, preload=not args.nopreload, oldsync=args.oldsync) cerebro.broker.getvalue() cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='SharpeRatio') cerebro.addanalyzer(bt.analyzers.DrawDown, _name='DW') end_portfolio_value = cerebro.broker.getvalue() #print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue()) #print('SR:', cerebro.analyzers.SharpeRatio.get_analysis()) #print('DW:', cerebro.analyzers.DW.get_analysis()) # Plot if requested if args.plot: cerebro.plot(numfigs=args.numfigs, volume=False, zdown=False,iplot= False) if __name__ == '__main__': runstrategy()