量化交易 PostgreSQL 建表指南:K 线数据 + 信号记录 + 性能优化

量化系统跑到一定阶段,CSV 一定会成为瓶颈。本文给出一个生产级的 PostgreSQL 建表方案。

为什么 CSV 不够用

场景 CSV 耗时 PostgreSQL 耗时
查茅台近 20 天收盘价 ~30s <0.1s
对比 50 只股一年涨幅 ~5min <1s
多策略并行读写 文件锁冲突 ACID 保障
重复数据去重 手动 UNIQUE INDEX

1. K 线数据表

sql 复制代码
CREATE TABLE daily_prices (
    id            SERIAL PRIMARY KEY,
    symbol        VARCHAR(10) NOT NULL,
    trade_date    DATE NOT NULL,
    open          NUMERIC(12,4),
    high          NUMERIC(12,4),
    low           NUMERIC(12,4),
    close         NUMERIC(12,4),
    volume        BIGINT,
    amount        NUMERIC(16,2),
    created_at    TIMESTAMP DEFAULT NOW()
);

CREATE UNIQUE INDEX idx_symbol_date 
  ON daily_prices(symbol, trade_date);

CREATE INDEX idx_date ON daily_prices(trade_date);

类型选择

类型 为什么
open/high/low/close NUMERIC(12,4) 定点数,无浮点误差。4 位兼容港股美股
volume BIGINT 日成交可达数亿股,INTEGER 不够
amount NUMERIC(16,2) 成交额可达数千亿,预留空间
trade_date DATE 不带时区,A 股统一北京时间

为什么不用 FLOAT?

python 复制代码
>>> 0.1 + 0.2 == 0.3
False

金融场景不允许这种误差。NUMERIC 是定点数,牺牲一点速度换绝对精度。


2. 信号表

sql 复制代码
CREATE TABLE signals (
    id            SERIAL PRIMARY KEY,
    symbol        VARCHAR(10) NOT NULL,
    strategy      VARCHAR(50) NOT NULL,
    signal_type   VARCHAR(10) NOT NULL CHECK (signal_type IN ('BUY','SELL','HOLD')),
    price         NUMERIC(12,4),
    reason        TEXT,
    created_at    TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_signals_time ON signals(created_at DESC);
CREATE INDEX idx_signals_symbol ON signals(symbol);

CHECK 约束防止脏数据(如 signal_type = 'buy' 大小写不一致)。


3. Upsert:避免重复拉取产生脏数据

python 复制代码
from sqlalchemy.dialects.postgresql import insert

def upsert_kline(engine, df):
    """插入或更新 K 线数据"""
    rows = df.to_dict('records')
    stmt = insert(DailyPrice).values(rows)
    stmt = stmt.on_conflict_do_update(
        constraint='idx_symbol_date',
        set_={
            'open': stmt.excluded.open,
            'high': stmt.excluded.high,
            'low': stmt.excluded.low,
            'close': stmt.excluded.close,
            'volume': stmt.excluded.volume,
            'amount': stmt.excluded.amount,
        }
    )
    engine.execute(stmt)

定时任务多次拉同一天数据 → ON CONFLICT DO UPDATE 只更新不复写。


4. Python 批量入库

python 复制代码
import pandas as pd
from sqlalchemy import create_engine

engine = create_engine(
    'postgresql://user:pass@localhost:5432/quantdb'
)

df = pd.read_csv('daily_data.csv')
df.to_sql('daily_prices', engine,
          if_exists='append',
          index=False,
          method='multi',       # 批量 INSERT
          chunksize=1000)       # 分批提交

method='multi' 把多行合并成一条 INSERT,比单条插入快 10 倍以上。


5. 常用查询

sql 复制代码
-- 最近 N 天 K 线
SELECT trade_date, open, high, low, close, volume
FROM daily_prices
WHERE symbol = '600519'
ORDER BY trade_date DESC
LIMIT 20;

-- 今日涨幅 TOP 10
SELECT symbol,
       ROUND((close - prev_close) / prev_close * 100, 2) AS pct_change
FROM (
    SELECT symbol, close,
           LAG(close) OVER (PARTITION BY symbol ORDER BY trade_date) AS prev_close
    FROM daily_prices
    WHERE trade_date >= CURRENT_DATE - INTERVAL '2 days'
) t
WHERE trade_date = (
    SELECT MAX(trade_date) FROM daily_prices WHERE symbol = t.symbol
)
ORDER BY pct_change DESC
LIMIT 10;

-- 连续上涨天数
SELECT symbol, COUNT(*) AS up_days
FROM (
    SELECT symbol, trade_date,
           close > LAG(close) OVER (PARTITION BY symbol ORDER BY trade_date) AS is_up
    FROM daily_prices
    WHERE trade_date > CURRENT_DATE - INTERVAL '10 days'
) t
WHERE is_up
GROUP BY symbol
HAVING COUNT(*) >= 3;

6. 数据量大了怎么办

数据量 方案 效果
<100 万条 默认配置 无需优化
100 万 ~ 1000 万 加索引 + 调 work_mem 查询毫秒级
>1000 万 (分钟线) TimescaleDB 插件 自动分区 + 10:1 压缩
sql 复制代码
-- TimescaleDB 一键转时序表
SELECT create_hypertable('daily_prices', 'trade_date');

-- 7 天后自动压缩
SELECT add_compression_policy('daily_prices', 
    INTERVAL '7 days');

选型速查

方案 适用
CSV 0-1 股回测,快速原型
SQLite 10-50 股,本地单机
PostgreSQL 全市场 5000+,生产环境
+TimescaleDB 分钟级 × 全市场,高频

早点切到 PG,省下的排查时间比写建表语句多得多。

相关推荐
极客三刀流1 天前
windows版jdk版本管理工具
产品
用户559135782634 天前
四大免费数据源代码实测
产品
用户559135782635 天前
Python + PostgreSQL + Docker 技术选型实战
产品
AskHarries6 天前
我如何从1000个产品里筛出方向
人工智能·产品·全栈
华洛7 天前
讲讲如何在传统产品中挖掘AI需求
javascript·产品经理·产品
小北的AI科技分享7 天前
产品管理:从概念到落地的全流程解析
产品··经理
字节逆旅10 天前
Marvis:腾讯悄悄搞了个 AI 桌面助手,有点意思
agent·产品
AskHarries10 天前
如何判断一个需求是真需求
人工智能·程序员·产品
全栈人月13 天前
技术人也要懂市场
产品