【量化系统从零构建 #04】存储设计:选型·建库·交易日历

【量化系统从零构建 #04】存储设计:选型·建库·交易日历

系列:《量化系统从零构建》|连载项目 · 纯 GET 取数 · 仅依赖 requests

适用:想给取数层配一个本地存储底座的读者;本篇是纯本地存储层,不发起网络请求,直接基于标准库 sqlite3 建库,为 #05 行情落库铺路。

1. 你将得到什么

  • 存储选型结论 :落库用 SQLite (零依赖、单文件、随开随用);分析导出用 Parquet (列式、压得小);即席分析用 DuckDB(直接 SQL 读 Parquet)。新手默认 SQLite 就够。
  • 建库函数 init_db :建好 trade_calendar(交易日历)与 stocks(股票清单)两张骨架表。
  • 交易日历 seed_calendar:用标准库生成工作日(周一至周五)写入日历表,并给出「取某月首个交易日」示例。
  • 本篇交付 :后续 #05--#08 的所有落库表都挂在这个库上,取数层(ZhituClient)拉到的数据落进这里。

2. 本篇取数约定

本篇是纯本地存储层,不发起任何网络请求 ,直接用 Python 标准库 sqlite3,不装任何第三方数据库驱动。下面的代码可在本地直接跑。

3. 存储选型对比

方案 角色 优点 何时用
SQLite 主落库 单文件、零依赖、事务稳 默认;每日增量更新、按代码/日期查询
Parquet 分析导出 列式压缩、读大表快 把日线/财务导出给 pandas 做离线分析
DuckDB 即席分析 直接 SQL 读 Parquet,免加载 多文件聚合、复杂 SQL 透视

本系列默认 SQLite 落库。Parquet / DuckDB 是「分析延伸」,用到时再引入,不影响主线。

4. 核心模板函数

python 复制代码
import sys, sqlite3, datetime

# ── 建库:交易日历 + 股票清单骨架 ──
def init_db(path=":memory:"):
    """建库并返回连接。path 给文件名即落盘,给 :memory: 即内存库。"""
    conn = sqlite3.connect(path)
    cur = conn.cursor()
    cur.execute("""
    CREATE TABLE IF NOT EXISTS trade_calendar (
        date TEXT PRIMARY KEY,
        year INT, month INT, day INT, weekday INT,
        is_trading_day INT
    )""")
    cur.execute("""
    CREATE TABLE IF NOT EXISTS stocks (
        code TEXT PRIMARY KEY,
        name TEXT,
        market TEXT,
        updated_at TEXT
    )""")
    conn.commit()
    return conn


def _weekdays(start, end):
    """生成 [start, end] 内的周一至周五(近似交易日,未剔除法定节假日)。"""
    s = datetime.date.fromisoformat(start)
    e = datetime.date.fromisoformat(end)
    d, out = s, []
    while d <= e:
        if d.weekday() < 5:            # 0=周一 ... 4=周五
            out.append(d)
        d += datetime.timedelta(days=1)
    return out


def seed_calendar(conn, start, end):
    """把 [start, end] 的工作日写入交易日历表,返回写入条数。"""
    cur = conn.cursor()
    rows = [(d.isoformat(), d.year, d.month, d.day, d.weekday(), 1)
            for d in _weekdays(start, end)]
    cur.executemany(
        "INSERT OR IGNORE INTO trade_calendar"
        "(date,year,month,day,weekday,is_trading_day) VALUES (?,?,?,?,?,?)", rows)
    conn.commit()
    return len(rows)


def first_trading_day(conn, year, month):
    """返回某年某月的第一个交易日(ISO 字符串),无则 None。"""
    cur = conn.cursor()
    cur.execute(
        "SELECT date FROM trade_calendar WHERE year=? AND month=? ORDER BY date LIMIT 1",
        (year, month))
    row = cur.fetchone()
    return row[0] if row else None


def run_check():
    # 合成数据仅逻辑校验(标准库,非真实行情)
    conn = init_db(":memory:")
    n = seed_calendar(conn, "2024-01-01", "2024-01-31")
    assert n == 23, n                      # 2024-01 共 23 个工作日
    cur = conn.cursor()
    cur.execute("SELECT COUNT(*) FROM trade_calendar WHERE weekday>=5")
    assert cur.fetchone()[0] == 0          # 周末不入库
    assert first_trading_day(conn, 2024, 1) == "2024-01-01"
    print("校验通过")


if __name__ == "__main__":
    if len(sys.argv) > 1 and sys.argv[1] == "--check":
        run_check()
    else:
        conn = init_db("quant.db")
        print("交易日历已建,2024-01 工作日数:",
              seed_calendar(conn, "2024-01-01", "2024-01-31"))

5. 跑通示例

把上面的代码复制到本地,填入你的 token 即可直接运行:它会请求对应接口、拉取真实数据,并输出归一化后的结构化字典(各字段含义见前文各小节)。

6. 坑与注意事项

  1. 近似交易日历要补节假日 :_weekdays 只排除周末,未剔除法定节假日(如元旦、春节)。实盘前需补一份交易日集合(可先用历史数据反推或手动维护一张表)。
  2. INSERT OR IGNORE 防重 :日历 date 是主键,重跑 seed_calendar 不会重复插入。
  3. 内存库 :memory: 仅当次会话有效 :run_check 用内存库验证逻辑;正式落库请传真实文件名(如 quant.db)。
  4. SQLite 并发写入弱:本系列是单进程定时更新,够用;多进程并发写要上 WAL 或换引擎。

7. 小结与下篇预告

本篇把存储底座钉死:SQLite 主库 + 交易日历表,并给出选型对比(Parquet / DuckDB 作分析延伸)。这是 #05--#08 落库章节的共同地基。

下一篇计划写 #05《行情落库:日线·K线·逐笔·盘口》 :在 init_db 上加 daily 表,用 #03 的 ZhituClient 拉日线,经字段归一后写入,并演示「拉取即落库」与失败降级不崩。

8. 免责声明

本文仅演示本地存储与接口字段归一的用法,所有代码示例均为演示数据,未含任何真实数据;文中示例数据仅作演示用途,不构成投资建议,亦不承诺收益。

相关推荐
Dawson Zhu21 小时前
【LLM推理与Serving⑨】业务模型推理引擎开发:以BEV自动驾驶为例的专用推理实践
人工智能·语言模型·架构·aigc·agi
用户0190275816121 小时前
AlphaFeed 标的池(universes)全解:CN_Stock / CN_ETF 与权限边界
python
文丑颜不良啊21 小时前
LeetCode2541~2560题目解析
java·leetcode
瑞雪兆丰年兮21 小时前
JavaWeb-day11-SpringBootWeb案例(文件上传)
java·运维·服务器·javaweb·oss
袁俪1 天前
数字孪生协同
人工智能
青少儿编程课堂1 天前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会Scratch考级:校园连连看解析
c++·python·算法·bfs·信息学竞赛
海拥✘1 天前
让 AI 修 AI 平台自己的 Bug:我用 SoduWork 给 SoduWork 提了一个 PR
人工智能·bug
挖掘狂人1 天前
AI 把代码写得飞快,然后呢?聊聊我验收生成代码的一套流程
人工智能·程序员·ai编程
汤姆宝库1 天前
推理服务器的调度器:连续批处理与请求生命周期
人工智能
Highcharts.js1 天前
Highcharts智能数据分析平台Orbit 多语言配置技术文档
java·前端·javascript·highcharts·orbit·智能数据分析·设置文档