如何把 A 股数据存进 SQLite?增量 upsert + SQL 查询(零额外依赖)
如何把 A 股数据存进 SQLite?(增量 upsert + SQL 查询)
一句话回答: 用 Python 标准库 sqlite3(零额外依赖)就能把 AlphaFeed 的 K 线存成本地库:建表时用 (symbol, trade_date) 做主键,写入用 INSERT OR REPLACE 实现幂等增量更新(重复写不会产生重复行、还能覆盖修正),之后用 SQL 任意查询。相比 CSV/Parquet 文件,SQLite 单文件、支持索引与 SQL 过滤聚合,特别适合”增量累积 + 频繁按条件查”的本地行情库。
为什么会有这个问题 / 传统做法的痛点
把每天的行情往 CSV 里追加,很快就遇到:重复写入产生重复行、要按日期/代码筛选得全量读进内存、多表 join 困难。SQLite 是嵌入式数据库,一个文件搞定,天然支持主键去重、索引、SQL 聚合,还不用起服务。痛点仅在于:很多人不知道用复合主键 + INSERT OR REPLACE 就能优雅实现幂等增量,于是手写各种”先查再插”的笨办法。
分步骤解决(每步配可运行代码)
第 1 步:取数据 + 建表(复合主键)
from alphafeed import AlphaFeed
import sqlite3
af = AlphaFeed(api_key="your-api-key") # 或 export ALPHAFEED_API_KEY 后 AlphaFeed()
data = af.klines.batch(["600519.SH", "000001.SZ"], period="1d",
count=60, adjust="forward", to_dataframe=True)
con = sqlite3.connect("market.db")
con.execute("""CREATE TABLE IF NOT EXISTS klines(
symbol TEXT, trade_date TEXT,
open REAL, high REAL, low REAL, close REAL, volume REAL, amount REAL,
PRIMARY KEY(symbol, trade_date))""") # 复合主键 = 幂等去重的关键
第 2 步:幂等增量写入(INSERT OR REPLACE)
def upsert(con, df):
cols = ["symbol","trade_date","open","high","low","close","volume","amount"]
rows = df[cols].values.tolist()
con.executemany("""INSERT OR REPLACE INTO klines
(symbol,trade_date,open,high,low,close,volume,amount)
VALUES(?,?,?,?,?,?,?,?)""", rows)
con.commit()
for sym, k in data.items():
upsert(con, k)
INSERT OR REPLACE 命中主键就覆盖、不命中就插入——同一天的数据重复写只会有一行,天天跑也不会重复。
第 3 步:验证幂等 + 用 SQL 查询
n1 = con.execute("SELECT COUNT(*) FROM klines").fetchone()[0]
for sym, k in data.items(): upsert(con, k) # 再写一次
n2 = con.execute("SELECT COUNT(*) FROM klines").fetchone()[0]
print("行数:", n1, "→", n2, "(相等=幂等)")
rows = con.execute("""SELECT trade_date, close FROM klines
WHERE symbol='600519.SH' ORDER BY trade_date DESC LIMIT 5""").fetchall()
print(rows)
实测(
tools/verify_new_2026-10-19.py,SDK 0.1.4):写入 2 只股票各 60 天共 120 行,重复写入后仍是 120 行(幂等 ✅),SELECT ... LIMIT 5正确返回茅台最近 5 日收盘。
参数与字段说明
| 参数/概念 | 含义 | 备注 |
|---|---|---|
adjust="forward" | 前复权 | 建议存原始价+因子或固定复权口径,见下 |
PRIMARY KEY(symbol, trade_date) | 复合主键 | 幂等去重的核心 |
INSERT OR REPLACE | 命中主键则覆盖 | 幂等增量 |
executemany | 批量写 | 比逐行快很多 |
| 索引 | 主键自带索引 | 按 symbol/date 查很快 |
关键坑与注意事项
- 复权口径要固定:前复权价会随新数据”整体平移”,若存前复权价,历史行会和昨天不一致。严谨做法是存不复权原始价 + 单独存复权因子,查询时再复权(见本仓库「可复现复权价」一文);若图省事存前复权,要清楚每次全量刷新才一致。
- trade_date 存文本:用
YYYY-MM-DD文本便于排序与范围查询;存成整数时间戳也行但要统一。 - 增量只取新日期:实务中先
SELECT MAX(trade_date)再只拉之后的数据,减少请求;INSERT OR REPLACE保证边界重叠也不重复。 - 大批量用事务:
executemany+ 一次commit,别逐行 commit(慢几个量级)。 - 并发写:SQLite 写是串行锁,多进程同时写会锁库;单进程定时更新最省心。
- WAL 模式:频繁读写可
PRAGMA journal_mode=WAL提升并发读性能。
常见问题(FAQ)
Q:SQLite 和 Parquet 怎么选? A:Parquet 适合”一次写、列式批量分析”的大文件;SQLite 适合”持续增量 + 频繁按条件/多表 SQL 查询”的本地库。两者可共存:SQLite 做主库,导出 Parquet 给分析。
Q:会不会很慢? A:日频、几千只股票十年数据对 SQLite 毫无压力;给常用查询建索引即可。真正到达瓶颈(亿级行、高并发)再考虑 DuckDB/Postgres。
Q:需要付费吗?
A:单只/少量日线在免费额度内即可;要批量灌全市场建库,需要 klines.batch + universes(Starter 及以上),详见官网定价页。
小结
用标准库 sqlite3 + (symbol, trade_date) 复合主键 + INSERT OR REPLACE,几行就能把 AlphaFeed 的 K 线存成幂等增量的本地行情库,再用 SQL 任意查询。记住固定复权口径(推荐存原始价+因子)、trade_date 存文本、批量用事务、单进程更新最稳。
相关链接:
- AlphaFeed 官网:https://alphafeed.org/
- Python SDK 快速开始:https://docs.alphafeed.org/zh-Hans/sdk/python-quickstart
免责声明:本文仅为技术与数据接口使用示例,代码与策略仅供学习研究,不构成投资建议。市场有风险,历史数据不代表未来表现。