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
set_margin_call_model
method of the portfolio
object.
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 your total margin used exceeds 10% of the total portfolio value, this model creates margin call orders.
It sorts the generated margin call orders in ascending order by their unrealized profit and then synchronously executes each order 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. | |
default_order_properties | IOrderProperties | The default order properties to be use in margin call orders. | |
margin_buffer | 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.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 get_margin_call_orders
and execute_margin_call
methods.
The 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 tuple where the first element is a list of SubmitOrderRequest
objects that represent the margin call orders and the second element is a boolean that represents whether or not to issue a margin call warning.
The execute_margin_call
method receives the list of SubmitOrderRequest
objects from the get_margin_call_orders
method, executes some of them, and returns a list of OrderTicket
objects.
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) -> tuple[List[SubmitOrderRequest], bool]: (margin_call_orders, issue_margin_call_warning) = super().get_margin_call_orders(issue_margin_call_warning) return (margin_call_orders, issue_margin_call_warning)
For a full example algorithm, see this backtest .
Monitor Margin Call Events
When the margin call model of your portfolio issues a margin call warning, we notify your algorithm through the on_margin_call_warning
event handler.
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 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.
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 |
---|---|---|---|
order_type | OrderType | The order type to be submitted | |
security_type | SecurityType | The security type of the asset | |
symbol | Symbol | The symbol to be traded | |
quantity | float | The number of units to order | |
stop_price | float | The stop price for stop orders | |
limit_price | float | The limit price for limit orders | |
trigger_price | float | The trigger price for limit if touched orders | |
time | datetime | The time this request was created | |
tag | str | A custom tag for this request | |
properties | IOrderProperties | The order properties for this request | None |