你大概有过这样的经历:打开行情软件,盯着五只自选股,手动把价格抄进表格,再用计算器一个个算涨跌幅。一天下来眼睛发酸不说,还总在某个小数点上抄错行。而隔壁那位会用 Python 的朋友,早上九点半跑一个脚本,五只股票的价格、涨跌幅、均价全部自动生成,他只是端着咖啡扫了一眼输出。差别不在谁更聪明,而在于他把重复劳动交给了程序。
这门手艺有个名字:量化交易(Quantitative Trading),用数据和程序代替「感觉」来做交易决策。它不是神秘黑盒,拆开看就三件事——把想法写成明确的规则,用历史数据检验规则靠不靠谱,再让程序按规则自动执行。Python 能成为量化世界的主流语言,靠的是一套成熟到「要什么有什么」的生态:NumPy 管数值计算、Pandas 管表格数据、matplotlib 管画图、akshare 管拉取公开行情、Backtrader 管回测,而且全部开源免费。
先泼一盆冷水:量化不等于稳赚,程序只是把你的想法执行得更快、更守纪律,想法本身对不对,要靠数据检验。所以这套教程的前几篇不急着写策略,先把地基打牢。本篇就是第一块砖:讲清什么是量化交易、认识 Python 量化生态、把环境装好,最后写出你的第一个量化程序——打印各库版本号,再画一张折线图。跑通它的那一刻,你的量化工具链就算正式通电了。
本篇目标
- 能用自己的话说清量化交易和手工交易的差别,以及它适合解决什么问题。
- 能独立安装 uv,并用它为本合集创建一个独立的虚拟环境。
- 能说清 Jupyter Notebook 与 VS Code 各自适合什么场景,并完成基础配置。
- 能运行环境自检脚本,打印 Python、NumPy、Pandas、matplotlib 的版本号。
- 能用 matplotlib 画出一张带标题、坐标轴标签和图例的收盘价折线图,并保存成图片。
核心概念
什么是量化交易
给一个可以带走的定义:量化交易(Quantitative Trading)是把交易想法规则化、数据化、程序化的过程。它对应三个环节:
- 规则化:把「跌多了会反弹」这类模糊感觉,改写成可执行的明确条件,例如「当 5 日均线上穿 20 日均线时买入,下穿时卖出」。
- 历史检验:把规则放到历史行情上模拟执行,看看收益和回撤(Drawdown,从最高点回落的最大幅度)大概什么水平。这一步叫回测(Backtesting),是本合集第三阶段的主角。
- 自动执行:规则验证可行后,让程序盯盘、下单,人只负责监督。这是第六阶段的内容。
和手工盯盘相比,程序有三个压倒性优势:不知疲倦,可以同时盯几千只股票;不带情绪,规则说买就买,不会手抖;可复制,这套规则换个时间段再跑一遍,就知道还行不行。但它也有边界:历史规律可能失效,数据可能有错,代码可能有 bug,所以量化不是印钞机,而是一套让你「犯更少的错、犯错了能发现」的纪律工具。
顺便统一系列口径:本合集所有涉及成本的示例,手续费一律按双边 0.1%(万 10);无风险利率一律按年化 2%;回测区间示例统一用 2020-01-01 至 2024-12-31。先记个脸熟,后面每篇都沿用。
划重点:量化的第一步不是找一个「稳赚」的策略,而是把模糊的想法变成可检验的规则。想法可检验了,后面的一切才有意义。
Python 量化生态:你要的工具都有人开源好了
列几个本合集会用到的核心库,混个脸熟,后面各篇会逐一细讲:
- NumPy(Numerical Python):数值计算的地基,提供高效的数组(ndarray)和数学运算,第 3 篇主角。
- Pandas(Panel Data):表格数据处理神器,行情数据基本都以它的 DataFrame 形态存在,第 4、5 篇主角。
- matplotlib:绘图库,折线、K 线、收益曲线都靠它,第 6 篇主角。
- akshare:开源财经数据接口库,一行代码拉取 A 股公开行情,免费、无需注册,第 7 篇主角。
- Backtrader:开源回测框架,把下单、撮合、手续费都模拟好,第 21、22 篇主角。
Python 常被叫作「胶水语言」:重活有 C 语言写的 NumPy,画图有 C++ 底座的 matplotlib,Python 负责把这些高性能零件粘成你的策略。这正是它又好写又够快的秘诀。
uv:环境与包管理从哪开始
先说为什么需要环境管理。不同项目可能依赖同一个库的不同版本:项目 A 要新版 pandas,项目 B 的代码只兼容旧版,全装进一个 Python 里必然打架。解决方案是虚拟环境(Virtual Environment):每个项目一个独立隔离的 Python 环境,互不干扰。
数据科学圈传统的选择是 Python 自带的 venv + pip,或科学计算圈的 conda;本合集选用更现代的 uv——Astral 公司用 Rust 编写的 Python 环境与包管理器,一条命令行工具管到底,四个特点对新手特别友好:
- 快:装包速度比传统 pip 快一个数量级,akshare 这类依赖多的库几秒装完。
- 全:装 Python(
uv python install)、建虚拟环境(uv venv)、装包(uv pip install/uv add)、锁版本(自动生成uv.lock),不用再拼装 venv + pip + pyenv 三件套。 - 兼容:
uv pip install与pip install用法几乎一致,网上老教程的命令前面加个uv就能用。 - 可复现:项目模式自动维护
pyproject.toml(依赖清单)与uv.lock(精确版本锁),换台机器一条uv sync还原全部依赖——第 41、44 篇工程化时会靠它救急。
安装 uv(认准官方文档 https://docs.astral.sh/uv ;国内网络慢时的兑底方案是从 PyPI 装,可走清华镜像):
# Windows PowerShell(官方脚本)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# macOS / Linux(官方脚本)
curl -LsSf https://astral.sh/uv/install.sh | sh
# 兑底: 本机已有 Python 时, 直接从 PyPI 安装
pip install uv
装好后为本合集创建专用环境并装上基础三件套:
uv venv --python 3.11 # 当前目录创建虚拟环境 .venv, 用 Python 3.11
.venv\Scripts\Activate.ps1 # Windows PowerShell 激活(每次开新终端都要先激活)
source .venv/bin/activate # macOS / Linux 激活
uv pip install numpy pandas matplotlib # 安装基础三件套
执行激活命令后,命令行提示符前面出现 (.venv) 字样,说明已经切进环境。uv venv 发现本机没有 Python 3.11 时会自动下载对应解释器,不用自己装 Python——这是它比传统方案省心的地方。第 7 篇会再装 akshare(uv pip install akshare),现在不急。
划重点:不要把所有包都装进系统全局 Python。「一个项目一个虚拟环境」的习惯,将来能救你一命。
Jupyter Notebook 与 VS Code:怎么选、怎么配
Jupyter Notebook / JupyterLab 是交互式笔记本(Notebook,把代码拆成一个个单元格、可以单独运行、随手看结果的工具),特别适合学习阶段:写两行、跑一下、画个图马上看。启动方式:
uv pip install jupyterlab # 仅需安装一次(先激活 .venv)
jupyter lab # 启动后浏览器会自动打开
VS Code(Visual Studio Code,微软出品的免费编辑器)是另一条路:文件式代码管理、强力的断点调试,适合后期把策略写成正经工程。装上官方 Python 插件和 Jupyter 插件后,VS Code 里也能直接运行 Notebook,两边可以打通。
本合集的建议:前半程(打基础、探索数据)用 JupyterLab,后半程(写策略、做工程)用 VS Code。配置上唯一要先知道的小坑:matplotlib 默认字体不含中文,图里的中文会显示成方块「□」,解决办法是运行前设置字体,本篇完整代码里已经写好,直接抄即可。
完整代码
依赖安装:激活 .venv 环境后执行 uv pip install numpy pandas matplotlib。第一个程序是环境自检脚本,整份保存为 environment_check.py,然后在终端执行 python environment_check.py 运行:
# environment_check.py —— 量化环境自检脚本: 保存为文件后直接运行
import sys # 查询 Python 自身版本
import io # 在内存里模拟文件, 用于测试 pandas 读数据
import importlib # 按名字动态导入库, 用来逐个检查
import numpy as np
import pandas as pd
import matplotlib
matplotlib.use("Agg") # 无界面后端: 只存文件不弹窗, 任何机器都能跑
import matplotlib.pyplot as plt
def check_python() -> bool:
"""检查 1: Python 版本必须达到 3.10+。"""
ok = sys.version_info >= (3, 10) # 版本号逐段比较
print(f"[1] Python 版本: {sys.version.split()[0]}(要求 3.10+)")
return ok
def check_libs() -> bool:
"""检查 2: 核心库是否齐全, 并打印各自版本号。"""
ok = True
for name in ("numpy", "pandas", "matplotlib"):
try:
lib = importlib.import_module(name) # 导入成功说明已安装
print(f"[2] {name:<11}已安装, 版本: {lib.__version__}")
except ImportError: # 没装上也不崩, 给出明确补救命令
print(f"[2] {name:<11}缺失! 请执行: uv pip install {name}")
ok = False
return ok
def check_pandas() -> bool:
"""检查 3: pandas 能否正确读入一小段行情数据。"""
csv_text = "date,close\n2024-09-02,10.2\n2024-09-03,10.5\n" # 内存中的迷你 CSV
df = pd.read_csv(io.StringIO(csv_text)) # 当成文件来读
print(f"[3] pandas 读入 {len(df)} 行, 收盘价: {df['close'].tolist()}")
return len(df) == 2
def check_plot() -> bool:
"""检查 4: matplotlib 能否正常出图并存盘。"""
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [2, 4, 3]) # 随手画一条线
fig.savefig("selftest.png", dpi=100)
plt.close(fig) # 释放画布资源
print("[4] matplotlib 出图正常, 已保存 selftest.png")
return True
if __name__ == "__main__":
results = [check_python(), check_libs(), check_pandas(), check_plot()]
verdict = "环境自检通过, 可以开始学习!" if all(results) else "有检查项未通过, 请按提示补装。"
print(verdict)
自检通过后,跑你的第一张量化折线图。保存为 first_chart.py 用 python first_chart.py 运行,或直接粘进 Jupyter 单元格:
# first_chart.py —— 第一个量化程序: 画一张收盘价折线图
import numpy as np # 数值计算库
import pandas as pd # 表格与时间序列工具
import matplotlib.pyplot as plt # 绘图库
# 让图里的中文正常显示(Windows/macOS 常见字体挨个试)
plt.rcParams["font.sans-serif"] = ["SimHei", "PingFang SC", "Microsoft YaHei"]
plt.rcParams["axes.unicode_minus"] = False # 让负号正常显示
# 1. 造 20 个交易日的模拟收盘价(教学示意数据, 第 7 篇会换成 akshare 真实行情)
rng = np.random.default_rng(seed=42) # 固定随机种子, 保证结果可复现
daily_returns = rng.normal(loc=0.0005, scale=0.015, size=19) # 19 个日收益率
close_prices = np.concatenate([[10.0], 10.0 * np.cumprod(1 + daily_returns)]) # 期初固定 10 元
dates = pd.date_range(start="2024-09-02", periods=20, freq="B") # 20 个工作日
# 2. 画图
fig, ax = plt.subplots(figsize=(8, 4)) # 新建一张 8×4 英寸的画布
ax.plot(dates, close_prices, marker="o", linewidth=1.5, label="收盘价")
ax.set_title("某虚拟股票近 20 个交易日收盘价(模拟数据)")
ax.set_xlabel("日期")
ax.set_ylabel("价格(元)")
ax.grid(alpha=0.3) # 半透明网格线
ax.legend() # 显示图例
# 3. 打印关键数字并把图保存到本地
print(f"期初价格: {close_prices[0]:.2f} 元")
print(f"期末价格: {close_prices[-1]:.2f} 元, 区间涨跌幅: {(close_prices[-1] / close_prices[0] - 1) * 100:.2f}%")
print(f"区间最高: {close_prices.max():.2f} 元, 区间最低: {close_prices.min():.2f} 元")
fig.savefig("first_chart.png", dpi=150, bbox_inches="tight") # 保存图片
plt.show() # 脚本方式弹窗显示, Jupyter 方式内嵌显示
代码逐段解释
- 导入与
matplotlib.use("Agg"):import把库加载进内存。Agg是「不出图窗、只写文件」的后端,让自检脚本在没有显示器的服务器上也能跑。注意:在 Jupyter 里运行画图代码时不要加这一行,否则图不会内嵌显示。 - 三个检查函数:各自负责一件事,返回
True/False。check_libs用try/except ImportError兜底——没装的库不让程序崩溃,而是打印补救命令,这才是自检脚本的正确姿势。 if __name__ == "__main__":意思是「直接运行本文件时才执行下面的代码」,将来被别的文件导入时不会自动执行。现在照抄即可,第 41 篇工程化改造会展开讲。- 汇总判定:把四个检查的布尔结果放进列表,
all(results)全为真才宣布通过,任何一个失败都会给出明确提示。 - 画图代码的模拟数据:
np.random.default_rng(seed=42)是新一代随机数生成器,固定种子保证每次运行结果一样;rng.normal(...)生成 19 个日收益率;np.cumprod(1 + 收益率)沿时间累乘还原价格曲线——这两行第 3 篇会细讲,先会用。np.concatenate([[10.0], ...])把期初价 10 元接在最前面,所以恰好 20 个价格、期初固定是 10.00。 - 时间轴与画图:
pd.date_range(..., freq="B")生成 20 个工作日(Business day)作横轴;ax.plot画线,set_title / set_xlabel / set_ylabel加标题与轴标签,grid加网格,legend加图例;savefig存图,plt.show展示。开头那两行rcParams字体设置就是解决中文乱码的关键。
自检脚本的运行结果(示意输出,具体版本号以你的环境为准):
[1] Python 版本: 3.11.9(要求 3.10+)
[2] numpy 已安装, 版本: 1.26.4
[2] pandas 已安装, 版本: 2.2.2
[2] matplotlib 已安装, 版本: 3.8.4
[3] pandas 读入 2 行, 收盘价: [10.2, 10.5]
[4] matplotlib 出图正常, 已保存 selftest.png
环境自检通过, 可以开始学习!
折线图脚本的运行结果(示意输出,随机数在固定种子下可复现,不同版本可能略有差异):
期初价格: 10.00 元
期末价格: 10.31 元, 区间涨跌幅: 3.10%
区间最高: 10.47 元, 区间最低: 9.72 元
同时当前目录会多出 first_chart.png,打开就是一条从 10 元附近出发、小幅波动的价格折线。
常见坑与小练习
常见坑:
- 系统里有多套 Python,包装错位置。现象:命令行里
python的版本和装包的位置对不上,包装了却 import 不到。原因:多套解释器共存,环境变量指向混乱。避免:养成「先激活.venv再动手」的习惯;uv 装包永远只进当前激活的虚拟环境,天然隔离。 - 包装进了全局 Python。现象:明明装了 pandas,Jupyter 里却报
ModuleNotFoundError。原因:装包前没激活.venv,包落在了别的环境里。避免:每次开终端先激活环境,再启动 Jupyter 或执行uv pip install。 - 画图中文变方块。现象:标题和轴标签显示成「□□」。原因:matplotlib 默认字体不含中文。避免:运行前设置
font.sans-serif(本篇代码已包含),字体名按操作系统换。 - Notebook 跑出「幽灵结果」。现象:改了代码重跑,输出却像新旧混合。原因:Jupyter 内核状态是累积的,旧变量还留在内存里。避免:改动大时用 Kernel → Restart & Run All,验证脚本从零可跑。
小练习:
- 创建第二个虚拟环境(Python 3.10),只装旧版 pandas 1.5.3,分别在两个环境里打印 pandas 版本,亲眼看到环境隔离。
思路提示:另建一个目录执行
uv venv --python 3.10,激活后uv pip install pandas==1.5.3,再依次在两个环境里运行python -c "import pandas; print(pandas.__version__)"。 - 把自检脚本的库清单加上 akshare:先
uv pip install akshare,再修改脚本让它一并检查并打印版本号。思路提示:
check_libs循环里的元组加一项"akshare"即可,它的导入名就是akshare。 - 把折线图改成 60 个交易日、起点价 50 元,保存文件名改成
first_chart_60d.png,观察曲线形态变化。思路提示:改
size=59、np.concatenate的起点值50.0和periods=60,三处要一致。
本文内容仅用于教学,不构成投资建议,实盘前请充分测试。