I keep getting margin called in my algorithm because of insufficient buying power. I've printed the TotalMarginUsed, MarginRemaining, Cash, and TotalPortfolioValue of self.Portfolio prior:
2019-09-04 12:00:00 2019-09-04 12:00:00 TMU:163635.91, MR:1394.14, C:492301.87, TPV:165030.05
2019-09-04 12:00:00 Order Error: id: 92, Insufficient buying power to complete order (Value:-15913.48), Reason: Id: 92, Initial Margin: -7969.72, Free Margin: 1394.14
2019-09-05 00:00:00 Order Error: id: 3, Insufficient buying power to complete order (Value:-4050), Reason: Id: 3, Initial Margin: -325, Free Margin: 0.
2019-09-05 00:00:00 Order Error: id: 44, Insufficient buying power to complete order (Value:-943.36), Reason: Id: 44, Initial Margin: -219.24, Free Margin: 0.
2019-09-05 00:00:00 Order Error: id: 58, Insufficient buying power to complete order (Value:-20020), Reason: Id: 58, Initial Margin: -274, Free Margin: 0.
2019-09-05 00:00:00 Order Error: id: 64, Insufficient buying power to complete order (Value:-13833.5), Reason: Id: 64, Initial Margin: -384.25, Free Margin: 0.
2019-09-05 00:00:00 09/05/2019 00:00:00 - Executed MarginCallOrder: <XYZ security> - Quantity: <Q> @ <P>
What I'm pretty sure is happening is, since I am doing Universe selection Resolution.Daily, at midnight my Short Sell orders get converted to Market On Open orders. But if I have a bunch of orders queued, I quickly eat up my margin as these orders get executed. Some fail because of insufficient margin. Regardless, I end up with only a small amount of margin left. Any price movement against me results in a margin call. Also, note that while in the example I had $1394.14 of margin left, I've also been called when I have $80000 in margin because of all the orders quicky eat up my buying power when they go through on open.
I've tried to do a couple things to fix this issue but none of these have worked.
1) I've tried to determine the impact on margin my orders will have. I don't execute the trade if it forces the margin remaining below 20% of TotalPortfolioValue. But this only checks if a single order disrupts the buying power and fails when multiple orders are queued.
cost = abs(q) * price
r = (self.Portfolio.MarginRemaining - cost)/self.Portfolio.TotalPortfolioValue
if r > 0.2:
self.LimitOrder(symbol, -q, price) # -q because shorting
2) I've tried to use the
OnMarginCallWarning()
method to handle low margin, but this method fires too late after I've already recieved my insufficient buying power warnings.
3) I tried handling this in the OnOrderEvent() method but this also doesn't work.
First, I tried to cancel all my outstanding orders with self.Transactions.CancelOpenOrders(), but this doesn't stop my orders from executing on market open. Then, I tried liquidating my entire portfolio:
def OnOrderEvent(self, orderEvent):
if orderEvent.Status == OrderStatus.Filled:
order = self.Transactions.GetOrderById(orderEvent.OrderId)
#self.Debug("{} Filled {} of {} at {}".format(self.Time, order.Quantity, order.Symbol, order.Price))
# invalid due to buying power issues most likely
if orderEvent.Status == OrderStatus.Invalid:
order = self.Transactions.GetOrderById(orderEvent.OrderId)
self.Liquidate()
self.Debug("{} Order Error: {} {} {}".format(self.Time, order.Symbol, order.Status, orderEvent.OrderId))
But this results in an unknown error:
[ERROR] FATAL UNHANDLED EXCEPTION: at (wrapper managed-to-native) Python.Runtime.Runtime.PyObject_Call (intptr, intptr, intptr) [0x00002] in :0, at Python.Runtime.PyObject.Invoke (Python.Runtime.PyTuple, Python.Runtime.PyDict) [0x00000] in :0, at Python.Runtime.PyObject.TryInvoke (System.Dynamic.InvokeBinder, object[],object&) [0x0001d] in :0, at (wrapper dynamic-method) object.CallSite.Target (System.Runtime.CompilerServices.Closure, System.Runtime.CompilerServices.CallSite, object, QuantConnect.Orders.OrderEvent) [0x00056] in :0, at QuantConnect.AlgorithmFactory.Python.Wrappers.AlgorithmPythonWrapper.OnOrderEvent (QuantConnect.Orders.OrderEvent) [0x00049] in <5dc47b3335e14c7781b5cd695e57e0f1>:0, at QuantConnect.Lean.Engine.TransactionHandlers.BrokerageTransactionHandler.HandleOrderEvent (QuantConnect.Orders.OrderEvent) [0x003ba] in <5954f57d4b2f4fb2a5
So now I'm completely unsure of how to handle my margin calls.
AK M
Update: I've decided to use OnMarginCallWarning() in order to handle low buying power. This isn't ideal because sometimes, it is too late. For this reason, I would like to have this event fire earlier.
Right now, it only fires when Portfolio.MarginRemaining is under 5% of the Portfolio.TotalPortfolioValue. Is there a way to change this method or schedule an event that fires at 20% or 30%?
Rahul Chowdhury
Hey AK M,
The errors we're getting here
2019-09-04 12:00:00 Order Error: id: 92, Insufficient buying power to complete order (Value:-15913.48), Reason: Id: 92, Initial Margin: -7969.72, Free Margin: 1394.14
aren't margin calls. These errors are produced by a lack of buying power to complete an order. When we place an order a market on open order, the order cost is calculated using the market close, however when the market opens the price may slip and the cost of the order may change, which results in the insufficient margin error.
One way to resolve this is to use higher resolution data and use scheduled events to trade. For example, we can use hourly resolution data and trade once per day right before market close or after market open using a scheduled event.
We could also use
margin = self.Portfoloo.GetMarginRemaining(symbol, OrderDirection.Buy)
to calculate the margin we have available for a symbol. Although if we are attempting to send orders for more than one security, the margin may not be there when the order attempts to fill.
Best RahulFor more help, please post a snippet of the code or a back test. It will help us figure out why the issue is arising.
AK M
Thanks for the clarification. I understand those warnings weren't margin calls. My issue was that I couldn't find a way to handle those buying power errors in time as they occured too close to the actual margin call.
Like you said, the best approach (and only approach I'm aware of) is to increase the resolution of the data. This is ultimately what I ended up doing. I increased my resolution from daily to hourly. This allows me to check my buying power in OnData() and rebalance my portfolio as necessary.
AK M
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!