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)