Overall Statistics
from AlgorithmImports import *

class SellCallWeekkly(QCAlgorithm):
    def Initialize(self):

        self.SetStartDate(2022, 2, 1)
        self.SetEndDate(2022, 3, 30)
        self.SetCash(10000000000) 

        self.SetName("Sell Call Strategy")

        self.equity = self.AddEquity("APPL", Resolution.Hour)
        self.option = self.AddOption("APPL", Resolution.Hour)

        self.option.SetFilter(self.UniverseFunc)
        
        chart = Chart("Stock Info Chart")
        chart.AddSeries(Series("Price", SeriesType.Line, 0))
        # chart.AddSeries(Series("IV", SeriesType.Line, 1))
        self.AddChart(chart)



    def UniverseFunc(self, universe):
        return universe.include_weeklys().calls_only().Expiration(0, 10)

    def get_holding_option(self):
        holding_options = []
        for kvp in self.Portfolio.Securities:
            security = kvp.Value

            # 确认这是一个期权且持仓不为零
            if security.Type == SecurityType.Option and security.Holdings.Quantity != 0:
                # 获取期权合约的详细信息 
                symbol = security.Symbol
                quantity = security.Holdings.Quantity
                # # self.Debug(f"持仓期权:{symbol}, 持仓数量:{quantity}")

                # # 解析合约细节
                # self.Debug(f"标的资产:{symbol.Underlying}, 到期日:{symbol.ID.Date}, "
                #            f"行权价:{symbol.ID.StrikePrice}, 类型:{symbol.ID.OptionRight}")
                
                holding_options.append(security)

        return holding_options
    def get_holding_stock(self):
        holding_stocks = []
        for kvp in self.Portfolio.Securities:
            security = kvp.Value

            # 确认这是一个股票且持仓不为零
            if security.Type == SecurityType.Equity and security.Holdings.Quantity != 0:
                # 获取股票合约的详细信息 
                symbol = security.Symbol
                quantity = security.Holdings.Quantity
                # self.Debug(f"持仓股票:{symbol}, 持仓数量:{quantity}")
                holding_stocks.append(security)

        return holding_stocks
    
    def get_target_strike_price_option(self,slice,traget_strike_price):
        
        target_strike = traget_strike_price
        
        chain_value  = slice.OptionChains[self.option.Symbol]
        contracts = sorted(chain_value.Contracts.Values, 
                   key=lambda x: (abs(x.Strike - target_strike), -x.Expiry.timestamp()))

        selected_contract  = contracts[0]
    

        return selected_contract
        

    def sell_option_at_115price(self,slice):
        
        self.Debug(f"当前时间:{self.Time}")
        stock_price = self.Securities[self.equity.Symbol].Price
        target_strike = stock_price * 1.15
        contract = self.get_target_strike_price_option(slice,target_strike)
        
        self.Debug(f"当前股票价格: {stock_price:.2f}, 目标行权价: {target_strike:.2f},当前时间:{self.Time},选中期权行权价: {contract.Strike:.2f}, 到期日: {contract.Expiry}")
        quantity = 10 
        self.MarketOrder(contract.Symbol, -quantity) 
        self.Debug(f"提交卖出订单: {contract.Symbol}, 数量: {quantity}")
    
    def sell_on_monday(self,slice):
        if self.Time.weekday() != 0:  # only monday
            return
        #先平仓所有正股
        self.Liquidate(self.equity.Symbol)
        self.sell_option_at_115price(slice)

       

    def check_to_buy_back(self,slice,hodling_options,holding_stocks):

        stock_price = self.Securities[self.equity.Symbol].Price
        option_security = hodling_options[0]
       
        symbol = option_security.Symbol
        strike_price = symbol.ID.StrikePrice
        

        if stock_price<=strike_price:
            return
        self.debug(f"stock_price{stock_price},strike_price{strike_price}") 
        
        
        # self.MarketOrder(symbol, abs(security.Holdings.Quantity))
        
        #购买期权对应的股票
        if len(holding_stocks)==0:
            self.debug(f"buy stock {option_security.Holdings.Quantity}") 
            self.MarketOrder(self.equity.Symbol, abs(option_security.Holdings.Quantity)*100)
        
        self.sell_option_at_115price(slice)

    def OnData(self, slice):
        
        current_time = self.Time
        exchange_hours = self.Securities[self.equity.Symbol].Exchange.Hours

        # 检查当前时间是否在市场开放时间内
        if not exchange_hours.IsOpen(current_time, False):
            self.Debug(f"{current_time},Market is not open.")
            return 

    
        self.Plot("Performance Chart", "Price", self.Securities[self.equity.Symbol].Price)
        stock_price = self.Securities[self.equity.Symbol].Price
        # iv = self.get_target_strike_price_option(slice,stock_price).impliedVolatility
        # self.Plot("Stock Info Chart", "IV", iv)
        
        # self.Debug(f"coming data...{self.time}")
        holding_options = self.get_holding_option()
        holding_stocks = self.get_holding_stock()
        # self.debug(f"holding optins:{holding_options},size:{len(holding_options)}")
        if len(holding_options)==0:
            self.sell_on_monday(slice)
            return 
        else:
            self.check_to_buy_back(slice,holding_options,holding_stocks)
            # pass


    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status == OrderStatus.Filled:
            self.Debug(f"Order Filled: {orderEvent.Symbol} - Quantity: {orderEvent.FillQuantity}")