| Overall Statistics |
|
Total Orders 353 Average Win 1.70% Average Loss -1.48% Compounding Annual Return 19.095% Drawdown 31.900% Expectancy 0.394 Start Equity 100000 End Equity 277424.27 Net Profit 177.424% Sharpe Ratio 0.745 Sortino Ratio 0.754 Probabilistic Sharpe Ratio 26.323% Loss Rate 35% Win Rate 65% Profit-Loss Ratio 1.14 Alpha 0.062 Beta 0.875 Annual Standard Deviation 0.175 Annual Variance 0.031 Information Ratio 0.508 Tracking Error 0.103 Treynor Ratio 0.149 Total Fees $1359.80 Estimated Strategy Capacity $11000000.00 Lowest Capacity Asset KBE TDP0JIUCTNJ9 Portfolio Turnover 4.73% |
from AlgorithmImports import *
from collections import defaultdict
import json
class WellDressedVioletChinchilla(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2017, 1, 1)
self.SetEndDate(2022, 11, 1)
self.SetCash(100000)
self._brainUniverseData = []
self._etfConstituentsDataBySymbol = defaultdict(list)
self._scoreBySector = {}
self._numEtfs = 3
self._portfolioValues = {}
self._rebalance = False
self.AddUniverse(BrainSentimentIndicatorUniverse, "BrainSentimentIndicatorUniverse", Resolution.Daily, self.BrainsentimentSelection)
tickers = [
"XLE", "XLF", "XLU", "XLI", "GDX", "XLK", "XLV", "XLY",
"XLP", "XLB", "XOP", "IYR", "XHB", "ITB", "VNQ", "GDXJ",
"IYE", "OIH", "XME", "XRT", "SMH", "IBB", "KBE", "KRE", "XTL"
]
for ticker in tickers:
etf_symbol = self.AddEquity(ticker, Resolution.Daily).Symbol
self.add_universe(self.universe.etf(etf_symbol, Market.USA, self.UniverseSettings, self.ETFConstituentSelection(etf_symbol)))
self.Schedule.On(self.DateRules.MonthStart(self.GetParameter("rebalance-day", 0)), self.TimeRules.Midnight, self.Rebalance)
def BrainsentimentSelection(self, altCoarse):
self._brainUniverseData = [x for x in altCoarse]
return []
def ETFConstituentSelection(self, etf_symbol):
def _ETFConstituentSelection(constituents):
self._etfConstituentsDataBySymbol[etf_symbol] = constituents
return []
return _ETFConstituentSelection
def OnData(self, data):
self._portfolioValues[self.Time] = self.Portfolio.TotalPortfolioValue
if not self._rebalance:
return
self._rebalance = False
for etf_symbol, etfConstituentsData in self._etfConstituentsDataBySymbol.items():
sector_symbols = {c.Symbol for c in etfConstituentsData}
etf_weight_by_symbol = {c.Symbol: c.Weight for c in etfConstituentsData}
self._scoreBySector[etf_symbol] = sum(
brain.Sentiment30Days * etf_weight_by_symbol[brain.Symbol]
for brain in self._brainUniverseData if brain.Symbol in sector_symbols
)
target_symbols = sorted(self._scoreBySector, key=self._scoreBySector.get, reverse=True)[:self._numEtfs]
self.SetHoldings(
[PortfolioTarget(kvp.Key, 0) for kvp in self.Portfolio if kvp.Value.Invested and kvp.Key not in target_symbols]
)
weight = 1.0 / self._numEtfs
self.SetHoldings([PortfolioTarget(symbol, weight) for symbol in target_symbols])
def Rebalance(self):
self._rebalance = True