| Overall Statistics |
|
Total Trades 1 Average Win 0% Average Loss 0% Compounding Annual Return 109.635% Drawdown 0.300% Expectancy 0 Net Profit 0.203% Sharpe Ratio 11.225 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0.023 Annual Variance 0.001 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $2.00 |
from datetime import datetime,timedelta
import pandas as pd
import numpy as np
import sys
class MomentumAlgorithm(QCAlgorithm):
def Initialize(self):
self.VERBOSEMODE = True
self.VERBOSEMODE2 = False
self.SetStartDate(2019,5,10)
self.SetEndDate(2019,5,12)
self.SetCash(100000)
self.benchmark = "SPY"
self.SetRiskManagement(TrailingStopRiskManagementModel(0.0172))
self.symbols = ["SPY","TLT","GLD"]
self.lastSymbol = None
self.contract = None
self.spy = self.AddEquity("SPY",Resolution.Minute)
self.spy.SetDataNormalizationMode(DataNormalizationMode.Raw)
self.spy.SetDataNormalizationMode(DataNormalizationMode.Raw)
self.tlt = self.AddEquity("TLT",Resolution.Minute)
self.protectedPositions = {'SPY': False , 'TLT': False , 'GLD': False}
self.myOptions={}
self.pauseOneMinute = True
for symbol in self.Securities.Keys:
self.Securities[symbol].FeeModel = ConstantFeeModel(2.00)
self.Securities[symbol].SetDataNormalizationMode(DataNormalizationMode.Raw)
self.myOptions[symbol] = self.AddOption(symbol.Value,Resolution.Minute)
#limit options strikes to 10 strikes away with 6 day minimum
self.myOptions[symbol].SetFilter(-10, +10, timedelta(0), timedelta(30))
def OnData(self, slice):
try:
#if self.VERBOSEMODE2:self.Log("Time: {}" . format(slice.Time) )
if slice is None:
if self.VERBOSEMODE2:self.Log("no slice " )
return
optionchain = slice.OptionChains
for element in slice:
symbol = element.Key
symbolStr = symbol.Value
#make sure only act on invested symbol
if self.pauseOneMinute:
if symbolStr in self.protectedPositions and self.protectedPositions[symbolStr] == False:
self.MarketOrder(symbol,100)
self.PrepCall(symbol)
self.pauseOneMinute = False
else:
if len(symbol.ToString()) > 3 : #workaround for ensuging not already an option
#self.MarketOrder(self.contract, 1,asynchronous = False)
self.SetHoldings(self.conrtract, 0.1)
self.pauseOneMinute = True
except:
if self.VERBOSEMODE:self.Log('An unknown error occurred trying OnData' + str(sys.exc_info()[0]) )
def calcNumberOptionsContractsNeeded(self,symbol):
symbolStr = symbol.Value
current = float(self.Securities[symbolStr].Price)
quantity = float(self.Portfolio[symbolStr].Quantity)
optionContractCount = round(current * quantity / 100)
if self.VERBOSEMODE: self.Log("contract count for symbol {} current {} quantity {} is {} " . format(symbolStr,current, quantity, optionContractCount))
return optionContractCount
def PrepCall(self,symbol):
if len(symbol.ToString()) > 3 : #workaround for ensuging not already an option
return
symbolStr = symbol.Value
contracts = self.OptionChainProvider.GetOptionContractList(symbol, self.Time.date()) # must be of type Symbol
if len(contracts) == 0: return
min_expiry = 0
max_expiry = 14
filtered_contracts = [i for i in contracts if min_expiry <= (i.ID.Date.date() - self.Time.date()).days <= max_expiry]
call = [x for x in filtered_contracts if x.ID.OptionRight == 0]
if len(call) == 0: return
# sorted the contracts according to their expiration dates and choose the ATM options
self.contract = sorted(sorted(call, key = lambda x: abs(self.Securities[symbolStr].Price - x.ID.StrikePrice)),
key = lambda x: x.ID.Date, reverse=True)[0]
self.AddOptionContract(self.contract, Resolution.Minute)
optionContractCount = self.calcNumberOptionsContractsNeeded(symbol)
if optionContractCount == 0:
return
optionContractCount = 1
#option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option]
orderId = self.MarketOrder(self.contract, optionContractCount,asynchronous = False)
self.protectedPositions[symbolStr] = True
if self.VERBOSEMODE: self.Log( "bought 1 call contract of {} {} " . format(symbolStr,self.contract ))