Live Trading
Brokerages
Introduction
Brokerages provide you with a connection to the market so you can fill trades. To avoid placing invalid orders for execution in live trading, LEAN validates your orders before sending them to the real brokerage. To view all of the integrated brokerages, see Brokerages.
Portfolio
In live trading, LEAN populates the Portfolio
portfolio
object with your account holdings and the Transactions
transactions
object with your open positions. If you don't manually subscribe to the assets in your account, LEAN subscribes to them with the lowest resolution of the subscriptions in your algorithm. For example, say you hold AAPL shares in your account and create the following subscriptions in your algorithm:
AddEquity("SPY", Resolution.Hour); AddEquity("MSFT", Resolution.Second);
self.add_equity("SPY", Resolution.HOUR) self.add_equity("MSFT", Resolution.SECOND)
In this case, LEAN subscribes to second-resolution data for AAPL since the lowest resolution in your algorithm is
Resolution.Second
Resolution.SECOND
.
Monitor the Brokerage Connection
We notify your algorithm when your brokerage connection disconnects and reconnects.
Lost Connections
If the brokerage connection breaks, we notify your algorithm through the OnBrokerageDisconnect
on_brokerage_disconnect
event handler.
public override void OnBrokerageDisconnect() { Debug("Brokerage connection lost"); }
def on_brokerage_disconnect(self) -> None: self.debug("Brokerage connection lost")
Restored Connections
When the brokerage connection restores after it disconnects, we notify your algorithm through the OnBrokerageReconnect
on_brokerage_reconnect
event handler.
public override void OnBrokerageReconnect() { Debug("Brokerage connection restored"); }
def on_brokerage_reconnect(self) -> None: self.debug("Brokerage connection restored")
When LEAN reconnects with your brokerage, it synchronizes the state of your live orders. For example, say the brokerage fills your limit order during the period of disconnection. When the connection restores, LEAN updates the state of your portfolio and orders to reflect the filled order, but you won't receive an order event.
Example Algorithm
For a full example algorithm that implements the OnBrokerageDisconnect
on_brokerage_disconnect
and OnBrokerageReconnect
on_brokerage_reconnect
methods, see the BrokerageActivityEventHandlingAlgorithmBrokerageActivityEventHandlingAlgorithm in the LEAN GitHub repository.
Monitor Brokerage Messages
When your brokerage sends you a message, we notify your algorithm through the OnBrokerageMessage
on_brokerage_message
event handler.
public override void OnBrokerageMessage(BrokerageMessageEvent messageEvent) { Debug(f"Brokerage message received: {messageEvent.Message}"); }
def on_brokerage_message(self, message_event: BrokerageMessageEvent) -> None: self.debug(f"Brokerage message received: {message_event.message}")
BrokerageMessageEvent
objects have the following attributes:
For a full example algorithm that implements the OnBrokerageMessage
on_brokerage_message
method, see the BrokerageActivityEventHandlingAlgorithmBrokerageActivityEventHandlingAlgorithm in the LEAN GitHub repository.
To handle brokerage messages outside of your algorithm class, create and set a BrokerageMessageHandler
. For a more information example, see the Reality Modeling > Brokerage Message Handler.
Brokerage Models
Brokerage features and limitations are realistically modelled with Brokerage Models. These reality models set the supported order and asset types for the brokerage. To learn how to set your specific brokerage, see Supported Models.
Examples
The following examples demonstrate common practices for handling live brokerage messages.
Example 1: Pre-Open Order Error
The following algorithm simulate extended market hour trading on Tradier Brokerage. We place a market-on-open order at 7:30am and expect the order cannot submit to the broker since it is not supported, resulting into an error.
public class OrderErrorsAlgorithm : QCAlgorithm { private Symbol _spy; public override void Initialize() { SetStartDate(2022, 1, 1); SetEndDate(2022, 1, 5); // Simulate Tradier brokerage, which does not support the market-on-open orders. SetBrokerageModel(BrokerageName.TradierBrokerage, AccountType.Cash); // Request extended market hour SPY data for trading. _spy = AddEquity("SPY", extendedMarketHours: true).Symbol; // Set a scheduled event to trade 2 hours pre-open to place the market-on-open-order. Schedule.On( DateRules.EveryDay(_spy), TimeRules.BeforeMarketOpen(_spy, 120), OpenPosition ); } private void OpenPosition() { // Buy on market open will result in an error since Tradier does not support it. MarketOnOpenOrder(_spy, 10); } // It will be triggered on live trading. public override void OnBrokerageMessage(BrokerageMessageEvent message) { if (message.Type == BrokerageMessageType.Error) { Log($"{Time}: {message.Type}: Message: {message.Message}"); } } }
class OrderErrorsAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2022, 1, 1) self.set_end_date(2022, 1, 5) # Simulate Tradier brokerage, which does not support the market-on-open orders. self.set_brokerage_model(BrokerageName.TRADIER_BROKERAGE, AccountType.CASH) # Request extended market hour SPY data for trading. self.spy = self.add_equity("SPY", extended_market_hours=True).symbol # Set a scheduled event to trade 2 hours pre-open to place the market-on-open-order. self.schedule.on( self.date_rules.every_day(self.spy), self.time_rules.before_market_open(self.spy, 120), self.open_position ) def open_position(self) -> None: # Buy on market open will result in an error since Tradier does not support it. self.market_on_open_order(self.spy, 10) # It will be triggered on live trading. def on_brokerage_message(self, message: BrokerageMessageEvent) -> None: if message.type == BrokerageMessageType.ERROR: self.log(f"{self.time}: {message.type}: Message: {message.message}")