Overall Statistics
Total Orders
17
Average Win
13.95%
Average Loss
-6.12%
Compounding Annual Return
2.796%
Drawdown
20.600%
Expectancy
1.186
Start Equity
100000
End Equity
102207.39
Net Profit
2.207%
Sharpe Ratio
-0.126
Sortino Ratio
-0.16
Probabilistic Sharpe Ratio
19.347%
Loss Rate
33%
Win Rate
67%
Profit-Loss Ratio
2.28
Alpha
-0.032
Beta
0.07
Annual Standard Deviation
0.169
Annual Variance
0.028
Information Ratio
-0.887
Tracking Error
0.194
Treynor Ratio
-0.304
Total Fees
$11.36
Estimated Strategy Capacity
$47000.00
Lowest Capacity Asset
ES 32L3A5AD9H0XW|ES YLZ9Z50BJE2P
Portfolio Turnover
5.47%
# region imports
from AlgorithmImports import *
# endregion

class StraddleFutureOptionAlgorithm(QCAlgorithm):
    '''
    In this strategy, we buy straddle for ES Options, and hold them to expiration
    Since options and the contract expire at the same date, 
    we can use self.portfolio.investe to buy new straddle after expiration
    '''
    def initialize(self):
        self.set_start_date(2024, 1, 1)
        # We will work with the contract with highest open interest
        self._future = self.add_future(Futures.Indices.SP_500_E_MINI,
            extended_market_hours=True,
            data_mapping_mode=DataMappingMode.OPEN_INTEREST,
            data_normalization_mode=DataNormalizationMode.BACKWARDS_RATIO,
            contract_depth_offset=0)
        self._future.set_filter(0, 182)

        self.add_future_option(self._future.symbol, self._option_filter) 
    
    def _option_filter(self, option_filter_universe):
        '''
        The option filter selects contracts with the futures expitration, 
        one strike above and one below the contracts' prices.
        '''
        return option_filter_universe.strikes(-1, 1)
    
    def on_data(self, data):
        if self.portfolio.invested:
            return
        
        symbol = Symbol.create_canonical_option(self._future.mapped)
        chain = data.option_chains.get(symbol)
        if not chain:
            return

        # We use the chain in pandas DataFrame to select the near expiry ATM options
        chain = chain.data_frame
        expiry = chain.expiry.min()
        chain = chain[chain.expiry==expiry].loc[abs(chain.strike-chain.underlyinglastprice).sort_values().index]
        strike = chain.strike.iloc[0]

        # Place the trade using helper methods
        long_straddle = OptionStrategies.straddle(symbol, strike, expiry)
        self.buy(long_straddle, 1)