| Overall Statistics |
|
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $0.00 |
import numpy as np
import datetime
from datetime import timedelta
import decimal
import time
import pandas as pd
from pandas.tseries.offsets import BDay
from QuantConnect.Algorithm import *
from QuantConnect.Data import *
from QuantConnect.Securities.Option import OptionPriceModels
from QuantConnect.Algorithm.Framework.Alphas import *
import json
#from earnings_dates import dates
class MultidimensionalHorizontalShield(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2018,7,20) # Set Start Date
self.SetEndDate(2018,7,30) # Set End Date
self.SetCash(30000) # Set Strategy Cash
# self.earningsDates is a list with AAPL earnings dates. The code to get these dates is
# in the file earnings_dates
# Is possible to do this approach with other stocks
# Set InteractiveBrokers Brokerage model
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.tickers = ['AAPL','NFLX','AMZN','GOOG']
self.earningDates = {}
#Select multiple stocks from API
if self.LiveMode:
url = 'https://cloud.iexapis.com/stable/stock/market/batch?symbols=aapl,nflx,amzn,goog&types=estimates&token=pk_7fed8485fc2e4539aa40b42e33d2e9eb'
apiResponse = self.Download(url)
apiData = json.loads(apiResponse)
self.Debug(apiData)
# In this case self.earningDates is a dictionary that would have stock symbols in keys
# and dates in values.
self.earningDates = {}
for map in apiData:
dates = apiData[map]['estimates']['estimates'][0]['reportDate']
dates_object = datetime.datetime.strptime(dates, "%Y-%m-%d")
self.earningDates[map] = dates_object
url = 'https://cloud.iexapis.com/stable/stock/market/batch?symbols=aapl,nflx,amzn,goog&types=earnings&last=10&token=pk_7fed8485fc2e4539aa40b42e33d2e9eb'
apiResponse = self.Download(url)
apiData = json.loads(apiResponse)
for map in apiData:
for i in range(0,len(apiData)):
dates = apiData[map]['earnings']['earnings'][i]['EPSReportDate']
dates_object = datetime.datetime.strptime(dates, "%Y-%m-%d")
self.earningDates.setdefault(map, [])
self.earningDates[map].append(dates_object)
self.Debug(self.earningDates)
for ticker in self.tickers:
equity = self.AddEquity(ticker, Resolution.Minute)
equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
self.equity = equity.Symbol
self.openTransaction = None
self.symbolToTrade = None
self.closeByExpiration = True
self.closeByProfitLoss = False
self.maxOpenPositions = 5
self.limitOrders = []
self.symbols = []
# Add the options
for ticker in self.tickers:
option = self.AddOption(ticker,Resolution.Minute)
self.symbols.append(option.Symbol)
option.SetFilter(lambda universe: universe.WeeklysOnly().Strikes(-10,+10).Expiration(timedelta(0), timedelta(30)))
#option.SetFilter(-10, +10, timedelta(0), timedelta(30))
#option = self.AddOption(self.symbol, Resolution.Minute)
#self.option_symbol = option.Symbol
# The default setFilter is with monthly expiration. I comment this to use weekly expiration
#option.SetFilter(-10, +10, timedelta(0), timedelta(30))
# Select contract by weekly expiration
#option.SetFilter(lambda universe: universe.WeeklysOnly().Strikes(-10,+10).Expiration(timedelta(0), timedelta(30)))
# This is the Pricing model to calculate the Delta for each contract
option.PriceModel = OptionPriceModels.CrankNicolsonFD() # Pricing model to gets delta
# Warm up period
self.SetWarmUp(TimeSpan.FromDays(10))
# One Schedule function that will run all days at 12:00 to look if the current time is 2 days before earnging date
self.Schedule.On(self.DateRules.EveryDay(),
self.TimeRules.At(12,0), self.ActivateTransaction)
# Schudele function to run the conditions to sell. Will run all days at 9:45 am
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(9, 45),
self.CloseTrade)
def OnData(self, slice):
'''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(self.IsWarmingUp):
return
# At 15:45 each day if self.openTransaction is True, look for options contracts to buy
if self.Time.hour ==15 and self.Time.minute ==45 and self.openTransaction==True:
options_info = self.select_options(slice)
#self.Debug(options_info)
if options_info is not None:
call , midPriceCall, put, midPricePut = options_info
self.Debug('call contract is %s' % call)
CallPrice = round(midPriceCall + 0.04,2)
PutPrice = round(midPricePut + 0.04,2)
# Buy Limit Orders for put and call
Callticket = self.LimitOrder(call,1,CallPrice)
Putticket = self.LimitOrder(put,1,PutPrice)
self.Debug('ticket is %s' % Callticket)
self.limitOrders.append(Callticket)
self.limitOrders.append(Putticket) # append the order ticket in the limitOrders list
self.openTransaction = False # Set self.openTransaction to false in order to stop buying in the current day
else:
self.Debug('Cannot processing options information')
return
def ActivateTransaction(self):
'''
This function look if the current date is 2 business days before the earnings date.
If this is the case the flag self.openTransaction is equal to True and the algo is
ready to make orders
'''
# if self.Time.date().isoweekday() ==1:
self.Debug(self.Time)
# Loop over the self.earningDates dictionary and if the earning dates of a stock is two days
# ahead the current date, allow to trade setting the self.openTransaction to True and grab
# that stock in self.symbolToTrade
# If current date is two days before earnings date and if is weekday, set self.openTransaction
# to True. This means to allow orders.
two_days_ahead = (self.Time.date() + BDay(2)).date()
for stock, dates in self.earningDates.items():
for date in dates:
if (two_days_ahead) == date.date() and self.Time.date().isoweekday() <=5:
self.Debug('Two days before earning release for stock %s %s %s ' % (two_days_ahead, date.date(),stock))
self.openTransaction = True
self.symbolToTrade = stock
break
def select_options(self,slice):
if (slice.OptionChains.Count == 0):
self.Debug('There are not options contracts in this chain at date %s' % self.Time.date())
return
for key in self.earningDates:
if key == self.symbolToTrade:
self.Debug('key is %s' % key)
self.Debug('symbolToTrade is %s' % self.symbolToTrade)
for kvp in slice.OptionChains:
self.Debug('kvpkey %s' % kvp.Key)
if kvp.Key == key:
chain = kvp.Value # Retrieve option chain only for the stock within 2 days for earnings report
self.Debug('symbol to look option chain %s' % key)
# Select At the Money calls and puts
# Make 2 lists called atm_calls and atm_puts
atm_calls = [x for x in chain if x.Strike <= x.UnderlyingLastPrice and x.Right == 0 and (x.Expiry.date() - self.Time.date()).days >= 7]
atm_puts = [x for x in chain if x.Strike >= x.UnderlyingLastPrice and x.Right == 1 and (x.Expiry.date() - self.Time.date()).days >= 7]
# Debugging messages that are comment to prevent flooding the screen
deltasCall = [x.Greeks.Delta for x in atm_calls]
deltasPut = [x.Greeks.Delta for x in atm_puts]
#self.Debug('Deltas for call contracts are %s' % deltasCall)
#self.Debug('Deltas for put contracts are %s' % deltasPut)
# Find the neares delta to 0.5 for both put and call
nearCallDelta = (np.abs(np.array(deltasCall)-0.5)).argmin()
nearPutDelta = (np.abs(np.array(deltasPut)+0.5)).argmin()
# The method argmin() return the index with the delta nearest to 0.5. Then we use that
# index to lookup atm_calls and atm_puts
call = atm_calls[nearCallDelta]
put = atm_puts[nearPutDelta]
self.Debug('Nearest call delta to 0.5 is %s' % call.Greeks.Delta)
self.Debug('Nearest put delta to -0.5 is %s' % put.Greeks.Delta)
callbid = call.BidPrice
callask = call.AskPrice
self.midPriceCall = round((callbid + callask)/2,2)
putbid = put.BidPrice
putask = put.AskPrice
self.midPricePut = round((putbid + putask)/2,2)
self.call = call.Symbol
self.put = put.Symbol
self.Debug('Underlying is %s' % self.Securities[self.equity].Price)
self.Debug('Call contract is %s delta %s expiration %s strike %s' % (call.Symbol, call.Greeks.Delta,call.Expiry,call.Strike))
self.Debug('Put contract is %s delta %s expiration %s strike %s' % (put.Symbol, put.Greeks.Delta,put.Expiry,put.Strike))
return self.call, self.midPriceCall , self.put, self.midPricePut
def CloseTrade(self):
# Get all orders by calling the limitOrders list which have all order tickets
orders = self.limitOrders # self.Transactions.GetOrders()
if len(orders) == 0:
return
# Use BDay(2) to substract 2 days to current date
# five_days_ahead = (self.Time.date() - BDay(2)).date()
# Use BDay(2) to substract 1 days to current date
five_days_ahead = (self.Time.date() - BDay(1)).date()
# The logic is the following: is self.closeByExpiration is set to True in Initialize,
# loop over orders and if current date is 5 days after order date and order status is filled
# sell the contract using order.Symbol by the QuantityFilled method.
if self.closeByExpiration:
for order in orders:
if (five_days_ahead >= order.Time.date()) and (order.Status == OrderStatus.Filled):
self.Sell(order.Symbol,order.QuantityFilled)
self.Debug('sell %s after 5 days of order date' % order.Symbol)
self.openTransaction = False
self.limitOrders.remove(order) # remove the order from self.limitOrders after sold
option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option]
option_invested_values = [x.Value for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option]
# If self.closeByProfitLoss is set to True in Initialize, loop over contract in Portfolio and
# get the current profit percentage of each contrct. If this profit percentage is greater than
# 50% or lower than -11%, Liquidate(sell) the contract.
if self.closeByProfitLoss:
for contract in option_invested:
self.Debug(self.Securities[contract].Symbol)
underlying = self.Securities[self.equity].Price
quantity = self.Portfolio[contract].Quantity
lastPrice = self.Securities[contract].Price
profits = round(self.Portfolio[contract].UnrealizedProfit,0)
profit_percentage = self.Portfolio[contract].UnrealizedProfitPercent
if (profit_percentage > 0.5) or (profit_percentage < -0.11):
self.Liquidate(contract)
self.Debug('Sell contract %s with profit/loss of %s' % (contract, profit_percentage))
#self.Debug("Contract: " + str(contract) + " - Underlying Price: " + str(underlying) + " - Quantity: " + str(quantity) + " - Last Price: " + str(lastPrice))
#self.Debug('Unrealized profits and profit percentage at date %s for contract %s are %s and %s' % (self.Time.date(), contract, profits,"{0:.0%}".format(profit_percentage)))
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)
self.Debug("{0}: {1}: {2}".format(self.Time, order.Type, orderEvent))