I was wondering - if a risk management model liquidates a position (such as through a trailing stop or maximum drawdown) but an insight is still active after that liquidation, won't the algorithm framework just enter the position again on the next update?
Derek Melchin
Hi Fabien,
Yes, that is exactly what happens in the Algorithm Framework. See the attached backtest for a demonstration. To overcome this behavior, the alpha model needs to be made aware of the securities the risk management model liquidates. However, doing so violates the separation of concerns design principle.
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.
Fabien
So using risk managment models inherently requires breaking separation of concerns?
Jared Broad
Not necessarily, but if the PCM is too simple it may result in that behavior. The execution targets set in the execution model should be emptied once they're hit removing the "immediate rebuy" case.
Â
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.
Fabien
By execution targets are you referring to portfolio targets handled in the execution model? I'm not clear on how that would avoid the rebuy.
Derek Melchin
Hi Fabien,
Yes, Jared is referring to the targets handled in the execution model's Execute method. To avoid rebuying, we can utilize a custom risk management model which saves the symbols that it has liquidated in the past. This way, if the PCM requests a position in a symbol that the risk management model has previously liquidated, it won't set targets for the execution model to repurchase.
class MaximumDrawdownPercentPerSecurityCustom(RiskManagementModel): def __init__(self, maximumDrawdownPercent = 0.05): self.maximumDrawdownPercent = -abs(maximumDrawdownPercent) self.liquidated = set() def ManageRisk(self, algorithm, targets): targets = [] for kvp in algorithm.Securities: security = kvp.Value pnl = security.Holdings.UnrealizedProfitPercent if pnl < self.maximumDrawdownPercent or security.Symbol in self.liquidated: # liquidate targets.append(PortfolioTarget(security.Symbol, 0)) if algorithm.Securities[security.Symbol].Invested: self.liquidated.add(security.Symbol) algorithm.Log(f"Liquidating {security.Symbol}") return targets
See that attached backtest for the full example.
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.
Adam W
Hi Derek, do you have any suggestions on how to reset self.liquidated every time new insights are emitted?Â
Use case would be:
Example:
from QuantConnect import * from QuantConnect.Algorithm import * from QuantConnect.Algorithm.Framework import * from QuantConnect.Algorithm.Framework.Portfolio import PortfolioTarget from QuantConnect.Algorithm.Framework.Risk import RiskManagementModel from Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel class RiskTest(QCAlgorithm): def Initialize(self): self.SetStartDate(2019, 1, 1) self.SetEndDate(2019,2,1) self.SetCash(1000) self.AddEquity("SPY", Resolution.Minute) self.Securities['SPY'].FeeModel = ConstantFeeModel(0) self.liquidated = set() # Emit new insights every Friday self.Schedule.On(self.DateRules.Every(DayOfWeek.Friday), self.TimeRules.AfterMarketOpen('SPY', 0), self.PlaceOrder ) self.SetPortfolioConstruction(MyPortfolioModel()) self.AddRiskManagement(MyRiskModel()) self.SetExecution(ImmediateExecutionModel()) def OnData(self, data): pass def PlaceOrder(self): """ Emit insight to short SPY every Friday """ self.liquidated = set() # Reset liquidated symbols insight = Insight.Price('SPY', timedelta(days=30), InsightDirection.Down, None, None, None, 1) self.EmitInsights([insight]) class MyPortfolioModel(EqualWeightingPortfolioConstructionModel): def __init__(self): pass def CreateTargets(self, algorithm, insights): # Filter out insights for symbols that have been liquidated by risk model filtered_insights = [insight for insight in insights if insight.Symbol not in algorithm.liquidated] # Simple insight weighting PCM targets = [] for insight in filtered_insights: targ = PortfolioTarget(insight.Symbol, insight.Direction*insight.Weight) targets.append(targ) return targets class MyRiskModel(RiskManagementModel): def __init__(self, maxDrawdown=1e-5): self.maxDrawdown = maxDrawdown def ManageRisk(self, algorithm, targets): riskTargets = [] for _ in algorithm.Securities: symbol = _.Key security = _.Value symbolPnL = security.Holdings.UnrealizedProfitPercent # Liquidate if (symbolPnL < -self.maxDrawdown): riskTargets.append(PortfolioTarget(symbol, 0)) algorithm.Debug('Trailing stop loss hit.') algorithm.liquidated.add(security.Symbol) return riskTargets
However this does not work as algorithm refers to the QCAlgorithm object, not RiskTest.Â
Adam W
Got it to work with:
class MyRiskModel(RiskManagementModel): def __init__(self, maxDrawdown=1e-5): self.maxDrawdown = maxDrawdown self.liquidated = set() self.currentTargets = set() def ManageRisk(self, algorithm, targets): # Reset liquidated symbols on new targets if set(targets) != self.currentTargets: self.currentTargets = set(targets) self.liquidated = set() riskTargets = [] for _ in algorithm.Securities: symbol = _.Key security = _.Value symbolPnL = security.Holdings.UnrealizedProfitPercent # Liquidate if (symbolPnL < -self.maxDrawdown) or (symbol in self.liquidated): riskTargets.append(PortfolioTarget(symbol, 0)) algorithm.Debug('Trailing stop loss hit.') self.liquidated.add(symbol) return riskTargets
Â
Derek Melchin
Hi Adam,
We can see in the attached backtest logs that the `liquidated` set is cleared on each call to the ManageRisk method. This causes the algorithm to reinvest in securities immediately after the risk management model liquidates a position, even if no new insights have been emitted by the alpha model. The only workarounds to this problem violate the separation of concerns design principle. We could either move the risk management logic inside the alpha model or just save a reference to the risk management model inside the alpha model. Applying the latter means removing any symbols in the `liquidated` set before the alpha model emits an insight for it.
In this situation, I recommend using the classic algorithm design instead.
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.
Adam W
Interesting. I think the reason why 'liquidated' is being cleared with every call to the risk model in your example is that EqualWeightingPortfolioConstructionModel is using '.DetermineTargetPercent' which is a function of portfolio value. Thus as portfolio value changes, new targets are set and continuously rebalanced.
Here's a slight modification of your example with a custom portfolio model's '.CreateTargets'. We can see that the workaround I posted above works in this case: 'liquidated' is reset once at the start of the algorithm, hits the stop loss, then remains flat for the rest of the backtest.
Logs:
2020-02-20 00:00:00 : Different Targets: Quantity 1.0 2020-02-26 00:00:00 : Liquidating SPY
Â
Adam W
Here's an example where multiple insights are emitted during a backtest (in this case, every Friday).
In short, the workaround:
# Reset trackers on new targets if set(targets) != self.currentTargets: self.liquidatedSymbols = set() self.currentTargets = set(targets)
can be used to reset the Risk Model when new insights are emitted only if the portfolio model does not change the targets (i.e. via rebalancing) in between insight emissions.
Derek Melchin
Hi Adam,
Nice catch. Indeed, this procedure works if we utilize the custom portfolio construction model described above. Although, it should be pointed out that if a risk management model relies on the use of a specific portfolio construction model to operate, the two models are still coupled together to some degree.
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.
Adam W
Agreed. For anyone considering implementing that workaround, please keep that in mind.
Separation of Concerns is a great programming design principle for developing clean modular code that is nicely abstracted (and very reusable via a plug-and-play approach), and I highly recommend users try to adhere to it as much as possible.Â
However for financial algorithms, there does often tend to be cases where it is necessary to break this separation to some extent. For instance, an Alpha Model based on computing relative weights of asset holdings in a portfolio does not make sense with an equal weighting portfolio model. Or a trend-following strategy based on some indicator cross-overs might want to set stop losses/targets (risk management) based on values computed by the Alpha Model rather than a fixed threshold. However the abstraction into modules and keeping the coupling to a minimum is still good practice.
What are your thoughts on implementing some sort of optional "state storage" that allows for minimal communication between modules in the Framework? For instance, we define an object StateStorage() that holds certain variables.Â
Simple example:
- In Alpha Model, compute something and set the variable StateStorage.stopLossPrice = 1.3 based on confidence
- In Risk Model, we liquidate if price < StateStorage.stopLossPrice
- As new data comes in, Alpha Model updates the variable
Naturally this violates the separation of concerns to an extent, but each module is still concerned with a specific task and at least any breaking (if necessary) is more readily transparent.
Jared Broad
I hope we can make the framework fully support all use cases. It does require thinking slightly differently though. The alphas are factors, not responsible for anything related to trading. They are simply setting a prediction of the future.
In your simple example I'd recommend:
 - Alpha Model - prediction and confidence.
 - Risk Model - Confidence Weighted Maximum Drawdown Risk Management Model
 - Alpha Model - continues to emit insights based on new information. The risk model can choose to update its risk exposure or not.
