Overall Statistics
Total Trades
4
Average Win
0.07%
Average Loss
-0.01%
Compounding Annual Return
0.764%
Drawdown
0.000%
Expectancy
6.100
Net Profit
0.064%
Sharpe Ratio
2.072
Probabilistic Sharpe Ratio
70.301%
Loss Rate
50%
Win Rate
50%
Profit-Loss Ratio
13.20
Alpha
0.005
Beta
0.008
Annual Standard Deviation
0.003
Annual Variance
0
Information Ratio
-0.453
Tracking Error
0.108
Treynor Ratio
0.641
Total Fees
$5.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
SPY Y8JTHA93KD46|SPY R735QTJ8XC9X
Portfolio Turnover
0.03%
from AlgorithmImports import *
from datetime import datetime

class AlertLightBrownHyena(QCAlgorithm):

    def Initialize(self):
        self.ticker = "SPY"
        self.numberContract = 5
        self.resolution = Resolution.Minute

        self.SetStartDate(2023, 5, 1) # Set Start Date
        self.SetEndDate(2023, 5, 31) # Set End Date
        self.SetCash(1000000) # Set Strategy Cash
        self.SetWarmUp(100, self.resolution)

        self.equity = self.AddEquity(self.ticker, self.resolution)
        self.equity.SetDataNormalizationMode(DataNormalizationMode.Raw)

        self.option = self.AddOption(self.ticker, self.resolution)
        self.option.SetFilter(-10, 10, 2, 2)

        self.symbol = self.option.Symbol
        self.rsi = self.RSI(self.equity.Symbol, 14)

        self.liquidContract = None
        self.liquidContractType = None
        self.liquidContractDate = None

        self.contractTypeCall = 0
        self.contractTypePut = 1
        

    def OnData(self, data: Slice):
        # Force sell option at the end of the next day
        if self.liquidContractDate and self.liquidContractDate < self.Time - timedelta(days=1) and self.Time.hour >= 15:
            self.liquidateExpiringOption()

        if self.rsi.IsReady:
            #self.Plot("RelativeStrengthIndex", "rsi", self.rsi.Current.Value)
                
            if self.rsi.Current.Value < 23:
                # Buy call
                if not self.Portfolio.Invested:
                    self.orderCall(data)
            elif self.rsi.Current.Value < 30 and self.liquidContractType == self.contractTypePut:
                # Sell put
                if self.Portfolio.Invested:
                    self.Log("Liquidated")
                    self.MarketOrder(self.liquidContract, -self.numberContract)
            elif self.rsi.Current.Value > 77:
                # Buy put
                if not self.Portfolio.Invested:
                    self.orderPut(data)
            elif self.rsi.Current.Value > 70 and self.liquidContractType == self.contractTypeCall:
                # Sell call
                if self.Portfolio.Invested:
                    self.Log("Liquidated")
                    self.MarketOrder(self.liquidContract, -self.numberContract)

    def getContracts(self, data, type):
        chain = data.OptionChains.get(self.symbol)
        if chain:
            contracts = [x for x in chain if x.Right == type] # Get the correct option types
            contracts = sorted(contracts, key = lambda x: x.Expiry, reverse = True) # Sort by the longest expiration first

            return contracts

        return []

    def orderCall(self, data):
        contracts = self.getContracts(data, self.contractTypeCall)
        if len(contracts) > 0:
            self.Log("Call Ordered (Market: " + str(self.Securities["SPY"].Price) + " Strike: " + str(contracts[0].Strike) + " Expiry: " + str(contracts[0].Expiry) + ")")
            self.liquidContract = contracts[0].Symbol
            self.liquidContractType = self.contractTypeCall
            self.liquidContractDate = self.Time
            self.MarketOrder(contracts[0].Symbol, self.numberContract)
        else:
            self.Log("Call cancelled (no contracts)")

    def orderPut(self, data):
        contracts = self.getContracts(data, self.contractTypePut)
        if len(contracts) > 0:
            self.Log("Put Ordered (Market: " + str(self.Securities["SPY"].Price) + " Strike: " + str(contracts[0].Strike) + " Expiry: " + str(contracts[0].Expiry) + ")")
            self.liquidContract = contracts[0].Symbol
            self.liquidContractType = self.contractTypePut
            self.liquidContractDate = self.Time
            self.MarketOrder(contracts[0].Symbol, self.numberContract)
        else:
            self.Log("Put cancelled (no contracts)")

    def liquidateExpiringOption(self):
        self.Log("Liquidated (time)")
        self.MarketOrder(self.liquidContract, -self.numberContract)
        self.liquidContract = None
        self.liquidContractType = None
        self.liquidContractDate = None