Overall Statistics |
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio -2.99 Tracking Error 0.065 Treynor Ratio 0 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset |
#region imports from AlgorithmImports import * #endregion # https://quantpedia.com/Screener/Details/77 from QuantConnect.Data.UniverseSelection import * from QuantConnect.Python import PythonData from collections import deque from datetime import datetime import math import numpy as np import pandas as pd import scipy as sp #from decimal import Decimal class BetaFactorInStocks(QCAlgorithm): def Initialize(self): self.SetStartDate(2018, 6, 1) self.SetEndDate(2018, 9, 1) self.SetCash(1000000) self.UniverseSettings.Resolution = Resolution.Daily self.AddUniverse(self.CoarseSelectionFunction) self.AddEquity("SPY", Resolution.Daily) # add Wilshire 5000 Total Market Index data from Dropbox self.AddData(Wilshire5000, "W5000", Resolution.Daily) self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.AfterMarketOpen("SPY"), self.rebalance) self.data = {} self.monthly_rebalance = False self.long = None self.short = None self.market_price = deque(maxlen=253) hist = self.History(["W5000"], 400, Resolution.Daily) for i in hist.loc["W5000"].itertuples(): self.market_price.append(i.value) def CoarseSelectionFunction(self, coarse): if self.Securities["W5000"].Price is not None: self.market_price.append(self.Securities["W5000"].Price) for i in coarse: if i.Symbol not in self.data: self.data[i.Symbol] = SymbolData(i.Symbol) self.data[i.Symbol].Update(i.AdjustedPrice) if self.monthly_rebalance: sortedByPrice = [i.Symbol for i in coarse if i.AdjustedPrice>5] ready_data = {symbol: data for symbol, data in self.data.items() if symbol in sortedByPrice and data.IsReady()} if len(ready_data) > 20: self.market_return = np.diff(np.array(self.market_price))/np.array(self.market_price)[:-1] # sort the dictionary in ascending order by beta value sorted_beta = sorted(ready_data, key = lambda x: ready_data[x].beta(self.market_return)) self.long = sorted_beta[:5] self.short = sorted_beta[-5:] return self.long+self.short else: self.monthly_rebalance = False return [] else: return [] def rebalance(self): self.monthly_rebalance = True def OnData(self, data): if not self.monthly_rebalance: return if self.long is None or self.short is None: return long_invested = [x.Key for x in self.Portfolio if x.Value.IsLong] short_invested = [x.Key for x in self.Portfolio if x.Value.IsShort] for i in long_invested: if i not in self.long: self.Liquidate(i) for i in short_invested: if i not in self.short: self.Liquidate(i) long_scale_factor = 0.5/sum(range(1,len(self.long)+1)) for rank, symbol in enumerate(self.long): self.SetHoldings(symbol, (len(self.long)-rank+1)*long_scale_factor) short_scale_factor = 0.5/sum(range(1,len(self.long)+1)) for rank, symbol in enumerate(self.short): self.SetHoldings(symbol, -(rank+1)*short_scale_factor) self.monthly_rebalance = False self.long = None self.short = None class SymbolData: def __init__(self, symbol): self.Symbol = symbol self.window = RollingWindow[float](2) self.returns = deque(maxlen=252) def Update(self, price): if price != 0: self.window.Add(price) if self.window.IsReady: self.returns.append((self.window[0]-self.window[1])/self.window[1]) def IsReady(self): return len(self.returns) == self.returns.maxlen def beta(self, market_ret): asset_return = np.array(self.returns, dtype=np.float32) market_return = np.array(market_ret, dtype=np.float32) return np.cov(asset_return, market_return)[0][1]/np.var(market_return) class Wilshire5000(PythonData): "Class to import Wilshire 5000 Total Market Index data from Dropbox" def GetSource(self, config, date, isLiveMode): return SubscriptionDataSource("https://www.dropbox.com/s/z9rof4fr9cqzgpt/W5000.csv?dl=1", SubscriptionTransportMedium.RemoteFile) def Reader(self, config, line, date, isLiveMode): if not (line.strip() and line[1].isdigit()): return None index = Wilshire5000() index.Symbol = config.Symbol try: # Example File Format: (Data starts from 01/04/2010) # Date Open High Low Close Adj Close Volume # 1/4/10 11549.13965 11749.37012 11549.13965 11743.54004 11743.54004 0 data = line.split(',') index.Time = datetime.strptime(data[0], "%Y-%m-%d") index.Value = float(data[5]) except: return None return index