| Overall Statistics |
|
Total Orders 486 Average Win 1.07% Average Loss -0.76% Compounding Annual Return 11.639% Drawdown 30.700% Expectancy 0.370 Start Equity 10000 End Equity 14364.15 Net Profit 43.642% Sharpe Ratio 0.282 Sortino Ratio 0.327 Probabilistic Sharpe Ratio 11.312% Loss Rate 43% Win Rate 57% Profit-Loss Ratio 1.41 Alpha 0.055 Beta 1.245 Annual Standard Deviation 0.222 Annual Variance 0.049 Information Ratio 0.504 Tracking Error 0.112 Treynor Ratio 0.05 Total Fees $353.00 Estimated Strategy Capacity $3000.00 Lowest Capacity Asset EEMV V0WRDXSSH205 Portfolio Turnover 3.72% |
#region imports
from AlgorithmImports import *
#endregion
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Common")
from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Data import *
from datetime import timedelta
import numpy as np
class ScheduledCAPM(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2022,1,1)
self.SetEndDate(2025,4,15)
self._cash = 10000
self.SetCash(self._cash)
self._tickers = ['AGG',
'IWM',
'IAU',
'COMT',
'USMV',
'DGRO',
'QUAL',
'DVY',
'MTUM',
'VLUE',
'EFAV',
'EEMV',
'IDV',
'IQLT',
'IYW',
'IGF',
'IYH']
self.symbols = [self.AddEquity(ticker).Symbol for ticker in self._tickers ]
self.spy = self.AddEquity("SPY", Resolution.Daily).Symbol
self.ivv = self.AddEquity("IVV", Resolution.Daily).Symbol
self._bench = self.spy
self.lookback = 30
self.SetWarmup(31)
self.counter = 0
self.reference = self.History(self.ivv, 5, Resolution.Daily)['close']
self._initialValue = self.reference.iloc[0]
self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday), self.TimeRules.AfterMarketOpen(self.spy, 10), self.Rebalance)
self._portfolioValue = [self._cash]
self._drawdown = -0.03
self.reference = self.History(self.spy, 10, Resolution.Daily)['close']
self._initialValue = self.reference.iloc[0]
def Rebalance(self):
self.counter += 1
self.Debug(f"Counter : {self.counter}")
if self.IsWarmingUp:
return
if self.counter % 3 == 0:
history = self.History(
self.symbols + [self._bench],
self.lookback,
Resolution.Daily).close.unstack(level=0)
self.symbols_alpha = self.SelectSymbols_alphas(history)
self.symbols_beta = self.SelectSymbols_betas(history)
for holdings in self.Portfolio.Values:
symbol = holdings.Symbol
if symbol not in self.symbols_alpha and symbol not in self.symbols_beta and holdings.Invested:
self.Liquidate(symbol)
for symbol in self.symbols_alpha:
self.SetHoldings(symbol, 0.1)
for symbol in self.symbols_beta:
if symbol in self.symbols_alpha:
self.SetHoldings(symbol, 0.2)
else:
self.SetHoldings(symbol, 0.1)
self.SetHoldings("SPY", 1.0)
def OnData(self,data):
self._portfolioValue.append(self.Portfolio.TotalPortfolioValue)
if (self._portfolioValue[-1]-self._portfolioValue[-2])/self._portfolioValue[-1] < self._drawdown:
self.Liquidate()
self.Plot("Relative Performance", "_bench", self._cash*self.Securities["SPY"].Close/self._initialValue)
self.Plot("Relative Performance", "Total Portfolio Value", self.Portfolio.TotalPortfolioValue)
def SelectSymbols_alphas(self, history):
alphas = dict()
_bench = history[self._bench].pct_change().dropna()
for symbol in self.symbols:
returns = history[symbol].pct_change().dropna()
bla = np.vstack([_bench, np.ones(len(returns))]).T
result = np.linalg.lstsq(bla , returns)
alphas[symbol] = result[0][1]
selected_alphas = sorted(alphas.items(), key=lambda x: x[1], reverse=True)[:5]
return [x[0] for x in selected_alphas]
def SelectSymbols_betas(self, history):
betas = dict()
_bench = history[self._bench].pct_change().dropna()
for symbol in self.symbols:
returns = history[symbol].pct_change().dropna()
bla = np.vstack([_bench, np.ones(len(returns))]).T
result = np.linalg.lstsq(bla , returns)
betas[symbol]= result[0][0]
selected_betas = sorted(betas.items(), key=lambda x: x[1], reverse=True)[:5]
return [x[0] for x in selected_betas]