资讯动态

AKShare期货基本面数据:基差库存仓单日频宽表构建

发布时间:2026/10/29 20:42:24 来源:尧图企业网站定制
期货基本面数据这块最难受的从来不是没有数据而是数据太散。基差要看现货报价和期货主力价格库存要分交易所库存和社会库存仓单有日报和明细两张表套利价差还得自己把近远月合约对齐。每一路数据的来源、频率、字段命名都不一样拼一次表能写两百行代码。AKShare 里有不少以“奇货可查”为数据来源的期货基本面函数把基差、库存、仓单、库存汇总这几类数据统一收进了一个 Python 包里省掉了大量抓取和维护的力气。这篇内容就围绕这几类接口展开它们各自返回什么、字段怎么对齐、基差率怎么算才不会算反、库存和仓单为什么不能混着用、以及怎么把这三张表拼成一张能直接下判断的日频宽表。适合已经会写基础 Pandas、正在搭期货研究数据底座的读者也适合刚接触基本面量化、想搞清楚“这些数字从哪来”的朋友。1. 基本面数据难拿的根子不在技术上1.1 基差、库存、仓单三组数字各自解决什么问题先说清楚这三样东西在交易逻辑里的位置不然后面写代码全是机械搬运。基差解决的是“期货贵不贵”的问题。基差 现货价 − 期货价它衡量的是期货相对现货的升贴水。基差走强意味着现货相对坚挺或者期货跌得更狠通常对应现货紧张、库存偏低基差走弱则相反。做期现套利的人盯着基差是否超出交割成本和资金成本构成的无套利区间做单边的人拿基差方向当情绪温度计。库存解决的是“货多不多”的问题。库存分好几层交易所注册仓单对应的显性库存、贸易商手里的社会库存、港口库存、厂库库存。不同口径差别巨大一个品种的社会库存可能是交易所库存的十几倍。库存的绝对量意义有限真正有价值的是环比变化和季节性位置——同样是 50 万吨在累库周期的起点和在去库周期的末端含义完全相反。仓单解决的是“能不能交割”的问题。仓单是注册在交易所的标准化提货凭证它直接决定了近月合约的交割压力和挤仓风险。仓单大幅增加往往意味着卖方交割意愿强近月承压仓单快速注销流出则说明货被拉走了现货可能转紧。仓单还有有效期和强制注销制度某些品种每到特定月份会集中注销这时候仓单数据的同比意义远大于环比。这三组数据合起来才构成了一个品种“现货紧张度”的完整画像。缺任何一块判断都会偏。1.2 数据源分散带来的三个现实麻烦我在实际拼数据的时候被这三件事反复折磨过。第一个是口径不一致。现货报价有含税不含税之分有的报价是出厂价有的是送到价有的是港口自提价。期货价格是含税的标准化价格。你如果直接拿一个不含税的现货价去减期货价算出来的基差可能整整差一个数量级看着像极端机会其实是口径错了。库存也一样有的数据源报的是“吨”有的是“手”有的是“张”一手对应多少吨每个品种还不一样。第二个是频率不一致。基差数据是日频库存有的是日频有的是周频仓单是日频但周末和节假日不更新。你在做时间序列对齐的时候如果用简单的 merge很容易出现大量 NaN或者不小心用了未来数据——比如周五的库存被填充到了周四。第三个是字段名漂移。同一个含义的列在不同接口里可能叫库存、inventory、stock、数量。接口升级一次列名改一次你的脚本就崩一次。这个问题在开源数据接口上尤其常见因为底层数据源改版是常态。下面这几个章节就是围绕怎么把这三种麻烦逐个按下去展开的。2. 把 AKShare 里这一类接口的清单先摸清楚2.1 函数名就是数据来源的指纹AKShare 的函数命名有一套隐含规律前缀标识资产类别后缀标识数据来源。期货相关的函数大多以futures_开头后面跟数据源标识或者数据内容标识。同一类基本面数据往往存在多个来源的版本——比如库存数据就有不止一个来源字段结构、覆盖品种、更新频率都不一样。这意味着你在动手写代码之前第一件事不是去查文档而是先把当前安装版本里所有相关函数列出来。因为文档更新永远滞后于代码而且不同版本的函数名、参数、返回列都可能不同。我踩过最典型的一次坑照着某篇教程写了函数名跑起来直接AttributeError查了半天才发现那个函数在后来某个版本里被重命名了。先确认版本import akshare as ak print(ak.__version__)这个数字很重要后面所有调试都以它为准。我建议在脚本开头就打印出来配合日志一起存出问题的时候一眼能看出是不是版本差异导致的。2.2 用 dir 加关键字自查接口清单不依赖文档的自查方法核心就一行import akshare as ak all_funcs [n for n in dir(ak) if not n.startswith(_)] hits [n for n in all_funcs if qhkch in n.lower()] print(len(hits)) for n in hits: print(n)这一段会把你当前版本里所有以“奇货可查”为数据来源的函数名打出来。这一步的价值在于它给你的是你这台机器上真实存在的函数而不是文档上写的、可能在你的版本里不存在的函数。拿到清单之后逐个看签名和文档字符串import inspect for n in hits: f getattr(ak, n) try: sig inspect.signature(f) except (TypeError, ValueError): sig 无法解析 doc (f.__doc__ or ).strip().splitlines() desc doc[0][:100] if doc else 无文档 print(f{n}\n 参数: {sig}\n 说明: {desc}\n)跑完这一段你手上就有了一张“函数名 → 参数 → 用途”的小表。这比翻文档快得多也不会被过时信息误导。我一般会把这个输出存成一个文本文件放在项目里升级 AKShare 之后重新跑一遍做 diff能立刻发现哪些接口变了。同样的方法可以推广到其他关键词比如想找基差相关就搜basis想找库存就搜inventory想找仓单就搜receipt。这套自查思路适用于任何开源数据包的探索阶段不止期货。2.3 返回值的第一眼要看什么拿到一个陌生接口不要急着写处理逻辑先做三件事df ak.某个接口(参数) print(df.shape) print(df.dtypes) print(df.head(10))shape告诉你数据量如果返回 0 行大概率是参数格式不对或者当天没数据。dtypes是最容易被忽略的很多接口返回的数值列是object类型因为里面混了单位字符或者空字符串。你直接拿它做减法Pandas 会静默地按字符串处理或者报错。head看的是实际内容重点确认日期列的格式是2024-04-30还是20240430还是带时分秒的 datetime、品种代码是大写还是小写、有没有多余的表头行。我的习惯是写一个通用探针函数每次接新接口都先过一遍def probe(df, name): print(f {name} ) print(shape:, df.shape) print(columns:, list(df.columns)) print(df.dtypes.to_string()) print(df.head(5).to_string()) print(空值统计:) print(df.isna().sum().to_string())这个函数后面会一直用得上。尤其是空值统计能提前暴露“某些品种缺数据”的问题——很多接口对主力品种覆盖很好对小品种就是一片 NaN你如果没提前发现后面聚合成宽表的时候会出现莫名其妙的空洞。3. 基差数据从两个价格到一条可用曲线的完整加工3.1 现货价与期货价的配对逻辑基差数据的原始输入只有两个现货价和期货价。AKShare 里跟基差直接相关的接口返回的通常是已经配对好的结果包含品种、现货价、近月合约及其价格、主力合约及其价格以及对应的基差和基差率。这里有个关键设计点值得说清楚为什么接口同时给了近月基差和主力基差。近月合约临近交割期货价格受交割规则约束强基差收敛是必然的所以近月基差反映的是“当下的现货紧张程度”主力合约距离交割还远价格里包含了大量预期成分主力基差反映的是“市场对未来供需的预期”。做期现套利的人看近月做趋势的人看主力两者不能混用。实际调用的时候要注意日期参数的含义。这类接口通常要求传入一个交易日如果不是交易日会报错或者返回空。稳妥的做法是维护一个交易日历或者用“往前找最近交易日”的方式做容错import akshare as ak import pandas as pd def fetch_basis(date_str, retry_prev5): 按日期取基差非交易日自动往前找 for i in range(retry_prev): try: df ak.futures_spot_price(datedate_str) if df is not None and len(df) 0: return df except Exception as e: print(f{date_str} 失败: {e}) # 简单回退一天实际项目里应接交易日历 date_str (pd.to_datetime(date_str) - pd.Timedelta(days1)).strftime(%Y%m%d) return pd.DataFrame()这段代码的重点不是回退逻辑本身而是永远不要假设你传入的日期一定有数据。节假日、数据源延迟、接口临时异常都会让返回变空。没有这层保护你的批量抓取脚本跑到一半就会断。如果需要一段时间的连续基差用批量接口比循环单日接口高效得多因为批量接口内部只发一次请求df ak.futures_spot_price_daily( start_day20240101, end_day20240430, vars_list[RB, CU, AL, I, M] )注意vars_list用的是品种代码不是中文名也不是合约代码。这个细节很容易搞错写错了要么报错要么返回空。3.2 主力合约换月基差序列里最大的假信号这是我在基差数据上踩过最深的坑。期货主力合约会换月比如螺纹钢从 05 合约换到 10 合约。换月当天你算出来的基差会发生一个跳变但这个跳变跟现货供需毫无关系纯粹是因为期货价格从一个月份的合约跳到了另一个月份的合约。如果你直接拿这条基差序列去做信号换月那天会冒出一个巨大的假突破。识别换月很简单在数据里同时保留dominant_contract这个字段一旦它跟上一行不同就说明发生了换月。处理方式有三种按需求选处理方式做法适用场景副作用保留跳变不做处理直接使用只看单日截面不做时序时序分析会出假信号分段拼接换月处断开分段分析研究单个合约周期内的规律长周期序列不连续价差调整用新旧合约价差做平移类似复权需要连续时序引入人为调整绝对值失真我个人的用法是信号计算用调整后的连续序列绝对水平判断用原始序列。两套都保留各取所需。还有一个更隐蔽的问题现货报价的品种对应关系。有些接口返回的品种是“螺纹钢”有的返回“RB”有的返回“螺纹钢HRB400E 20mm”不同来源的现货标的规格不同价格自然不同。你在做跨源数据合并的时候必须先把品种映射表建好不能靠字符串模糊匹配。3.3 基差率的单位陷阱与符号方向基差率看起来简单实际是单位问题的高发区。基差率的算法有两种常见口径基差率 基差 / 现货价基差率 基差 / 期货价两者差异在小基差的时候不明显但在极端行情下会长得不一样。更麻烦的是百分数和小数的区别有的接口返回0.0523表示 5.23%有的直接返回5.23。你如果不检查直接拿去做阈值判断一个是“基差率超过 5% 才触发”另一个可能变成“超过 5 才触发”等于永远不触发。检查方法很简单看这一列的数值分布col dom_basis_rate # 列名以实际返回为准 print(df[col].describe()) print(df[col].abs().quantile([0.5, 0.9, 0.99]))如果 99 分位数在 1 以内基本可以判断是小数如果在几十的级别那就是百分数。我一般会在入库之前统一转成小数并在字段名里明确标注_pct或者_ratio避免后面的人再猜一次。符号方向也要固定下来。基差 现货 − 期货这个定义下正基差叫“现货升水”负基差叫“期货升水”。有些文献用反过来的定义你在读别人的策略逻辑时一定要先确认他用的是哪种否则整个方向会反。4. 库存与仓单长得像用起来完全是两回事4.1 库存数据的三条获取路径与差异对照AKShare 里库存数据不止一个来源按品种覆盖和字段结构区分各有适用场景。第一类是按品种拉取的单品种库存接口参数传中文品种名返回的是该品种的库存时间序列通常带日期、库存量、增减三个核心列。这类接口的优点是简单直接缺点是品种名必须写对而且不同来源支持的品种清单不一样。第二类是交易所口径的库存覆盖的是注册在交易所的仓单对应库存颗粒度更细能看到分仓库、分地区的明细。这类数据对判断交割压力特别有用但只覆盖交易所体系内的货看不到社会库存。第三类是汇总类库存接口一次返回多个品种适合批量初始化。差异对照可以这样记维度单品种库存接口交易所库存社会/港口库存覆盖范围单一品种仅注册仓单对应量全市场流通量更新频率日频日频多为周频颗粒度总量分库分地区分地区用途趋势跟踪交割压力判断供需平衡表关键认知是这三者不能互相替代也不能简单相加。交易所库存是社会库存的子集你把它加进去就是重复计算。正确的做法是明确你要回答什么问题——判断交割压力就用交易所库存判断供需宽松度就用社会库存。4.2 仓单日报的结构与品种过滤仓单接口的典型调用方式是指定起止日期和品种代码列表df ak.get_receipt( start_date20240101, end_date20240430, vars_list[CU, AL, ZN, RB, I, M] )返回的数据通常是长表结构每一行是一个品种有时细到合约在某一天的仓单量和当日增减。拿到之后第一件事是确认品种列的取值形式是纯代码还是带交易所后缀是大写还是小写。品种过滤建议在接口层面就做掉传vars_list而不是先全量拉下来再筛。原因很实际全量拉取的返回体可能非常大既慢又容易触发超时而且你大概率用不上那么多品种。仓单数据有一个必须处理的问题注销和有效期。大部分品种的仓单有强制注销规定比如每年特定月份标准仓单必须全部注销重新注册。这个制度会导致仓单数据在特定时间点出现断崖式下跌这个下跌不代表需求爆发只是制度性注销。如果你拿仓单变化做信号必须先把这些制度性节点标记出来否则每年都会在同一时间被骗一次。处理方法是在数据里加一列标记把历史上已知的集中注销月份标出来信号计算时跳过或者单独处理。这个清单需要按品种维护不同品种的注销规则不一样属于必须提前查清楚的业务知识。4.3 库存的季节性与同比处理库存的绝对值几乎没有独立意义。50 万吨螺纹钢库存在一月是高位在三月可能是低位因为螺纹钢有明确的季节性累库和去库节奏。我看到过很多人直接把库存量丢进模型结果模型学到的是季节性不是供需。正确做法至少要做两步处理。第一步是同比。同比能消除季节性也能消除长期产能扩张带来的中枢上移。计算上就是拿当期值减去去年同期值或者做比值df df.sort_values(date) df[inv_yoy] df[inventory] - df[inventory].shift(52) # 周频数据 df[inv_yoy_pct] df[inventory] / df[inventory].shift(52) - 1注意 shift 的步数要跟数据频率匹配日频数据不能用 52必须先用resample转成周频或者按交易日数算。我见过有人对日频数据用shift(52)相当于比的是两个月前的数据结果全错。第二步是季节性分位。把历史上同一周或者同一旬的库存值收集起来算当前值在历史分布中的分位。这个指标比同比更直观直接告诉你“现在这个库存水平在往年的这个时候算高还是算低”df[week] pd.to_datetime(df[date]).dt.isocalendar().week seasonal_rank df.groupby(week)[inventory].rank(pctTrue) df[seasonal_pct] seasonal_rank这段代码算的是每个值在同周历史样本中的百分位。注意样本量要够至少要有五年以上的数据否则分位数没意义。5. 把三张表拼成一张能下判断的宽表5.1 数据对齐日期、品种、频率三重统一三张表要合并必须先把三个维度统一。日期维度把所有的日期列统一成datetime64类型去掉时分秒。这一步看着简单但如果你从不同接口拿到的日期格式不一样有的是字符串20240430有的是带时区的时间戳直接 merge 会匹配不上而且是静默失败不报错但结果是空的。def norm_date(s): return pd.to_datetime(s.astype(str), errorscoerce).dt.normalize()品种维度建一张映射表把各接口的品种标识统一到一个标准代码上。variety_map { 螺纹钢: RB, RB: RB, 螺纹钢HRB400E: RB, 沪铜: CU, CU: CU, 铜: CU, } df[std_code] df[raw_name].map(variety_map)映射表一定要显式写出来不要用模糊匹配。字符串模糊匹配在品种少的时候看着能用品种一多就会出现“铜”匹配到“铜精矿”这种事故。频率维度如果库存是周频而基差是日频合并的时候要么把周频数据前向填充到日频注意不能后向填充那是用未来数据要么把日频数据聚合到周频。我倾向于降频到周频因为前向填充会让同一周的五个交易日共享同一个库存值模型容易误以为库存五天没变。# 日频转周频取每周最后一个交易日的值 daily[week] daily[date].dt.to_period(W) weekly daily.groupby([std_code, week]).last().reset_index()5.2 用库存和仓单给基差信号做方向过滤单看基差容易做反。基差走强有两种可能现货真的紧了或者期货预期太悲观在修复。这两种情况下后续走势完全不同。加一层库存过滤能显著提高胜率。核心逻辑是这样基差走强 库存低位去化说明现货确实紧张基差走强有基本面支撑基差走强 库存高位累库说明现货并不缺基差走强更多是期货端的情绪修复持续性存疑。这个过滤用代码实现不复杂# 假设宽表 wide 已有 basis_chg基差5日变化、inv_pct库存季节性分位、 # inv_chg库存5日变化 def classify(row): if pd.isna(row[basis_chg]) or pd.isna(row[inv_pct]): return 数据不足 if row[basis_chg] 0 and row[inv_pct] 0.3 and row[inv_chg] 0: return 强支撑 if row[basis_chg] 0 and row[inv_pct] 0.7 and row[inv_chg] 0: return 弱支撑 if row[basis_chg] 0 and row[inv_pct] 0.7: return 偏空 if row[basis_chg] 0 and row[inv_pct] 0.3: return 跌不深 return 中性 wide[signal] wide.apply(classify, axis1)这段代码的价值不在于分类本身准不准而在于它把“一个数字”变成了“一组条件”逼你去想清楚每个组合背后的产业逻辑。阈值0.3 和 0.7是我根据经验随手定的实际用的时候应该做参数扫描看不同阈值下的稳定性。如果某个阈值稍微一动结果就翻脸说明这个信号本身不稳不要用。仓单在这里的角色是验证。如果基差走强、库存去化同时仓单还在持续注销流出三者同向这个信号的可靠性就比单看基差高得多。反过来如果基差走强但仓单在暴增说明有人在大量注册准备交割近月的紧张可能是假的要警惕。5.3 一个可复用的日频拼装脚本骨架把上面所有东西串起来结构大概是这样import akshare as ak import pandas as pd def build_fundamental_panel(codes, start, end): frames [] # 1. 基差 basis ak.futures_spot_price_daily( start_daystart, end_dayend, vars_listcodes ) basis[date] pd.to_datetime(basis[date]).dt.normalize() basis basis.rename(columns{symbol: raw_name}) frames.append((basis, basis)) # 2. 库存单品种循环注意限频 inv_list [] for c in codes: try: tmp ak.futures_inventory_em(symbolname_of(c)) tmp[std_code] c inv_list.append(tmp) except Exception as e: print(f库存 {c} 失败: {e}) if inv_list: frames.append((inventory, pd.concat(inv_list, ignore_indexTrue))) # 3. 仓单 try: receipt ak.get_receipt( start_datestart, end_dateend, vars_listcodes ) frames.append((receipt, receipt)) except Exception as e: print(f仓单失败: {e}) return frames def merge_panel(frames): wide None for name, df in frames: agg (df.groupby([std_code, date]) .agg({col: last for col in df.columns if col not in (std_code, date)}) .add_prefix(name _) .reset_index()) wide agg if wide is None else wide.merge( agg, on[std_code, date], howouter ) return wide.sort_values([std_code, date]).reset_index(dropTrue)这个骨架里有两个刻意设计一是每个数据源都包了 try单个失败不影响整体二是合并用 outer宁可留 NaN 也不要丢行。用 inner 合并会让你在某个数据源缺失的时候整段样本静默消失而且你很难发现。实际跑之前还要处理一个细节name_of(c)这种品种代码到中文名的映射必须有而且要在代码里硬编码一张表不要靠接口自动识别。有些接口对某些中文名的支持不稳定硬编码至少能让你在出错时知道问题在哪一层。6. 生产环境里真正会咬人的几个问题6.1 限频、超时与重试策略批量抓取最容易死在限频上。同一天内连续请求几十个品种前面的正常返回后面开始超时或者返回空。这时候你的代码如果没做区分就会把“限频导致的空”当成“当天真的没数据”存进去形成一条假记录。正确做法是把“空结果”和“请求异常”分开处理import time import requests def safe_fetch(func, retries3, sleep1.5, **kwargs): last_err None for i in range(retries): try: return func(**kwargs) except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e: last_err e time.sleep(sleep * (i 1)) # 指数退避 except Exception as e: # 非网络异常直接抛出不要重试 raise print(f重试耗尽: {kwargs}, 最后错误: {last_err}) return None这里的关键判断是只有网络类异常才重试。如果是参数错误、品种不存在这类逻辑错误重试多少次都一样只会浪费时间和加重限频。我吃过这个亏一个参数写错的循环重试了三次把当天的请求配额全耗光了。另外请求之间加一个固定的间隔哪怕 0.5 秒比不加间隔的稳定性高一个量级。这个成本完全可以接受因为基本面数据是日频的你不需要抢那几秒钟。6.2 数据落地格式选择与字段稳定性落地格式我建议用Parquet 而不是 CSV。原因有三个一是能保留 dtype不会出现日期变字符串、数值变 object 的问题二是压缩率高几年的日频基本面数据也就几十兆三是读取快做回测的时候能省大量时间。但 Parquet 有个坑字段一旦固定后续新增列要处理 schema 合并。如果接口升级加了新字段你直接覆写会丢掉历史数据里的旧字段。我的做法是每次写入前先读已有的 schema做并集之后再写import pyarrow as pa import pyarrow.parquet as pq def append_parquet(path, new_df): try: old pq.read_table(path).to_pandas() merged pd.concat([old, new_df], ignore_indexTrue) merged merged.drop_duplicates( subset[std_code, date], keeplast ) except FileNotFoundError: merged new_df merged.to_parquet(path, indexFalse)drop_duplicates里keeplast是刻意的新抓的数据覆盖旧数据这样接口修正历史值时能自动更新。如果用keepfirst修正值永远进不来。还有一点字段名的元数据要单独存一份。我会在旁边放一个 JSON记录每个字段的含义、单位、口径含税/不含税、吨/手以及这个字段是从哪个接口的哪一列映射过来的。这个东西在半年后你自己回来看的时候价值极高。6.3 定时任务与数据完好性校验日频数据的抓取时间点很关键。太早抓当天的库存和仓单还没更新完太晚抓如果任务失败就没有补救窗口。我的经验是基差和行情类数据在收盘后一到两小时抓库存和仓单类数据在晚上固定时间抓并且第二天早上做一次补抓只针对前一天缺失的记录。完好性校验至少要覆盖三项校验项检查方法触发后的动作覆盖品种数当日品种数 vs 近 20 日均值低于 80% 告警日期连续性检查日期序列有无断档断档则补抓数值合理性库存是否为负、基差率是否超过阈值标记异常人工确认第三项最容易被跳过但最有用。我遇到过接口返回的库存是负数的情况原因是“增减”列被错误地当成了库存列。如果没做合理性检查这个负库存会一路进到模型里而且因为在正常范围内不会报错可能几周后才发现。7. 几个我反复验证过的实操细节7.1 现货报价的含税口径一定要提前确认这一点单独拎出来说因为它造成的错误最隐蔽。很多品种的现货报价默认是含税价但也有部分来源报的是不含税价或者净价。期货价格是含税的标准化价格。如果口径不一致你算出来的基差会系统性偏移而且这个偏移是常数看起来像“这个品种基差长期偏高”很容易被误判成结构性机会。确认方法不是看接口文档往往没写而是用历史数据反推找一个交割月临近、基差必然收敛的时点看那时候的基差是否接近零或者接近交割成本。如果长期稳定偏离一个固定值那基本就是口径问题。7.2 单位换算表要建在代码里不同品种的“一手”对应吨数完全不同螺纹钢一手 10 吨铜一手 5 吨铁矿石一手 100 吨。库存接口有的返回吨有的返回手。如果你的宽表里混着两种单位横向比较就完全失效。做法是维护一张常量表CONTRACT_SIZE { RB: 10, CU: 5, AL: 5, ZN: 5, I: 100, M: 10, Y: 10, P: 10, }所有入库的库存字段统一转成吨并在字段名里标明_ton。这条规则听起来啰嗦但能省掉后面无数次“这个数到底是吨还是手”的返工。7.3 别指望接口的历史数据能无限回溯这是我在做长周期回测时最痛的一次教训。很多基本面接口的历史深度是有限的你往前拉三年可能正常拉到五年就开始大面积缺失而且缺失是静默的——不是报错是返回的 DataFrame 行数变少了。所以每次拉取之后必须做一次覆盖度检查def check_coverage(df, start, end, min_ratio0.8): expected pd.date_range(start, end, freqB) actual pd.to_datetime(df[date]).dt.normalize().unique() ratio len(set(expected) set(actual)) / len(expected) if ratio min_ratio: print(f覆盖度不足: {ratio:.2%}期望{len(expected)}天实际{len(actual)}天) return ratio如果某个品种的覆盖度不达标正确的做法是缩短回测区间而不是用插值把洞补上。基本面数据的插值等于编造会让回测结果虚高而且这种虚高在样本外会原形毕露。我个人在实际操作中的体会是这套基本面数据的价值不在于接口本身多好用而在于你愿不愿意花时间把口径、单位、频率这三件事钉死。接口只是把数据搬过来剩下的判断全是人的活儿。上面那些看起来琐碎的校验和映射表恰恰是让数据能真正用于决策的分水岭。刚开始会觉得麻烦做两三个品种之后就会形成模板后面加新品种基本是十分钟的事。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