Overall Statistics |
Total Trades 4 Average Win 0% Average Loss 0% Compounding Annual Return 80.354% Drawdown 2.400% Expectancy 0 Net Profit 1.465% Sharpe Ratio 3.028 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0.604 Beta 0.328 Annual Standard Deviation 0.137 Annual Variance 0.019 Information Ratio 3.704 Tracking Error 0.267 Treynor Ratio 1.268 Total Fees $4.00 |
import numpy as np from datetime import datetime from datetime import timedelta import decimal import time from QuantConnect.Algorithm import * from QuantConnect.Data import * ### <summary> ### Basic template algorithm simply initializes the date range and cash. This is a skeleton ### framework you can use for designing an algorithm. ### </summary> class VIX_SPY_ALGO(QCAlgorithm): '''Basic template algorithm simply initializes the date range and cash''' def Initialize(self): '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.''' self.SetStartDate(2015,8,20) #Set Start Date self.SetEndDate(2015,8,30) #Set End Date self.SetCash(10000) #Set Strategy Cash self.vix = 'CBOE/VIX' self.spy = "SPY" equity = self.AddEquity("SPY", Resolution.Minute) equity.SetDataNormalizationMode(DataNormalizationMode.Raw) self.underlyingsymbol = equity.Symbol # Add Quandl VIX price (daily) self.AddData(QuandlVix, "CBOE/VIX", Resolution.Minute) # Add VIX 10 and 15 SMA self.sma_10 = self.SMA(self.vix, 10, Resolution.Daily) self.sma_15 = self.SMA(self.vix, 15, Resolution.Daily) option = self.AddOption("SPY", Resolution.Minute) option.SetFilter(-10, +10, timedelta(0), timedelta(250)) self.symbol = option.Symbol self.order_times = {} self.buy_spy = None self.SetBenchmark(equity.Symbol) #self.Plot("VIX", self.vix_price) self.Debug("numpy test >>> print numpy.pi: " + str(np.pi)) self.date_first_level = (self.Time) self.buy_ticket = None self.number_of_spy_transactions = 0 # Add differents EMA for SPY self.ema_50 = self.EMA(self.spy, 50, Resolution.Daily) self.ema_100 = self.EMA(self.spy, 100, Resolution.Daily) self.ema_200 = self.EMA(self.spy, 200, Resolution.Daily) self.ema_365 = self.EMA(self.spy, 365, Resolution.Daily) self.ema_50 = self.EMA("SPY", 50) self.ema_100 = self.EMA("SPY", 100) self.ema_200 = self.EMA("SPY", 200) self.ema_365 = self.EMA("SPY", 365) # self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.Every(timedelta(minutes=60)), Action(self.sell_intraday)) self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.Every(timedelta(minutes=60)), self.LiquidateUnrealizedProfits) def OnData(self, data): '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. Arguments: data: Slice object keyed by symbol containing the stock data ''' if not data.ContainsKey(self.vix): return #self.Debug(self.Time + timedelta(days=7)) #current_date = datetime.strptime(self.Time, '%Y-%m-%d') if (self.Securities[self.vix].Price > 19) and (self.Securities[self.vix].Price < 25) and (self.Time >= self.date_first_level): self.Debug('vix price is %s on date %s spy price is %s' % (self.Securities[self.vix].Price, data.Time,self.Securities[self.spy].Price)) quantity = int(2500 / self.Securities[self.spy].Price) self.Debug('Margin Remaining is %s' % self.Portfolio.MarginRemaining) self.MarketOrder("SPY", quantity) self.buy_first_level = self.Time self.Debug('time is %s' % self.Time) self.date_first_level = self.Time + timedelta(days=7) self.number_of_spy_transactions +=1 # self.sell_intraday() elif self.Securities[self.vix].Price > 25 and self.Securities[self.vix].Price < 30:# and not self.buy_spy: self.Debug('vix price is %s on date %s spy price is %s' % (self.Securities[self.vix].Price,data.Time,self.Securities[self.spy].Price)) quantity = int(2500 / self.Securities[self.spy].Price) self.Debug('Margin Remaining is %s' % self.Portfolio.MarginRemaining) self.MarketOrder("SPY", quantity) self.buy_second_level = True self.number_of_spy_transactions +=1 #self.sell_intraday() #limit_order_ticker = self.LimitOrder('SPY',1, decimal.Decimal(.999)) elif self.Securities[self.vix].Price > 30 and self.Securities[self.vix].Price < 35:# and not self.buy_spy: self.Debug('vix price is %s on date %s spy price is %s' % (self.Securities[self.vix].Price,data.Time,self.Securities[self.spy].Price)) quantity = int(2500 / self.Securities[self.spy].Price) self.Debug('Margin Remaining is %s' % self.Portfolio.MarginRemaining) self.MarketOrder("SPY", quantity) self.buy_third_level = True self.buy_day = data.Time self.number_of_spy_transactions +=1 #self.sell_intraday() #limit_order_ticker = self.LimitOrder('SPY',1, decimal.Decimal(.999)) elif self.Securities[self.vix].Price > 35 and self.Securities[self.vix].Price < 42:# and not self.buy_option: self.Debug('buy option with vix price is %s on date %s spy price is %s' % (self.Securities[self.vix].Price,data.Time,self.Securities[self.spy].Price)) option_contract = self.BuyCall()[0] self.AddOptionContract(option_contract, Resolution.Minute) self.Buy(option_contract, 2) #self.buy_option = True # #limit_order_ticker = self.LimitOrder('SPY',1, decimal.Decimal(.999)) #self.sell_intraday(self) elif self.Securities[self.vix].Price > 42:# and not self.buy_option: self.Debug('buy option with vix price is %s on date %s spy price is %s' % (self.Securities[self.vix].Price,data.Time,self.Securities[self.spy].Price)) option_contract = self.BuyCall()[1] self.AddOptionContract(option_contract, Resoluation.Minute) self.Buy(option_contract, 3) self.TradeOptions(slice) #self.buy_option = True #limit_order_ticker = self.LimitOrder('SPY',1, decimal.Decimal(.999)) elif self.Securities[self.vix].Price > 53:# and not self.buy_option: self.Debug('buy option with vix price is %s on date %s spy price is %s' % (self.Securities[self.vix].Price,data.Time,self.Securities[self.spy].Price)) option_contract = self.BuyCall()[2] self.AddOptionContract(option_contract, Resoluation.Minute) self.Buy(option_contract, 2) #self.buy_option = True #limit_order_ticker = self.LimitOrder('SPY',1, decimal.Decimal(.999)) elif self.Securities[self.vix].Price > 75:# and not self.buy_option: self.Debug('vix price is %s on date %s spy price is %s' % (self.Securities[self.vix].Price,data.Time,self.Securities[self.spy].Price)) option_contract = self.BuyCall()[3] self.AddOptionContract(option_contract, Resoluation.Minute) self.Buy(option_contract, 2) #self.buy_option = True #self.LimitOrder('SPY',1, decimal.Decimal(.999)) self.Debug('vix price is %s vix 10 SMA is %s , vix 15 SMA is %s on date %s' % (self.Securities[self.vix].Price, self.sma_10.Current.Value,self.sma_15.Current.Value,self.Time)) # Track the value of the SPY ETF and the Portfolio instrument invested # if self.Portfolio["SPY"].Invested: # self.Debug('Unrealized Profits on SPY is %s on time %s' % (self.Portfolio["SPY"].UnrealizedProfit, data.Time)) # self.Debug('Number of transactions is %s' % self.number_of_transactions) if self.Portfolio.Invested: self.Debug('Total Value of the Portfolio is %s' % self.Portfolio.TotalHoldingsValue) self.Debug('Number of transactions %s' % self.number_of_spy_transactions) if self.buy_spy == True: if self.Portfolio['SPY'].HoldingsValue < 200 and (self.sma_10.Current.Value < 11): put_contract = self.Buy_Put()[0] self.AddOptionContract(put_contract, Resolution.Minute) self.Buy(put_contract, 2) elif self.Portfolio['SPY'].HoldingsValue < 200 and (self.sma_15.Current.Value < 10): put_contract = self.Buy_Put()[1] self.AddOptionContract(put_contract, Resolution.Minute) self.Buy(put_contract, 3) def BuyCall(self): contracts = self.OptionChainProvider.GetOptionContractList(self.underlyingsymbol, self.Time.date()) # if there is no contracts in this optionchain, pass the instance if len(contracts) == 0 : return filtered_contracts = self.InitialFilter(self.underlyingsymbol, contracts, -3, 3, 30, 300) # Get call options call = [x for x in filtered_contracts if x.ID.OptionRight == 0] # sorted the contracts according to their expiration dates and the difference between strike price and current price call_contracts_first_entry = [x for x in call if ((x.ID.StrikePrice - self.Securities[self.spy].Price) / (self.Securities[self.spy].Price)) >= 0.08 and ((x.ID.Date.date() - self.Time.date()).days) >= 90] call_contracts_first_entry_sorted = sorted(call_contracts_first_entry, key = lambda x: abs(x.ID.StrikePrice - self.Securities[self.underlyingsymbol].Price))#[0]#.ID.StrikePrice contract_first_entry = call_contracts_first_entry_sorted[0] self.Debug('first entry contract is %s' % contract_first_entry.ID.StrikePrice) self.Debug('first entry contract expire in %s' % contract_first_entry.ID.Date.date()) call_contracts_second_entry = [x for x in call if ((x.ID.StrikePrice - self.Securities[self.spy].Price) / (self.Securities[self.spy].Price)) >= 0.14 and ((x.ID.Date.date() - self.Time.date()).days) >= 120] call_contracts_second_entry_sorted = sorted(call_contracts_second_entry, key = lambda x: abs(x.ID.StrikePrice - self.Securities[self.underlyingsymbol].Price))#[0]#.ID.StrikePrice contract_second_entry = call_contracts_second_entry_sorted[0] self.Debug('second entry contract is %s' % contract_second_entry.ID.StrikePrice) self.Debug('second entry contract expiry in %s' % contract_second_entry.ID.Date.date()) call_contracts_third_entry = [x for x in call if ((x.ID.StrikePrice - self.Securities[self.spy].Price) / (self.Securities[self.spy].Price)) >= 0.2 and ((x.ID.Date.date() - self.Time.date()).days) >= 150] call_contracts_third_entry_sorted = sorted(call_contracts_third_entry, key = lambda x: abs(x.ID.StrikePrice - self.Securities[self.underlyingsymbol].Price))#[0]#.ID.StrikePrice contract_third_entry = call_contracts_third_entry_sorted[0] self.Debug('third entry contract is %s' % contract_third_entry.ID.StrikePrice) self.Debug('third entry contract expire in %s' % contract_third_entry.ID.Date.date()) call_contracts_forth_entry = [x for x in call if ((x.ID.StrikePrice - self.Securities[self.spy].Price) / (self.Securities[self.spy].Price)) >= 0.2 and ((x.ID.Date.date() - self.Time.date()).days) >= 180] call_contracts_forth_entry_sorted = sorted(call_contracts_forth_entry, key = lambda x: abs(x.ID.StrikePrice - self.Securities[self.underlyingsymbol].Price))#[0]#.ID.StrikePrice contract_forth_entry = call_contracts_forth_entry_sorted[0] self.Debug('forth entry contract is %s' % contract_forth_entry.ID.StrikePrice) self.Debug('forth entry contract expire in %s' % contract_forth_entry.ID.Date.date()) return contract_first_entry ,contract_second_entry,contract_third_entry ,contract_forth_entry def BuyPut(self): contracts = self.OptionChainProvider.GetOptionContractList(self.underlyingsymbol, self.Time.date()) # if there is no contracts in this optionchain, pass the instance if len(contracts) == 0: return filtered_contracts = self.InitialFilter(self.underlyingsymbol, contracts, -10, 10, 30, 300) # Select put contracts from the filtered_contracts list puts = [x for x in filtered_contracts if x.ID.OptionRight == 1] put_contracts_first_entry = [x for x in call if ((self.Securities[self.spy].Price - x.ID.StrikePrice) / (self.Securities[self.spy].Price)) >= 0.1 and ((x.ID.Date.date() - self.Time.date()).days) >= 120] put_contracts_first_entry_sorted = sorted(put_contracts_first_entry, key = lambda x: abs(self.Securities[self.underlyingsymbol].Price - x.ID.StrikePrice))#[0]#.ID.StrikePrice put_contract_first_entry = put_contracts_first_entry_sorted[0] self.Debug('put contract first entry is %s' % put_contract_first_entry.ID.StrikePrice) self.Debug('put first entry contract expire in %s' % put_contract_first_entry.ID.Date.date()) put_contracts_second_entry = [x for x in call if ((self.Securities[self.spy].Price - x.ID.StrikePrice) / (self.Securities[self.spy].Price)) >= 0.1 and ((x.ID.Date.date() - self.Time.date()).days) >= 180] put_contracts_second_entry_sorted = sorted(put_contracts_second_entry, key = lambda x: abs(self.Securities[self.underlyingsymbol].Price - x.ID.StrikePrice))#[0]#.ID.StrikePrice put_contract_second_entry = put_contracts_second_entry_sorted[0] self.Debug('put contract second entry is %s' % put_contract_second_entry.ID.StrikePrice) self.Debug('put second entry contract expire in %s' % put_contract_second_entry.ID.Date.date()) return put_contract_first_entry, put_contract_second_entry def InitialFilter(self, underlyingsymbol, symbol_list, min_strike_rank, max_strike_rank, min_expiry, max_expiry): ''' This method is an initial filter of option contracts according to the range of strike price and the expiration date ''' if len(symbol_list) == 0 : return #fitler the contracts based on the expiry range contract_list = [i for i in symbol_list if min_expiry < (i.ID.Date.date() - self.Time.date()).days < max_expiry] return contract_list # self.Log(str("sell intraday function has triggered")) # self.Debug("sell intraday function has triggered") #filledSpyOrders = [x for x in orders if x.Symbol == "SPY" and x.Status == OrderStatus.Filled] #orderTime = filledSpyOrders.Last().Time #self.Debug('order time is %s' % orderTime) #self.Log('order time is %s' % orderTime) # if self.Portfolio["SPY"].Invested: #if self.buy_first_level == True: #orders = self.Transactions.GetOrders() #if orders: # self.Log(str(orders)) # if (self.Portfolio["SPY"].UnrealizedProfit > 200): # quantity = self.Portfolio['SPY'].Quantity # quantity_to_sell = quantity * 0.60 # self.Debug('sell SPY in the same day with a profit of %s' % self.Portfolio["SPY"].UnrealizedProfit) # self.MarketOrder('SPY',-quantity_to_sell) # elif self.buy_second_level == True: # def sell_intraday(self): if (self.Time.year == self.year) and (self.Time.day == self.day) and (self.Time.hour > self.hour): if (self.Portfolio["SPY"].UnrealizedProfit > 200): quantity = self.quantity quantity_to_sell = quantity * 0.60 self.Debug('sell SPY in the same day with a profit of %s' % self.Portfolio["SPY"].UnrealizedProfit) self.MarketOrder('SPY',-quantity_to_sell) def LiquidateUnrealizedProfits(self): ''' if we have over 1500 dollars in unrealized profits, liquidate''' if self.Portfolio["SPY"].Invested: if (self.sma_15.Current.Value <= 13) and (self.Portfolio['SPY'].UnrealizedProfit > 1000): self.Log("Liquidated unrealized profits at: {0}".format(self.Time)) self.Debug("Liquidated unrealized profits at %s" % self.Time) self.Liquidate('SPY') #self.buy_spy = False def OnOrderEvent(self, orderEvent): ''' Event when the order is filled. Debug log the order fill. :OrderEvent:''' self.Log(str(orderEvent)) order = self.Transactions.GetOrderById(orderEvent.OrderId) if order.Status == OrderStatus.Filled: self.order_times['time'] = order.Time self.Debug('order times are %s' % self.order_times) self.Debug('Info from OrderEvent object') self.Debug('order status is %s' % order.Status) self.Debug('order time is %s' % order.Time) self.Debug('order quantity is %s' % order.Quantity) self.Debug('order time hour is %s' % order.Time.hour) self.Debug('order time day is %s' % order.Time.day) self.Debug('order time year is %s' % order.Time.year) self.Debug('order id is %s' % order.Id) self.Debug('order type is %s' % order.Type) self.Debug('order symbol is %s' % order.Symbol) self.Debug('order direction is %s' % orderEvent.Direction) self.Debug('filled price of the order is %s' % order.Price) self.year = order.Time.year self.month = order.Time.month self.day = order.Time.day self.hour = order.Time.hour self.quantity = order.Quantity #self.Debug('next day of trading is %s' % datetime.strptime(order.Time,'m%/d%/Y% %H:%M:%S') + timedelta(days=1)) self.Log("{0}: {1}: {2}".format(self.Time, order.Type, OrderEvent)) #if self.Portfolio['SPY'].Invested: # orders = self.Transactions.GetOrders() # if orders: # self.Log(str(orders)) # if OrderEvent.FillQuantity == 0: # return # fetched = self.Transactions.GetOrderById(OrderEvent.OrderId) # self.Debug("{} was filled. Symbol: {}. Quantity: {}. Direction: {}" # .format(str(fetched.Type), # str(OrderEvent.Symbol), # str(OrderEvent.FillQuantity), # str(OrderEvent.Direction))) class QuandlVix(PythonQuandl): def __init__(self): self.ValueColumnName = "vix Close"