Research infrastructure · Introductory
QuantConnect and LEAN
One open-source engine runs the same algorithm in backtest and live, and its defaults decide how far the two drift apart.
Educational material only. Not investment advice.
Contents
Abstract
QuantConnect is a hosted research and trading platform built on LEAN, an open-source engine released in 2015. One algorithm runs in backtest and live because the engine swaps the data and transaction handlers underneath it. The parity mostly holds. Where it fails, the cause is usually a default the user should override: the fill model, the data resolution, or the timing of orders placed after the close. Going live changes the handlers, the starting book and what a restart costs, and each can be prepared for in the backtest.
Key takeaways
- LEAN is an open-source (Apache 2.0) C# engine, released in 2015, with Python supported through Python.NET.
- Backtest and live parity comes from swapping the data feed and transaction handlers while the algorithm stays the same.
- The algorithm framework separates universe, alpha, portfolio construction, risk and execution.
- US equity data runs from 1998, point-in-time and free of survivorship bias; options, futures, forex and CFDs are also covered.
- A daily bar arrives at the close, when the market has shut: a market order sent then fills at the next open, and a market-on-close order at the next close.
- Live, the book starts from the account and a restart reruns initialize: set the brokerage model in the backtest, paper trade first, and persist any state that warm-up cannot rebuild.
- Set reality models explicitly and test at the resolution you trade; then reconcile live results against the backtest.
Before you start
- Basic Python
- Indicators and the 200-day moving average, for the backtest conventions and the trend rule used as the example
QuantConnect is a hosted platform for researching, backtesting and trading systematic strategies, built on LEAN, an open-source trading engine. Its central promise is that one algorithm runs unchanged in backtest and in live trading. Claims about the platform cite QuantConnect’s own documentation or source.
What it is, and a short history
LEAN was released as open source on 12 January 2015, in a forum announcement by Jared Broad that described it as the result of three years of development, which places the start of the engine around 2012; the repository’s first public commit carries the release date.1,2 It is licensed under Apache 2.0, so it can be run, modified and deployed privately without the hosted platform.2
| Date | Milestone | Source |
|---|---|---|
| 12 January 2015 | LEAN released as open source (Apache 2.0) | Forum announcement; GitHub |
| 1 May 2017 | LEAN v2.4.0.0: Python library support, re-engineered on Python.NET | LEAN release notes |
| January 2021 | First release of the lean command-line tool on PyPI (announced June 2021) | PyPI; QuantConnect announcement3,4 |
| April 2024 | Python API moves to PEP 8 names (snake_case) for new projects; the old names keep working | QuantConnect announcement |
Dates as published by QuantConnect, GitHub and PyPI.
The engine is written in C#. Python algorithms call the same engine through Python.NET, so a Python strategy uses the C# order, portfolio and data machinery rather than a separate reimplementation.5,6 Since 2024 the Python API uses PEP 8 names (set_holdings, on_data), and the older CamelCase names remain valid; the announcement warns that attribute names of your own can now clash with API methods, which is why the examples below prefix theirs with an underscore.7
Architecture
One algorithm, two worlds
LEAN is event-driven. The documentation describes it as a streaming analysis system: data is fed to the algorithm one time slice at a time, in fast-forward during a backtest and in real time when live, so the same algorithm code runs in both.8 The engine achieves this by assembling itself from handlers chosen by configuration. The data feed, the transaction handler, the setup handler and the real-time clock each have a backtesting and a live implementation. The algorithm sees the same interface either way.9
- Step 1 of 4
The algorithm
An algorithm is a class derived from QCAlgorithm: an
initializemethod, anon_datamethod, a portfolio and the order methods. It asks for data, reads the time, sends orders and starts from some cash and holdings, but nothing in it says where any of these come from. The engine plugs that in when it starts. - Step 2 of 4
The backtest’s handlers
In a backtest, FileSystemDataFeed reads history from files and BacktestingRealTimeHandler moves the clock straight to the next data, so years of history run in minutes. BacktestingTransactionHandler fills orders with the fill, fee and slippage models, and BacktestingSetupHandler starts the book from
set_cash.9,8 - Step 3 of 4
The live handlers
Live, LiveTradingDataFeed takes data as it streams in, LiveTradingRealTimeHandler fires scheduled events on the wall clock, BrokerageTransactionHandler sends orders to the broker and receives its fills, and BrokerageSetupHandler loads cash and holdings from the account. LEAN’s own paper-trading environment keeps the backtesting transaction handler, so paper trading exercises the live data and clock while its fills are still modelled.9
- Step 4 of 4
Where they part
Since the algorithm is identical, every difference sits at a seam: when data arrives, when events fire, how an order fills and what the book starts with. On daily data, for example,
set_holdingsfrom a 10:00 scheduled event decides on the previous close, 99.73. The backtest works the order at the close and fills at 101.05; live, the broker fills it at 10:00, at 99.61. The two fills are 145 bp and 6 hours apart.10
Handler names as in LEAN’s Launcher/config.json. The order in the last step is the synthetic path of Figure 3, computed by the same function as that laboratory. Without script, or with reduced motion, the figure shows its final state.
Inside the engine, one loop turns the handlers’ output into calls on the algorithm. For each time slice it sets the clock, updates prices and the portfolio, lets the fill models try the open orders, fires scheduled events, updates consolidators and the indicators registered on them, calls on_data and the framework models, and then processes the orders they sent.11 In a backtest all of it runs on one thread, in data time. Live, the scheduled events run on a timer thread and fills arrive from the broker whenever they happen, so an event can fire, and a position can change, between slices (Figure 1).
- 1 A time slice arrives ◆
- 2 Missed events catch up ◆
- 3 Prices and portfolio update
- 4 Open orders meet the prices ◆
- 5 Scheduled events fire ◆
- 6 Consolidators and indicators
- 7 on_data and the framework
- 8 Orders are processed ◆
1. A time slice arrives (backtest, Tuesday 16:00). FileSystemDataFeed reads the next bars from files. The clock jumps straight to their end time: Tuesday’s daily bar is due at 16:00, so the engine goes to 16:00.
Stations marked ◆ are where a live handler replaces a backtesting one. Switch the engine at any step to compare; the last two steps are the next day’s slice, where the two runs meet again.
The algorithm framework
A strategy can be written as a single class, or as five pluggable models that the framework runs in sequence: universe selection chooses the securities, the alpha model emits directional insights, portfolio construction turns insights into portfolio targets (a quantity for each security), risk management adjusts the targets, and execution places the orders that move the portfolio towards them.12 The separation is the same one this series uses: a signal (Indicators and the 200-day moving average), sizing (Volatility targeting) and execution (TWAP, slicing and jitter) are different problems and are easier to test apart.
Around the algorithm, a brokerage model sets what a given broker allows and charges. It fixes fees, order types and leverage, supplies the fill, slippage and buying-power models, and validates each order before it is sent.13 Data arrives at tick, second, minute, hour or daily resolution; US equity subscriptions default to minute.14
Using it
A first algorithm
The smallest useful algorithm sets a date range and starting cash, subscribes to a security and trades on data. This is LEAN’s own template, in the current Python naming:15
from AlgorithmImports import *
class BasicTemplateAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2013, 10, 7)
self.set_end_date(2013, 10, 11)
self.set_cash(100000)
self.add_equity("SPY", Resolution.MINUTE)
def on_data(self, data):
if not self.portfolio.invested:
self.set_holdings("SPY", 1)A slightly larger example, the trend rule from Indicators and the 200-day moving average, shows the pieces a real strategy uses: a built-in indicator registered with the engine, a warm-up period that fills it before trading starts, and an explicit guard while it warms up.16
from AlgorithmImports import *
class SmaTrend(QCAlgorithm):
"""Hold the ETF while it is above its 200-day simple moving average; otherwise hold cash.
The rule from Indicators and the 200-day moving average, written for LEAN. With daily bars the signal is only known at the
close, when the market has shut, so LEAN turns the market order into a market-on-open order that fills at the next open.
"""
def initialize(self):
self.set_start_date(2010, 1, 1)
self.set_end_date(2024, 12, 31)
self.set_cash(100_000)
# Leading underscores: in the PEP 8 API, `symbol` and `sma` are QCAlgorithm methods.
self._symbol = self.add_equity("SPY", Resolution.DAILY).symbol
self._trend = self.sma(self._symbol, 200, Resolution.DAILY) # a registered indicator
self.set_warm_up(200, Resolution.DAILY) # fill it before trading
def on_data(self, data: Slice):
if self.is_warming_up or not self._trend.is_ready:
return
price = self.securities[self._symbol].price
above = price > self._trend.current.value
if above and not self.portfolio.invested:
self.set_holdings(self._symbol, 1.0)
elif not above and self.portfolio.invested:
self.liquidate(self._symbol)
When an order fills
LEAN passes a bar to the algorithm at its end time, so a daily bar arrives at the close, when the market has shut.17 What an order sent then, or at any other moment, actually does depends on its type, the data and the mode. A market order sent while the market is closed, and on US equities 16:00 counts as closed, becomes a market-on-open order and fills at the next session’s open.18 A market-on-open order is refused during the session unless the security has daily data only, and a market-on-close order must arrive at least 15.5 minutes before the close (LEAN’s default buffer, which is configurable); sent after the close, it is for the next one.19,20 Since June 2026 (LEAN pull request 9534), a backtest on daily data no longer fills a market order sent during the session at the previous day’s close: it works the order at that day’s close or, if it arrives within the close buffer, at the next open. Live, where the broker has a price, the same order fills at once.10 Figure 3 lays the combinations out on one synthetic path.
At 16:00 the market is closed, so LEAN turns the market order into a market-on-open order: it fills at Wednesday’s open, after the overnight gap. In the backtest the fill is booked only when Wednesday’s daily bar arrives, at 16:00, priced at its open.
site_research/fieldnotes/leanorders.py; the page recomputes them in the browser and the build checks each case against the Python. Try daily bars at 16:00 with a market order, then with an order at the close; then daily bars at 10:00 with a market order, and switch between backtest and live.Where the work is done
The hosted platform provides a browser IDE, research notebooks attached to the data library, cloud backtesting and live deployment.22,23 The lean command-line tool brings the same workflow to a local editor: it runs the engine locally in Docker and can push projects to and pull them from the cloud. Its documentation states that using it requires membership of a paid organisation tier.24,25
pip install --upgrade lean # needs Docker for local runs
lean login # link the CLI to your QuantConnect account
lean init # set up a workspace in the current directory
lean create-project "SMA Trend"
lean backtest "SMA Trend" # run LEAN locally in Docker
lean cloud backtest "SMA Trend" --push # or push and run in the cloudFrom backtest to live
When an algorithm goes live its code stays as it is. The handlers around it change (the step-by-step figure in Architecture), and with them the account it starts from, the clock it runs on and what a restart costs.
- The brokerage model. Set the model of the broker you will trade through in
initialize, so the backtest already charges its fees, accepts only its order types and applies its margin or cash-account rules. The default is QuantConnect’s paper-trading model.13 - The starting book. Live, most brokerages load the account’s cash, positions and open orders when the algorithm starts; for the others, cash and positions are entered when deploying, and open orders are not restored.26 The algorithm must cope with starting from a position it did not open.
- State across restarts. A redeploy, an update or an automatic restart after an error starts a new instance and runs
initializeagain.26 Warm-up rebuilds the indicators; anything else the algorithm remembers must be saved, for example in the Object Store, which persists across restarts; it is shared by every backtest and live deployment in the organisation, so keep live state under a key that backtests do not touch. Paper and real-money deployments of the same project share that key too, so delete it, or use a new key, when moving from paper to real money.27 Building strategies from components treats what a component must re-derive after a crash. - Paper first. The documentation recommends paper trading before real money.26 It tests the live data feed, the clock and the start-up path; the fills are still simulated. It also runs in live mode, so the backtest-only conversion of daily-data market orders does not apply there.
- Logs and notifications.
self.logwrites to the live log, andself.notifysends email, SMS, Telegram or webhook messages; backtests ignore notifications.28
# In initialize(): the broker's fees, order types and margin rules, in the backtest too.
self.set_brokerage_model(BrokerageName.DEFAULT, AccountType.CASH) # name your broker here
# State that warm-up cannot rebuild, kept across live restarts (import json at the top).
# The Object Store is shared by the project's backtests and its live deployment: keep live
# state under its own key, and let backtests neither read nor write it.
self._key = f"{self.project_id}/live/state" # paper and real money share it: clear it when switching
self._state = (json.loads(self.object_store.read(self._key))
if self.live_mode and self.object_store.contains_key(self._key) else {})
def on_order_event(self, order_event: OrderEvent):
if order_event.status == OrderStatus.FILLED:
self.log(f"{order_event.symbol} {order_event.fill_quantity} at {order_event.fill_price}")
self._state["last_fill"] = str(self.time)
if self.live_mode: # backtests ignore notifications anyway, and must not touch live state
self.object_store.save(self._key, json.dumps(self._state))
self.notify.email(address="alerts@example.com", subject="Fill", message=str(order_event))Deployment is a wizard, in the browser or in the terminal: it asks for the brokerage and its credentials, the live data provider, the node and the notifications. From the CLI, lean live deploy runs the engine on your own machine in Docker, with paper trading among the brokerages it offers, and lean cloud live deploy starts the same project on QuantConnect Cloud.26,29,30
lean live deploy "SMA Trend" # live on this machine, in Docker
lean cloud live deploy "SMA Trend" --push # or push and deploy on QuantConnect CloudKeep the data resolution the backtest used, and remember the one order rule that differs by design: live, a market order on daily data fills at the market price at once (Figure 3). Release discipline, staged capital and the kill switch are the subject of Going live; comparing the account with its backtest day by day is that of Live versus backtest reconciliation.
Data
The data library covers point-in-time US equities free of survivorship bias, plus derivatives and alternative datasets, usable directly in backtests and notebooks; some datasets are licensed separately. The documented coverage of the core price data:31,32,33,34,35,36
| Asset class | Vendor (as named by QuantConnect) | From | Resolution / scope |
|---|---|---|---|
| US equities | AlgoSeek | January 1998 | Tick to daily; about 27,500 securities from the full consolidated (SIP) feed, free of survivorship bias |
| US equity options | AlgoSeek | January 2012 | Minute; OPRA feed |
| US futures | AlgoSeek | May 2009 | The 162 most liquid contracts on CME, CBOT, NYMEX, COMEX, CFE and ICE |
| Forex | QuantConnect (a forex dealer’s tick data) | January 2007 | 71 pairs, tick to daily |
| CFDs | QuantConnect (a forex dealer’s tick data) | May 2002 | 51 contracts |
| US fundamentals | Morningstar | January 1998 | Company fundamentals |
From QuantConnect’s dataset pages; coverage changes, so check the page before relying on a start date. The library also lists crypto, index and index-option, future-option and alternative datasets; check each dataset page for its own start date and terms.
Equity prices are split- and dividend-adjusted by default, and raw, split-adjusted and total-return modes can be chosen per subscription (a scaled-raw mode applies to history requests).14 The choice matters: under the default adjusted mode a backtest also fills at adjusted prices, which differ from the prices a live order will see, so a strategy whose sizing, limit prices or cost model depends on the traded price may be better tested on raw data.
Strengths and cautions
Problems in a LEAN backtest usually trace to defaults and data assumptions rather than to the engine, and four habits address most of them.
| Strengths | Cautions |
|---|---|
| Open source: behaviour can be read and verified in the code, not guessed | Defaults are permissive: under the default brokerage model, slippage is zero until you set a model |
| One algorithm for backtest and live, with the same order and portfolio logic | Daily bars hide intraday timing: on daily data a backtest can only fill at an open or a close, so it cannot show what an order sent during the session pays live |
| Broad data, free of survivorship bias, in the same environment as the code | Cloud resources depend on the plan: backtest, research and live nodes and log sizes are capped |
| Python and C#, with a large public example library and an active forum | The Python-to-C# bridge adds a layer to debug, and API names changed in 2024 |
| Daily-data backtests no longer fill a market order sent during the session at the previous close | That conversion is made in backtests only: live, the same market order fills at once at the market price, so the two runs trade at different prices |
Four habits make results from any backtesting engine, this one included, closer to what live trading will deliver:
- Set the reality models explicitly. Choose the brokerage model for the broker you will use and a slippage model; do not rely on the defaults.37,38
- Backtest at the resolution you will trade. If live orders are sent intraday, backtest on minute data, so fills see the same prices and times.
- Record the engine version and parameters with every result. The engine evolves; a backtest that cannot be rerun on the same code is an anecdote.
- Reconcile live against backtest from the first day. Compare positions and fills, not only returns. Differences found in the first week are cheap; differences found after a year are not.
Documentation
The official documentation is extensive. These pages are the most useful entry points.
| Topic | URL | What it covers |
|---|---|---|
| Documentation home | www.quantconnect.com/docs/v2 | Start here |
| Writing algorithms | www.quantconnect.com/docs/v2/writing-algorithms | The API: securities, data, orders, scheduling |
| Algorithm framework | www.quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/overview | Universe, alpha, portfolio, risk and execution models |
| Algorithm engine | www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/algorithm-engine | The streaming design behind backtest and live parity |
| Datasets | www.quantconnect.com/docs/v2/writing-algorithms/datasets/overview | What data exists, from whom, since when |
| Reality modelling | www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/key-concepts | Fills, slippage, fees, brokerage models |
| Research environment | www.quantconnect.com/docs/v2/research-environment | Notebooks attached to the data |
| LEAN CLI | www.quantconnect.com/docs/v2/lean-cli | Local and cloud workflows from a terminal |
| Live trading | www.quantconnect.com/docs/v2/cloud-platform/live-trading | Deployment and supported brokerages |
| LEAN engine docs | www.quantconnect.com/docs/v2/lean-engine | Running and extending the engine itself |
| LEAN on GitHub | github.com/QuantConnect/Lean | Source, issues and releases (Apache 2.0) |
References
- QuantConnect (2015). Lean open source release (forum announcement, 12 January 2015). QuantConnect. www.quantconnect.com/forum/discussion/400/lean-open-source-release
- QuantConnect (n.d.). QuantConnect/Lean: Lean Algorithmic Trading Engine (source repository, Apache-2.0). GitHub. github.com/QuantConnect/Lean
- QuantConnect (n.d.). lean: the LEAN CLI on the Python Package Index (release history). Python Package Index. pypi.org/project/lean/
- QuantConnect (2021). LEAN CLI for streamlining cloud and local workflows (announcement). QuantConnect. www.quantconnect.com/announcements/15565/lean-cli-for-streamlining-cloud-and-local-workflows/
- QuantConnect (n.d.). Python and LEAN. QuantConnect documentation. www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/python-and-lean
- QuantConnect (2017). LEAN release v2.4.0.0: Python library support. GitHub. github.com/QuantConnect/Lean/releases/tag/v2.4.0.0
- QuantConnect (2024). PEP8 Python API migration (announcement). QuantConnect. www.quantconnect.com/announcements/16830/pep8-python-api-migration/
- QuantConnect (n.d.). Algorithm engine. QuantConnect documentation. www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/algorithm-engine
- QuantConnect (n.d.). Launcher/config.json (handler configuration). GitHub. github.com/QuantConnect/Lean/blob/master/Launcher/config.json
- QuantConnect (2026). Convert daily resolution market orders to MarketOnClose/MarketOnOpen (LEAN pull request 9534). GitHub. github.com/QuantConnect/Lean/pull/9534
- QuantConnect (n.d.). Engine/AlgorithmManager.cs: the main loop. GitHub. github.com/QuantConnect/Lean/blob/master/Engine/AlgorithmManager.cs
- QuantConnect (n.d.). Algorithm framework overview. QuantConnect documentation. www.quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/overview
- QuantConnect (n.d.). Brokerages: key concepts. QuantConnect documentation. www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/brokerages/key-concepts
- QuantConnect (n.d.). US equity: requesting data (resolutions, data normalization modes). QuantConnect documentation. www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/us-equity/requesting-data
- QuantConnect (n.d.). BasicTemplateAlgorithm.py. GitHub. github.com/QuantConnect/Lean/blob/master/Algorithm.Python/BasicTemplateAlgorithm.py
- QuantConnect (n.d.). Warm up periods. QuantConnect documentation. www.quantconnect.com/docs/v2/writing-algorithms/historical-data/warm-up-periods
- QuantConnect (n.d.). Time modeling: periods. QuantConnect documentation. www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/time-modeling/periods
- QuantConnect (n.d.). Market orders. QuantConnect documentation. www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/market-orders
- QuantConnect (n.d.). Market on close orders. QuantConnect documentation. www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/market-on-close-orders
- QuantConnect (n.d.). Market on open orders. QuantConnect documentation. www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/market-on-open-orders
- QuantConnect (n.d.). Common/Orders/Fills/EquityFillModel.cs. GitHub. github.com/QuantConnect/Lean/blob/master/Common/Orders/Fills/EquityFillModel.cs
- QuantConnect (n.d.). Cloud IDE. QuantConnect documentation. www.quantconnect.com/docs/v2/cloud-platform/projects/ide
- QuantConnect (n.d.). Research environment. QuantConnect documentation. www.quantconnect.com/docs/v2/research-environment
- QuantConnect (n.d.). LEAN CLI. QuantConnect documentation. www.quantconnect.com/docs/v2/lean-cli
- QuantConnect (n.d.). Installing the LEAN CLI. QuantConnect documentation. www.quantconnect.com/docs/v2/lean-cli/installation/installing-lean-cli
- QuantConnect (n.d.). Live trading: deployment. QuantConnect documentation. www.quantconnect.com/docs/v2/cloud-platform/live-trading/deployment
- QuantConnect (n.d.). Object Store. QuantConnect documentation. www.quantconnect.com/docs/v2/writing-algorithms/object-store
- QuantConnect (n.d.). Live trading: notifications. QuantConnect documentation. www.quantconnect.com/docs/v2/writing-algorithms/live-trading/notifications
- QuantConnect (n.d.). lean live deploy (CLI reference). QuantConnect documentation. www.quantconnect.com/docs/v2/lean-cli/api-reference/lean-live-deploy
- QuantConnect (n.d.). lean cloud live deploy (CLI reference). QuantConnect documentation. www.quantconnect.com/docs/v2/lean-cli/api-reference/lean-cloud-live-deploy
- QuantConnect (n.d.). AlgoSeek US equities (dataset). QuantConnect data library. www.quantconnect.com/data/algoseek-us-equities
- QuantConnect (n.d.). AlgoSeek US equity options (dataset). QuantConnect data library. www.quantconnect.com/data/algoseek-us-equity-options
- QuantConnect (n.d.). AlgoSeek US futures (dataset). QuantConnect data library. www.quantconnect.com/data/algoseek-us-futures
- QuantConnect (n.d.). QuantConnect forex (dataset). QuantConnect data library. www.quantconnect.com/data/quantconnect-forex
- QuantConnect (n.d.). QuantConnect CFD (dataset). QuantConnect data library. www.quantconnect.com/data/quantconnect-cfd
- QuantConnect (n.d.). Morningstar US fundamentals (dataset). QuantConnect data library. www.quantconnect.com/data/morning-star-us-fundamentals
- QuantConnect (n.d.). Slippage: key concepts. QuantConnect documentation. www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/slippage/key-concepts
- QuantConnect (n.d.). Transaction fees: key concepts. QuantConnect documentation. www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/transaction-fees/key-concepts