| Overall Statistics |
|
Total Trades 9 Average Win 64.79% Average Loss -38.59% Compounding Annual Return 351.420% Drawdown 58.800% Expectancy 0.339 Net Profit 132.792% Sharpe Ratio 9.307 Probabilistic Sharpe Ratio 69.794% Loss Rate 50% Win Rate 50% Profit-Loss Ratio 1.68 Alpha 16.985 Beta -3.459 Annual Standard Deviation 1.78 Annual Variance 3.167 Information Ratio 7.658 Tracking Error 2.147 Treynor Ratio -4.789 Total Fees $15.75 |
from datetime import timedelta
from itertools import combinations
import pandas as pd
class BearPutSpreadAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 1, 1)
self.SetCash(10000)
self.spy = self.AddEquity("SPY", Resolution.Minute).Symbol
option = self.AddOption("SPY", Resolution.Minute)
self.symbol = option.Symbol
option.SetFilter(-5, 5, timedelta(1), timedelta(90))
self.SetBenchmark(self.spy)
def OnData(self, data):
if self.Portfolio.Invested or \
not data.OptionChains.ContainsKey(self.symbol) or \
not data.ContainsKey(self.spy):
return
for symbol, chain in data.OptionChains.items():
contracts = [contract for contract in chain]
if len(contracts) == 0:
return
underlying_price = data[self.spy].Close
self.TradeOptions(contracts, underlying_price)
def TradeOptions(self, contracts, underlying_price):
# Get all put contracts
all_puts = [contract for contract in contracts if contract.Right == OptionRight.Put]
# Get all unique expiries
expires = set([contract.Expiry for contract in all_puts])
rankings_df = pd.DataFrame()
for expiry in expires:
puts = [contract for contract in all_puts if contract.Expiry == expiry]
if len(puts) == 0:
continue
for option_combinations in combinations(puts, 2):
buy_put = option_combinations[0]
sell_put = option_combinations[1]
strike_width = buy_put.Strike - sell_put.Strike
net_cost = buy_put.LastPrice - sell_put.LastPrice
# We ignore the contract multiplier here
max_loss = net_cost
max_profit = strike_width - net_cost
# Calculate factors
inverted_profit_loss_ratio = max_loss / max_profit if max_profit != 0 else float('inf')
break_even_distance = underlying_price - buy_put.Strike + net_cost
days_to_expiry = (expiry - self.Time).days
# Save factor results
row = pd.DataFrame({'inverted_profit_loss_ratio' : [inverted_profit_loss_ratio],
'break_even_distance' : [break_even_distance],
'days_to_expiry' : [days_to_expiry]},
index=[option_combinations])
rankings_df = rankings_df.append(row)
if not rankings_df.empty:
# Rank put contracts by factors
selected_contracts = rankings_df.rank().sum(axis=1).idxmin()
# Create Bear Put Spread
buy_symbol = selected_contracts[0].Symbol
sell_symbol = selected_contracts[1].Symbol
quantity = self.CalculateOrderQuantity(buy_symbol, 0.5)
if quantity > 0:
self.Buy(buy_symbol, quantity)
self.Sell(sell_symbol, quantity)