Overall Statistics |
Total Trades 396 Average Win 0.17% Average Loss -0.06% Compounding Annual Return -2.515% Drawdown 3.600% Expectancy 0.003 Net Profit -1.878% Sharpe Ratio -0.916 Sortino Ratio -1.013 Probabilistic Sharpe Ratio 8.147% Loss Rate 74% Win Rate 26% Profit-Loss Ratio 2.89 Alpha -0.043 Beta -0.035 Annual Standard Deviation 0.048 Annual Variance 0.002 Information Ratio -0.529 Tracking Error 0.149 Treynor Ratio 1.261 Total Fees $456.50 Estimated Strategy Capacity $3900000.00 Lowest Capacity Asset PEP R735QTJ8XC9X Portfolio Turnover 4.55% |
from AlgorithmImports import * from datetime import timedelta, datetime class SMAPairsTrading(QCAlgorithm): def Initialize(self): self.SetStartDate(2018, 7, 1) self.SetEndDate(2019, 3, 31) self.SetCash(100000) self.ko = self.AddEquity("KO", Resolution.Hour, dataNormalizationMode=DataNormalizationMode.Raw).Symbol self.pep = self.AddEquity("PEP", Resolution.Hour, dataNormalizationMode=DataNormalizationMode.Raw).Symbol self.spreadMean = SimpleMovingAverage(500) self.spreadStd = StandardDeviation(500) self.period = timedelta(hours=2) #1. Call for 500 bars of history data for each symbol in the pair and save to the variable history history = self.History[TradeBar]([self.ko, self.pep], 500) #2. Iterate through the history and update the mean and standard deviation with historical data for bars in history: time, spread = self.GetSpread(bars) if spread: self.UpdateIndicators(time, spread) def GetSpread(self, bars: TradeBars): pep_bar = bars.get(self.pep) ko_bar = bars.get(self.ko) if not (pep_bar and ko_bar): return None, None return pep_bar.EndTime, abs(pep_bar.Close - ko_bar.Close) def UpdateIndicators(self, time, spread): self.spreadMean.Update(time, spread) self.spreadStd.Update(time, spread) def OnData(self, data): _, spread = self.GetSpread(data.Bars) if not spread: return self.UpdateIndicators(self.Time, spread) weight = .5 spreadMean = self.spreadMean.Current.Value upperthreshold = spreadMean + self.spreadStd.Current.Value lowerthreshold = spreadMean - self.spreadStd.Current.Value # Close positions if reverses to the mean ko_holdings = self.Portfolio[self.ko] if ko_holdings.IsLong and spread < spreadMean: self.PlotSpread(spread, lowerthreshold, spreadMean, upperthreshold) self.Liquidate() return if ko_holdings.IsShort and spread > spreadMean: self.Liquidate() self.PlotSpread(spread, lowerthreshold, spreadMean, upperthreshold) return if spread > upperthreshold: self.PlotSpread(spread, lowerthreshold, spreadMean, upperthreshold) self.SetHoldings([ PortfolioTarget(self.ko, weight), PortfolioTarget(self.pep, -weight) ]) if spread < lowerthreshold: self.PlotSpread(spread, lowerthreshold, spreadMean, upperthreshold) self.SetHoldings([ PortfolioTarget(self.ko, -weight), PortfolioTarget(self.pep, weight) ]) def PlotSpread(self, spread, lowerthreshold, mean, upperthreshold): self.Plot('Spread', 'Current', spread) self.Plot('Spread', 'Mean', mean) self.Plot('Spread', 'Lower', lowerthreshold) self.Plot('Spread', 'Upper', upperthreshold)