Overall Statistics
Total Orders
22
Average Win
0.68%
Average Loss
-1.33%
Compounding Annual Return
-0.001%
Drawdown
1.400%
Expectancy
-0.372
Start Equity
100000
End Equity
99977
Net Profit
-0.023%
Sharpe Ratio
-4.642
Sortino Ratio
-0.802
Probabilistic Sharpe Ratio
0.000%
Loss Rate
58%
Win Rate
42%
Profit-Loss Ratio
0.51
Alpha
-0.017
Beta
0.003
Annual Standard Deviation
0.004
Annual Variance
0
Information Ratio
-0.524
Tracking Error
0.164
Treynor Ratio
-5.804
Total Fees
$14.00
Estimated Strategy Capacity
$320000.00
Lowest Capacity Asset
SPY XKGCMWNHHL5Y|SPY R735QTJ8XC9X
Portfolio Turnover
0.03%
# 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 *
# endregion

class UglyOrangeBadger(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2008, 1, 1)
        self.set_cash(100_000)
        self._equity = self.add_equity("SPY")
        self._option = self.add_option(self._equity.symbol)
        self._option.set_filter(1, 1, 30, 90)
        election_dates = [datetime(2008, 11, 4), datetime(2012, 11, 6), datetime(2016, 11, 8), datetime(2020, 11, 3)]
        self._should_open_position = False
        for dt in election_dates:
            self.schedule.on(
                self.date_rules.on(dt.year, dt.month, dt.day),
                self.time_rules.after_market_open(self._equity.symbol, 30),
                self._enable_trading
            )

    def _enable_trading(self):
        self._should_open_position = True

    def on_data(self, data):
        # Wait until it's election and we have the Option chain.
        if not self._should_open_position:
            return
        chain = data.option_chains.get(self._option.symbol, None)
        if not chain:
            return
        self._should_open_position = False
        
        # Open the position.        
        straddle = OptionStrategies.short_straddle(
            self._option.symbol, 
            sorted(chain, key=lambda x: abs(x.strike - chain.underlying.price))[0].strike, 
            min([x.expiry for x in chain])
        )
        self.buy(straddle, 1)
    
    def on_order_event(self, order_event):
        # When one of the straddle legs are assigned/exercised
        # and we now have a position in the underlying Equity, 
        # liquidate everything.
        if (order_event.status == OrderStatus.FILLED and
            self._equity.invested):
            self.liquidate()