Overall Statistics
Total Orders
4
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Sortino Ratio
0
Probabilistic Sharpe Ratio
0%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
0
Tracking Error
0
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$21000.00
Lowest Capacity Asset
SPXW 31YRWVWLMTUB2|SPX 31
Portfolio Turnover
0.15%
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from AlgorithmImports import *
from QuantConnect.Orders.Fills import FillModel
from QuantConnect.Orders import OrderEvent, OrderStatus, OrderDirection
from QuantConnect import Resolution
from QuantConnect.Securities.Option import Option

class MyFillModel(FillModel):  
    
    def StopMarketFill(self, asset, order):
        self.Log("I'm in the custom stopmarket fill model")
        lastData = asset.GetLastData()
        fillPrice = 0
        if lastData is not None:
            # Determine the fill price based on the order direction and stop price            
            self.Log(lastData.Close)
            self.Log(order.StopPrice)                
            if order.Direction == OrderDirection.Buy and lastData.Close > order.StopPrice:
                fillPrice = lastData.Close  # Use the close price for the fill
            elif order.Direction == OrderDirection.Sell and lastData.Close < order.StopPrice:
                fillPrice = lastData.Close  # Use the close price for the fill

        # If a fill price was determined, create and return an OrderEvent
        if fillPrice != 0:
            orderEvent = OrderEvent(order.OrderId, asset.Symbol, lastData.EndTime, OrderStatus.Filled, order.Direction, fillPrice, order.Quantity, "Custom StopMarketOrder Fill")
            return [orderEvent]
        if fillPrice == 0:
            return []


class SellAPutOvernight(QCAlgorithm):

    def Initialize(self):
        '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''

        self.SetStartDate(2022, 6, 23)
        self.SetEndDate(2022,6,25)        
        self.SetCash(1000000)           #Set Strategy Cash
        
        # weekly option SPX contracts
        self.spx = self.AddIndex("SPX").Symbol
        self.option = self.AddOption(self.spx, "SPXW")

        # set our strike/expiry filter for this option chain.
        # Every first tick of the day the filter goes 100 strikes down, with tomorrow expiries
        self.option.SetFilter(lambda u: (u.Strikes(-100, 1)
                                     # Day Ahead SPXW Puts
                                     .Expiration(1, 5).WeeklysOnly().PutsOnly()))

        self.targetBid = 0.5
        self.security_exchange_hours = self.Securities["SPX"].Exchange.Hours
        self.activeOption = []

    def OnData(self, slice):
        '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.'''

        if self.Time.hour == 16 and self.Time.minute == 0:
            nextTradingDay = self.security_exchange_hours.GetNextTradingDay(self.Time).date()
            chain = slice.OptionChains.GetValue(self.option.Symbol)
            if chain is None: return            
            bids = [i.BidPrice for i in chain if i.Expiry.date() == nextTradingDay]
            findBid = sorted([i for i in bids if i <= self.targetBid])
            # Check if findBid is populated, if not, return
            if findBid:
                findBid = findBid[-1]
            else:
                return
            option = [i for i in chain if i.BidPrice == findBid and i.Expiry.date() == nextTradingDay][0]
            self.activeOption = self.AddOptionContract(option.Symbol)
            self.activeOption.SetFillModel(MyFillModel())
            self.MarketOrder(self.activeOption.Symbol, -1, tag="Market Order")
            self.stopMarketOrderTicket = self.StopMarketOrder(self.activeOption.Symbol, 1, 29, tag="StopMarket Order")
            
            
    
    def OnOrderEvent(self, orderEvent):
        self.Debug(str(orderEvent))
        self.Log(orderEvent.Symbol)
        self.Log(self.Securities[orderEvent.Symbol].Close)
        self.Log(self.Securities["SPX"].Price)
        self.Log(orderEvent.Ticket.Tag)
        self.Log(orderEvent.Ticket.SecurityType)
        self.Log(orderEvent.Ticket.OrderType)