Overall Statistics |
Total Trades 40 Average Win 5.12% Average Loss -2.78% Compounding Annual Return 17.916% Drawdown 22.200% Expectancy 0.279 Net Profit 17.916% Sharpe Ratio 0.602 Probabilistic Sharpe Ratio 33.239% Loss Rate 55% Win Rate 45% Profit-Loss Ratio 1.84 Alpha 0.017 Beta 1.646 Annual Standard Deviation 0.302 Annual Variance 0.091 Information Ratio 0.335 Tracking Error 0.243 Treynor Ratio 0.111 Total Fees $47.12 |
import numpy as np class BetaAlgorithm(QCAlgorithm): def Initialize(self): self.SetStartDate(2016, 1, 1) # Set Start Date self.SetEndDate(2017, 1, 1) # Set End Date self.SetCash(10000) # Set Strategy Cash # Dow 30 companies. self.symbols = [self.AddEquity(ticker).Symbol for ticker in ['AAPL', 'AXP', 'BA', 'CAT', 'CSCO', 'CVX', 'DD', 'DIS', 'GE', 'GS', 'HD', 'IBM', 'INTC', 'JPM', 'KO', 'MCD', 'MMM', 'MRK', 'MSFT', 'NKE', 'PFE', 'PG', 'TRV', 'UNH', 'UTX', 'V', 'VZ', 'WMT', 'XOM'] ] # Benchmark self.benchmark = Symbol.Create('SPY', SecurityType.Equity, Market.USA) # Set number days to trace back self.lookback = 21 # Schedule Event: trigger the event at the begining of each month. self.Schedule.On(self.DateRules.MonthStart(self.symbols[0]), self.TimeRules.AfterMarketOpen(self.symbols[0]), self.Rebalance) # Adding the DIA ETF which tracks the Dow Jones self.dow = self.AddEquity("DIA", Resolution.Daily).Symbol # Defining a 200 day Simple Moving Average indicator for DIA self.sma = self.SMA("DIA", 200, Resolution.Daily) # Warming up our indicator self.SetWarmUp(timedelta(days = 200)) def Rebalance(self): # If the algorithm is still warming up, we wait if self.IsWarmingUp: return # If the Dow Jones is under its 200 day moving average if self.Securities[self.dow].Close <= self.sma.Current.Value: # We liquidate any assets if we have any if self.Portfolio.Invested: self.Liquidate() # We wait until it is over the 200 day moving average return # Fetch the historical data to perform the linear regression history = self.History( self.symbols + [self.benchmark], self.lookback, Resolution.Daily).close.unstack(level=0) symbols = self.SelectSymbols(history) # Liquidate positions that are not held by selected symbols for holdings in self.Portfolio.Values: symbol = holdings.Symbol if symbol not in symbols and holdings.Invested: self.Liquidate(symbol) # Invest 100% in the selected symbols for symbol in symbols: self.SetHoldings(symbol, 1) def SelectSymbols(self, history): '''Select symbols with the highest intercept/alpha to the benchmark ''' alphas = dict() # Get the benchmark returns benchmark = history[self.benchmark].pct_change().dropna() # Conducts linear regression for each symbol and save the intercept/alpha for symbol in self.symbols: # Get the security returns returns = history[symbol].pct_change().dropna() returns = np.vstack([returns, np.ones(len(returns))]).T # Simple linear regression function in Numpy result = np.linalg.lstsq(returns, benchmark) alphas[symbol] = result[0][1] # Select symbols with the highest intercept/alpha to the benchmark selected = sorted(alphas.items(), key=lambda x: x[1], reverse=True)[:2] return [x[0] for x in selected]