Debugging some strange issues with an implementation of a custom Risk Model in the Framework - attached a simple example algorithm below.
Expected behavior:
- Every Monday, emit an insight to Long EURUSD with duration 1 week
- Portfolio Model computes quantity (100% of portfolio value) and returns array of targets
- Risk Model checks for drawdowns in portfolio value (set to a very small number in example), and liquidates positions
- Portfolio should be fully liquidated for the rest of the week until the next insight emission
- Logs confirm that the drawdown is being hit, and is returning PortfolioTarget(symbol, 0). However, the algorithm remains invested.
- Only a single order was placed at algorithm start despite Risk Model being triggered. Expecting place order, liquidate, do nothing for rest of week, then repeat every week.
2015-01-06 04:44:00 Risk Model triggered with realized -0.00% drawdown. Liquidated.
2015-01-06 04:45:00 Risk Model triggered with realized -0.00% drawdown. Liquidated.
2015-01-06 04:46:00 Risk Model triggered with realized -0.00% drawdown. Liquidated.
2015-01-06 04:47:00 Risk Model triggered with realized -0.00% drawdown. Liquidated.
This is related to thisĀ discussion, where Derek's answer implied that the Risk Model should be continuously returning PortfolioTarget(symbol, 0) once liquidated to achieve the expected behavior. Anyone see where the potential issue may be?
Derek Melchin
Hi Adam,
The issue here is the line
return [ PortfolioTarget(target.Symbol, 0) for target in targets]
`targets` are passed to the method when insights are emitted. Instead of loop through them, we should loop through the portfolio's holdings.
portfolio_targets = [] for kvp in algorithm.Securities: security = kvp.Value if security.Invested: portfolio_targets.append(PortfolioTarget(security.Symbol, 0)) return portfolio_targets
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.
Adam W
Thanks Derek! That makes sense - I think this should be added in the documentation.
That also seems to imply that, instead of:
# Reset trackers on new targets if set(targets) != set(self.currentTargets): self.currentTargets = set(targets) self.portfolioHigh = 0 self.isLiquidated = False
to reset the tracking variables with new insight emissions, it's better to do:
# New insights emitted if targets: self.portfolioHigh = 0 self.isLiquidated = False
As originally, the period immediately after an insight emission incorrectly triggers the if statement. Do you see any potential bugs/unexpected behavior with this?
On a side note, I ran this with the example algorithm above:
def ManageRisk(self, algorithm, targets): algorithm.Debug(f'Targs: {len(targets)}') return []
and for some reason ManageRisk is being called twice with every timestep:
2015-01-01 17:01:00 Targs: 0 2015-01-06 00:15:00 Targs: 1 2015-01-06 00:15:00 Targs: 0 2015-01-13 00:15:00 Targs: 1 2015-01-13 00:15:00 Targs: 0 2015-01-20 00:15:00 Targs: 1 2015-01-20 00:15:00 Targs: 0
Ā
Derek Melchin
Hi Adam,
Great point above. However, if we use
if targets: self.portfolioHigh = 0 self.isLiquidated = False
The portfolio's high water mark we use to calculate the drawdown will be reset when new insights are emitted. Thus, it's possible for the portfolio to experience a 100% drawdown if we just emit an insight at each time step.
Instead, we change this to
# Initialize self.isLiquidated = True # ManageRisk portfolioValue = algorithm.Portfolio.TotalPortfolioValue if targets and self.isLiquidated: self.portfolioHigh = portfolioValue self.isLiquidated = False
With this, the high water mark is only reset after the risk model has liquidated the portfolio and a new insight has been emitted. See the attached backtest for reference.
In regards to the ManageRisk being called twice at each time step, it only appears this way because the above uses Debug instead of Log. The rate-limiting of debug messages causes the misleading timestamps. In reality, ManageRisk is called once at each time step.
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
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!