# How to Implement Custom Fee Models in Backtesting Frameworks: A QuantConnect Guide

> Learn to implement custom fee models in QuantConnect backtesting. Inherit FeeModel, override GetOrderFee, and attach to securities for realistic transaction cost simulation.

- Repository: [Papers With Backtest/awesome-systematic-trading](https://github.com/paperswithbacktest/awesome-systematic-trading)
- Tags: best-practices
- Published: 2026-07-31

---

**Implement custom fee models in QuantConnect by inheriting from `FeeModel`, overriding `GetOrderFee` to return a `CashAmount`, and attaching the model to each security via `SetFeeModel()` to ensure realistic transaction cost simulation.**

Accurate backtesting requires realistic transaction cost modeling beyond default assumptions. The `paperswithbacktest/awesome-systematic-trading` repository demonstrates how to implement custom fee models in backtesting frameworks by encapsulating commission logic into reusable classes that derive from the `FeeModel` abstraction. This pattern separates cost calculations from strategy logic, enabling precise control over how fees impact performance metrics across different securities and markets.

## Understanding the FeeModel Abstraction

QuantConnect exposes a `FeeModel` base class that defines how transaction costs are calculated for each order. The framework calls the `GetOrderFee` method for every order execution, passing an `OrderFeeParameters` object containing the security and order details. By overriding this single method in a derived class, you can implement everything from fixed commissions to complex tiered pricing structures without modifying your strategy's core logic.

## Six Best Practices for Custom Fee Models

### 1. Encapsulate Fee Logic in a Dedicated Class

Create a separate class that inherits from `FeeModel` and implement only the `GetOrderFee` method. This isolation prevents fee calculations from cluttering your algorithm code and makes the model testable and portable across different strategies.

### 2. Parameterize Fee Rates Instead of Hard-Coding

Store commission rates as class attributes or constructor parameters rather than magic numbers. This allows you to experiment with different broker fee structures—such as 4 basis points versus 5 basis points—without touching the algorithm implementation.

### 3. Handle Currencies Correctly

Always return fees wrapped in a `CashAmount` object with the appropriate currency code, typically `"USD"` for US equities. Using `CashAmount(fee, currency)` ensures proper currency conversion and prevents accounting errors when backtesting multi-currency portfolios.

### 4. Attach Models During Initialization

Call `security.SetFeeModel(CustomFeeModel())` immediately after adding the security to your algorithm, typically within the `Initialize` method. This ensures every order processed for that security uses your custom logic rather than default commission assumptions.

### 5. Maintain Deterministic Calculations

Avoid random components in fee calculations unless explicitly modeling stochastic costs like slippage or market impact. Deterministic fees ensure that backtest results remain reproducible when rerunning the same strategy parameters.

### 6. Document Fee Assumptions

Include inline comments describing the source and rationale for your commission rates, such as "0.5 bps typical broker fee" or "exchange minimum plus clearing fee." This documentation helps future maintainers understand whether the model represents retail or institutional pricing tiers.

## Complete Implementation Example

Here is a reusable, parameterized fee model that applies a fixed commission rate in basis points:

```python

# ----------------------------------------------------------------------

# Example: Parametrised custom fee model (re‑usable across strategies)

# ----------------------------------------------------------------------

from AlgorithmImports import *

class FixedCommissionFeeModel(FeeModel):
    """Applies a fixed commission rate (in basis points) to every order."""
    def __init__(self, rate_bps: float = 5.0):
        # Convert basis points to a decimal proportion (e.g., 5 bps → 0.00005)

        self._rate = rate_bps / 1_00_000

    def GetOrderFee(self, parameters: OrderFeeParameters) -> OrderFee:
        # fee = price × quantity × rate

        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * self._rate
        return OrderFee(CashAmount(fee, "USD"))

# ----------------------------------------------------------------------

# Usage inside a QuantConnect algorithm

# ----------------------------------------------------------------------

class MyStrategy(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2020, 1, 1)
        self.SetCash(1_000_000)

        # Add an equity and attach the custom fee model

        equity = self.AddEquity("SPY", Resolution.Daily)
        equity.SetFeeModel(FixedCommissionFeeModel(rate_bps=4.0))   # 4 bps

        # Add another security with the default 5 bps fee model

        another = self.AddEquity("EWJ", Resolution.Daily)
        another.SetFeeModel(FixedCommissionFeeModel())             # uses default 5 bps

```

Key implementation details include:

- The fee rate is **configurable** via the constructor (`rate_bps`).
- The model is **stateless** aside from the rate, making it safe for parallel backtests.
- `CashAmount` is used with the **correct currency** (`"USD"`), matching QuantConnect's expectations.

## Real-World Patterns in the Repository

The `paperswithbacktest/awesome-systematic-trading` repository demonstrates these practices across multiple strategy implementations. In [`static/strategies/value-factor-effect-within-countries.py`](https://github.com/paperswithbacktest/awesome-systematic-trading/blob/main/static/strategies/value-factor-effect-within-countries.py), lines 42-46 define a minimal `CustomFeeModel` that multiplies security price by order quantity and a fixed rate of 0.00005 (5 basis points).

Similarly, [`static/strategies/momentum-factor-effect-in-stocks.py`](https://github.com/paperswithbacktest/awesome-systematic-trading/blob/main/static/strategies/momentum-factor-effect-in-stocks.py) at lines 17-21 reuses this exact pattern, illustrating a consistent approach to fee modeling throughout the codebase. The same structure appears in [`static/strategies/short-term-reversal-in-stocks.py`](https://github.com/paperswithbacktest/awesome-systematic-trading/blob/main/static/strategies/short-term-reversal-in-stocks.py) and [`static/strategies/fx-carry-trade.py`](https://github.com/paperswithbacktest/awesome-systematic-trading/blob/main/static/strategies/fx-carry-trade.py), demonstrating how a single fee model implementation can service diverse strategy types from equity factors to foreign exchange carry trades.

## Summary

- **Encapsulate** fee logic in dedicated `FeeModel` subclasses to separate concerns from strategy code.
- **Parameterize** commission rates via constructors to enable rapid experimentation without code changes.
- **Use** `CashAmount` with the correct currency code to prevent accounting errors in multi-currency backtests.
- **Attach** custom models via `SetFeeModel()` immediately after security creation in your `Initialize` method.
- **Reference** the `paperswithbacktest/awesome-systematic-trading` repository for consistent implementation patterns across value, momentum, and FX strategies.

## Frequently Asked Questions

### How do I convert basis points to the decimal format expected by QuantConnect fee models?

Divide your basis points value by 1,000,000 (or use `rate_bps / 1_00_000` as shown in the repository examples). For instance, 5 basis points converts to 0.00005, which represents the decimal multiplier applied to the total order value to calculate the commission fee.

### Can I assign different fee models to different securities in the same algorithm?

Yes, you can instantiate different `FeeModel` subclasses or pass different parameters to the same class when calling `SetFeeModel()` for each security. This allows you to model varying commission structures for equities versus forex, or apply institutional discounts to certain assets while charging retail rates for others.

### Why should I avoid hard-coding commission rates in my strategy code?

Hard-coded rates require code modifications and redeployment to test different broker scenarios, breaking the separation of concerns between trading logic and execution costs. Parameterized fee models allow you to run systematic sweeps across commission levels to assess strategy sensitivity to transaction costs without altering the underlying algorithm.

### What currency should I use for CashAmount when trading international equities?

Always match the `CashAmount` currency to the security's quote currency as provided by `parameters.Security.QuoteCurrency.Symbol`. For US equities traded in USD, use `"USD"`, but for international assets, ensure you reference the correct three-letter ISO code to prevent currency conversion errors in your backtest P&L calculations.