Hi everyone,
I am new to this whole algorithm framework and was just wondering whether it's possible to set a stop loss and take profit orders for my strategy? I know it's possible to set those orders using the classical algorithm but was just wondering for the algorithm framework, do I implement this within the Execution Model, Risk Management Model, or the Alpha Model?
Any help would be greatly appreciated! Thanks everyone.
Adam W
Probably best to go in Risk Management in the Framework - see here for example on trailing stop losses. If they are simple fixed stop losses, you can just define some variable in your Alpha Model and do a if-then condition in the Risk Management model
Arthur Asenheimer
Hi Adam, it looks like the referenced TrailingStop example only works for Long positions (quantity > 0) as it only uses the highs of a security and don't distinguish between long and short positions.Â
@Ben Tay  If I'm right in my assumption, you should extend the referenced example so that it also works for short positions (if needed).Â
Arthur Asenheimer
edit: Ofir was so kind and has already provided a solution for that --> Long and Short Trailing Stop Loss
Ben Tay
Thank you, Arthur Asenheimer and Adam WÂ
Maybe could you advise me how do I set fixed stop losses based on values at the time that the order was placed?
For example, take a Moving Average Crossover strategy when the fast MA crosses above the slow MA...
- The Alpha Model would generate an Up insight
- Would like the stop loss for this order to be placed at the slow MA and be fixed there
How do I go about doing so?ÂAdam W
You can do something like this:
class MyAlgorithm(QCAlgorithm): def Initialize(self): # List of symbols self.symbols = ['SPY', 'AAPL',] # Dictionary of stop loss targets self.symbolStopLossTargets = {symbol: None for symbol in self.symbols} self.AddAlpha(MyAlphaModel()) self.AddRiskManagement(MyRiskModel) class MyAlphaModel(AlphaModel): def Update(self, algorithm, data): insights = [] for symbol in algorithm.symbols: fastEMA = # slowEMA = # # Long if fast > slow if fastEMA > slowEMA: insight = Insight.Price(symbol, timedelta(*args), InsightDirection.Up) algorithm.symbolStopLossTargets[symbol] = slowEMA # Update stop loss targets insights.append(insight) return insights class MyRiskModel(RiskManagementModel): def ManageRisk(self, algorithm, targets): targets = [] for kvp in algorithm.Securities: symbol = kvp.Key security = kvp.Value if security.Holdings.IsLong: # Check if closing price is below the stop loss close = security.Close if close <= algorithm.symbolStopLossTargets[symbol.Symbol.Value]: targets.append(PortfolioTarget(security.Symbol, 0) return targets
Â
Derek Melchin
Hi Ben,
This strategy is not possible to implement in the Algorithm Framework design without violating the separation of concerns principle. I recommend using the classic algorithm design for this.
Best,
Derek Melchin
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.
Stephen Hyer
#Imports from itertools import groupby from datetime import datetime, timedelta from pytz import utc from clr import AddReference AddReference("System") AddReference("QuantConnect.Common") AddReference("QuantConnect.Algorithm") AddReference("QuantConnect.Algorithm.Framework") from QuantConnect import Resolution, Extensions from QuantConnect.Algorithm.Framework.Portfolio import * from QuantConnect.Algorithm.Framework.Risk import * #Global variables Zero = int(0) class TrailingStop(RiskManagementModel): def __init__(self): ''' Initialization variables ''' # Long Position Variables self.LongTrail = {} self.LongTrailingDrawdown = float(0.125) # Short Position Variables self.ShortTrail = {} self.ShortTrailingDrawdown = float(0.125) def ManageRisk(self, algorithm, targets): ''' Main risk management handler. Passes algorithm and targets ''' RiskAdjustedTargets = [] for asset in self.LongTrail: if not algorithm.Portfolio[asset].Invested: self.LongTrail[asset] = [algorithm.Securities[asset].Price, 0] for asset in self.ShortTrail: if not algorithm.Portfolio[asset].Invested: self.ShortTrail[asset] = [algorithm.Securities[asset].Price, 0] invested = [x.Key for x in algorithm.Portfolio if x.Value.Invested] if invested: for asset in invested: if algorithm.Portfolio[asset].IsLong: if asset not in self.LongTrail or self.LongTrail[asset][1] == 0: self.LongTrail[asset] = [algorithm.Portfolio[asset].Price, algorithm.Portfolio[asset].Quantity] elif algorithm.Portfolio[asset].IsShort: if asset not in self.ShortTrail or self.ShortTrail[asset][1] == 0: self.ShortTrail[asset] = [algorithm.Portfolio[asset].Price, algorithm.Portfolio[asset].Quantity] self.TrailingStop(algorithm, asset, RiskAdjustedTargets) return RiskAdjustedTargets def TrailingStop(self, algorithm, asset, RiskAdjustedTargets): ''' Manages trailing stop for both long and short assets respectively ''' if algorithm.Portfolio[asset].IsLong: if algorithm.Portfolio[asset].Price > self.LongTrail[asset][0]: self.LongTrail[asset][0] = algorithm.Portfolio[asset].Price elif algorithm.Portfolio[asset].Price / self.LongTrail[asset][0] < (1-self.LongTrailingDrawdown): RiskAdjustedTargets.append(PortfolioTarget(asset, 0)) algorithm.Debug(f'Long trailing Stop Triggered for {asset}. Current Price: {algorithm.Portfolio[asset].Price} | Highest Price: {self.LongTrail[asset][0]} | Loss: {algorithm.Portfolio[asset].Price / self.LongTrail[asset][0]} | Date: {algorithm.Time}') self.LongTrail.pop(asset) if algorithm.Portfolio[asset].IsShort: if algorithm.Portfolio[asset].Price < self.ShortTrail[asset][0]: self.ShortTrail[asset][0] = algorithm.Portfolio[asset].Price elif algorithm.Portfolio[asset].Price / self.ShortTrail[asset][0] > 1 / (1-self.ShortTrailingDrawdown): RiskAdjustedTargets.append(PortfolioTarget(asset, 0)) algorithm.Debug(f'Short trailing Stop Triggered for {asset}. Current Price: {algorithm.Portfolio[asset].Price} | Lowest Price: {self.ShortTrail[asset][0]} | Loss: {algorithm.Portfolio[asset].Price / self.ShortTrail[asset][0]} | Date: {algorithm.Time}') self.ShortTrail.pop(asset) return RiskAdjustedTargets
This works for me. Â
Derek Melchin
Hi Stephen,
The technique above works when the insights emitted from the alpha model have a long duration. However, if we emit insights daily from the alpha model, this risk management model will continue to reinvest after each time the trailing stop is hit.
See the attached backtest for reference.
Best,
Derek Melchin
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.
Stephen Hyer
Derek Melchin A 1% stop loss is really tight, especially for Apple and Tesla in 2021. Also, you seem to be shorting the market every day which is typically destructive to any portfolio. On average both Apple and Tesla have intraday moves greater than 1% in either direction from their open price during this period. Changing the insight direction to up and the maximum drawdown to 3% yields a much different result with many fewer stop loss triggers. If we look at the most recent debug for SPY:
Long trailing Stop Triggered for SPY. Current Price: 405.41 | Highest Price: 422.12 | Loss: 0.9604141002558515 | Date: 2021-05-13 00:00:00
We see that 422.12 is the close price as of 5/8/2021. If the universe resolution was in hours or minutes this value would likely be higher since SPY reached a peak of 422.74 on 5/10/2021 before the selloff started. In any case, it seems the high was correctly captured for this data resolution. Similarly, the stop price reflects the close of 5/12/2021 which is below the 3% threshold, as expected. I think the code is working as intended. The only change I might make is to the short drawdown being (1+self.ShortTrailingDrawdown) instead of 1 / (1-self.ShortTrailingDrawdown). Â
Â
Assets = [
SPY Average intraday gain: 0.518% | Average intraday loss: -0.56%qb.AddEquity("SPY"),
qb.AddEquity("AAPL"),
qb.AddEquity("TSLA")]
SymbolList = []
for x in Assets:
SymbolList.append(x.Symbol)
history = qb.History(SymbolList, timedelta(days=174), Resolution.Daily)
History = history.loc['TSLA']
Gain_From_Open = History['high']/History['open']-1
Loss_From_Open = History['low']/History['open']-1
for x in SymbolList:
History = history.loc[x]
Gain_From_Open = History['high']/History['open']-1
Loss_From_Open = History['low']/History['open']-1
Mean_Gain_From_Open = round(Gain_From_Open.mean()*100,3)
Mean_Loss_From_Open = round(Loss_From_Open.mean()*100,3)
print(x, f'Average intraday gain: {Mean_Gain_From_Open}% | Average intraday loss: {Mean_Loss_From_Open}%')
AAPL Average intraday gain: 1.147% | Average intraday loss: -1.307%
TSLA Average intraday gain: 2.292% | Average intraday loss: -2.705%
 Â
