Overall Statistics
Total Trades
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe 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.421
Tracking Error
0.191
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
Portfolio Turnover
0%
from datetime import timedelta
from AlgorithmImports import *

class SimpleOptionStrategy(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2021, 1, 1)  # Setting start date
        self.SetCash(100000)  # Setting initial cash

        # Add equity data for the underlying stock
        self.equity = self.AddEquity("TSLA", Resolution.Minute)
        self.equity.SetDataNormalizationMode(DataNormalizationMode.Raw)

        # Add option data
        self.option = self.AddOption("TSLA", Resolution.Minute)
        
        # Set our option filter
        self.option.SetFilter(self.UniverseFunc)

        # Flag to determine if we've invested in options
        self.invested = False

    def UniverseFunc(self, universe):
        return universe.IncludeWeeklys() \
                       .Strikes(-2, 2) \
                       .Expiration(timedelta(14), timedelta(15))

    def OnData(self, slice):

        # Check if we have any option data
        if slice.OptionChains.Count == 0: 
            return

        if not self.invested:
            for kvp in slice.OptionChains:
                chain = kvp.Value
                
                # Logging the underlying equity price
                self.Log(f"Underlying equity price: {chain.Underlying.Price}")
                
                # We're sorting the contracts to find at the money option (with minimum difference from current price) and volume > 0
                contracts = sorted([i for i in chain if i.Volume > 0], key = lambda x: abs(chain.Underlying.Price - x.Strike))
                
                if len(contracts) == 0:
                    self.Log("No tradable contracts available.")
                    continue
                
                # Selecting the first contract (which is the nearest ATM)
                contract = contracts[0]
                self.Log(f"Selected contract: {contract.Symbol}, Strike: {contract.Strike}, LastPrice: {contract.LastPrice}")

                # Buy the contract
                self.Buy(contract.Symbol, 10)

                # Logging the purchase
                self.Log(f"Purchased contract: {contract.Symbol}")

                # Setting our invested flag to True
                self.invested = True

        else:
            for kvp in slice.OptionChains:
                chain = kvp.Value
                for contract in chain:
                    if self.Portfolio[contract.Symbol].IsLong:
                        unrealizedProfitPercent = self.Portfolio[contract.Symbol].UnrealizedProfitPercent
                        
                        # Logging unrealized profit percent
                        self.Log(f"Unrealized Profit %: {unrealizedProfitPercent*100}")
                        
                        if unrealizedProfitPercent > 0.10 or unrealizedProfitPercent < -0.05:
                            self.Liquidate(contract.Symbol)
                            
                            # Logging the liquidation
                            self.Log(f"Liquidated contract: {contract.Symbol}")
                            
                            self.invested = False
from AlgorithmImports import *
from datetime import timedelta

class StrangleStrategy(QCAlgorithm):
    
    OtmPercentage = 0.10
    OtmSellContracts = 35
    OtmBuyContracts = 10
    ExpiryDays = 10

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)
        self.SetCash(100000)
        
        self.equity = self.AddEquity("TSLA", Resolution.Minute)
        self.equitySymbol = self.equity.Symbol
        self.option = self.AddOption("TSLA", Resolution.Minute)

        # Set the filter for options data
        self.option.SetFilter(-100, +100)
        self.option.SetFilter(lambda x: x.Expiration(timedelta(days=4), timedelta(days=7)))

        self.initialPositionValue = 0
        self.underlyingEquityValueAtPurchase = 0  # Member variable to store the underlying equity value

