Overall Statistics
Total Orders
72
Average Win
8.94%
Average Loss
-6.46%
Compounding Annual Return
229.011%
Drawdown
27.200%
Expectancy
0.266
Start Equity
100000
End Equity
148388.4
Net Profit
48.388%
Sharpe Ratio
2.602
Sortino Ratio
3.458
Probabilistic Sharpe Ratio
64.737%
Loss Rate
47%
Win Rate
53%
Profit-Loss Ratio
1.38
Alpha
0
Beta
0
Annual Standard Deviation
0.71
Annual Variance
0.504
Information Ratio
2.679
Tracking Error
0.71
Treynor Ratio
0
Total Fees
$2199.60
Estimated Strategy Capacity
$2000.00
Lowest Capacity Asset
SPY YIQ3S0PODCLI|SPY R735QTJ8XC9X
Portfolio Turnover
9.41%
# region imports
from AlgorithmImports import *
# endregion

class JumpingYellowGreenGaur(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2024, 1, 1)
        self.set_end_date(2024, 4, 30)
        self.set_cash(100000)        
        
        self.universe_settings.asynchronous = True
        option = self.add_option("SPY", Resolution.MINUTE)
        option.set_slippage_model(VolumeShareSlippageModel())
        self.symbol = option.symbol
        self.indicator = self.add_data(Signal, "CUSTOM1", Resolution.MINUTE).symbol

        #iron_condor(min_days_till_expiry: int, near_strike_spread: float, far_strike_spread: float)
        #Selects four contracts to form Long Iron Condor or Short Iron Condor Option strategies.
        
        option.set_filter(lambda universe: universe.include_weeklys().iron_condor(30, 5, 10))

        self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.CASH)
        

    def on_data(self, data: Slice):
        # Get the OptionChain
        chain = data.option_chains.get(self.symbol, None)

        if self.indicator in data:            
            received_signal = data[self.indicator].value
            if not chain:
                self.log(str(self.time) + str(' ') + str('No chanin available'))
                return
            
            if (not self.portfolio.invested and received_signal == 1):
                # Find put and call contracts with the farthest expiry       
                expiry = max([x.expiry for x in chain])
                chain = sorted([x for x in chain if x.expiry == expiry], key = lambda x: x.strike)

                put_contracts = [x for x in chain if x.right == OptionRight.PUT]
                call_contracts = [x for x in chain if x.right == OptionRight.CALL]

                if len(call_contracts) < 2 or len(put_contracts) < 2:
                    return
                
                # Select the strategy legs
                far_put = put_contracts[0]
                near_put = put_contracts[1]
                near_call = call_contracts[0]
                far_call = call_contracts[1]

                quantity_far_put = self.portfolio.total_portfolio_value*0.25 / far_put.ask_price
                quantity_near_put = self.portfolio.total_portfolio_value*0.25 / near_put.ask_price
                quantity_near_call = self.portfolio.total_portfolio_value*0.25 / near_call.ask_price
                quantity_far_call = self.portfolio.total_portfolio_value*0.25 / far_call.ask_price

                quantity = min(quantity_far_put, quantity_near_put,quantity_near_call,quantity_far_call)
                quantity = int(quantity/ 100)
                short_iron_condor = OptionStrategies.short_iron_condor(
                                    self.symbol, 
                                    far_put.strike,
                                    near_put.strike,
                                    near_call.strike,
                                    far_call.strike,
                                    expiry)

                self.buy(short_iron_condor, quantity)
            
            elif self.portfolio.invested and received_signal == 0:
                #option_invested = [x.key for x in self.portfolio if x.value.invested and x.value.type==SecurityType.OPTION ]
                
                self.liquidate()
                self.log("Sell Order" + str(self.time) + str('  ') + str(received_signal))
            
            else:
                # self.set_holdings(self.spy, 0)
                self.log("Do Nothing " + str(self.time) + str('  ') + str(received_signal))

class Signal(PythonData):   

    def get_source(self, config, date, isLive):
        source = "https://www.dropbox.com/scl/fi/mynxp0hpeexq2dfjeiset/ml_output_old.csv?rlkey=fd2jghurd7pgzraw8zpnw4fyf&st=yqtpi1fd&dl=1"
        return SubscriptionDataSource(source, SubscriptionTransportMedium.REMOTE_FILE)
    
    def reader(self, config, line, date, isLive):        
        if not (line.strip() and line[0].isdigit()):                
            return None
         
        csv = line.split(',')        
        xyz = Signal()        
        
        xyz.symbol = config.symbol
        xyz.time = datetime.strptime(csv[0], '%Y-%m-%d %H:%M:%S') 
                  
        
        xyz.value = int(csv[1])   
        return xyz