Â
Derek Melchin
Hi Stephen,
The algorithm above shorts the market to demonstrate that if we emit insights on a daily basis, the algorithm will continue to open new positions after the risk management model liquidated the position.
Best,
Derek Melchin
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.
Stephen Hyer
Hey Derek,Â
By design the EWPCM will create a new target for each new active insight. If the goal is to remove the asset from the universe if it stops out I imagine that can be done but the current code simply tracks open positions and applies a trailing stop loss. If the drawdown is exceeded, the risk management model produces a liquidation target for the asset. If a new insight is generated for that asset at a later time, then the EWPCM will generate a new target and the immediate execution model a new order respectively. I'm still unsure why the posted code doesn't work as intended. Â
Derek Melchin
Hi Stephen,
That's correct. The issue is that in some cases, we don't know how long the insight should last for, so we emit insights during every timestep. See the Ichimoku Clouds in the Energy Sector tutorial for reference. In cases like these, if we are using the risk management model above, the algorithm will open a new position immediately after the risk management model liquidates the position. As a result, if we want to stop the alpha model from emitting insights for securities that the risk management model has liquidated, we oftentimes need to break the separation of concerns principle.
On the other hand, if the algorithm is designed to not emit insights at every timestep and instead emits 1 insight per trade, then the risk management model above works as intended.
Best,
Derek Melchin
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.
Mislav Sagovac
Derek Melchin ,
If emmited signals tahe short time (say Expiry.Day or even few minutes) and if we use market roders on very liquid istruments (to avoid transaction costs), and if we use wide SL an PT ranges, can we use trailing stop risk model you demonstred above ?
Ot is it better to just use flat insights inside Alpha model ?
Varad Kabade
Hi Mislav,
We recommend testing both the approaches in your algorithm and running with the one we are comfortable with
Best,
Varad Kabade
Ben Tay
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!