---
title: "Order Factory"
description: "The order factory creates order requests without submitting them, so you can estimate their fees, submit them together, or build contingent orders."
canonical: https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-management/order-factory
markdown: https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-management/order-factory.md
language: python
source: https://github.com/QuantConnect/Documentation/tree/master/03%20Writing%20Algorithms/22%20Trading%20and%20Orders/02%20Order%20Management/01%20Order%20Factory
modified: 2026-11-09
index: https://www.quantconnect.com/llms.txt
---

# Order Factory

[Documentation](https://www.quantconnect.com/docs/v2.md) > [Writing Algorithms](https://www.quantconnect.com/docs/v2/writing-algorithms.md) > Trading and Orders > Order Management > Order Factory

> Code examples are shown in Python. Append `?lang=csharp` to this URL for the C# version of this page.

## Introduction

The order factory creates order requests without submitting them. Use order requests to estimate fees and check buying power before you place orders, to submit several orders together, and to build [contingent orders](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/contingent-orders.md). When you submit an order request, you get an [order ticket](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-management/order-tickets.md) to manage the order.

## Create Order Requests

To create an order request, call one of the methods of the `order_factory` member. Each method returns a `SubmitOrderRequest` object.

```python
request = self.order_factory.limit_order(self._symbol, 100, limit_price, tag="Entry")
```

The order factory has a method for each order type. The following table shows the required arguments of each method:

| Method | Order Type |
| --- | --- |
| `market_order(symbol, quantity)` | [Market](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/market-orders.md) |
| `limit_order(symbol, quantity, limit_price)` | [Limit](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/limit-orders.md) |
| `limit_if_touched_order(symbol, quantity, trigger_price, limit_price)` | [Limit if touched](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/limit-if-touched-orders.md) |
| `stop_market_order(symbol, quantity, stop_price)` | [Stop market](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/stop-market-orders.md) |
| `stop_limit_order(symbol, quantity, stop_price, limit_price)` | [Stop limit](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/stop-limit-orders.md) |
| `trailing_stop_order(symbol, quantity, trailing_amount, trailing_as_percentage)` | [Trailing stop](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/trailing-stop-orders.md) |
| `trailing_stop_order(symbol, quantity, stop_price, trailing_amount, trailing_as_percentage)` | [Trailing stop with an initial stop price](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/trailing-stop-orders.md) |
| `market_on_open_order(symbol, quantity)` | [Market on open](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/market-on-open-orders.md) |
| `market_on_close_order(symbol, quantity)` | [Market on close](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/market-on-close-orders.md) |
| `combo_market_order(legs, quantity)` | [Combo market](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/combo-market-orders.md) |
| `combo_limit_order(legs, quantity, limit_price)` | [Combo limit](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/combo-limit-orders.md) |
| `combo_leg_limit_order(legs, quantity)` | [Combo leg limit](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/combo-leg-limit-orders.md) |
| `option_strategy_order(strategy, quantity)` | [Option strategy](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/option-strategies.md) |
| `exercise_option(option_symbol, quantity)` | [Option exercise](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/option-exercise-orders.md) |

Every method also accepts the optional `asynchronous`, `tag`, and `order_properties` arguments.

The combo and Option strategy methods return a list with one order request for each leg. The order request stores the current time and a copy of the [default order properties](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-properties.md), unless you pass order properties. If the ticker of the security changed, the order request uses the current `Symbol`.

## Submit Order Requests

To submit order requests, pass a single request or a list of requests to the `order` method. The method returns a list with the order ticket of each order. For a combo order, include all the legs.

```python
tickets = self.order([
    self.order_factory.market_order(self._spy, 10),
    self.order_factory.limit_order(self._aapl, -20, aapl_limit_price)
])
```

LEAN runs the [pre-order checks](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-errors.md) on every request before it submits any of them. If a request fails the checks, LEAN submits none of the orders and the method returns a list with a single invalid order ticket. LEAN checks the [buying power](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/buying-power.md) of each order after you submit it.

LEAN applies the usual order adjustments when you submit the request. For example, LEAN converts a market order into a market on open order if the market is closed. LEAN also sets the initial stop price of a trailing stop order from the market price at that time.

You can submit each order request once. After you submit a request, its `order_id` property holds the order Id. To get the order ticket of a request, [get it from the transaction manager](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-management/transaction-manager.md#02-Get-a-Single-Order-Ticket).

```python
ticket = self.transactions.get_order_ticket(request.order_id)
```

## Estimate Order Fees

To estimate the modeled fee of an order before you place it, create an order request with the order factory and convert it into an `Order` object with the `Order.create_order` method. Then pass the order and its security to the [fee model](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/transaction-fees/key-concepts.md) of the security. The conversion doesn't submit the order.

```python
security = self.securities[self._symbol]
request = self.order_factory.limit_order(self._symbol, 100, limit_price)
order = Order.create_order(request)
fee = security.fee_model.get_order_fee(OrderFeeParameters(security, order)).value
self.debug(f"Estimated fee: {fee.amount} {fee.currency}")
```

The estimate is a modeled fee. The fee model calculates it inside your algorithm with the current order and security values. In live trading, LEAN doesn't request the estimate from the brokerage. The fee that the brokerage charges can differ from the modeled fee, especially if the fee depends on the fill price or the fill quantity. To place the order after the estimate, pass the same request to the `order` method.

## Check Buying Power

The following sections explain how to check if you have enough [buying power](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/buying-power.md) to cover the initial [margin requirements](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/buying-power.md#03-What-is-Margin3F) of an order before you place it.

### Check Requirements of Regular Orders

To check if you have enough buying power for a regular order, create an order request with the order factory and convert it into an `Order` object. Then compare the absolute initial margin that the order requires with the buying power of your portfolio in the direction of the order. The initial margin is negative for sell orders and includes the modeled order fees. The buying power in the direction of the order includes the margin that the order frees when it reduces or reverses a position.

```python
security = self.securities[self._symbol]
request = self.order_factory.market_order(self._symbol, 100)
order = Order.create_order(request)
initial_margin = security.buying_power_model.get_initial_margin_required_for_order(
    InitialMarginRequiredForOrderParameters(self.portfolio.cash_book, security, order)).value
if abs(initial_margin) <= self.portfolio.get_buying_power(self._symbol, order.direction):
    self.order(request)
```

The `has_sufficient_buying_power_for_order` method of the security buying power model requires an order ticket, so it only works for orders that you already submitted. When you submit the order, LEAN runs its own buying power check.

### Check Requirements of Option Strategy Orders

To check if you have enough buying power for an [Option strategy](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/option-strategies.md) order, follow these steps:

1. Create an `OptionStrategy` object with the strategy you want to trade.
   For example, create a [Bull Put Spread](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/option-strategies/bull-put-spread.md) strategy.
   ```python
   def initialize(self) -> None:
       # Subscribe to option data and cache the canonical symbol to obtain the option data
       self._symbol = self.add_option("SPY").symbol

   def on_data(self, slice: Slice) -> None:
       # Trade on updated option chain data
       chain = slice.option_chains.get(self._symbol)
       if not chain:
           return

       itm_strike = max(x.strike for x in chain)
       otm_strike = min(x.strike for x in chain)
       expiry = min(x.expiry for x in chain)

       option_strategy = OptionStrategies.bull_put_spread(self._symbol, itm_strike, otm_strike, expiry)
   ```
2. Create the order requests of the strategy legs with the order factory and convert each request into an `Order` object.
   ```python
       requests = self.order_factory.option_strategy_order(option_strategy, 2)
       orders = [Order.create_order(request) for request in requests]
   ```
3. Call the `has_sufficient_buying_power_for_order` method of the portfolio with the list of orders.
   ```python
       result = self.portfolio.has_sufficient_buying_power_for_order(orders)
   ```
   The `has_sufficient_buying_power_for_order` method returns a `HasSufficientBuyingPowerForOrderResult` object, which has the following properties:
   *Members of `QuantConnect.Securities.HasSufficientBuyingPowerForOrderResult` (JSON): https://www.quantconnect.com/services/inspector?type=T:QuantConnect.Securities.HasSufficientBuyingPowerForOrderResult&language=python*
4. If the result is sufficient, submit the order requests.
   ```python
       if result.is_sufficient:
           self.order(requests)
       else:
           self.debug(f"You don't have sufficient margin for this order: {result.reason}")
   ```

The method combines the orders with your current holdings into [position groups](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/buying-power.md#05-What-Are-Position-Groups3F), so it accounts for strategy orders that reduce or close a position. If the strategy has a single leg, such as a naked put, follow the steps in the preceding section.

## Examples

The following examples demonstrate common practices for using the order factory.

### Example 1: Skip Expensive Rebalance Orders

The following algorithm rebalances an equal-weight portfolio every month. For each security, it creates a market order request for the difference between the target and current quantities and estimates the fee. The algorithm drops the orders whose fee exceeds 0.1% of the order value and submits the rest together, with the sell orders first.

```python
class OrderFactoryExampleAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 1, 1)
        self.set_end_date(2024, 12, 31)
        self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.MARGIN)
        self._symbols = [self.add_equity(ticker, Resolution.DAILY).symbol for ticker in ["SPY", "TLT", "GLD"]]
        self.schedule.on(self.date_rules.month_start(self._symbols[0]), self.time_rules.after_market_open(self._symbols[0], 30), self._rebalance)

    def _rebalance(self) -> None:
        requests = []
        for symbol in self._symbols:
            quantity = self.calculate_order_quantity(symbol, 1 / len(self._symbols))
            if not quantity:
                continue
            security = self.securities[symbol]
            request = self.order_factory.market_order(symbol, quantity)
            # Estimate the fee without submitting the order.
            fee = security.fee_model.get_order_fee(OrderFeeParameters(security, Order.create_order(request))).value.amount
            if fee <= 0.001 * abs(quantity) * security.price:
                requests.append(request)
        # Place the sell orders first to free up buying power.
        self.order(sorted(requests, key=lambda request: request.quantity))
```
