| Overall Statistics |
|
Total Orders 1925 Average Win 0.16% Average Loss -0.10% Compounding Annual Return 20.844% Drawdown 36.600% Expectancy 0.732 Start Equity 10000000 End Equity 26197386.24 Net Profit 161.974% Sharpe Ratio 0.73 Sortino Ratio 0.759 Probabilistic Sharpe Ratio 30.473% Loss Rate 32% Win Rate 68% Profit-Loss Ratio 1.56 Alpha 0.041 Beta 0.932 Annual Standard Deviation 0.183 Annual Variance 0.034 Information Ratio 0.387 Tracking Error 0.089 Treynor Ratio 0.144 Total Fees $30826.07 Estimated Strategy Capacity $62000000.00 Lowest Capacity Asset HONI R735QTJ8XC9X Portfolio Turnover 0.69% |
# region imports
from AlgorithmImports import *
# endregion
industry_codes = [
'AGRICULTURAL_INPUTS',
'BUILDING_MATERIALS',
'CHEMICALS',
'SPECIALTY_CHEMICALS',
'LUMBER_AND_WOOD_PRODUCTION',
'PAPER_AND_PAPER_PRODUCTS',
'ALUMINUM',
'COPPER',
'OTHER_INDUSTRIAL_METALS_AND_MINING',
'GOLD',
'SILVER',
'OTHER_PRECIOUS_METALS_AND_MINING',
'COKING_COAL',
'STEEL',
'AUTO_AND_TRUCK_DEALERSHIPS',
'AUTO_MANUFACTURERS',
'AUTO_PARTS',
'RECREATIONAL_VEHICLES',
'FURNISHINGS',
'FIXTURES_AND_APPLIANCES',
'RESIDENTIAL_CONSTRUCTION',
'TEXTILE_MANUFACTURING',
'APPAREL_MANUFACTURING',
'FOOTWEAR_AND_ACCESSORIES',
'PACKAGING_AND_CONTAINERS',
'PERSONAL_SERVICES',
'RESTAURANTS',
'APPAREL_RETAIL',
'DEPARTMENT_STORES',
'HOME_IMPROVEMENT_RETAIL',
'LUXURY_GOODS',
'INTERNET_RETAIL',
'SPECIALTY_RETAIL',
'GAMBLING',
'LEISURE',
'LODGING',
'RESORTS_AND_CASINOS',
'TRAVEL_SERVICES',
'ASSET_MANAGEMENT',
'BANKS_DIVERSIFIED',
'BANKS_REGIONAL',
'MORTGAGE_FINANCE',
'CAPITAL_MARKETS',
'FINANCIAL_DATA_AND_STOCK_EXCHANGES',
'INSURANCE_LIFE',
'INSURANCE_PROPERTY_AND_CASUALTY',
'INSURANCE_REINSURANCE',
'INSURANCE_SPECIALTY',
'INSURANCE_BROKERS',
'INSURANCE_DIVERSIFIED',
'SHELL_COMPANIES',
'FINANCIAL_CONGLOMERATES',
'CREDIT_SERVICES',
'REAL_ESTATE_DEVELOPMENT',
'REAL_ESTATE_SERVICES',
'REAL_ESTATE_DIVERSIFIED',
'REIT_HEALTHCARE_FACILITIES',
'REIT_HOTEL_AND_MOTEL',
'REIT_INDUSTRIAL',
'REIT_OFFICE',
'REIT_RESIDENTIAL',
'REIT_RETAIL',
'REIT_MORTGAGE',
'REIT_SPECIALTY',
'REIT_DIVERSIFIED',
'BEVERAGES_BREWERS',
'BEVERAGES_WINERIES_AND_DISTILLERIES',
'BEVERAGES_NON_ALCOHOLIC',
'CONFECTIONERS',
'FARM_PRODUCTS',
'HOUSEHOLD_AND_PERSONAL_PRODUCTS',
'PACKAGED_FOODS',
'EDUCATION_AND_TRAINING_SERVICES',
'DISCOUNT_STORES',
'FOOD_DISTRIBUTION',
'GROCERY_STORES',
'TOBACCO',
'BIOTECHNOLOGY',
'DRUG_MANUFACTURERS_GENERAL',
'DRUG_MANUFACTURERS_SPECIALTY_AND_GENERIC',
'HEALTHCARE_PLANS',
'MEDICAL_CARE_FACILITIES',
'PHARMACEUTICAL_RETAILERS',
'HEALTH_INFORMATION_SERVICES',
'MEDICAL_DEVICES',
'MEDICAL_INSTRUMENTS_AND_SUPPLIES',
'DIAGNOSTICS_AND_RESEARCH',
'MEDICAL_DISTRIBUTION',
'UTILITIES_INDEPENDENT_POWER_PRODUCERS',
'UTILITIES_RENEWABLE',
'UTILITIES_REGULATED_WATER',
'UTILITIES_REGULATED_ELECTRIC',
'UTILITIES_REGULATED_GAS',
'UTILITIES_DIVERSIFIED',
'TELECOM_SERVICES',
'ADVERTISING_AGENCIES',
'PUBLISHING',
'BROADCASTING',
'ENTERTAINMENT',
'INTERNET_CONTENT_AND_INFORMATION',
'ELECTRONIC_GAMING_AND_MULTIMEDIA',
'OIL_AND_GAS_DRILLING',
'OIL_AND_GAS_E_AND_P',
'OIL_AND_GAS_INTEGRATED',
'OIL_AND_GAS_MIDSTREAM',
'OIL_AND_GAS_REFINING_AND_MARKETING',
'OIL_AND_GAS_EQUIPMENT_AND_SERVICES',
'THERMAL_COAL',
'URANIUM',
'AEROSPACE_AND_DEFENSE',
'SPECIALTY_BUSINESS_SERVICES',
'CONSULTING_SERVICES',
'RENTAL_AND_LEASING_SERVICES',
'SECURITY_AND_PROTECTION_SERVICES',
'STAFFING_AND_EMPLOYMENT_SERVICES',
'CONGLOMERATES',
'ENGINEERING_AND_CONSTRUCTION',
'INFRASTRUCTURE_OPERATIONS',
'BUILDING_PRODUCTS_AND_EQUIPMENT',
'FARM_AND_HEAVY_CONSTRUCTION_MACHINERY',
'INDUSTRIAL_DISTRIBUTION',
'BUSINESS_EQUIPMENT_AND_SUPPLIES',
'SPECIALTY_INDUSTRIAL_MACHINERY',
'METAL_FABRICATION',
'POLLUTION_AND_TREATMENT_CONTROLS',
'TOOLS_AND_ACCESSORIES',
'ELECTRICAL_EQUIPMENT_AND_PARTS',
'AIRPORTS_AND_AIR_SERVICES',
'AIRLINES',
'RAILROADS',
'MARINE_SHIPPING',
'TRUCKING',
'INTEGRATED_FREIGHT_AND_LOGISTICS',
'WASTE_MANAGEMENT',
'INFORMATION_TECHNOLOGY_SERVICES',
'SOFTWARE_APPLICATION',
'SOFTWARE_INFRASTRUCTURE',
'COMMUNICATION_EQUIPMENT',
'COMPUTER_HARDWARE',
'CONSUMER_ELECTRONICS',
'ELECTRONIC_COMPONENTS',
'ELECTRONICS_AND_COMPUTER_DISTRIBUTION',
'SCIENTIFIC_AND_TECHNICAL_INSTRUMENTS',
'SEMICONDUCTOR_EQUIPMENT_AND_MATERIALS',
'SEMICONDUCTORS',
'SOLAR'
]# region imports
from AlgorithmImports import *
from industry_codes import industry_codes
# endregion
class CreativeRedCow(QCAlgorithm):
def initialize(self):
self.set_start_date(2019, 9, 1)
self.set_end_date(2024, 9, 30)
self.set_cash(10_000_000)
self.settings.min_absolute_portfolio_target_percentage = 0
self.set_warm_up(self.start_date - datetime(2007, 1, 1))#datetime(1998, 2, 1))
self.set_security_initializer(BrokerageModelSecurityInitializer(self.brokerage_model, FuncSecuritySeeder(self.get_last_known_prices)))
spy = Symbol.create('SPY', SecurityType.EQUITY, Market.USA)
self.universe_settings.schedule.on(self.date_rules.month_start())
self.universe_settings.resolution = Resolution.DAILY
self._universe = self.add_universe(self._select_assets)
self.schedule.on(self.date_rules.month_start(spy, 1), self.time_rules.midnight, self._rebalance)
self._lookback = 12*12 # 144 months = 12 years = 3 presidential terms.
self._previous_selection_time = None
self._outperforming_industries = pd.DataFrame(columns=industry_codes + ['party=R'])
self._winning_party_by_result_date = {date(1996, 11, 6): "D", date(2000, 11, 8): "R", date(2004, 11, 3): "R", date(2008, 11, 5): "D", date(2012, 11, 7): "D", date(2016, 11, 9): "R", date(2020, 11, 8): "D"}
def _select_assets(self, fundamentals):
ruling_party = [party for t, party in self._winning_party_by_result_date.items() if t < self.time.date()][-1]
# Record which industries outperformed over the previous month.
if self._previous_selection_time:
# Determine which industries outerperformed.
history = self.history(list(self._leader_by_industry.values()), self._previous_selection_time, self.time, Resolution.DAILY)['close'].unstack(0)
monthly_returns = (history.iloc[-1] - history.iloc[0]) / history.iloc[0]
outperformers = (monthly_returns > monthly_returns.median()).astype(int)
# Append the result to the `self._outperforming_industries` DataFrame.
row = [outperformers.get(self._leader_by_industry.get(industry_code, None), 0) for industry_code in industry_codes]
row.append(int(ruling_party == 'R'))
self._outperforming_industries.loc[self._previous_selection_time] = row
# Trim off the samples that fall out of the lookback window.
self._outperforming_industries = self._outperforming_industries.iloc[-self._lookback:]
self._previous_selection_time = self.time
# Get the largest asset of each industry.
self._leader_by_industry = {}
for industry_code in industry_codes:
industry_assets = [f for f in fundamentals if f.asset_classification.morningstar_industry_code == eval(f"MorningstarIndustryCode.{industry_code}") and f.market_cap]
if industry_assets:
self._leader_by_industry[industry_code] = sorted(industry_assets, key=lambda f: f.market_cap)[-1].symbol
# During warm-up, keep the universe empty.
if self.is_warming_up:
return []
# Calculate correlation coefficient of each industry.
correlation_coefficients = self._outperforming_industries.corr().drop('party=R')['party=R'].sort_values()
if ruling_party == 'D':
correlation_coefficients *= -1
self._corr_by_symbol = {
self._leader_by_industry[industry]: corr
for industry, corr in correlation_coefficients[correlation_coefficients > 0].items()
if industry in self._leader_by_industry
}
return list(self._corr_by_symbol.keys())
def _rebalance(self):
if not self._universe.selected:
return
corr_sum = sum(self._corr_by_symbol.values())
targets = [PortfolioTarget(symbol, corr/corr_sum) for symbol, corr in self._corr_by_symbol.items()]
self.set_holdings(targets, True)