计算机应用技术博士,10年金融科技风控模型和策略经验。现在用AI + Python,把这套背景重新用在量化交易系统上——从数据、策略、回测到实盘,每一步都公开代码和结果,不讲空话。 如果你也想用AI武装自己的交易系统,欢迎加入「AI量化」社群,和一群真正动手做的人一起,把量化这件事跑通。
Day1 我们跑通了 MT5 + Python 的连接测试,Day2 我们画好了系统的"建筑蓝图"——数据层、策略层、执行层、监控与回测层。
从今天开始,我们正式动工,第一站:数据层。
量化圈有句话很扎心:"策略再花哨,数据一脏,全是幻觉。" 今天我们要做的,就是给系统打好这块地基——用 Python 一键拉取黄金(XAUUSD)过去10年的历史行情数据,并顺手计算第一个技术指标,验证数据是"能用"的。
01 为什么数据层要先做,而且要做扎实
很多人学量化,第一反应是"我要一个能赚钱的策略",直接跳到策略层。但策略是建立在数据之上的——
- 历史数据的时间跨度不够长:只用近1-2年数据回测,很容易把"牛市里怎么做都赚钱"误认为"策略有效"
- 数据里混着杂质:跳空、缺失、错误的tick,会让回测结果失真,你以为策略赢了,其实是数据骗了你
- 多周期数据没对齐:日线定趋势、小时线找入场点,这是后面策略层要用到的,今天先把"取数据"这件事做对、做稳
所以今天这篇,看起来"朴素",但决定了后面十几天的策略和回测结果是否可信。
02 环境确认
沿用 Day2 搭好的 mt5ea 虚拟环境,今天新增两个包:
conda activate mt5ea
pip install pyarrow python-dotenv
pyarrow 用来把数据存成 Parquet 格式——比 CSV 更小、读写更快,这一点在后面几天数据量变大之后你会有体感。python-dotenv 用来管理登录凭据,原因见下一节。
03 环境验证:先解决连接问题,再谈拉数据
这一节是我实测跑通过程中踩的坑,专门加出来,因为十个人里至少有三四个会卡在这一步,比拉数据本身更容易出问题。
第一步:用最小脚本单独验证连接,别直接跑大脚本
import MetaTrader5 as mt5
from loguru import logger
logger.info("正在验证交易环境...")
ifnot mt5.initialize():
logger.error(f"MT5 初始化失败, error code = {mt5.last_error()}")
else:
logger.success("AI 交易环境 Ready!")
mt5.shutdown()
如果这一步报错 (-6, 'Terminal: Authorization failed'),按顺序排查:
- MT5终端和运行脚本的进程,权限级别要一致:Windows 不允许管理员权限进程和普通权限进程互相通信,两边要么都以管理员身份运行,要么都不是。
- 如果权限对齐后依然报 -6,大概率是终端的登录会话已经失效,哪怕界面上显示仍是登录状态。最快的解决方式不是找回密码,而是在MT5里"文件→打开一个交易账户"重新申请一个新的模拟账户,记录下新的登录名/密码/服务器,问题基本能解决。
- 申请新账户时会遇到"锁仓交易(Hedging)"选项:建议勾选,因为这更贴近真实经纪商的交易环境(同一品种可同时持有多空仓位)。记住这个选择,Day18写订单管理模块时要按 Hedging 模式设计,用 ticket 号追踪单个订单,不能假设"一个品种=一个仓位"。
第二步:登录凭据不要硬编码,用 .env 管理
mt5.initialize() 不带参数时是"蹭"已打开终端的登录会话,会话失效就会报错。更稳妥的做法是显式传入账号信息,同时把凭据放进 .env 文件而不是写死在代码里——毕竟这套代码后面要发到公众号、可能要开源,硬编码密码会很尴尬。
项目根目录新建 .env:
MT5_LOGIN=你的账号
MT5_PASSWORD=你的密码
MT5_SERVER=MetaQuotes-Demo
再新建 .gitignore,写入一行 .env,确保这个文件永远不会被传到GitHub或其他公开渠道。
04 实战:一键拉取10年黄金历史数据
新建 fetch_gold_history.py:
import os
import MetaTrader5 as mt5
import pandas as pd
from datetime import datetime
from dotenv import load_dotenv
from loguru import logger
load_dotenv()
SYMBOL = "XAUUSD"
TIMEFRAME = mt5.TIMEFRAME_D1 # 先从日线开始
START = datetime(2016, 1, 1)
END = datetime.now()
deffetch_history():
authorized = mt5.initialize(
login=int(os.getenv("MT5_LOGIN")),
password=os.getenv("MT5_PASSWORD"),
server=os.getenv("MT5_SERVER"),
)
ifnot authorized:
logger.error(f"MT5初始化失败: {mt5.last_error()}")
returnNone
# 确保品种在市场报价窗口中可见
ifnot mt5.symbol_select(SYMBOL, True):
logger.error(f"品种{SYMBOL}不可用,请检查MT5市场报价窗口")
mt5.shutdown()
returnNone
rates = mt5.copy_rates_range(SYMBOL, TIMEFRAME, START, END)
mt5.shutdown()
if rates isNoneor len(rates) == 0:
logger.error("未获取到任何数据,请检查经纪商历史数据窗口限制")
returnNone
df = pd.DataFrame(rates)
df["time"] = pd.to_datetime(df["time"], unit="s")
df = df.rename(columns={
"time": "datetime", "open": "open", "high": "high",
"low": "low", "close": "close", "tick_volume": "volume"
})
df = df[["datetime", "open", "high", "low", "close", "volume"]]
logger.success(f"拉取成功: {len(df)}条记录,时间范围 {df['datetime'].min()} ~ {df['datetime'].max()}")
return df
if __name__ == "__main__":
df = fetch_history()
if df isnotNone:
df.to_parquet("XAUUSD_D1_history.parquet", index=False)
logger.info(f"已保存至 XAUUSD_D1_history.parquet,占用空间约 {df.memory_usage(deep=True).sum() / 1024:.1f} KB")
print(df.head())
print(df.tail())
运行结果验证:
2026-08-06 19:38:20.496 | SUCCESS | __main__:fetch_history:46 - 拉取成功: 2734条记录,时间范围 2016-01-04 00:00:00 ~ 2026-08-06 00:00:00
2026-08-06 19:38:20.536 | INFO | __main__:<module>:53 - 已保存至 XAUUSD_D1_history.parquet,占用空间约 128.3 KB
三个关键点务必对照检查:
- 记录条数:日线10年大约2500-2700条(剔除周末),如果只有几百条,大概率是经纪商历史数据窗口限制,需要在MT5客户端里先手动下拉图表加载历史数据,再跑脚本
- 文件大小:Parquet比同样数据的CSV通常小60%-80%,这是后面几天数据量增加后你会用到的优势
05 顺手计算第一个技术指标:20日均线
拉到数据后,别急着收工,我们用最基础的方式(不引入第三方指标库,先自己手写一遍,理解原理),计算一个20日简单移动平均线:
import pandas as pd
df = pd.read_parquet("XAUUSD_D1_history.parquet")
df["MA20"] = df["close"].rolling(window=20).mean()
print(df[["datetime", "close", "MA20"]].tail(10))
为什么先手写而不是直接调库?
因为下一篇(Day4)我们会用 pandas-ta 一次性算出200+个指标,如果没有先理解"移动平均线 = 过去N根K线收盘价的算术平均"这个最基础的逻辑,调库只会变成"黑箱调用"——知道函数名,不知道数字从哪来,后面调参和排查异常都会很吃力。
06 今日踩坑与代码验证清单
对照检查你的运行结果:
- [ ] MT5客户端已登录模拟账户,且未处于"演示行情已过期"状态
- [ ] 单独跑第03节的最小验证脚本,确认返回 "AI 交易环境 Ready!" 再执行拉数据脚本
- [ ] 如遇
(-6, 'Terminal: Authorization failed'),先对齐终端和脚本的权限级别,仍不行则重开模拟账户 - [ ]
.env 文件已正确配置三个变量,且被 .gitignore 排除 - [ ]
symbol_select 返回 True(品种已加入市场报价) - [ ] Parquet文件能被正常读取(
pd.read_parquet 无报错) - [ ] MA20 前19行为 NaN(正常现象,滚动窗口不足20根K线时无法计算)
07 接下来的计划
数据层还剩4天:
- Day4:用
pandas-ta 一键计算200+技术指标,理解"指标≠策略" - Day5:多周期数据对齐 + 实时Tick数据接入
- Day6:数据质量校验体系——缺失值、异常跳空、时区错位三大坑
- Day7:把这4天代码整合成可复用的数据模块,数据层收官
这一步你踩坑了吗?如果你遇到 (-6, 'Terminal: Authorization failed'),或者 copy_rates_range 拿到的数据条数远少于预期,欢迎把报错信息和经纪商名称发到群里,一起排查。
加入「AI量化」社群我们在这里做一件事:把"学AI量化"从看文章变成真动手——每天有人贴出自己的代码、数据、回测结果,互相挑错、互相验证。21天系列的完整代码库和后续实盘验证进展,也会优先在群里更新。
扫码加入 👇
备注:量化