| Overall Statistics |
|
Total Trades 446 Average Win 0.20% Average Loss -0.29% Compounding Annual Return -24.983% Drawdown 7.100% Expectancy -0.072 Net Profit -5.834% Sharpe Ratio -3.465 Loss Rate 45% Win Rate 55% Profit-Loss Ratio 0.68 Alpha -0.246 Beta 0.152 Annual Standard Deviation 0.065 Annual Variance 0.004 Information Ratio -2.904 Tracking Error 0.126 Treynor Ratio -1.471 Total Fees $426.00 |
from clr import AddReference
from QuantConnect.Securities.Option import OptionPriceModels
import decimal as d
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Common")
from System import *
from QuantConnect import *
from QuantConnect.Data import *
from QuantConnect.Algorithm import *
import numpy as np
from datetime import timedelta
class My1(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019, 6, 1)
self.SetEndDate(2019, 8, 15)
self.SetCash(25000)
self.date = None
# add the underlying asset
self.stock= "SPY"
self.equity = self.AddEquity(self.stock, Resolution.Minute)
self.equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
option = self.AddOption(self.stock)
option.SetFilter(lambda universe: universe.IncludeWeeklys().Strikes(-5, +5).Expiration(timedelta(0), timedelta(7)))
# for greeks and pricer (needs some warmup) - https://github.com/QuantConnect/Lean/blob/21cd972e99f70f007ce689bdaeeafe3cb4ea9c77/Common/Securities/Option/OptionPriceModels.cs#L81
option.PriceModel = OptionPriceModels.CrankNicolsonFD() # both European & American, automatically
# this is needed for Greeks calcs
self.SetWarmUp(TimeSpan.FromDays(3)) # timedelta(7)
self.contract = str()
self.contractsAdded = set()
self.delta_treshold = 0.1
self.Delta = 0.0
def OnData(self, data):
if self.Time.date != self.date:
self.date = self.Time.date
for chain in data.OptionChains.Values:
# sort contracts to find at the money (ATM) contract with the farthest expiration
contracts = sorted(sorted(chain,
key = lambda x: abs(chain.Underlying.Price - x.Strike)), \
key = lambda x: x.Expiry, reverse=True)
expiry = sorted(contracts,key = lambda x: x.Expiry, reverse=True)[0].Expiry
#self.Debug("best expiry is" + str(expiry))
calls = [i for i in contracts if i.Expiry == expiry and i.Right == 0 and i.Strike > chain.Underlying.Price]
# sorted the contracts according to their strike prices
call_contracts = sorted(calls,key = lambda x: x.Strike)
if len(call_contracts) == 0: continue
# choose the deep OTM call option
self.call = call_contracts[0]
# select the put options which have the same expiration date with the call option
puts = [i for i in contracts if i.Expiry == expiry and i.Right == 1 and i.Strike < chain.Underlying.Price]
# sort the put options by strike price
put_contracts = sorted(puts, key = lambda x: x.Strike)
# choose the deep OTM put option
self.put = put_contracts[-1]
if not self.Portfolio.Invested:
#self.Transactions.CancelOpenOrders("SPY")
self.Debug("------------------------------- price is " + str(self.Securities[self.stock].Close))
self.Debug("Trade: Call " + str(self.call.Strike) + " " + str(self.call.Expiry))
self.Debug("Trade: Put " + str(self.put.Strike) + " " + str(self.put.Expiry))
self.Buy(self.call.Symbol ,1)
self.Buy(self.put.Symbol ,1)
#self.StopMarketOrder(self.stock, 50, self.call.Strike)
#self.StopMarketOrder(self.stock, -50, self.put.Strike)
else:
#if self.Time.minute == 59:
self.get_greeks(data)
self.doDeltaHedge()
def doDeltaHedge(self):
fut = self.Portfolio[self.stock].Quantity
#self.Debug("+++ time: "+ str(self.Time) +" delta is " + str(self.Delta) + " fut pos: " + str(fut))
if abs(self.Delta) > self.delta_treshold:
needfut = round(self.Delta*-100)
self.MarketOrder(self.stock,needfut)
self.Debug(str(self.Time) + " delta_hedging: self.Delta {} add fut contracts: {}" .format(self.Delta, needfut))
def get_greeks(self, slice):
sumdelta = 0.00
symbols = set()
for sym in self.Portfolio:
symbols.add(sym.Value.Symbol)
opt = self.Securities[sym.Value.Symbol]
for kvp in slice.OptionChains:
chain = kvp.Value # option contracts for each 'subscribed' symbol/key
traded_contracts = filter(lambda x: x.Symbol in symbols, chain)
#if not traded_contracts: self.Log("No traded cointracts"); return
deltas = [i.Greeks.Delta*self.Portfolio[i.Symbol].Quantity for i in traded_contracts]
sumdelta=sum(deltas)
futpos = self.Portfolio[self.stock].Quantity
self.Delta=sumdelta + futpos/100