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

To set the margin call model, call the SetMarginCallModelset_margin_call_model method of the Portfolioportfolio 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:

ArgumentData TypeDescriptionDefault Value
portfolioSecurityPortfolioManagerThe portfolio object to receive margin calls.
defaultOrderPropertiesdefault_order_propertiesIOrderPropertiesThe default order properties to be use in margin call orders.
marginBuffermargin_bufferdecimalfloatThe percent margin buffer to use when checking whether the total margin used is above the total portfolio value to generate margin call orders.0.10m0.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 GetMarginCallOrdersget_margin_call_orders and ExecuteMarginCallexecute_margin_call methods.

The GetMarginCallOrdersget_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 ExecuteMarginCallexecute_margin_call method receives the list of SubmitOrderRequest objects from the GetMarginCallOrdersget_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.

Disable Margin Calls

To disable margin calls, set the margin call model to the NullMarginCallModel.

public override void Initialize()
{
	Portfolio.MarginCallModel = MarginCallModel.Null;
}
def initialize(self) -> None:
	self.portfolio.margin_call_model = MarginCallModel.NULL

Monitor Margin Call Events

When the margin call model of your portfolio issues a margin call warning, we notify your algorithm through the OnMarginCallWarningon_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 OnMarginCallon_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:

ArgumentData TypeDescriptionDefault Value
orderTypeorder_typeOrderTypeThe order type to be submitted
securityTypesecurity_typeSecurityTypeThe security type of the asset
symbolSymbolThe symbol to be traded
quantitydecimalfloatThe number of units to order
stopPricestop_pricedecimalfloatThe stop price for stop orders
limitPricelimit_pricedecimalfloatThe limit price for limit orders
triggerPricetrigger_pricedecimalfloatThe trigger price for limit if touched orders
timeDateTimedatetimeThe time this request was created
tagstringstrA custom tag for this request
propertiesIOrderPropertiesThe order properties for this requestnullNone

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: