Overall Statistics |
Total Trades 13 Average Win 213.17% Average Loss -4.54% Compounding Annual Return 23.515% Drawdown 75.800% Expectancy 6.989 Net Profit 137.172% Sharpe Ratio 0.564 Probabilistic Sharpe Ratio 5.924% Loss Rate 83% Win Rate 17% Profit-Loss Ratio 46.93 Alpha 0.532 Beta -1.314 Annual Standard Deviation 0.629 Annual Variance 0.396 Information Ratio 0.311 Tracking Error 0.709 Treynor Ratio -0.27 Total Fees $1562.75 Estimated Strategy Capacity $120000.00 Lowest Capacity Asset VIX XUJS4Z3KE3GU|VIX 31 |
from datetime import timedelta, date from talib import MACD, EMA from collections import deque from numpy import sum import numpy as np from scipy import stats class SmoothBlueBat(QCAlgorithm): def Initialize(self): self.SetStartDate(2017, 11, 15) #self.SetEndDate(2020, 5, 1) self.SetCash(100000) self.last_date = datetime(2000, 1, 1) self.mode = 1 # sell with MACD #self.mode = 2 # sell with preset limit order self.lookbackIV = 150 self.SetSecurityInitializer(self.security_initializer) self.underly = self.AddIndex('VIX', Resolution.Daily).Symbol self.vix = self.AddData( CBOE, "VIX", Resolution.Daily).Symbol self.macd = self.MACD(self.vix, 12, 26, 9, MovingAverageType.Exponential, Resolution.Daily) self.ordered = False self.contract = str() self.contract_without_limit_order = str() self.stop_buy=False self.count=0 self.options_percentage = 0.05 # percentage of options self.DaysBeforeExp = 2 self.SetWarmUp(timedelta(self.lookbackIV)) self.Schedule.On(self.DateRules.EveryDay(self.underly), \ self.TimeRules.BeforeMarketClose(self.underly, 30), \ self.Plotting) def security_initializer(self, security): if security.Type == SecurityType.Equity: security.SetDataNormalizationMode(DataNormalizationMode.Raw) def OnData(self, data): if(self.IsWarmingUp): return # decide when to buy if self.Securities[self.vix].Close > 25 and self.Securities[self.vix].Close < 30: for kvp in self.Portfolio: if self.Securities[kvp.Key].Invested: symbol = kvp.Key id = symbol.ID security_type = id.SecurityType if security_type == 10:#SecurityType.Option: if self.last_date < id.Date: self.last_date = id.Date if (self.last_date - self.Time) < timedelta(10): # x days overlap of options if not self.stop_buy: self.Buy_Option( data) # decide when to sell if self.mode == 1: if (self.Securities[self.vix].Close > 25) and (self.macd.Current.Value < self.macd.Signal.Current.Value): self.stop_buy=True for kvp in self.Portfolio: if self.Securities[kvp.Key].Invested: symbol = kvp.Key id = symbol.ID security_type = id.SecurityType if security_type == 10: #SecurityType.Option for VIX Calls self.Liquidate(symbol) else: self.stop_buy=False if self.mode == 2: # set a limit order if self.contract_without_limit_order: self.Set_limit_order(data) def Buy_Option(self, data): if not (data.ContainsKey(self.underly) and data[self.underly] is not None): return if not self.contract: #min_strike = data[self.underly].Price + 10 #max_strike = data[self.underly].Price + 15 min_strike = 70 max_strike = 120 min_expiry = self.Time + timedelta(days=75) # 60 around 3 month max_expiry = self.Time + timedelta(days=95) #sorted_function = lambda x: x.BidSize sorted_function = lambda x: x.StrikePrice direction = True self.contract = self.GetOption(data, self.underly, OptionRight.Call, min_strike, max_strike, min_expiry, max_expiry, sorted_function, direction) if not self.contract: return if data.ContainsKey(self.contract.Symbol): contract_value = self.Securities[self.contract.Symbol].AskPrice if contract_value > 0: quantity = self.CalculateOrderQuantity(self.contract.Symbol, self.options_percentage) self.MarketOrder(self.contract.Symbol, quantity) self.contract_without_limit_order = self.contract self.contract = str() self.ordered = True def Set_limit_order(self, data): if not self.contract_without_limit_order: return number_cont = self.Portfolio[self.contract_without_limit_order.Symbol].Quantity cost_base = self.Portfolio[self.contract_without_limit_order.Symbol].AveragePrice self.LimitOrder(self.contract_without_limit_order.Symbol, - number_cont * 1/3, cost_base*1.5) self.LimitOrder(self.contract_without_limit_order.Symbol, - number_cont * 1/3, cost_base*4) self.LimitOrder(self.contract_without_limit_order.Symbol, - number_cont * 1/3, cost_base*8) self.contract_without_limit_order = str() def GetOption(self,data,underlying,optionright,MinStrike,\ MaxStrike,MinExpiry,MaxExpiry,sortedfunction,reverse): ## Get list of Options Contracts for a specific time chainProvider = self.OptionChainProvider contracts = chainProvider.GetOptionContractList(underlying, self.Time) if len(contracts) == 0: return filtered_options = [x for x in contracts if x.ID.OptionRight == optionright and\ x.ID.StrikePrice > MinStrike and\ x.ID.StrikePrice < MaxStrike and\ x.ID.Date > MinExpiry and\ x.ID.Date < MaxExpiry] if len(filtered_options) == 0: return added_contracts = [] for x in filtered_options: option = self.AddOptionContract(x, Resolution.Minute) optionsymbol = self.Securities[option.Symbol] if data.ContainsKey(optionsymbol.Symbol): added_contracts.append(optionsymbol) sorted_options=sorted(added_contracts,key=sortedfunction,reverse=reverse) if len(sorted_options) > 0: selected = sorted_options[0] else: selected = None return selected def Plotting(self): # plot underlying's price self.Plot("Data Chart VIX", self.vix, self.Securities[self.underly].Close) # plot macd self.Plot("Macd Signal", "Value", self.macd.Current.Value) self.Plot("Macd Signal", "Signal", self.macd.Signal.Current.Value) for kvp in self.Portfolio: symbol = kvp.Key id = symbol.ID security_type = id.SecurityType if security_type == 10: #SecurityType.Option: if self.Securities[symbol].Invested: self.Plot("Options Price", symbol, self.Securities[symbol].Price) option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type== 10] if option_invested: self.Plot("Data Chart invested", "strike", option_invested[0].ID.StrikePrice)