Reality Modeling
Brokerage Message Handler
Introduction
When your brokerage sends a message, you receive this information in the algorithm and can take any actions. When you place an order through your brokerage platform instead of placing it through LEAN, you can decide whether the transaction handler should process the order. By default, the transaction handler only process orders that you place through LEAN. Custom brokerage message handlers enable you to instruct the transaction handler to process orders that you create directly through your brokerage's platform.
Set Models
To set a brokerage message handler, in the Initialize
initialize
method, call the SetBrokerageMessageHandler
set_brokerage_message_handler
method.
public override void Initialize() { // Set a custom brokerage message handler for the algorithm in Initialize method // It handles different type of returned message from the broker, helping you filter or abstract for the ones you care about SetBrokerageMessageHandler(new MyBrokerageMessageHandler(this)); }
def initialize(self) -> None: # Set a custom brokerage message handler for the algorithm in Initialize method # It handles different type of returned message from the broker, helping you filter or abstract for the ones you care about self.set_brokerage_message_handler(MyBrokerageMessageHandler(self))
Default Behavior
The default brokerage message handler is the DefaultBrokerageMessageHandler
. The following table describes how the DefaultBrokerageMessageHandler
processes brokerage messages:
Brokerage Message Type | Action |
---|---|
BrokerageMessageType.InformationINFORMATION | Sends a debug message for the algorithm. |
BrokerageMessageType.WarningWARNING | Sends an error message for the algorithm. |
BrokerageMessageType.ErrorERROR | Sets the algorithm runtime error and stops it. |
BrokerageMessageType.DisconnectDISCONNECT | Stops the algorithm after 15 minutes if the market is open. Otherwise, it stops five minutes after market open. |
BrokerageMessageType.ReconnectRECONNECT | Cancels the disconnection process. |
The default brokerage message handler rejects orders you create through the brokerage. An example of this is when you place an order using the brokerage website or a third-party software.
The following table describes the arguments the model accepts:
Argument | Data Type | Description | Default Value |
---|---|---|---|
algorithm algorithm | IAlgorithm | The running algorithm. | |
initialDelay initial_delay | TimeSpan? timedelta/NoneType | The amount of time LEAN will wait after a brokerage disconnection message for a reconnection message. If the reconnection message doesn't arrive before the time limit, LEAN stops running. If you don't provide a value, it uses TimeSpan.FromMinutes(15) timedelta(minutes=15) . | null None |
openThreshold open_threshold | TimeSpan? timedelta/NoneType | Defines how long before market open to re-check for brokerage reconnect message. If you don't provide a value, it uses TimeSpan.FromMinutes(5) timedelta(minutes=5) . | null None |
To view the implementation of this model, see the LEAN GitHub repository.
Model Structure
Brokerage message handlers extend the DefaultBrokerageMessageHandler
class.
Extensions of the DefaultBrokerageMessageHandler
class should define the HandleMessage
handle_message
and HandleOrder
handle_order
methods.
The HandleMessage
handle_message
method processes the brokerage message event. It triggers any actions in the algorithm or notifications system required.
The HandleOrder
handle_order
method defines whether the transaction handler should process a new order you placed directly through the brokerage's website or third-party software.
public class CustomBrokerageMessageHandlerExampleAlgorithm : QCAlgorithm { public override void Initialize() { // In the Initialize method, set the brokerage message handler SetBrokerageMessageHandler(new MyBrokerageMessageHandler(this)); } } // Define the custom brokerage message handler public class MyBrokerageMessageHandler : DefaultBrokerageMessageHandler { private readonly IAlgorithm _algorithm; public MyBrokerageMessageHandler(IAlgorithm algorithm) : base(algorithm) { _algorithm = algorithm; } public void HandleMessage(BrokerageMessageEvent message) { _algorithm.Debug($"{_algorithm.Time.ToStringInvariant("o")} Event: {message.Message}"); } public bool HandleOrder(NewBrokerageOrderNotificationEventArgs eventArgs) { return false; } }
class CustomBrokerageMessageHandlerExampleAlgorithm(QCAlgorithm): def initialize(self) -> None: # In the Initialize method, set the brokerage message handler self.set_brokerage_message_handler(MyBrokerageMessageHandler(self)) # Define the custom brokerage message handler class MyBrokerageMessageHandler(DefaultBrokerageMessageHandler): def __init__(self, algorithm): self._algorithm = algorithm def handle_message(self, message: BrokerageMessageEvent) -> None: self._algorithm.debug(f"{self._algorithm.time} Event: {message.message}") def handle_order(self, event_args: NewBrokerageOrderNotificationEventArgs) -> bool: return False
The BrokerageMessageEvent
class has the following properties:
The NewBrokerageOrderNotificationEventArgs
class has the following properties:
Brokerage Support
Most QuantConnect brokerage integrations don't support brokerage-side orders.
If you create an order directly through your brokerage instead of through LEAN, your algorithm won't process the order because the return value of the HandleOrder
handle_order
method is ignored.
Terminal Link is the exception that can support brokerage-side orders.
This algorithmThis algorithm demonstrates how to implement a custom brokerage handler that accepts orders with a target TerminalLinkOrderProperties.CustomNotes1
TerminalLinkOrderProperties.custom_notes_1
value.
Examples
The following examples demonstrate common practices for implementing a custom brokerage message handler.
Example 1: Notification
The following algorithm buys and holds SPY. It implemented a custom brokerage message handler to send notifications to users through email and SMS in cases of disconnection, reconnections, and outside trades.
public class CustomBrokerageMessageHandlerAlgorithm : QCAlgorithm { private Symbol _spy; public override void Initialize() { // To simulate the connection to IB brokerage. SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin); // Set the brokerage message handler to our custom model. SetBrokerageMessageHandler(new CustomBrokerageMessageHandler(this)); // Request SPY data for trading. _spy = AddEquity("SPY").Symbol; } public override void OnData(Slice slice) { // Buy and hold SPY as a strategy. if (!Portfolio.Invested) { SetHoldings(_spy, 1m); } } } // Define the custom brokerage message handler. public class CustomBrokerageMessageHandler : DefaultBrokerageMessageHandler { private readonly IAlgorithm _algorithm; public CustomBrokerageMessageHandler(IAlgorithm algorithm) : base(algorithm) { _algorithm = algorithm; } public void HandleMessage(BrokerageMessageEvent message) { // Notify the user by SMS on disconnection of the algorithm instance from the brokerage. if (message.Type == BrokerageMessageType.Disconnect) { _algorithm.Notify.Sms( phoneNumber: "<YOUR_PHONE_NUMBER>", message: "Your QC Algorithm instance 'CustomBrokerageMessageHandlerAlgorithm' was disconnected from the IB brokerage." ); } // Notify the user by SMS on reconnection of the algorithm instance to the brokerage after disconnection. else if (message.Type == BrokerageMessageType.Reconnect) { _algorithm.Notify.Sms( phoneNumber: "<YOUR_PHONE_NUMBER>", message: "Your QC Algorithm instance 'CustomBrokerageMessageHandlerAlgorithm' was reconnected to the IB brokerage." ); } } public bool HandleOrder(NewBrokerageOrderNotificationEventArgs eventArgs) { // Notify the user by email on receiving an order from outside the algorithm. _algorithm.Notify.Email( address: "<YOUR_EMAIL_ADDRESS@example.com>", subject: "Outside Order", message: "Your QC Algorithm instance 'CustomBrokerageMessageHandlerAlgorithm' detected an outside order from the IB brokerage; it has been processed to the algorithm." ); // Process a new order placed through the brokerage's website or third-party software to handle it in the algorithm instance. return true; } }
class CustomBrokerageMessageHandlerAlgorithm(QCAlgorithm): def initialize(self) -> None: # To simulate the connection to IB brokerage. self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.MARGIN) # Set the brokerage message handler to our custom model. self.set_brokerage_message_handler(CustomBrokerageMessageHandler(self)) # Request SPY data for trading. self.spy = self.add_equity("SPY").symbol def on_data(self, slice: Slice) -> None: # Buy and hold SPY as a strategy. if not self.portfolio.invested: self.set_holdings(self.spy, 1) class CustomBrokerageMessageHandler(DefaultBrokerageMessageHandler): def __init__(self, algorithm: QCAlgorithm) -> None: self._algorithm = algorithm def handle_message(self, message: BrokerageMessageEvent) -> None: # Notify the user by SMS of the disconnection of the algorithm instance from the brokerage. if message.type == BrokerageMessageType.DISCONNECT: self._algorithm.notify.sms( phone_number="<YOUR_PHONE_NUMBER>", message="Your QC Algorithm instance 'CustomBrokerageMessageHandlerAlgorithm' was disconnected from the IB brokerage." ) # Notify the user by SMS on reconnection of the algorithm instance to the brokerage after disconnection. elif message.type == BrokerageMessageType.RECONNECT: self._algorithm.notify.sms( phone_number="<YOUR_PHONE_NUMBER>", message="Your QC Algorithm instance 'CustomBrokerageMessageHandlerAlgorithm' was reconnected to the IB brokerage." ) def handle_order(self, event_args: NewBrokerageOrderNotificationEventArgs) -> bool: # Notify the user by email on receiving an order from outside the algorithm. self._algorithm.notify.email( address="<YOUR_EMAIL_ADDRESS@example.com>", subject="Outside Order", message="Your QC Algorithm instance 'CustomBrokerageMessageHandlerAlgorithm' detected an outside order from the IB brokerage; it has been processed to the algorithm." ) # Process a new order placed through the brokerage's website or third-party software to handle it in the algorithm instance. return True
Other Examples
For more examples, see the following algorithms: