import math
from System.Drawing import Color
class SJMACD(QCAlgorithm):
entryStopOrderTicket = {} #entry stop Market order
slStopOrderTicket = {} #stop loss stop Market Order
orderPlacedTime = {}
entryPrice = {}
stopLossPrice = {}
quantity = {}
def Initialize(self):
self.SetStartDate(2014, 6, 15) # Set Start Date
self.SetEndDate(2018, 6, 25) # Set End Date
self.SetCash(100000) # Set Strategy Cash
self.AddEquity("SPY", Resolution.Daily)
self.SetWarmup(timedelta(days=365))
self.secData = {}
##VARIABLES
self.smaPeriod = 20
self.macdFast = 5
self.macdSlow = 25
self.macdSignal = 5
self.waitFillDuration = 3 #number of days unfilled orders stay open for
#Order
self.entryMargin = 0.2/100 # 0.08% entry Margin on market order
self.stopLossMargin = 0.2/100 # 0.08% stoploss Margin on market order
self.tradeRisk = 0.01/100 # % Trade Risk
#Regimes
self.regLPMA = 100 #Regime Long Period Moving Average
self.regSPMA = 50 #Regime Short Period Moving Average
#Plotting
# MAIN CHART
plotter = Chart("Chart")
plotter.AddSeries(Series("Close", SeriesType.Line, 0))
plotter.AddSeries(Series("SMA", SeriesType.Line, 0))
plotter.AddSeries(Series("StopLoss", SeriesType.Scatter, 0))
self.AddChart(plotter)
# SIGNALS
signalplotter = Chart("Signals")
signalplotter.AddSeries(Series("Long", SeriesType.Scatter))
signalplotter.AddSeries(Series("Short", SeriesType.Scatter))
self.AddChart(signalplotter)
# Orders
signalplotter = Chart("Orders")
signalplotter.AddSeries(Series("Submitted", SeriesType.Scatter, '$', Color.Red, ScatterMarkerSymbol.Triangle))
signalplotter.AddSeries(Series("Filled", SeriesType.Scatter, '$', Color.Red, ScatterMarkerSymbol.Triangle))
signalplotter.AddSeries(Series("Liquidate Order", SeriesType.Scatter, '$', Color.Red, ScatterMarkerSymbol.Triangle))
self.AddChart(signalplotter)
# HISTOGRAM
secondplotter = Chart("Histogram")
secondplotter.AddSeries(Series("Histogram", SeriesType.Bar, 0))
self.AddChart(secondplotter)
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
'''
for sec, secdata in self.secData.items():
'''
Define Variables for the loop
'''
#Define
# self.Debug("{} Starting on data".format(self.Time))
self.goLong = False
self.goShort = False
self.allowLong = True
self.allowShort = True
closePrice = data.Bars[sec.Symbol].Close
openPrice = data.Bars[sec.Symbol].Open
highPrice = data.Bars[sec.Symbol].High
lowPrice = data.Bars[sec.Symbol].Low
sma = self.secData[sec].sma.Current.Value
histo = self.secData[sec].macd.Histogram.Current.Value
#Regime
regLPMA = self.secData[sec].regLPMA.Current.Value
regSPMA = self.secData[sec].regSPMA.Current.Value
#Update SecurityData
self.secData[sec].updatedata(self.Time, closePrice, regLPMA, regSPMA,sma)
# Waiting for SMA and MACD to be ready
if self.secData[sec].sma.IsReady and self.secData[sec].macd.IsReady and self.secData[sec].closeWindow.IsReady and self.secData[sec].regLPMAWindow.IsReady:
prevClose = self.secData[sec].closeWindow[1]
prevSma = self.secData[sec].smaWindow[1]
# Plot Graphs
self.Plot("Chart", "Close", closePrice)
self.Plot("Chart", "SMA", sma)
self.Plot("Histogram", "Histogram", histo)
'''
Check Signals
'''
# LONG #
self.Debug("{} prevclose is {} preSma is {} sma {} closePrice {} hist {}".format(self.Time, prevClose, prevSma, sma, closePrice, histo))
if prevClose < prevSma and closePrice > sma and histo > 0:
self.goLong = True
self.Plot("Signals", "Long", 1)
self.Debug("{} Long signal".format(self.Time))
# SHORT #
if prevClose > prevSma and closePrice < sma and histo < 0:
self.goShort = True
self.Plot("Signals", "Short", -1)
self.Debug("{} Short signal".format(self.Time))
# self.Debug("{} self.self.goLong is {} and self.goshort is {}".format(self.Time, self.goLong, goShort))
'''
If the security is invested.
'''
if self.Portfolio[sec.Symbol].Invested:
self.Debug("{} symbol {} in portfolio is invested qty {}".format(self.Time, sec.Symbol, self.Portfolio[sec.Symbol].Quantity))
# CHART THE STOP LOSS #
self.Plot("Chart", "StopLoss", self.slStopOrderTicket[sec.Symbol].Get(OrderField.StopPrice))
'''
If long portfolio switches to goshort signal
'''
if self.Portfolio[sec.Symbol].IsLong and self.goShort:
self.Debug("{} symbol {} isLong qty {} and goShort is {}".format(self.Time, sec.Symbol, self.Portfolio[sec.Symbol].Quantity, self.goShort))
# EXIT LONG POSITION
self.Liquidate(sec.Symbol)
self.Plot("Orders", "Liquidate Order", closePrice*1.05)
self.response = self.slStopOrderTicket[sec.Symbol].Cancel("Closed position and cancelled slStopOrderTicket")
if self.response.IsSuccess:
self.Debug("{} entryStopOrderTicket successfully canceled".format(self.Time))
# SUBMIT SHORT ORDER
if self.allowShort:
self.Debug("{} submitting short order for {}".format(self.Time, sec.Symbol))
#Short Variables
self.entryPrice[sec.Symbol] = lowPrice * (1 - self.entryMargin)
self.stopLossPrice[sec.Symbol] = highPrice * (1 + self.stopLossMargin)
self.quantity[sec.Symbol] = math.floor((self.Portfolio.TotalPortfolioValue * self.tradeRisk ) / (self.entryPrice[sec.Symbol] - self.stopLossPrice[sec.Symbol]))
#Short Order
self.entryStopOrderTicket[sec.Symbol] = self.StopMarketOrder(sec.Symbol, self.quantity[sec.Symbol], self.entryPrice[sec.Symbol])
self.Debug("{} short entryStopOrder placed {} @ {} sl {} qty {}".format(self.Time, sec.Symbol, self.entryPrice[sec.Symbol], self.stopLossPrice[sec.Symbol], self.quantity[sec.Symbol]))
self.orderPlacedTime[sec.Symbol] = self.Time
#PlotOrders
self.Plot("Orders", "Submitted", self.entryPrice[sec.Symbol]) #would like to plot this in the OnOrderEvent but can't manage to retrieve the OrderId to match it with the orderEvent.OrderId
'''
If short portfolio switches to self.goLong signal
'''
if self.Portfolio[sec.Symbol].IsShort and self.goLong:
self.Debug("{} symbol {} isShort qty {} and goLong is {}".format(self.Time, sec.Symbol, self.Portfolio[sec.Symbol].Quantity, self.goLong))
# EXIT SHORT POSITION
self.Liquidate(sec.Symbol)
self.Plot("Orders", "Liquidate Order", closePrice*1.05)
self.response = self.slStopOrderTicket[sec.Symbol].Cancel("Closed position and cancelled slStopOrderTicket")
if self.response.IsSuccess:
self.Debug("{} entryStopOrderTicket successfully canceled".format(self.Time))
# SUBMIT LONG ORDER
if self.allowLong:
self.Debug("{} submitting long order for {}".format(self.Time, sec.Symbol))
#Long Variables
self.entryPrice[sec.Symbol] = highPrice * (1 + self.entryMargin)
self.stopLossPrice[sec.Symbol] = lowPrice * (1 - self.stopLossMargin)
self.quantity[sec.Symbol] = math.floor((self.Portfolio.TotalPortfolioValue * self.tradeRisk ) / (self.entryPrice[sec.Symbol] - self.stopLossPrice[sec.Symbol]))
self.Debug("{} 2long order quantity calculation totalportfoliovalue {} tradeRisk {} entryprice {} stoplossprice {}".format(self.Time, self.Portfolio.TotalPortfolioValue, self.tradeRisk, self.entryPrice[sec.Symbol], self.stopLossPrice[sec.Symbol]))
#Long Order
self.entryStopOrderTicket[sec.Symbol] = self.StopMarketOrder(sec.Symbol, self.quantity[sec.Symbol], self.entryPrice[sec.Symbol])
self.Debug("{} long entryStopOrder placed {} @ {} sl {} qty {}".format(self.Time, sec.Symbol, self.entryPrice[sec.Symbol], self.stopLossPrice[sec.Symbol], self.quantity[sec.Symbol]))
self.orderPlacedTime[sec.Symbol] = self.Time
#PlotOrders
self.Plot("Orders", "Submitted", self.entryPrice[sec.Symbol]) #would like to plot this in the OnOrderEvent but can't manage to retrieve the OrderId to match it with the orderEvent.OrderId
'''
If the security is not invested
'''
if not self.Portfolio[sec.Symbol].Invested:
self.Debug("{} symbol {} in portfolio is not invested".format(self.Time, sec.Symbol))
self.Debug("{} golong is {} allow long is {}".format(self.Time, self.goLong, self.allowLong))
self.Debug("{} goShort is {} allow short is {}".format(self.Time, self.goShort, self.allowShort))
'''
Cancel unfilled Orders which are older than the waitFillDuration
'''
if sec.Symbol in self.entryStopOrderTicket and not self.entryStopOrderTicket[sec.Symbol].Status == OrderStatus.Filled and (self.Time - self.orderPlacedTime[sec.Symbol]).days >= self.waitFillDuration:
self.Debug("{} cancelling unfilled orders which are older than waitfill duration.".format(self.Time))
#Cancel Order
self.response = self.entryStopOrderTicket[sec.Symbol].Cancel("Canceled entryStopOrderTicket")
if self.response.IsSuccess:
self.Debug("{} entryStopOrderTicket successfully canceled".format(self.Time))
self.entryStopOrderTicket.pop(sec.Symbol) #removes it from the dictionary
if sec.Symbol not in self.entryStopOrderTicket and self.goLong and self.allowLong:
'''
Submit Long Orders if no long tickets exist
'''
self.Debug("{} submitting long order for {}".format(self.Time, sec.Symbol))
#Long Variables
self.entryPrice[sec.Symbol] = highPrice * (1 + self.entryMargin)
self.stopLossPrice[sec.Symbol] = lowPrice * (1 - self.stopLossMargin)
self.quantity[sec.Symbol] = math.floor((self.Portfolio.TotalPortfolioValue * self.tradeRisk ) / (self.entryPrice[sec.Symbol] - self.stopLossPrice[sec.Symbol]))
self.Debug("{} 1long order quantity calculation totalportfoliovalue {} tradeRisk {} entryprice {} stoplossprice {}".format(
self.Time, self.Portfolio.TotalPortfolioValue, self.tradeRisk, self.entryPrice[sec.Symbol], self.stopLossPrice[sec.Symbol]))
#Long Order
self.entryStopOrderTicket[sec.Symbol] = self.StopMarketOrder(sec.Symbol, self.quantity[sec.Symbol], self.entryPrice[sec.Symbol])
self.Debug("{} long entryStopOrder placed {} @ {} sl {} qty {}".format(self.Time, sec.Symbol, self.entryPrice[sec.Symbol], self.stopLossPrice[sec.Symbol], self.quantity[sec.Symbol]))
self.orderPlacedTime[sec.Symbol] = self.Time
#PlotOrders
# self.Plot("Orders", "Submitted", self.entryPrice[sec.Symbol]) #would like to plot this in the OnOrderEvent but can't manage to retrieve the OrderId to match it with the orderEvent.OrderId
if sec.Symbol not in self.entryStopOrderTicket and self.goShort and self.allowShort:
'''
Submit Short Orders if no long tickets exist
'''
self.Debug("{} submitting short order for {}".format(self.Time, sec.Symbol))
#Short Variables
self.entryPrice[sec.Symbol] = lowPrice * (1 - self.entryMargin)
self.stopLossPrice[sec.Symbol] = highPrice * (1 + self.stopLossMargin)
self.quantity[sec.Symbol] = math.floor((self.Portfolio.TotalPortfolioValue * self.tradeRisk ) / (self.entryPrice[sec.Symbol] - self.stopLossPrice[sec.Symbol]))
#Short Order
self.entryStopOrderTicket[sec.Symbol] = self.StopMarketOrder(sec.Symbol, self.quantity[sec.Symbol], self.entryPrice[sec.Symbol])
self.Debug("{} short entryStopOrder placed {} @ {} sl {} qty {}".format(self.Time, sec.Symbol, self.entryPrice[sec.Symbol], self.stopLossPrice[sec.Symbol], self.quantity[sec.Symbol]))
self.orderPlacedTime[sec.Symbol] = self.Time
#PlotOrders
self.Plot("Orders", "Submitted", self.entryPrice[sec.Symbol]) #would like to plot this in the OnOrderEvent but can't manage to retrieve the OrderId to match it with the orderEvent.OrderId
def OnSecuritiesChanged(self, changes):
for sec in changes.AddedSecurities:
self.secData[sec] = SecurityData(sec.Symbol, self, self.smaPeriod, self.macdFast, self.macdSlow, self.macdSignal, self.regLPMA, self.regSPMA)
def OnOrderEvent(self, orderEvent):
if orderEvent.Status == OrderStatus.Submitted:
self.Debug("{} OnOrderEvent has been submitted {} @ {}(fill price) qty {}".format(self.Time, orderEvent.Symbol, orderEvent.FillPrice, orderEvent.Quantity))
pass
if orderEvent.Status == OrderStatus.Filled:
self.Plot("Orders", "Filled", orderEvent.FillPrice)
self.Debug("{} order has been filled {} @ {} qty {} ".format(self.Time, orderEvent.Symbol, orderEvent.FillPrice, orderEvent.Quantity))
'''
Submit the stop loss order if we are holding a position
'''
if self.Portfolio[orderEvent.Symbol].Invested:
self.slStopOrderTicket[orderEvent.Symbol] = self.StopMarketOrder(orderEvent.Symbol, -orderEvent.Quantity, self.stopLossPrice[orderEvent.Symbol], "Stop Loss Order")
self.Debug("{} submitting the stoploss order for {} @ {} (stop loss) qty {}".format(self.Time, orderEvent.Symbol, self.stopLossPrice[orderEvent.Symbol], -orderEvent.Quantity, ))
class SecurityData():
def __init__(self, symbol, algorithm, smaPeriod, macdFast, macdSlow, macdSignal, regLPMA, regSPMA):
# Indicators
self.sma = SimpleMovingAverage(smaPeriod)
self.macd = algorithm.MACD(symbol, macdFast, macdSlow, macdSignal, MovingAverageType.Simple, Resolution.Daily)
self.closeWindow = RollingWindow[float](2)
self.smaWindow = RollingWindow[float](2)
# Regimes
self.regLPMA = SimpleMovingAverage(regLPMA)
self.regSPMA = SimpleMovingAverage(regSPMA)
self.regLPMAWindow = RollingWindow[float](2)
self.regSPMAWindow = RollingWindow[float](2)
def updatedata(self, time, closePrice, regLPMA, regSPMA, sma):
# Indicators
self.sma.Update(time, closePrice)
self.closeWindow.Add(closePrice)
self.smaWindow.Add(sma)
# Regimes
self.regLPMA.Update(time, closePrice)
self.regSPMA.Update(time, closePrice)
self.regLPMAWindow.Add(regLPMA)
self.regSPMAWindow.Add(regSPMA)