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.

Flow of ordering and filling between algorithm and brokerage

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.FilledOrderStatus.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 SetPositionsset_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 SetBuyingPowerModelset_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)

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: