Overall Statistics |
Total Trades 109 Average Win 0.32% Average Loss -0.02% Compounding Annual Return 57.930% Drawdown 1.500% Expectancy 2.979 Net Profit 3.909% Sharpe Ratio 5.652 Probabilistic Sharpe Ratio 90.435% Loss Rate 73% Win Rate 27% Profit-Loss Ratio 13.85 Alpha 0.436 Beta 0.091 Annual Standard Deviation 0.082 Annual Variance 0.007 Information Ratio 1.18 Tracking Error 0.156 Treynor Ratio 5.052 Total Fees $123.12 Estimated Strategy Capacity $3400000.00 |
from datetime import timedelta, datetime class SMAPairsTrading(QCAlgorithm): def Initialize(self): self.SetStartDate(2021, 3, 1) self.SetEndDate(2021, 3, 31) self.SetCash(100000) pairIndex = int(self.GetParameter("pairIndex")) symbolPairs = [] symbolPairs.append ( [Symbol.Create("DISH", SecurityType.Equity, Market.USA), Symbol.Create("UNM", SecurityType.Equity, Market.USA)] ) symbolPairs.append ( [Symbol.Create("SBUX", SecurityType.Equity, Market.USA), Symbol.Create("IBM", SecurityType.Equity, Market.USA)] ) symbolPairs.append ( [Symbol.Create("TSLA", SecurityType.Equity, Market.USA), Symbol.Create("SPY", SecurityType.Equity, Market.USA)] ) symbols = symbolPairs[pairIndex] self.AddUniverseSelection(ManualUniverseSelectionModel(symbols)) self.UniverseSettings.Resolution = Resolution.Hour self.UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw self.AddAlpha(PairsTradingAlphaModel()) self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) self.SetExecution(ImmediateExecutionModel()) def OnEndOfDay(self, symbol): self.Log("Taking a position of " + str(self.Portfolio[symbol].Quantity) + " units of symbol " + str(symbol)) class PairsTradingAlphaModel(AlphaModel): def __init__(self): self.pair = [ ] self.spreadMean = SimpleMovingAverage(500) self.spreadStd = StandardDeviation(500) self.period = timedelta(hours=2) def Update(self, algorithm, data): spread = self.pair[1].Price - self.pair[0].Price self.spreadMean.Update(algorithm.Time, spread) self.spreadStd.Update(algorithm.Time, spread) upperthreshold = self.spreadMean.Current.Value + self.spreadStd.Current.Value lowerthreshold = self.spreadMean.Current.Value - self.spreadStd.Current.Value if spread > upperthreshold: return Insight.Group( [ Insight.Price(self.pair[0].Symbol, self.period, InsightDirection.Up), Insight.Price(self.pair[1].Symbol, self.period, InsightDirection.Down) ]) if spread < lowerthreshold: return Insight.Group( [ Insight.Price(self.pair[0].Symbol, self.period, InsightDirection.Down), Insight.Price(self.pair[1].Symbol, self.period, InsightDirection.Up) ]) return [] def OnSecuritiesChanged(self, algorithm, changes): self.pair = [x for x in changes.AddedSecurities] #1. Call for 500 bars of history data for each symbol in the pair and save to the variable history history = algorithm.History([x.Symbol for x in self.pair], 500) #2. Unstack the Pandas data frame to reduce it to the history close price history = history.close.unstack(level=0) #3. Iterate through the history tuple and update the mean and standard deviation with historical data for tuple in history.itertuples(): self.spreadMean.Update(tuple[0], tuple[2]-tuple[1]) self.spreadStd.Update(tuple[0], tuple[2]-tuple[1])