---
title: "Algorithm Engine"
description: "LEAN Engine is an open-source algorithmic trading engine built for easy strategy research, backtesting, and live trading with Python or C#."
canonical: https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/algorithm-engine
markdown: https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/algorithm-engine.md
language: python
source: https://github.com/QuantConnect/Documentation/tree/master/03%20Writing%20Algorithms/01%20Key%20Concepts/03%20Algorithm%20Engine
modified: 2026-10-29
index: https://www.quantconnect.com/llms.txt
---

# Algorithm Engine

[Documentation](https://www.quantconnect.com/docs/v2.md) > [Writing Algorithms](https://www.quantconnect.com/docs/v2/writing-algorithms.md) > Key Concepts > Algorithm Engine

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

## Introduction

LEAN Engine is an open-source algorithmic trading engine built for easy strategy research, backtesting, and live trading. We integrate with common data providers and brokerages, so you can quickly deploy algorithmic trading strategies. The core of the LEAN Engine is written in C#, but it operates seamlessly on Linux, Mac and Windows operating systems. To use it, you can write algorithms in Python 3.11 or C#. QuantConnect maintains the LEAN project and uses it to drive the web-based algorithmic trading platform on the website.

Since LEAN is open-source, you aren't locked-in to the QuantConnect platform. You can run LEAN with your own infrastructure, data, and brokerage connections. If you use QuantConnect, our team of engineers manage the infrastructure, you can run the latest version of LEAN with all of its brokerage connections, and you can utilize the datasets in the [Dataset Market](https://www.quantconnect.com/datasets).

## Your Algorithm and LEAN

To create a trading algorithm with LEAN, define a subclass of the `QCAlgorithm` class. LEAN loads your algorithm into the engine during the building and compilation process. LEAN runs an algorithm manager that synchronizes the data your algorithm requests, injects the data into your algorithm so you can place trades, processes your orders, and then updates your algorithm state.

The LEAN engine manages your portfolio and data feeds, so you focus on your algorithm strategy and execution. We automatically provide basic portfolio management and [reality modeling](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/key-concepts.md) underneath the hood. The `QCAlgorithm` class provides some key helper properties for you to use, including the Security Manager, Portfolio Manager, Transactions Manager, Notification Manager, and Scheduling Manager. The class also has hundreds of helper methods to make the API easy to use.

The [Securities](https://www.quantconnect.com/docs/v2/writing-algorithms/securities/key-concepts.md) property is a dictionary of `Security` objects. Each asset (Equity, Forex pair, etc) in your algorithm has a `Security` object. All the models for a security live on these objects. For example, `self.Securities["IBM"].FeeModel` and `self.Securities["IBM"].Price` return the [fee model](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/transaction-fees/key-concepts.md) and price of IBM, respectively.

The [Portfolio](https://www.quantconnect.com/docs/v2/writing-algorithms/portfolio/key-concepts.md) is a dictionary of `SecurityHolding` objects. These classes track the profits, losses, fees, and quantity of individual portfolio holdings. For example, `self.portfolio["IBM"].last_trade_profit` returns the profit of your last IBM trade.

Other helpers like [Transactions](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-management/transaction-manager.md), [Schedule](https://www.quantconnect.com/docs/v2/writing-algorithms/scheduled-events.md), [Notify](https://www.quantconnect.com/docs/v2/writing-algorithms/live-trading/notifications.md), and [Universe](https://www.quantconnect.com/docs/v2/writing-algorithms/universes/key-concepts.md) have their own helper methods.

```python
class QCAlgorithm:
    securities   # Array of Security objects.
    portfolio    # Array of SecurityHolding objects
    transactions # Transactions helper
    schedule     # Scheduling helper
    notify       # Email, SMS helper
    universe     # Universe helper

    # Set up Requested Data, Cash, Time Period.
    def initialize(self) -> None:

    # Other Event Handlers
    def on_data(self, slice: Slice) -> None:
    def on_end_of_day(self, symbol: Symbol) -> None:
    def on_end_of_algorithm(self) -> None:

    # Indicator Helpers
    def sma(self, symbol: Symbol, period: int) -> SimpleMovingAverage:
```

Only define one algorithm class per project. To trade multiple strategies in a single algorithm, implement an [Algorithm Framework](https://www.quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/overview.md) design with [multiple Alpha models](https://www.quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/alpha/key-concepts.md#03-Multi-Alpha-Algorithms). To be notified when you can define more than one algorithm class per project, subscribe to [GitHub Issue #6968](https://github.com/QuantConnect/Lean/issues/6968).

## Threads in LEAN

LEAN is multi-threaded and attempts to consume as much CPU as possible to perform given work as quickly as possible. The analysis engine loads data parallel and synchronizes it to generate the requested security information.

The client algorithm is plugged into LEAN, and has its events triggered synchronously in backtesting. The primary bottle neck to LEAN execution is executing client code.

In live trading, most events are synchronous as in backtesting, however order events are triggered immediately from the brokerage thread (asynchronously) to ensure the lowest latency. For example; a strategy using hourly data, with a limit order could fill between data bars. This fill event is triggered when it occurs in live trading.

We recommend using thread safe collections when possible, or locks around collections to ensure they are thread-safe.

## Batch vs Stream Analysis

Backtesting platforms come in two general varieties, batch processing and event streaming. Batch processing backtesting is much simpler. It loads all data into an array and passes it to your algorithm for analysis. Because your algorithm has access to future data points, it is easy to introduce [look-ahead bias](https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/glossary.md#18-look-ahead-bias). Most home-grown analysis tools are batch systems.

QuantConnect/LEAN is a streaming analysis system. In live trading, your algorithm receives data points one after another over time. QuantConnect models this in backtesting, streaming data to your algorithm in fast-forward mode. Because of this, you can't access price data beyond the [Time Frontier](https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/time-modeling/timeslices.md). Although streaming analysis is slightly trickier to understand, it allows your algorithm to seamlessly work in backtests and live trading with no code changes.

## Event Flow

When you deploy an algorithm, LEAN first calls the [initialize](https://www.quantconnect.com/docs/v2/writing-algorithms/initialization.md) method. In live mode, the engine loads your holdings and open orders from your brokerage account to add data subscriptions and populate the `securities`, `portfolio`, and `transactions` objects. LEAN receives the data from the subscriptions, synchronizes the data to create a [timeslice](https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/time-modeling/timeslices.md), and then performs the following steps. Your algorithm can spend up to 10 minutes on each timeslice unless you call the [train](https://www.quantconnect.com/docs/v2/writing-algorithms/machine-learning/training-models.md) method.

1. If it's a backtest, check if there are [Scheduled Events](https://www.quantconnect.com/docs/v2/writing-algorithms/scheduled-events.md) in the past that didn't fire because there was no data between the previous [slice](https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/time-modeling/timeslices.md) and the current slice. LEAN automatically creates a Scheduled Event to call the `on_end_of_day` method at the end of each day.
   In live mode, Scheduled Events occur in a separate thread from the algorithm manager, so they run at the correct time.
2. Update the algorithm time.
3. Update the `current_slice`.
4. Pass the `SymbolChangedEvents` to the `on_symbol_changed_events` method.
5. Cancel all open orders for securities that [changed their ticker](https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/us-equity/corporate-actions.md#04-Symbol-Changes).
6. Add a `Security` object to the `securities` collection for each new security in the universe.
7. Update the `Security` objects with the latest data.
8. Update the `Cash` objects in the [CashBook](https://www.quantconnect.com/docs/v2/writing-algorithms/portfolio/cashbook.md) with the latest data.
9. Process [fill models](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/trade-fills/key-concepts.md) for non-market orders.
10. Submit market on open orders to liquidate Equity Option contracts if the underlying Equity has a [split warning](https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/us-equity/corporate-actions.md#02-Splits).
11. Process [margin calls](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/margin-calls.md).
12. If it's time to settle [unsettled cash](https://www.quantconnect.com/docs/v2/writing-algorithms/portfolio/cashbook.md#03-Settled-vs-Unsettled-Cash), perform settlement.
13. Call the [on_securities_changed](https://www.quantconnect.com/docs/v2/writing-algorithms/universes/key-concepts.md#06-Security-Changed-Events) method with the latest security changes.
14. Apply dividends to the portfolio.
15. For securities that have a split warning, update their portfolio holdings and adjust their open orders to account for the split.
16. Update [consolidators](https://www.quantconnect.com/docs/v2/writing-algorithms/consolidating-data/getting-started.md) with the latest data.
17. Pass the `Dividends` to the `on_dividends` method.
18. Pass the `Splits` to the `on_splits` method.
19. Pass the `Delistings` to the `on_delistings` method.
20. Pass the `Slice` to the `on_data` method.
21. Perform [universe selection](https://www.quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/universe-selection/key-concepts.md).
22. Pass the `Slice` to the `update` method of each [Alpha model](https://www.quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/alpha/key-concepts.md).
23. Pass the `Insight` objects from the Alpha model to the [Portfolio Construction model](https://www.quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/portfolio-construction/key-concepts.md).
24. Pass the `PortfolioTarget` objects from the Portfolio Construction model to each [Risk Management model](https://www.quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/risk-management/key-concepts.md).
25. Pass the risk-adjusted `PortfolioTarget` objects from the Risk Management models to the [Execution model](https://www.quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/execution/key-concepts.md).

When your algorithm stops executing, LEAN calls the `on_end_of_algorithm` [method](https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/event-handlers.md#15-End-Of-Algorithm-Events).

## Python Support

The LEAN engine is written in C#, but you can create algorithms in C# or Python. If you program in Python, LEAN uses Python.Net to bridge between the C# engine and your algorithm. It can be slow to move from Python to C#. If you access C# objects in your Python algorithm, it's fastest to only access them once and save a reference if you need to access them again.

```python
# Store the security holding in a variable for better readability and performance.
security_holding = self.portfolio[self._symbol]
avg_price = security_holding.average_price
quantity = security_holding.quantity

# Avoid indexing the portfolio object multiple times for each attribute.
avg_price = self.portfolio[self._symbol].average_price
quantity = self.portfolio[self._symbol].quantity
```
