一句话回答:做因子计算的本地库,核心原则是存不复权原始价 + 单独存除权因子记录(复权在查询/计算时按需生成,别把某种复权价写死进库),并用长表(long format)、(symbol, trade_date)联合主键、按日期分区。用 AlphaFeed 的klines.batch(返回dict{symbol: DataFrame})灌历史、ex_factors存除权事件、instruments存标的元数据,三张核心表就能撑起大部分因子研究。AlphaFeed 不含财务/另类数据,基本面因子需从 Tushare/Wind 等另建表。
设计原则(避免以后返工)
- 存原始价,不存写死的复权价:前复权价会随最新除权变化,写死进库会导致历史被"改写"、不可复现。存
adjust="none"原始价 + 除权因子,复权在计算时生成。 - 长表优于宽表:
(symbol, trade_date, field...)长表便于加标的、加因子、做 groupby,别用"一列一只票"的宽表。 - 联合主键 + 幂等写入:
PRIMARY KEY(symbol, trade_date),用 upsert 保证增量重跑不产生重复。 - 元数据分离:标的信息(上市日、股本、tick、涨跌停)单独一张表,按需 join。
三张核心表
| 表 | 内容 | 数据来源(AlphaFeed) | 主键 |
|---|---|---|---|
daily_bar | 不复权日线 OHLCV+amount | klines.batch(adjust="none") | (symbol, trade_date) |
ex_factor | 除权因子事件记录 | ex_factors | (symbol, trade_date) |
instrument | 标的元数据(上市日/股本/tick/涨跌停) | instruments.batch | symbol |
fundamental*(可选) | 财务/基本面因子 | 需 Tushare/Wind 等 | (symbol, report_date) |
*AlphaFeed 不提供财务/龙虎榜/北向等,基本面因子表需从专门源灌入。
建表 + 灌数(可运行片段)
-- PostgreSQL / SQLite 通用思路CREATETABLEdaily_bar(symbolTEXTNOTNULL,trade_dateDATENOTNULL,openDOUBLEPRECISION,highDOUBLEPRECISION,lowDOUBLEPRECISION,closeDOUBLEPRECISION,volumeBIGINT,amountDOUBLEPRECISION,PRIMARYKEY(symbol,trade_date));CREATEINDEXidx_bar_dateONdaily_bar(trade_date);-- 因子按截面(某日全市场)取数时高效fromalphafeedimportAlphaFeedimportpandasaspd af=AlphaFeed()# export ALPHAFEED_API_KEYsymbols=["600519.SH","000001.SZ"]# batch 返回 dict{symbol: DataFrame}bars=af.klines.batch(symbols,period="1d",count=250,adjust="none",to_dataframe=True)frames=[]forsym,dfinbars.items():frames.append(df[["symbol","trade_date","open","high","low","close","volume","amount"]])daily=pd.concat(frames,ignore_index=True)# 长表,直接 to_sql / upsert 入 daily_barex=af.klines.ex_factors(symbols,to_dataframe=True)# 入 ex_factor 表meta=af.instruments.batch(symbols)# 入 instrument 表(展开 ext)print(daily.shape,ex.shape,len(meta))关键坑与注意事项
- 别把复权价写死进库:前复权随最新除权变化,写死会导致回测不可复现;存原始价 + 因子,计算时复权。
- 截面因子建日期索引:因子研究常"取某日全市场",
trade_date索引/分区能大幅提速。 - 幂等增量:每日增量用 upsert(
ON CONFLICT(symbol,trade_date) DO UPDATE),重跑不产生重复。 - 停牌与对齐:停牌日无成交(volume=0 或缺行),做因子前按交易日历对齐、明确停牌处理,别乱填充。
- 基本面另建源:财务因子 AlphaFeed 不提供,需从 Tushare/Wind 等灌入
fundamental表,注意用report_date/公告日避免未来函数。
常见问题(FAQ)
Q:存前复权还是不复权?
A:库里存不复权原始价,复权在查询/计算时按统一adjust口径生成,保证可复现。
Q:PostgreSQL 还是 SQLite?
A:个人单机 SQLite 够用;多进程/大数据量/并发写用 PostgreSQL。表结构思路一致。
Q:AlphaFeed 能提供因子/财务数据吗?
A:不提供财务与另类数据;它负责行情底座(原始价、除权因子、标的元数据),基本面因子需另建源。
小结
因子库设计三原则:存原始价 + 单独存除权因子(复权按需算)、长表 +(symbol,trade_date)主键、元数据分离。用 AlphaFeedklines.batch(dict 返回)灌行情、ex_factors存事件、instruments存元数据,三表起步;财务因子诚实地从专门源另建。地基对了,加因子、改复权口径、跑截面都不返工。
参考
- AlphaFeed Python SDK 文档:https://docs.alphafeed.org/zh-Hans/sdk/python-quickstart