| Overall Statistics |
|
Total Trades 230 Average Win 0.01% Average Loss -0.01% Compounding Annual Return 50.104% Drawdown 1.600% Expectancy -0.300 Net Profit 7.381% Sharpe Ratio 5.928 Probabilistic Sharpe Ratio 98.096% Loss Rate 61% Win Rate 39% Profit-Loss Ratio 0.78 Alpha 0.054 Beta 1.014 Annual Standard Deviation 0.074 Annual Variance 0.006 Information Ratio 1.33 Tracking Error 0.044 Treynor Ratio 0.434 Total Fees $241.08 Estimated Strategy Capacity $8700000.00 |
from datetime import timedelta
from QuantConnect.Data.UniverseSelection import *
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
from Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel
class SectorBalancedPortfolioConstruction(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2016, 12, 28)
self.SetEndDate(2017, 3, 1)
self.SetCash(100000)
self.UniverseSettings.Resolution = Resolution.Hour
self.SetUniverseSelection(MyUniverseSelectionModel())
self.SetAlpha(ConstantAlphaModel(InsightType.Price, InsightDirection.Up, timedelta(1), 0.025, None))
self.SetPortfolioConstruction(MySectorWeightingPortfolioConstructionModel(Resolution.Daily))
self.SetExecution(ImmediateExecutionModel())
class MyUniverseSelectionModel(FundamentalUniverseSelectionModel):
def __init__(self):
super().__init__(True, None, None)
def SelectCoarse(self, algorithm, coarse):
filtered = [x for x in coarse if x.HasFundamentalData and x.Price > 0]
sortedByDollarVolume = sorted(filtered, key=lambda x: x.DollarVolume, reverse=True)
return [x.Symbol for x in sortedByDollarVolume][:100]
def SelectFine(self, algorithm, fine):
filtered = [f for f in fine if f.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.Technology]
self.technology = sorted(filtered, key=lambda f: f.MarketCap, reverse=True)[:3]
filtered = [f for f in fine if f.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.FinancialServices]
self.financialServices = sorted(filtered, key=lambda f: f.MarketCap, reverse=True)[:2]
filtered = [f for f in fine if f.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.ConsumerDefensive]
self.consumerDefensive = sorted(filtered, key=lambda f: f.MarketCap, reverse=True)[:1]
return [x.Symbol for x in self.technology + self.financialServices + self.consumerDefensive]
class MySectorWeightingPortfolioConstructionModel(EqualWeightingPortfolioConstructionModel):
def __init__(self, rebalance = Resolution.Daily):
super().__init__(rebalance)
self.symbolBySectorCode = dict()
def OnSecuritiesChanged(self, algorithm, changes):
for security in changes.AddedSecurities:
#1. When new assets are added to the universe, save the Morningstar sector code
# for each security to the variable sectorCode
sectorCode = security.Fundamentals.AssetClassification.MorningstarSectorCode
# 2. If the sectorCode is not in the self.symbolBySectorCode dictionary, create a new list
# and append the symbol to the list, keyed by sectorCode in the self.symbolBySectorCode dictionary
if sectorCode not in self.symbolBySectorCode:
self.symbolBySectorCode[sectorCode] = list()
self.symbolBySectorCode[sectorCode].append(security.Symbol)
for security in changes.RemovedSecurities:
#3. For securities that are removed, save their Morningstar sector code to sectorCode
sectorCode = security.Fundamentals.AssetClassification.MorningstarSectorCode
#4. If the sectorCode is in the self.symbolBySectorCode dictionary
if sectorCode in self.symbolBySectorCode:
symbol = security.Symbol
# If the symbol is in the dictionary's sectorCode list;
if symbol in self.symbolBySectorCode[sectorCode]:
# Then remove the corresponding symbol from the dictionary
self.symbolBySectorCode[sectorCode].remove(symbol)
# We use the super() function to avoid using the base class name explicity
super().OnSecuritiesChanged(algorithm, changes)