def OnData(self, data):
    self.Log(f"OnData triggered for date: {self.Time}")

    if not self.Portfolio.Invested:
        if self.equitySymbol in data.OptionChains:
            chain = data.OptionChains[self.equitySymbol]
            self.Log(f"Option chain fetched. Total contracts: {len(chain)}")

            callsAtTheMoney = [contract for contract in chain if contract.Right == OptionRight.Call and contract.Expiry < self.Time + timedelta(days=self.ExpiryDays) and contract.Expiry > self.Time + timedelta(days=self.ExpiryDays - 5)]
            self.Log(f"Number of ATM Call contracts: {len(callsAtTheMoney)}")

            putsOutOfTheMoney = [contract for contract in chain if contract.Right == OptionRight.Put and contract.Strike < self.equity.Price * (1 - self.OtmPercentage) and contract.Expiry < self.Time + timedelta(days=self.ExpiryDays) and contract.Expiry > self.Time + timedelta(days=self.ExpiryDays - 5)]
            self.Log(f"Number of OTM Put contracts: {len(putsOutOfTheMoney)}")

            sentiment = self.DetermineSentiment()
            self.Log(f"Determined sentiment: {sentiment}")

            if sentiment == "bullish":
                atms = self.GetAtTheMoneyOptions(callsAtTheMoney)
                atmCallCost = 0
                if atms:
                    atmCallCost = atms.AskPrice * self.OtmBuyContracts * 100
                    self.Log(f"Buying ATM calls. Symbol: {atms.Symbol}, Ask Price: {atms.AskPrice}, Cost: {atmCallCost}")
                else:
                    self.Log("ATM calls not found.")

                otmCallProceeds = 0
                otmsCalls = self.GetOutOfTheMoneyOptionsForCalls(callsAtTheMoney, atmCallCost)
                if otmsCalls:
                    otmCallProceeds = otmsCalls.BidPrice * self.OtmSellContracts * 100
                    self.Log(f"Selling OTM calls. Symbol: {otmsCalls.Symbol}, Bid Price: {otmsCalls.BidPrice}")
                else:
                    self.Log("Suitable OTM calls for selling not found.")

                otmsPuts = self.GetOutOfTheMoneyOptionsForPuts(putsOutOfTheMoney, atmCallCost, otmCallProceeds)
                if otmsPuts:
                    self.Log(f"Selling OTM puts. Symbol: {otmsPuts.Symbol}, Bid Price: {otmsPuts.BidPrice}")
                else:
                    self.Log("Suitable OTM puts for selling not found.")
        else:
            self.Log("Failed to fetch option chain.")
    else:
        self.Log("Portfolio already invested.")


    def DetermineSentiment(self):
        return "bullish"

    def GetAtTheMoneyOptions(self, options):
        sorted_options = sorted(options, key=lambda x: abs(x.Strike - self.equity.Price))
        return sorted_options[0] if sorted_options else None

    def GetOutOfTheMoneyOptionsForCalls(self, options, atmCallCost):
        otmCalls = [option for option in options if option.Strike > self.equity.Price]
        otmCalls = sorted(otmCalls, key=lambda x: x.Strike)
        
        for otmCall in otmCalls:
            proceedsFromOtmCall = otmCall.BidPrice * self.OtmSellContracts * 100
            netProceeds = proceedsFromOtmCall - atmCallCost
            
            if netProceeds > 0.015 * self.equity.Price * 1000:
                return otmCall
        return None

    def GetOutOfTheMoneyOptionsForPuts(self, options, atmCallCost, otmCallProceeds):
        otmPuts = [option for option in options if option.Strike < self.equity.Price]
        otmPuts = sorted(otmPuts, key=lambda x: x.Strike)
        
        for otmPut in otmPuts:
            proceedsFromOtmPut = otmPut.BidPrice * self.OtmBuyContracts * 100
            netProceeds = otmCallProceeds + proceedsFromOtmPut - atmCallCost
            
            if netProceeds > 0.015 * self.equity.Price * 1000:
                return otmPut
        return None

    def AdjustPosition(self):
        if self.underlyingEquityValueAtPurchase == 0:
            return

        currentProfitPercentage = (self.Portfolio.TotalPortfolioValue - self.initialPositionValue) / self.underlyingEquityValueAtPurchase
        if currentProfitPercentage > 0.01:
            self.Liquidate()
            self.initialPositionValue = 0
            self.underlyingEquityValueAtPurchase = 0
from AlgorithmImports import *

class SquareMagentaHamster(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2018, 1, 1)  # Set Start Date
        self.SetEndDate(2019, 1, 1)
        self.SetCash(1000000)  # Set Strategy Cash
        index = self.AddIndex("SPX", Resolution.Minute)
        self.spx = index.Symbol 
        option = self.AddOption(index.Symbol, Resolution.Minute)
        option.SetFilter(self.UniverseFunc)
        self.symbol = option.Symbol
        
        self.indicator = SimpleMovingAverage(200)
        self.RegisterIndicator(self.spx, self.indicator, Resolution.Daily)
        self.entryTicket = None
        self.SLTicket = None
        self.TPTicket = None
        self.entryTime = datetime.min
        self.AddRiskManagement(TrailingStopRiskManagementModel(0.15))
    def UniverseFunc(self, universe: OptionFilterUniverse) -> OptionFilterUniverse:
        return universe.IncludeWeeklys().Strikes(1, 2).Expiration(timedelta(45), timedelta(50))
    def OnData(self, data: Slice):
        if not(data.ContainsKey(self.spx) and data[self.spx] is not None): return
        if not self.indicator.IsReady: return
        option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option]
    
        if option_invested:
            for option in option_invested:
                if self.Time + timedelta(1) > option.ID.Date:
                    self.Liquidate(option, "Option too close to expiration.")
        lvl = self.indicator.Current.Value
        atSMA = self.Securities[self.spx].AskPrice > lvl - 2 and self.Securities[self.spx].AskPrice < lvl + 2
        if atSMA and not self.Portfolio.Invested:
            self.BuyCall(data)
            self.BuyPut(data)
    def BuyCall(self, data: Slice) -> None:
        # Get the OptionChain
        chain = data.OptionChains.get(self.symbol, None)
        if not chain: return
        # Get the furthest expiry date of the contracts
        expiry = sorted(chain, key = lambda x: x.Expiry, reverse=True)[0].Expiry
        
        # Select the call Option contracts with the furthest expiry
        calls = [i for i in chain if i.Expiry == expiry and i.Right == OptionRight.Call]
        if len(calls) == 0: return
        call_contracts = sorted(calls, key = lambda x: abs(x.Strike - x.UnderlyingLastPrice))
        if len(call_contracts) == 0:
            return
        self.call = call_contracts[0]
        self.entryTicket = self.MarketOrder(self.call.Symbol, 5)
    def BuyPut(self, data: Slice) -> None:
        # Get the OptionChain
        chain = data.OptionChains.get(self.symbol, None)
        if not chain: return
        # Get the furthest expiry date of the contracts
        expiry = sorted(chain, key = lambda x: x.Expiry, reverse=True)[0].Expiry
        
        # Select the call Option contracts with the furthest expiry
        puts = [i for i in chain if i.Expiry == expiry and i.Right == OptionRight.Put]
        if len(puts) == 0: return
        put_contracts = sorted(puts, key = lambda x: abs(x.Strike - x.UnderlyingLastPrice))
        if len(put_contracts) == 0:
            return
        self.put = put_contracts[0]
        self.entryTicket = self.MarketOrder(self.put.Symbol, 5)