I have this MACD Crossover strategy I've adapted so that, after each entry position, a stop loss is created and the price of which is subsequently updated so it acts as a trailing stop loss. I am having difficulty getting it to initialize and would appreciate any guidance as to what I may be doing incorrectly (error below). Also, how can I set this so that it will only run once every hour? Every x number of minutes? Thanks in advance!
from AlgorithmImports import *
class MACDTrendAlgorithm(QCAlgorithm):
# establish project objects
stopMarketTicket = None
stopMarketOrderFillTime = datetime.min
stopPrice = 0
def Initialize(self):
# initialize our algorithm with the basics
self.SetStartDate(2018, 1, 1)
self.SetEndDate(2021, 10, 22)
self.SetCash(25000)
tqqq = self.AddEquity("TQQQ", Resolution.Daily)
tqqq.SetDataNormalizationMode(DataNormalizationMode.Raw)
# define our macd parameters
self.__macd = self.MACD("TQQQ", 6, 35, 6, MovingAverageType.Exponential, Resolution.Daily)
self.__previous = datetime.min
self.PlotIndicator("MACD", True, self.__macd, self.__macd.Signal)
self.PlotIndicator("TQQQ", self.__macd.Fast, self.__macd.Slow)
def OnData(self, data):
# wait for our macd to fully initialize
if not self.__macd.IsReady:
return
# define a small tolerance on our checks to avoid bouncing
tolerance = 0.0025
holdings = self.Portfolio["TQQQ"].Quantity
signalDeltaPercent = (self.__macd.Current.Value - self.__macd.Signal.Current.Value)/self.__macd.Fast.Current.Value
if holdings == 0:
if signalDeltaPercent > tolerance:
self.SetHoldings("TQQQ", 1.0)
self.stopMarketTicket = self.StopMarketOrder("TQQQ", -self.Portfolio["TQQQ"].Quantity, 0.9 * self.Portfolio["TQQQ"].Price)
if signalDeltaPercent < -tolerance:
self.SetHoldings("TQQQ", -1.0)
self.stopMarketTicket = self.StopMarketOrder("TQQQ", self.Portfolio["TQQQ"].Quantity, 0.9 * self.Portfolio["TQQQ"].Price)
elif holdings != 0:
if holdings < 0 and signalDeltaPercent > tolerance:
self.Liquidate("TQQQ")
self.SetHoldings("TQQQ", 1.0)
self.stopMarketTicket = self.StopMarketOrder("TQQQ", -self.Portfolio["TQQQ"].Quantity, 0.9 * self.Portfolio["TQQQ"].Price)
if holdings > 0 and signalDeltaPercent < -tolerance:
self.Liquidate("TQQQ")
self.SetHoldings("TQQQ", -1.0)
self.stopMarketTicket = self.StopMarketOrder("TQQQ", self.Portfolio["TQQQ"].Quantity, 0.9 * self.Portfolio["TQQQ"].Price)
if holdings >=0 and self.Securities["TQQQ"].Close > self.stopPrice:
self.stopPrice = self.Securities["TQQQ"].Close
updateFields = UpdateOrderFields()
updateFields.StopPrice = self.stopPrice * 0.95
self.stopMarketTicket.Update(updateFields)
elif holdings <=0 and self.Securities["TQQQ"].Close < self.stopPrice:
self.stopPrice = self.Securities["TQQQ"].Close
updateFields = UpdateOrderFields()
updateFields.StopPrice = self.stopPrice * 0.95
self.stopMarketTicket.Update(updateFields)
self.__previous = self.Time
Errors:
42 | 17:29:57:
Runtime Error: InvalidOperationException : Sequence contains no elements
at System.Linq.ThrowHelper.ThrowNoElementsException()
at System.Linq.Enumerable.Last[TSource](IEnumerable`1 source)
at QuantConnect.Orders.OrderTicket.Update(UpdateOrderFields fields) in /LeanCloud/CI.Builder/bin/Debug/src/QuantConnect/Lean/Common/Orders/OrderTicket.cs:line 279
at OnData
self.stopMarketTicket.Update(updateFields)
===
at Python.Runtime.PyObject.Invoke(PyTuple args in main.py: line 66 (Open Stacktrace)
43 | 17:30:07:
Algorithm Id:(15bdaac636f5d7f605a7df768009cb99) completed in 10.63 seconds at 0k data points per second. Processing total of 328 data points.
44 | 17:30:07:
Backtest Handled Error: Unable to submit order with id -10 that has zero quantity.
Vladimir
James Hawkins,
Here is the "MACD Signal Delta Percent simplified".
It runs once an hour and has the build-in
self.SetRiskManagement(MaximumDrawdownPercentPerSecurity(0.10)).
If this is what you are looking for, please accept it.
James Hawkins
Thanks, Vladimir 💪!!! A few follow up questions if you don't mind 😁:
Vladimir
James Hawkins,
Here is the same algorithm with requested options:
It runs every minute.
You can uncomment line 11
self.stock.SetDataNormalizationMode(DataNormalizationMode.Raw)
and see what happens on split history dates.
TQQQ Split History Table
Date Ratio
02/25/2011 2 for 1
05/11/2012 2 for 1
01/24/2014 2 for 1
01/12/2017 2 for 1
05/24/2018 3 for 1
01/21/2021 2 for 1
So I don't recommend it.
You can find details about
self.SetRiskManagement(MaximumDrawdownPercentPerSecurity(0.10))
on github.com
If you are satisfied with my answer, please accept it.
James Hawkins
Vladimir - thanks! Each time I go long/short, I am protected by the drawdown. However, if I am liquidated before the indicator reverses, I will re-enter/exit on drawdown multiple times before the indicator switches (and vice versa). I need to logically tell the algorithm that once the drawdown is hit, DO NOT enter a new position until the indicator flips. I.E. Go Long→drawdown hit→ wait for indicator reversal→ indicator reversal→ go short
James Hawkins
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!