| Overall Statistics |
|
Total Orders 870 Average Win 0.20% Average Loss -0.25% Compounding Annual Return -4.439% Drawdown 29.600% Expectancy -0.219 Start Equity 100000 End Equity 75567.66 Net Profit -24.432% Sharpe Ratio -0.806 Sortino Ratio -1.03 Probabilistic Sharpe Ratio 0.000% Loss Rate 57% Win Rate 43% Profit-Loss Ratio 0.82 Alpha -0.022 Beta -0.179 Annual Standard Deviation 0.049 Annual Variance 0.002 Information Ratio -1.077 Tracking Error 0.129 Treynor Ratio 0.22 Total Fees $1006.83 Estimated Strategy Capacity $17000.00 Lowest Capacity Asset ADRU SJNVOV70T9B9 Portfolio Turnover 0.90% |
#region imports
from AlgorithmImports import *
from collections import deque
import calendar
#endregion
class BetaAlphaModel(AlphaModel):
def __init__(self):
self.name = 'BetaAlphaModel'
self._assets = {}
self._month = datetime.min
def update(self, algorithm, data):
if data.contains_key("SPY"):
self._market_price.append(float(algorithm.securities["SPY"].price))
for key, value in self._assets.items():
if data.contains_key(key):
value.price.append(float(algorithm.securities[key].price))
insights = []
if self._month != algorithm.time.month:
self._month = algorithm.time.month
beta_values = {}
market_return = np.diff(np.array(self._market_price))/np.array(self._market_price)[:-1]
long_ = None
for key, value in self._assets.items():
if key != "SPY" and len(value.price) == value.price.maxlen:
asset_return = np.diff(np.array(value.price))/np.array(value.price)[:-1]
beta_values[key] = self._beta(asset_return, market_return)
sorted_by_beta = sorted(beta_values, key = lambda x: beta_values[x])
long_ = sorted_by_beta[:int(0.25*len(sorted_by_beta))]
short = sorted_by_beta[-int(0.25*len(sorted_by_beta)):]
# day: the weekday of first day of the month
# num_days: number of days in month
day, num_days = calendar.monthrange(algorithm.time.year, algorithm.time.month)
insight_period = num_days - algorithm.time.day - 1
if long_ and short:
invested = [x.key for x in algorithm.portfolio if x.value.invested]
for i in invested:
if algorithm.portfolio[i].is_long and i not in long_:
insights.append(Insight.price(i, timedelta(days=1), InsightDirection.FLAT))
if algorithm.portfolio[i].is_short and i not in short:
insights.append(Insight.price(i, timedelta(days=1), InsightDirection.FLAT))
for i in long_:
insights.append(Insight.price(i, timedelta(days=insight_period), InsightDirection.UP))
for i in short:
insights.append(Insight.price(i, timedelta(days=insight_period), InsightDirection.DOWN))
return insights
def on_securities_changed(self, algorithm, changes):
for added in changes.added_securities:
if added.symbol.value == "SPY":
self._market_price = deque(maxlen=253)
hist_spy = algorithm.history(["SPY"], 500, Resolution.DAILY)
for i in hist_spy.loc["SPY"].itertuples():
self._market_price.append(i.close)
if added not in self._assets and added.symbol.value != "SPY":
hist = algorithm.history([added.symbol.value], 500, Resolution.DAILY)
if not hist.empty:
self._assets[added.symbol] = SymbolData(added)
for i in hist.loc[added.symbol.value].itertuples():
self._assets[added.symbol].price.append(i.close)
for removed in changes.removed_securities:
if removed.symbol in self._assets:
self._assets.pop(removed.symbol)
def _beta(self, asset_return, market_return):
asset_return = np.array(asset_return, dtype=np.float32)
market_return = np.array(market_return, dtype=np.float32)
return np.cov(asset_return, market_return)[0][1]/np.var(market_return)
class SymbolData:
def __init__(self, symbol):
self.symbol = symbol
self.price = deque(maxlen=253)
#region imports
from AlgorithmImports import *
from alpha import BetaAlphaModel
from portfolio import MonthlyPortfolioConstructionModel
#endregion
class BetaAlgorithm(QCAlgorithmFramework):
def initialize(self):
self.set_start_date(2012, 1, 1) #Set Start Date
self.set_end_date(2018, 3, 1) #Set End Date
self.set_cash(100000) #Set Strategy Cash
self.universe_settings.resolution = Resolution.DAILY
tickers = [
"EWJ", # iShares MSCI Japan Index ETF
"EZU", # iShares MSCI Eurozone ETF
"EFNL", # iShares MSCI Finland Capped Investable Market Index ETF
"EWW", # iShares MSCI Mexico Inv. Mt. Idx
"ERUS", # iShares MSCI Russia ETF
"IVV", # iShares S&P 500 Index
"ICOL", # Consumer Discretionary Select Sector SPDR Fund
"AAXJ", # iShares MSCI All Country Asia ex Japan Index ETF
"AUD", # Australia Bond Index Fund
"EWQ", # iShares MSCI France Index ETF
"BUND", # Pimco Germany Bond Index Fund
"EWH", # iShares MSCI Hong Kong Index ETF
"EPI", # WisdomTree India Earnings ETF
"EIDO" # iShares MSCI Indonesia Investable Market Index ETF
"EWI", # iShares MSCI Italy Index ETF
"GAF", # SPDR S&P Emerging Middle East & Africa ETF
"ENZL", # iShares MSCI New Zealand Investable Market Index Fund
"NORW" # Global X FTSE Norway 30 ETF
"EWY", # iShares MSCI South Korea Index ETF
"EWP", # iShares MSCI Spain Index ETF
"EWD", # iShares MSCI Sweden Index ETF
"EWL", # iShares MSCI Switzerland Index ETF
"GXC", # SPDR S&P China ETF
"EWC", # iShares MSCI Canada Index ETF
"EWZ", # iShares MSCI Brazil Index ETF
"ARGT", # Global X FTSE Argentina 20 ETF
"AND", # Global X FTSE Andean 40 ETF
"AIA", # iShares S&P Asia 50 Index ETF
"EWO", # iShares MSCI Austria Investable Mkt Index ETF
"EWK", # iShares MSCI Belgium Investable Market Index ETF
"BRAQ", # Global X Brazil Consumer ETF
"ECH", # iShares MSCI Chile Investable Market Index ETF
"CHIB", # Global X China Technology ETF
"EGPT", # Market Vectors Egypt Index ETF
"ADRU"] # BLDRS Europe 100 ADR Index ETF
symbols = [Symbol.create(ticker, SecurityType.EQUITY, Market.USA) for ticker in tickers]
self.set_universe_selection(ManualUniverseSelectionModel(symbols))
self.set_alpha(BetaAlphaModel())
self.set_portfolio_construction(MonthlyPortfolioConstructionModel())
self.set_execution(ImmediateExecutionModel())
self.set_risk_management(NullRiskManagementModel())
self.add_equity("SPY", Resolution.DAILY)
#region imports
from AlgorithmImports import *
#endregion
class MonthlyPortfolioConstructionModel(PortfolioConstructionModel):
def __init__(self):
self._month = datetime.min
def create_targets(self, algorithm, insights):
if self._month == algorithm.time.month:
return []
targets = []
self._month = algorithm.time.month
if len(insights) != 0:
percent = 1 / len(insights)
for insight in insights:
target = PortfolioTarget.percent(algorithm, insight.symbol, insight.direction * percent)
if not target is None:
targets.append(target)
return targets