第 1 章 · 01 Lean 定位与 .NET 量化引擎 本节摘要:本节是整本教程的第一视角——先建立 Lean 是什么的全局认知。QuantConnect Lean 是业界规模最大的开源量化交易引擎之一(Apache 2.0,QuantConnect Corporation 出品),约 112 万行 C# 代码 / 23 个项目,跑在很新的 .NET 10.0 上。它的两大工程哲学是:C# + Python 双语言(靠 Python.NET 互操作,454 个 .py 示例与 C# 算法完全对等),以及回测与实盘统一(同一份 IAlgorithm 用户代码,靠换 config.json 里的 handler 字符串就能从回测切到真实券商)。
本节摘要:本节是整本教程的第一视角——先建立 Lean 是什么的全局认知。QuantConnect Lean 是业界规模最大的开源量化交易引擎之一(Apache 2.0,QuantConnect Corporation 出品),约 112 万行 C# 代码 / 23 个项目,跑在很新的 .NET 10.0 上。它的两大工程哲学是:C# + Python 双语言(靠 Python.NET 互操作,454 个 .py 示例与 C# 算法完全对等),以及回测与实盘统一(同一份 IAlgorithm 用户代码,靠换 config.json 里的 handler 字符串就能从回测切到真实券商)。本节先讲清楚定位、规模、技术栈、生态,再与 vnpy / backtrader 做对比,为后续钻取打地基。
内容来源:原项目源码
Launcher/Program.cs、Common/Globals.cs、Directory.build.props、Dockerfile*、Launcher/config.json,以及项目根目录结构。
⚠️ 注意:Lean 当前目标框架是
net10.0(.NET 10.0),非常新,默认 .NET 8/9 SDK 跑不起来,必须先装 dotnet 10 SDK。C# 与 Python 的对照关系贯穿全书——Lean 的 Python 算法不是"另一种引擎",而是通过 Python.NET(Python.Runtime/QuantConnect.pythonnet 2.0.64)直接复用 C# 引擎,语法是 Python,执行体是 C#。这点与 vnpy(纯 Python)有本质区别。
阅读完本节,你应当能够:
QuantConnect Lean 是一个云端 + 本地两用的开源算法交易引擎。开源协议是 Apache License 2.0(允许商用、允许修改、允许闭源衍生),出品方是 QuantConnect Corporation(美国纽约的量化平台公司)。Lean 既是 QuantConnect 自家云端平台 quantconnect.com 的底层引擎,也能在本地裸跑(本教程聚焦的 Launcher 项目就是本地入口)。
打开任意 Lean 源码文件,顶部都能看到统一的版权与协议头(如 Launcher/Program.cs:1-14):
1 /* 2 * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. 3 * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); ... 13 * limitations under the License. 14 */
注意第 2 行那句口号"Democratizing Finance, Empowering Individuals"(让金融民主化,赋能个人)——这解释了 Lean 的工程取向:面向个人和小团队,门槛要低,能力要工业级。这也是它坚持双语言、坚持开源、坚持 Docker 化的根本原因。
💡 钻取要点:Lean 的版本号是
v2.0(代码注释里写死),但实际版本由Globals.Version(Common/Globals.cs:111)在编译期注入。Program.cs:30里有一句关键告警常量_collapseMessage,描述的是"算法节点崩溃导致未处理异常外溢",这正是 Lean 把自己定位为"长期跑、不能崩"的服务进程的体现。
Lean 是个大体量项目。粗略统计,C# 文件约 4300 个、总代码量在百万行级。按子项目拆,核心几块的角色与体量大致是:
| 子项目 | 角色 | 大致行数(C#) |
|---|---|---|
| Common | 核心共享:数据结构、证券、组合、订单、Composer 装配、Python 互操作 | 约 27.4 万 |
| Engine | 引擎主体:Engine.cs / AlgorithmManager.cs / 各 handler 接口实现 | 约 3.7 万 |
| Indicators | 200+ 内置技术指标(EMA / RSI / MACD ...) | 约 3.1 万 |
| Algorithm | QCAlgorithm 基类 + 证券/组合的算法侧 API | 约 2.1 万 |
| Algorithm.Framework | 框架式建模(Alpha / Risk / Portfolio / Execution / Universe 五段流水线) | 约 0.75 万 |
| Brokerages | 40+ 券商对接 | 约 0.57 万 |
| ToolBox | 数据下载/转换工具 | 约 0.66 万 |
可以看出,Common 是绝对的体量大头(27.4 万行),因为所有共享的数据模型(Slice / BaseData / Tick / Bar)、证券体系(Security / Cash / Portfolio)、订单(Order / OrderTicket)、以及 Composer 装配器都在这里。Engine 本体反而只有 3.7 万行——这说明 Lean 的设计哲学是"引擎薄、模型厚":核心循环很紧凑,但每个概念都有详尽的数据模型支撑。
💡 钻取要点:对比 vnpy 整个仓库约 4 万行 Python,Lean 的 Common 一项就 27 万行——这是 C# 工业级引擎与 Python 轻量框架的数量级差异。但不要被行数吓到:本教程的钻取路线是"引擎层(Engine 3.7 万)→ 核心循环(AlgorithmManager 单文件 1045 行)",从最薄的入口切入,逐步深入 Common 的厚模型。
Lean 的目标框架写在 Directory.build.props(所有子项目共享):
<TargetFramework>net10.0</TargetFramework>
net10.0 是 .NET 10,发布周期上属于很新的版本。这意味着:
dotnet build 或 dotnet run --project Launcher 之前,先 dotnet --list-sdks 确认能看到 10.x。⚠️ 注意:
net10.0对应 C# 14 语法,Lean 源码里大量使用新特性:文件范围的 namespace、using全局指令、init属性、record、可空引用类型(NRT)。读源码时若看到string?这种带问号的类型,那是可空引用类型注解,不是可空值类型。
Lean 最大的工程亮点之一是同一套引擎,两种语言写算法。Python 不是"另一种引擎",而是通过 Python.NET(Python.Runtime DLL)直接调用 C# 引擎:
QuantConnect.pythonnet 2.0.64(NuGet 包),本质是 Python.Runtime.dll。Algorithm.Python/ 目录,共 454 个 .py 示例,每个都能找到对应的 C# 版本(如 BasicTemplateAlgorithm.py ↔ BasicTemplateAlgorithm.cs)。AlgorithmFactory 在 algorithm-language: "Python" 时,用 AlgorithmPythonWrapper 包装 .py 文件,内部经 Python.NET 把 Python 对象桥接成 C# 的 IAlgorithm。Program.cs:36-45 的静态构造器专门监控 Python 程序集的加载:
36 static Program() 37 { 38 AppDomain.CurrentDomain.AssemblyLoad += (sender, e) => 39 { 40 if (e.LoadedAssembly.FullName.ToLowerInvariant().Contains("python")) 41 { 42 Log.Trace($"Python for .NET Assembly: {e.LoadedAssembly.GetName()}"); 43 } 44 }; 45 }
这段代码订阅了 AppDomain.AssemblyLoad 事件——每当任何名字含 "python" 的程序集被加载,就打一条日志。说明 Python.NET 程序集是懒加载的:只有当 job 真的需要跑 Python 算法时,PythonInitializer.Initialize()(Common/Python/PythonInitializer.cs:31)才会触发 Python.Runtime 的初始化。回测纯 C# 算法时,Python 子系统根本不启动。
💡 钻取要点:C# / Python 对照表贯穿全书。例如:
IAlgorithm.OnData(Slice)↔ Python 里def OnData(self, slice):。algorithm.SetHoldings("SPY", 1.0)在两种语言里方法名与参数完全一致,因为 Python 端的self.AddEquity/self.SetHoldings实际都是经 Python.NET 调到 C# 的QCAlgorithm。- 写 Python 算法时遇到的奇怪报错(如"Unable to find method OnData"),多半是 Python.NET 的方法签名匹配问题,不是 Python 本身的问题。
Lean 提供一套 Dockerfile 覆盖多种部署形态:
| 文件 | 用途 |
|---|---|
Dockerfile |
主镜像,跑回测/实盘的默认容器 |
DockerfileLeanFoundation |
x86_64 基础镜像,装 Python 包 + 数据依赖 |
DockerfileLeanFoundationARM |
ARM64(如 Apple Silicon / 树莓派)基础镜像 |
DockerfileJupyter |
Jupyter 研究环境(Research) |
多架构的意义:Lean 既能跑在云端的 x86 集群上,也能在本地 M 系列 Mac 上原生跑 ARM 镜像,避免 QEMU 模拟的性能损耗。
除了裸 Docker,QuantConnect 还提供 lean CLI(Python 写的命令行工具,pip install lean),把 Docker 镜像封装成易用的命令:
lean init —— 初始化本地项目结构。lean backtest "My Algorithm" —— 用容器跑回测。lean live "My Algorithm" --brokerage ib —— 一键起实盘。lean cloud push/pull —— 与云端账户同步代码与结果。⚠️ 注意:本教程聚焦"裸跑"——直接
dotnet run --project Launcher+config.json,不用 lean CLI 也不用 Docker。这样能看清 Engine 的真实流程,不被容器层和 CLI 层遮蔽。理解了裸跑,Docker 和 CLI 只是包装层。
Lean 不只是股票引擎。它的资产类覆盖面(从 Common/SecurityType 枚举可数):
券商对接(Brokerages/ 项目 + 各 *Brokerage 命名的 NuGet/Project)覆盖 40+ 家:Interactive Brokers、Binance、Alpaca、Coinbase、Tradier、Oanda、Fxcm、Bitfinex、IQFeed、Zerodha、Samco 等。每家券商都通过统一的 IBrokerage 接口接入,详见后续章节。
把 Lean 放在中文社区最熟知的两个量化框架坐标里:
| 维度 | Lean | vnpy | backtrader |
|---|---|---|---|
| 语言 | C#(主)+ Python(算法) | 纯 Python | 纯 Python |
| 定位 | 工业级引擎,云端+本地 | 事件驱动框架,主打中国期货 | 教学/研究向回测框架 |
| 代码量 | 约 112 万行 C# | 约 4 万行 Python | 约 2 万行 Python |
| 事件模型 | 事件驱动(Synchronizer + TimeSlice) | 事件驱动(EventEngine + Queue) | 事件驱动(Cerebro + Strategy) |
| 实盘能力 | 强(40+ 券商官方对接) | 强(中国期货 CTP 最全) | 弱(主要回测) |
| 双语言 | C# + Python(Python.NET) | 单语言 | 单语言 |
| 部署 | Docker 多架构 + lean CLI | 本地 pip install + Qt GUI | 本地 pip install |
三者的共同点是事件驱动:都用"数据到来 → 触发回调 → 算法响应"的核心模型。差异在工程取向——Lean 是 C# 工业级、vnpy 是 Python 国产生态、backtrader 是轻量教学。本教程选 Lean,正是因为它的工业级设计(handler 装配、Isolator 隔离、MEF 反射)在量化工程上最有学习价值。
💡 钻取要点:如果你已经读过 vnpy 的 EventEngine(本系列 vnpy 卷第 2 章),会发现 Lean 的"事件"概念更重——它不是一条
Event(type, data)消息,而是一个 TimeSlice(一个时间点上所有订阅证券的数据快照)。Lean 主循环foreach (var timeSlice in Stream(...))直接按时间片迭代,粒度比 vnpy 的逐条 Queue 消息更粗,但每个片里数据更全。这是回测引擎(批量喂历史数据)和实盘网关(逐条推 tick)的设计分野。
QuantConnect.pythonnet 2.0.64)桥接,454 个 .py 示例与 C# 算法对等;Python 子系统懒加载,跑纯 C# 时不启动。pip install lean)。下一节,我们钻进
config.json——看 Lean 怎么靠"两层结构 + 字符串注入 handler"实现"回测实盘统一",这是理解整个 Engine 装配哲学的钥匙。