Overall Statistics
Total Trades
7
Average Win
0%
Average Loss
-0.35%
Compounding Annual Return
-15.633%
Drawdown
1.100%
Expectancy
-1
Net Profit
-0.310%
Sharpe Ratio
-7.213
Probabilistic Sharpe Ratio
1.216%
Loss Rate
100%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
-0.191
Beta
0.068
Annual Standard Deviation
0.025
Annual Variance
0.001
Information Ratio
-3.347
Tracking Error
0.11
Treynor Ratio
-2.598
Total Fees
$7.00
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Common")

from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Securities.Option import OptionPriceModels
from QuantConnect.Securities.Option import OptionStrategies
import pandas as pd
import numpy as np
import math 

class QuantumVerticalInterceptor(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)
        self.SetEndDate(2020, 1, 7)
        self.SetCash(10000)
        self.DELTA_TARGET=0.5
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Cash)
        self.df_calls = None
        #set a risk limit of 1% of portfolio value
        self.investment_limit = self.Portfolio.TotalPortfolioValue * 0.01 
        # Add the option
        option = self.AddOption("SPY")
        self.optionSymbol = option.Symbol

        # Add the initial contract filter
        option.SetFilter(-5, +5, 5, 10)

        # Define the Option Price Model
        option.PriceModel = OptionPriceModels.CrankNicolsonFD()
        #option.PriceModel = OptionPriceModels.BlackScholes()
        #option.PriceModel = OptionPriceModels.AdditiveEquiprobabilities()
        #option.PriceModel = OptionPriceModels.BaroneAdesiWhaley()
        #option.PriceModel = OptionPriceModels.BinomialCoxRossRubinstein()
        #option.PriceModel = OptionPriceModels.BinomialJarrowRudd()
        #option.PriceModel = OptionPriceModels.BinomialJoshi()
        #option.PriceModel = OptionPriceModels.BinomialLeisenReimer()
        #option.PriceModel = OptionPriceModels.BinomialTian()
        #option.PriceModel = OptionPriceModels.BinomialTrigeorgis()
        #option.PriceModel = OptionPriceModels.BjerksundStensland()
        #option.PriceModel = OptionPriceModels.Integral()

        # Set warm up with 30 trading days to warm up the underlying volatility model
        self.SetWarmUp(30, Resolution.Daily)


    def OnData(self,slice):
        self.Plot("Portfolio", "Margin Remaining", self.Portfolio.MarginRemaining)         # Remaining margin on the account
        self.Plot("Portfolio", "Margin Used", self.Portfolio.TotalMarginUsed)         # Sum of margin used across all securities

        if self.IsWarmingUp or not slice.OptionChains.ContainsKey(self.optionSymbol):
            return

        chain = slice.OptionChains[self.optionSymbol]
        #set float format so delta displays correctly
        pd.set_option('display.float_format', lambda x: '%.5f' % x)
        #put the relevant data into the dataframe
        df = pd.DataFrame([[x.Right,float(x.Strike),x.Expiry,float(x.BidPrice),float(x.AskPrice),x.Greeks.Delta,x.UnderlyingLastPrice] for x in chain],
        index=[x.Symbol.Value for x in chain],
        columns=['type', 'strike', 'expiry', 'ask price', 'bid price', 'delta','underlyinglast'])
        #ensure expiry column is in datetime format
        df['expiry'] = pd.to_datetime(df['expiry'])
        # sort by expiry, descending
        df.sort_values(by=['expiry'],ascending=False)
        # get the most future date
        furthest_date = df['expiry'].iloc[0]
        # keep only those rows which have that furthest date
        df = df[df.expiry == furthest_date]
        #split the dataframe into calls and puts (calls are 0, puts are 1)
        self.df_calls = df[df.type==0]
        #sort by delta
        self.df_calls.sort_values(by=['delta'],ascending=False)

        #select the closest two records to the DELTA TARGET
        #try:
        uppercall_ind = self.df_calls[self.df_calls.delta<self.DELTA_TARGET].delta.idxmax()
        lowercall_ind = self.df_calls[self.df_calls.delta>self.DELTA_TARGET].delta.idxmin()
        self.df_calls  = self.df_calls[self.df_calls.index.isin([lowercall_ind,uppercall_ind])]
        spread_value = self.df_calls.at[lowercall_ind,'bid price'] - self.df_calls.at[uppercall_ind,'ask price']
        max_risk = self.df_calls.at[uppercall_ind,'strike'] - self.df_calls.at[lowercall_ind,'strike']
        max_risk_contract = max_risk * 100
        max_investment = math.trunc(self.investment_limit / max_risk_contract)
        self.Sell(OptionStrategies.BearCallSpread(self.optionSymbol, self.df_calls.at[lowercall_ind,'strike'], self.df_calls.at[uppercall_ind,'strike'] , self.df_calls.at[uppercall_ind,'expiry']), max_investment)
        #except:
        #    return