Reality Modeling
Margin Calls
Introduction
If the value of your portfolio falls below the maintenance margin, you receive a margin call. If you receive a margin call, you either need to add more capital to your brokerage account or the brokerage will liquidate some of your holdings to reduce your exposure and their risk. A margin call model monitors the margin levels of your portfolio, issues margin call warnings, and submits orders when margin calls occur.
Set Models
SetMarginCallModel
set_margin_call_model
method of the Portfolio
portfolio
object.
public override void Initialize() { // Set margin call model for the whole portfolio, better with reference to your broker information Portfolio.SetMarginCallModel(new DefaultMarginCallModel(Portfolio, DefaultOrderProperties)); }
def initialize(self) -> None: # Set margin call model for the whole portfolio, better with reference to your broker information self.portfolio.set_margin_call_model(DefaultMarginCallModel(self.portfolio, self.default_order_properties))
Default Behavior
The brokerage model of your algorithm automatically sets the margin call model for the portfolio. The default brokerage model is the DefaultBrokerageModel
, which sets the DefaultMarginCallModel
. The DefaultMarginCallModel
issues margin call warnings when the margin remaining in your portfolio is less than or equal to 5% of the total portfolio value. When a margin call occurs, this model sorts the generated margin call orders in ascending order by their unrealized profit and then executes each order synchronously until your portfolio is within the margin requirements.
The following table describes the arguments the model accepts:
Argument | Data Type | Description | Default Value |
---|---|---|---|
portfolio | SecurityPortfolioManager | The portfolio object to receive margin calls. | |
defaultOrderProperties default_order_properties | IOrderProperties | The default order properties to be use in margin call orders. | |
marginBuffer margin_buffer | decimal float | The percent margin buffer to use when checking whether the total margin used is above the total portfolio value to generate margin call orders. | 0.10m 0.10 (10%) |
To view the implementation of this model, see the LEAN GitHub repository.
Model Structure
Margin call models must extend the DefaultMarginCallModel
class. Extensions of the DefaultMarginCallModel
class can override the GetMarginCallOrders
get_margin_call_orders
and ExecuteMarginCall
execute_margin_call
methods.
The GetMarginCallOrders
get_margin_call_orders
method scans the portfolio and the updated data for a potential margin call situation that may get the equity below zero. The method must return a list of SubmitOrderRequest
objects that represent the margin call orders. To issue a margin call warning during this method, set the issueMarginCallWarning
argument of the method to true.
The ExecuteMarginCall
execute_margin_call
method receives the list of SubmitOrderRequest
objects from the GetMarginCallOrders
get_margin_call_orders
method, executes some of them, and returns a list of OrderTicket
objects.
public class CustomMarginCallModelExampleAlgorithm : QCAlgorithm { public override void Initialize() { // Set margin call model for the whole portfolio, better with reference to your broker information Portfolio.SetMarginCallModel(new MyMarginCallModel(Portfolio, DefaultOrderProperties)); } } // Define the custom margin call model public class MyMarginCallModel : DefaultMarginCallModel { public MyMarginCallModel( SecurityPortfolioManager portfolio, IOrderProperties defaultOrderProperties) : base(portfolio, defaultOrderProperties) { } public override List<OrderTicket> ExecuteMarginCall( IEnumerable<SubmitOrderRequest> generatedMarginCallOrders) { return base.ExecuteMarginCall(generatedMarginCallOrders); } public List<SubmitOrderRequest> GetMarginCallOrders(out bool issueMarginCallWarning) { return base.GetMarginCallOrders(out issueMarginCallWarning); } }
class CustomMarginCallModelExampleAlgorithm(QCAlgorithm): def initialize(self) -> None: # Set margin call model for the whole portfolio, better with reference to your broker information self.portfolio.set_margin_call_model(MyMarginCallModel(self.portfolio, self.default_order_properties)) # Define the custom margin call model class MyMarginCallModel(DefaultMarginCallModel): def __init__(self, portfolio: SecurityPortfolioManager, default_order_properties: IOrderProperties): super().__init__(portfolio, default_order_properties) def execute_margin_call(self, generatedMarginCallOrders: List[SubmitOrderRequest]) -> List[OrderTicket]: return super().execute_margin_call(generatedMarginCallOrders) def get_margin_call_orders(self, issue_margin_call_warning: bool) -> List[SubmitOrderRequest]: return super().get_margin_call_orders(issue_margin_call_warning)
For a full example algorithm, see this backtestthis backtest.
Monitor Margin Call Events
When the margin call model of your portfolio issues a margin call warning, we notify your algorithm through the OnMarginCallWarning
on_margin_call_warning
event handler.
public override void OnMarginCallWarning() { Debug("Warning: Close to margin call"); }
def on_margin_call_warning(self) -> None: self.debug(f"Warning: Close to margin call")
Before we send the orders that the margin call model produces, we notify your algorithm through the OnMarginCall
on_margin_call
event handler. This notification gives your algorithm a chance to liquidate some positions or modify the margin call orders. To modify the orders, adjust the list of SubmitOrderRequest
objects the event handler receives.
public override void OnMarginCall(List<SubmitOrderRequest> requests) { for (var i = 0; i < requests.Count; i++) { var order = requests[i]; // liquidate an extra 10% each time you get a margin call to give yourself more padding var newQuantity = (int)(order.Quantity * 1.1m); requests[i] = new SubmitOrderRequest(order.OrderType, order.SecurityType, order.Symbol, newQuantity, order.StopPrice, order.LimitPrice, 0, Time, "OnMarginCall"); } }
def on_margin_call(self, requests: List[SubmitOrderRequest]) -> List[SubmitOrderRequest]: for i, order in enumerate(requests): # liquidate an extra 10% each time you get a margin call to give yourself more padding new_quantity = int(order.quantity * 1.1) requests[i] = SubmitOrderRequest(order.order_type, order.security_type, order.symbol, new_quantity, order.stop_price, order.limit_price, 0, self.time, "OnMarginCall") return requests
Submit Order Request
If you receive a margin call or create a margin call model, you'll need to work with SubmitOrderRequest
objects. These objects have the following properties:
The following table describes the arguments of the SubmitOrderRequest
constructor:
Argument | Data Type | Description | Default Value |
---|---|---|---|
orderType order_type | OrderType | The order type to be submitted | |
securityType security_type | SecurityType | The security type of the asset | |
symbol | Symbol | The symbol to be traded | |
quantity | decimal float | The number of units to order | |
stopPrice stop_price | decimal float | The stop price for stop orders | |
limitPrice limit_price | decimal float | The limit price for limit orders | |
triggerPrice trigger_price | decimal float | The trigger price for limit if touched orders | |
time | DateTime datetime | The time this request was created | |
tag | string str | A custom tag for this request | |
properties | IOrderProperties | The order properties for this request | null None |