| Overall Statistics |
|
Total Trades 79 Average Win 2.60% Average Loss -2.54% Compounding Annual Return 1.895% Drawdown 2.400% Expectancy 0.038 Net Profit 1.921% Sharpe Ratio 0.591 Probabilistic Sharpe Ratio 32.704% Loss Rate 49% Win Rate 51% Profit-Loss Ratio 1.02 Alpha 0.009 Beta 0.019 Annual Standard Deviation 0.033 Annual Variance 0.001 Information Ratio -1.515 Tracking Error 0.35 Treynor Ratio 1.005 Total Fees $98.75 |
from QuantConnect.Securities.Option import OptionPriceModels
from datetime import timedelta
class OptionsAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 1, 1)
#self.SetEndDate(2020, 3, 1)
self.SetCash(100000)
self.shortDelta = 0.70
self.longDelta = 0.80
self.equity = self.AddEquity("QQQ", Resolution.Minute)
option = self.AddOption("QQQ", Resolution.Minute)
self.symbol = option.Symbol
option.SetFilter(self.UniverseFunc)
option.PriceModel = OptionPriceModels.CrankNicolsonFD()
self.SetWarmUp(TimeSpan.FromDays(7))
self.SetBenchmark(self.equity.Symbol)
self.ema8 = self.EMA(self.equity.Symbol, 8, Resolution.Daily)
self.sma21 = self.SMA(self.equity.Symbol, 21, Resolution.Daily)
self.ema21 = self.EMA(self.equity.Symbol, 21, Resolution.Daily)
self.sma50 = self.SMA(self.equity.Symbol, 50, Resolution.Daily)
#self.ema50 = self.EMA(self.equity.Symbol, 50, Resolution.Daily)
#self.sma200 = self.SMA(self.equity.Symbol, 200, Resolution.Daily)
self.SetWarmUp(timedelta(350))
#self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen(self.equity.Symbol, 120),
# self.calculate_signal)
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen(self.equity.Symbol, 30), self.report_portfolio)
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen(self.equity.Symbol, 45), self.CheckForExpiry)
def CheckForExpiry(self):
if self.Portfolio.Invested and self.expirydate.date() == self.Time.date():
self.Liquidate()
self.Debug(f"Normal End Date: {self.Time}, TotalPortfolioValue: {self.Portfolio.TotalPortfolioValue}")
def report_portfolio(self):
if self.Portfolio.Invested:
#self.Debug(f"TotalPortfolioValue: {self.Portfolio.TotalPortfolioValue}, TotalMarginUsed: {self.Portfolio.TotalMarginUsed}, MarginRemaining: {self.Portfolio.MarginRemaining}, Cash: {self.Portfolio.Cash}")
#shortProfit = 0
#longProfit = 0
for key in sorted(self.Portfolio.keys()):
if self.Portfolio[key].Quantity > 0.0 or self.Portfolio[key].Quantity < 0.0:
#if self.Portfolio[key].Quantity > 0.0:
# longProfit = self.Portfolio[key].UnrealizedProfitPercent
#if self.Portfolio[key].Quantity < 0.0:
# shortProfit = self.Portfolio[key].UnrealizedProfit
#self.Debug(f"Symbol/Qty: {key} / {self.Portfolio[key].Quantity}, Avg: {self.Portfolio[key].AveragePrice}, Curr: { self.Portfolio[key].Price}, Profit($): {self.Portfolio[key].UnrealizedProfit}")
if key == self.equity.Symbol:
self.Liquidate(key)
#if longProfit + shortProfit != 0:
#self.Debug(f"Date/Expiry/Profit: {self.Time}, {self.expirydate}, {longProfit + shortProfit}")
return
def OnData(self,slice):
if not self.ema8.IsReady: return
if not self.sma21.IsReady: return
if not self.ema21.IsReady: return
if not self.sma50.IsReady: return
#if not self.ema50.IsReady: return
#if not self.sma200.IsReady: return
self.allChecksPassed = False
if(self.Time.hour == 10 and self.Time.minute == 30):
if slice.ContainsKey(self.equity.Symbol) and slice[self.equity.Symbol]:
if self.ema8.Current.Value > self.sma21.Current.Value and self.ema21.Current.Value > self.sma50.Current.Value:
if not self.Portfolio.Invested:
#if self.ema8.Current.Value > self.sma21.Current.Value and self.ema21.Current.Value > self.sma50.Current.Value and self.ema50.Current.Value > self.sma200.Current.Value:
#self.Debug(str(self.Time))
#self.Debug(f"equity:{slice[self.equity.Symbol].High} ema8:{self.ema8.Current.Value} sma21:{self.sma21.Current.Value} ema21:{self.ema21.Current.Value} sma50:{self.sma50.Current.Value}")
self.shortContract = None
self.longContract = None
for kvp in slice.OptionChains:
if kvp.Key != self.symbol: continue
chain = kvp.Value
contracts = [i for i in chain]
if len(contracts) == 0: continue
contracts = sorted(contracts, key=lambda x: (x.Expiry, x.Greeks.Delta))
self.shortContract = min(contracts, key=lambda x: abs(x.Greeks.Delta-self.shortDelta))
self.longContract = min([c for c in contracts if c.Expiry==self.shortContract.Expiry], key=lambda x: abs(x.Greeks.Delta-self.longDelta))
#self.Debug(str(self.Time))
#self.Debug(f"equity:{slice[self.equity.Symbol].High} ema8:{self.ema8.Current.Value} sma21:{self.sma21.Current.Value} ema21:{self.ema21.Current.Value} sma50:{self.sma50.Current.Value}")
self.Debug(f"Start Date: {self.Time}, TotalPortfolioValue: {self.Portfolio.TotalPortfolioValue}")
self.Debug(f"Short Strike: {self.shortContract.Strike} Expiry: {self.shortContract.Expiry} Delta: {self.shortContract.Greeks.Delta}")
self.Debug(f"Long Strike: {self.longContract.Strike} Expiry: {self.longContract.Expiry} Delta: {self.longContract.Greeks.Delta}")
#self.Debug(f"Short Strike: {self.shortContract.Strike}")
#self.Debug(f"Long Strike: {self.longContract.Strike}")
#self.Debug("Delta: " + str([i.Greeks.Delta for i in contracts]))
if self.shortContract != self.longContract:
pass
self.allChecksPassed = True
self.Sell(self.shortContract.Symbol, 5)
self.Buy(self.longContract.Symbol, 5)
self.expirydate = self.longContract.Expiry
break
else:
if self.Portfolio.Invested:
self.Liquidate()
self.Debug(f"Signal End Date: {self.Time}, TotalPortfolioValue: {self.Portfolio.TotalPortfolioValue}")
#def calculate_signal(self):
# if self.allChecksPassed and not self.Portfolio.Invested:
# self.Buy(longContract.Symbol, 1)
# self.Sell(shortContract.Symbol, 1)
def UniverseFunc(self, universe):
# include weekly contracts
return universe.IncludeWeeklys().Expiration(TimeSpan.FromDays(8),
TimeSpan.FromDays(8)).Strikes(-40, 40)
#def OnOrderEvent(self, orderEvent):
# self.Debug(str(orderEvent))