I know its tempting to install a storage/communication system but I think/hope there's always a way to avoid it!Â
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.
Adam W
That makes sense. If i'm not mistaken however, the risk model receives the algorithm instance and an array of PortfolioTargets. Thus if someone wanted to set stop loss drawdowns based on real-time Alpha Model's computations (to let's say, a drawdown % of 1-confidence), how would a Confidence Weighted Drawdown Risk Model work?
"Communication" between Alpha Model/Portfolio Model is feasible and enough for most use cases based on the emitted Insight properties, but between Alpha Model/Risk is a bit unclear.
Derek Melchin
Hi Adam,
After confirming with Jared, the above is a typo. Instead, it should read
As explained above, the risk model does not receive insights and thus cannot make decisions based on confidence.
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.
Miguel Palanca
Hi Derek,
Was encountering something similar when trying to use the max drawdown per security risk management model. In the above I saw you mentioned referencing the risk management class in the alpha source. I wanted to ask if this was in regards to maybe importing the risk targets list into the alpha and using that to clear the insights if it is present in the list? Or would there be another way to clear out the insights?Â
Or would it be better to call the risk management module in the OnData class of the main algo and clear insights there? My main concern here is that because the liqudate command is in the RM class, the portfolio just reinvests.Â
Thanks in advance for your help!
Derek Melchin
Hi Miguel,
Yes, if the alpha model has a reference to the risk management model, we can choose to only emit insights in the alpha model for symbols that aren't in the risk management model's `liquidated` set. Although, if a framework algorithm violates the separation of concerns principle like this, we recommend resorting to the classic algorithm design instead.
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.
Fabien
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!