Live Trading
Trading and Orders
Introduction
LEAN has dozens of methods to create, update, and cancel orders. You can place orders automatically with helper methods or manually through methods on the algorithm API. You can fetch, update, and cancel manual orders with order tickets. As the state of your orders change, LEAN creates events that notify your algorithm.
In backtesting, LEAN simulates order fills with historical data, but you can create your own fill, fee, slippage, and margin models via plugin points. You control how optimistic or pessimistic order fills are with transaction model classes. For more information about these types of models, see Reality Modeling.
In live trading, orders fill asynchronously. We send your order to the API of your brokerage and wait for their response to update the state of your algorithm and portfolio. The timing of live order fills doesn't depend on the resolution of your security subscriptions. When your order fills, the fill price and fee is set by your brokerage. You can add event handlers to your algorithm to monitor the brokerage connection and brokerage messages.
In backtesting, the trade fill timing depends on the resolution of your security subscription. For example, if you subscribe to a security with minute resolution data, the algorithm only receives data in one-minute time slices. As a result, the fill model can only evaluate if the order should fill on a minute-by-minute frequency.
Order Life Cycle
When you call one of the order methods to place an order, LEAN performs pre-order checks to ensure that the order meets some requirements and uses the last known price to check you have enough capital. To see the requirements of each order, see the Requirements section of the documentation for the order types and the Orders section of your brokerage model. If you can place the order, LEAN creates Order
and OrderTicket objects. The order ticket is sent to your brokerage. As the brokerage processes your order, it returns another order ticket and it's compared against the order to see if the order is satisfied. Orders are asynchronous in live trading, so if you want to change an order, you must request it with the order ticket. Order changes are not guaranteed since your order may fill by the time brokerage receives the request.
When you create an order ticket, LEAN validates it to avoid sending orders that will be rejected by your brokerage. If the order is invalid, it's status is set to OrderStatus.Invalid
. Otherwise, LEAN sets the order status to OrderStatus.New
, sends the order to your brokerage, and waits for the brokerage message. If your brokerage accepts the order, the order status becomes OrderStatus.Submitted
. Otherwise, it becomes OrderStatus.Canceled
.
You can update orders until they fill or the brokerage prevents modifications. If you place an order update request, LEAN validates it to avoid sending orders that will be rejected by you brokerage. If the order update is valid, LEAN sends the update request and waits for the brokerage message. If your brokerage accepts the update, the order status becomes OrderStatus.UpdateSubmitted
. Otherwise, it becomes OrderStatus.Canceled
.
The brokerage notifies LEAN when you order fills (OrderStatus.Filled
OrderStatus.FILLED
), partially fills (OrderStatus.PartiallyFilled
) or is canceled (OrderStatus.Canceled
). The brokerage can cancel your order before it completely fills. For example, if you place a market on open and the asset price moves before the market open to where you can't afford the quantity of the order, the brokerage rejects your order. The brokerage can also cancel your market on open order after partial fills if there is no shares left to trade.
Disable Buying Power
You can disable order margin checks and opt to let your brokerage decide to accept or reject the trades.
This is helpful in live trading if you have a more permissive brokerage margin allowance that what LEAN models.
The default position group buying power models are helpful for Option trading strategies.
However, it can be counterproductive if it's not a supported Option strategy.
To disable the validations of the default position group buying power model, use the NullSecurityPositionGroupModel
.
To set the NullSecurityPositionGroupModel
for the portfolio, during initialization, call the SetPositions
set_positions
method with the SecurityPositionGroupModel.NullNULL
argument.
Portfolio.SetPositions(SecurityPositionGroupModel.Null);
self.portfolio.set_positions(SecurityPositionGroupModel.NULL)
To disable the validations of the default buying power model, use the NullBuyingPowerModel
. To set the NullBuyingPowerModel
for a security subscription, call the SetBuyingPowerModel
set_buying_power_model
method with the BuyingPowerModel.NullNULL
argument.
public override void Initialize() { var equity = AddEquity("SPY"); // To disable any buying power of the selected security equity.SetBuyingPowerModel(BuyingPowerModel.Null); // Alias: // equity.SetMarginModel(SecurityMarginModel.Null); }
def initialize(self) -> None: equity = self.add_equity("SPY") # To disable any buying power of the selected security equity.set_buying_power_model(BuyingPowerModel.NULL) # Alias: # equity.set_margin_model(SecurityMarginModel.NULL)
You can also set the NullBuyingPowerModel
in a security initializer.
If your algorithm has a universe, use the security initializer technique.
To set the buying power of securities in the security initializer, set the brokerage model, set the security initializer, and then create security subscriptions.
public class BrokerageModelExampleAlgorithm : QCAlgorithm { public override void Initialize() { // In the Initialize method, set the security initializer to seed initial the prices and models of assets. SetSecurityInitializer(new MySecurityInitializer(BrokerageModel, new FuncSecuritySeeder(GetLastKnownPrices))); } } public class MySecurityInitializer : BrokerageModelSecurityInitializer { public MySecurityInitializer(IBrokerageModel brokerageModel, ISecuritySeeder securitySeeder) : base(brokerageModel, securitySeeder) {} public override void Initialize(Security security) { // First, call the superclass definition. // This method sets the reality models of each security using the default reality models of the brokerage model. base.Initialize(security); // Next, overwrite the security buying power security.SetBuyingPowerModel(BuyingPowerModel.Null); } }
class BrokerageModelExampleAlgorithm(QCAlgorithm): def initialize(self) -> None: # In the Initialize method, set the security initializer to seed initial the prices and models of assets. self.set_security_initializer(MySecurityInitializer(self.brokerage_model, FuncSecuritySeeder(self.get_last_known_prices))) # Outside of the algorithm class class MySecurityInitializer(BrokerageModelSecurityInitializer): def __init__(self, brokerage_model: IBrokerageModel, security_seeder: ISecuritySeeder) -> None: super().__init__(brokerage_model, security_seeder) def initialize(self, security: Security) -> None: # First, call the superclass definition. # This method sets the reality models of each security using the default reality models of the brokerage model. super().initialize(security) # Next, overwrite the security buying power security.set_buying_power_model(BuyingPowerModel.NULL)