---
title: "Key Concepts"
description: "Fill models model how each type of order fills to accurately simulate the behavior of a real brokerage."
canonical: https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/trade-fills/key-concepts
markdown: https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/trade-fills/key-concepts.md
language: python
source: https://github.com/QuantConnect/Documentation/tree/master/03%20Writing%20Algorithms/24%20Reality%20Modeling/02%20Trade%20Fills/01%20Key%20Concepts
modified: 2026-10-31
index: https://www.quantconnect.com/llms.txt
---

# Key Concepts

[Documentation](https://www.quantconnect.com/docs/v2.md) > [Writing Algorithms](https://www.quantconnect.com/docs/v2/writing-algorithms.md) > Reality Modeling > Trade Fills > Key Concepts

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

## Introduction

A trade fill is the quantity and price at which your brokerage executes your order in the market. Fill models model how each type of order fills to accurately simulate the behavior of a real brokerage. Fill models determine the price and quantity of your fills, can incorporate spread costs, and work with the [slippage model](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/slippage/key-concepts.md) to add slippage into the fill price. If you trade US Equities, our built-in fill models can fill your orders at the [official opening and closing auction prices](https://www.quantconnect.com/docs/v2/cloud-platform/datasets/misconceptions.md#07-Opening-and-Closing-Auctions).

## Set Models

The brokerage model of your algorithm automatically sets the fill model for each security, but you can override it. To manually set the fill model of a security, call the `set_fill_model` method on the Security object.

```python
def initialize(self) -> None:
    security = self.add_equity("SPY")
    # Set the fill model for the requested security to backtest with the most realistic scenario
    # ImmediateFillModel provide no delay from network issue or brokerage rules
    security.set_fill_model(ImmediateFillModel())
```

You can also set the fill model in a [security initializer](https://www.quantconnect.com/docs/v2/writing-algorithms/initialization.md#07-Set-Security-Initializer). If your algorithm has a dynamic universe, use the security initializer technique. In order to initialize single security subscriptions with the security initializer, call `add_security_initializer` before you create the subscriptions.

```python
class AddSecurityInitializerExampleAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        # In the Initialize method, set the security initializer to set models of assets.
        self.add_security_initializer(self._custom_security_initializer)

    def _custom_security_initializer(self, security: Security) -> None:
        # Overwrite some of the reality models
        security.set_fill_model(ImmediateFillModel())
```

To view all the pre-built fill models, see [Supported Models](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/trade-fills/supported-models.md).

## Default Behavior

The brokerage model of your algorithm automatically sets the fill model of each security. The default brokerage model is the `DefaultBrokerageModel`, which sets the [EquityFillModel](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/trade-fills/supported-models/equity-model.md) for Equities, the [FutureFillModel](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/trade-fills/supported-models/future-model.md) for Futures, the [FutureOptionFillModel](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/trade-fills/supported-models/future-option-model.md) for Future Options, and the [ImmediateFillModel](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/trade-fills/supported-models/immediate-model.md) for all other asset classes.

## Model Structure

Fill Models should extend the `FillModel` class. To implement your own fill model, override the methods in the `FillModel` class you wish to change. The class has a dedicated method for each order type. Most of the methods receive a `Security` and `Order` object and return an `OrderEvent` object that contains information about the order status, fill quantity, and errors.

```python
class CustomFillModelExampleAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2024, 9, 1)
        self.set_end_date(2024, 12, 31)
        # In the Initialize method, set the custom fill model for an added security to use the custom model
        security = self.add_equity("SPY")
        security.set_fill_model(MyFillModel())

# Define the custom fill model outside of the algorithm
class MyFillModel(FillModel):

    def market_fill(self, asset: Security, order: MarketOrder) -> OrderEvent:
        return super().market_fill(asset, order)

    def limit_fill(self, asset: Security, order: LimitOrder) -> OrderEvent:
        return super().limit_fill(asset, order)

    def limit_if_touched_fill(self, asset: Security, order: LimitIfTouchedOrder) -> OrderEvent:
        return super().limit_if_touched_fill(asset, order)

    def stop_market_fill(self, asset: Security, order: StopMarketOrder) -> OrderEvent:
        return super().stop_market_fill(asset, order)

    def stop_limit_fill(self, asset: Security, order: StopLimitOrder) -> OrderEvent:
        return super().stop_limit_fill(asset, order)

    def trailing_stop_fill(self, asset: Security, order: TrailingStopOrder) -> OrderEvent:
        return super().trailing_stop_fill(asset, order)

    def market_on_open_fill(self, asset: Security, order: MarketOnOpenOrder) -> OrderEvent:
        return super().market_on_open_fill(asset, order)

    def market_on_close_fill(self, asset: Security, order: MarketOnCloseOrder) -> OrderEvent:
        return super().market_on_close_fill(asset, order)

    def combo_market_fill(self, order: Order, parameters: FillModelParameters) -> List[OrderEvent]:
        return super().combo_market_fill(order, parameters)

    def combo_limit_fill(self, order: Order, parameters: FillModelParameters) -> List[OrderEvent]:
        return super().combo_limit_fill(order, parameters)

    def combo_leg_limit_fill(self, order: Order, parameters: FillModelParameters) -> List[OrderEvent]:
        return super().combo_leg_limit_fill(order, parameters)
```

The `FillModelParameters` class has the following properties:

*Members of `QuantConnect.Orders.Fills.FillModelParameters` (JSON): https://www.quantconnect.com/services/inspector?type=T:QuantConnect.Orders.Fills.FillModelParameters&language=python*

## Partial Fills

In live trading, your orders can partially fill. For example, if you have a buy limit order at the bid price for 100 shares and someone sells 10 shares with a market order, your order is partially filled. In backtests, the pre-built fill models assume orders completely fill. To simulate partial fills in backtests, create a custom fill model.

## Stale Fills

Stale fills occur when you fill an order with price data that is timestamped an hour or more into the past. Stale fills usually only occur if you trade illiquid assets or if your algorithm uses daily data but you trade intraday with Scheduled Events. If your order is filled with stale data, the fill price may not be realistic. The pre-built fill models can only fill market orders with stale data. To adjust the length of time that needs to pass before an order is considered stale, set the `stale_price_time_span` setting.

```python
def initialize(self) -> None:
    # Adjust the stale price time span to be 10 minutes.
    self.settings.stale_price_time_span = timedelta(minutes=10)
```

## Examples

The following examples demonstrate common practices for implementing a custom fill model.

### Example 1: Default Model Wrapper

The following algorithm defines a subclass of the default `FillModel` and overrides its built-in members so you can easily customize the parts you need.

```python
class CustomFillModelAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 9, 1)
        self.set_end_date(2024, 10, 15)
        self.set_cash(100000)
        security = self.add_equity('SPY', Resolution.DAILY)
        security.set_fill_model(MyFillModel())

    def on_data(self, data: Slice) -> None:
        if not self.portfolio.invested:
            self.set_holdings('SPY', 1)

class MyFillModel(FillModel):

    def market_fill(self, asset: Security, order: MarketOrder) -> OrderEvent:
        return super().market_fill(asset, order)

    def limit_fill(self, asset: Security, order: LimitOrder) -> OrderEvent:
        return super().limit_fill(asset, order)

    def limit_if_touched_fill(self, asset: Security, order: LimitIfTouchedOrder) -> OrderEvent:
        return super().limit_if_touched_fill(asset, order)

    def stop_market_fill(self, asset: Security, order: StopMarketOrder) -> OrderEvent:
        return super().stop_market_fill(asset, order)

    def stop_limit_fill(self, asset: Security, order: StopLimitOrder) -> OrderEvent:
        return super().stop_limit_fill(asset, order)

    def trailing_stop_fill(self, asset: Security, order: TrailingStopOrder) -> OrderEvent:
        return super().trailing_stop_fill(asset, order)

    def market_on_open_fill(self, asset: Security, order: MarketOnOpenOrder) -> OrderEvent:
        return super().market_on_open_fill(asset, order)

    def market_on_close_fill(self, asset: Security, order: MarketOnCloseOrder) -> OrderEvent:
        return super().market_on_close_fill(asset, order)

    def combo_market_fill(self, order: Order, parameters: FillModelParameters) -> List[OrderEvent]:
        return super().combo_market_fill(order, parameters)

    def combo_limit_fill(self, order: Order, parameters: FillModelParameters) -> List[OrderEvent]:
        return super().combo_limit_fill(order, parameters)

    def combo_leg_limit_fill(self, order: Order, parameters: FillModelParameters) -> List[OrderEvent]:
        return super().combo_leg_limit_fill(order, parameters)
```

### Example 2: Volume Share Fill

The following algorithm longs the top 10 liquid constituents and short the bottom 10 liquid constituents of QQQ. To realistically fill the less liquid stocks, we implement a fill model that only fills with at most 30% of the previous second bar.

```python
class VolumeShareFillModelAlgorithm(QCAlgorithm):
    longs = []
    shorts = []

    def initialize(self) -> None:
        self.set_start_date(2024, 9, 1)
        self.set_end_date(2024, 12, 31)
        # The security initializer applies the VolumeShareFillModel to all assets.
        self.settings.seed_initial_prices = True
        self.add_security_initializer(self._volume_share_fill_security_initializer)

        # Request extended market hour SPY data for trading.
        qqq = self.add_equity("QQQ").symbol

        # Weekly portfolio updating to allow time to capitalize on the popularity gap.
        self.universe_settings.schedule.on(self.date_rules.week_start())
        # Set the resolution to second since the fill model is based on the second bar.
        self.universe_settings.resolution = Resolution.SECOND
        # Add universe to trade on the most and least liquid stocks among QQQ constituents.
        self.add_universe(
            self.universe.etf(qqq, Market.USA, self.universe_settings, lambda constituents: [c.symbol for c in constituents]),
            self.fundamental_selection
        )

        # Set a scheduled event to rebalance the portfolio at the start of every week.
        self.schedule.on(
            self.date_rules.week_start(qqq),
            self.time_rules.after_market_open(qqq),
            self.rebalance
        )

    def fundamental_selection(self, fundamentals: List[Fundamental]) -> List[Symbol]:
        sorted_by_dollar_volume = sorted(fundamentals, key=lambda f: f.dollar_volume)
        # Add the 10 most liquid stocks to the universe to long later.
        self.longs = [f.symbol for f in sorted_by_dollar_volume[-10:]]
        # Add the 10 least liquid stocks to the universe to short later.
        self.shorts = [f.symbol for f in sorted_by_dollar_volume[:10]]

        return self.longs + self.shorts

    def rebalance(self) -> None:
        # Equally invest in the selected stocks to dissipate capital risk evenly.
        # Dollar neutral of long and short stocks to eliminate systematic risk, only capitalize the popularity gap.
        targets = [PortfolioTarget(symbol, 0.05) for symbol in self.longs]
        targets += [PortfolioTarget(symbol, -0.05) for symbol in self.shorts]

        # Liquidate the ones not being the most and least popular stocks to release funds for higher expected return trades.
        self.set_holdings(targets, liquidate_existing_holdings=True)

    def _volume_share_fill_security_initializer(self, security: Security) -> None:
        # Create a slippage model to fill only 30% of the volume of the previous second bar to fill illiquid stocks realistically.
        security.set_fill_model(VolumeShareFillModel(self, 0.3))

class VolumeShareFillModel(FillModel):
    def __init__(self, algorithm: QCAlgorithm, maximum_ratio: float = 0.3):
        self.algorithm = algorithm
        self.maximum_ratio = maximum_ratio
        self.absolute_remaining_by_order_id = {}

    def market_fill(self, asset, order):
        absolute_remaining = self.absolute_remaining_by_order_id.get(order.id, order. AbsoluteQuantity)

        fill = super().market_fill(asset, order)
        # Set the fill amount to 30% of the previous second trade bar.
        fill.fill_quantity = np.sign(order.quantity) * asset.volume * self.maximum_ratio

        if (min(abs(fill.fill_quantity), absolute_remaining) == absolute_remaining):
            fill.fill_quantity = np.sign(order.quantity) * absolute_remaining
            fill.status = OrderStatus.FILLED
            self.absolute_remaining_by_order_id.pop(order.id, None)
        else:
            fill.status = OrderStatus.PARTIALLY_FILLED
            self.absolute_remaining_by_order_id[order.id] = absolute_remaining - abs(fill.fill_quantity)
            price = fill.fill_price

        return fill
```

### Other Examples

For more examples, see the following algorithms:

**Demonstration Algorithms**

- [CustomModelsAlgorithm.py](https://github.com/QuantConnect/Lean/blob/master/Algorithm.Python/CustomModelsAlgorithm.py) (Python)
- [CustomPartialFillModelAlgorithm.py](https://github.com/QuantConnect/Lean/blob/master/Algorithm.Python/CustomPartialFillModelAlgorithm.py) (Python)
- [ComboOrdersFillModelAlgorithm.py](https://github.com/QuantConnect/Lean/blob/master/Algorithm.Python/ComboOrdersFillModelAlgorithm.py) (Python)
- [ForwardDataOnlyFillModelAlgorithm.py](https://github.com/QuantConnect/Lean/blob/master/Algorithm.Python/ForwardDataOnlyFillModelAlgorithm.py) (Python)
