用Python解读期货持仓排名:外资席位加多别急着跟单
在商品期货的公开信息里“外资机构席位持续加多有色金属和黄金”这类标题经常出现。8 月 7 日的持仓排名数据公布后不少人的第一反应是外资在买我是不是该跟着做多直接把一条资讯标题当成交易信号很容易踩坑。持仓排名数据虽然公开但解读它需要先搞清楚几个问题席位到底代表谁持仓量是怎么样统计的“加多”指的是单日变化还是多日趋势这个信号能不能和价格、库存、基差互相验证。这篇文章从数据口径讲起用 Python 对两个交易日的持仓排名数据做一次最小分析闭环最后给出可复用的核查流程。1. 先把概念说清楚席位、持仓量和外资机构席位1.1 席位是期货交易的“入口”不是资金本身在期货市场普通投资者不能直接向交易所下单必须通过期货公司会员席位完成。交易所每日公布的“持仓排名”展示的是会员维度的统计数据常见字段包括合约代码、会员名称、成交量、持买单量、持卖单量。这里有一个容易混淆的点一个席位下面往往挂着大量客户席位持仓变化可能是期货公司自营资金也可能是代客资金。因此“某席位加多”并不等于“某一家机构加多”更不能自动等价于“某一笔确定的资金在看涨”。用一张简化数据表说明合约会员席位持买单量持卖单量净持仓cu2409外资席位A1200030009000au2410外资席位B500010004000持买单量减持卖单量得到净持仓。分析多空倾向时用净持仓变化比用总量更合理。1.2 “外资机构席位”在不同市场有不同口径“外资机构席位”不是一个统一的官方概念不同市场的数据口径差别很大。在境内商品期货市场境外资金参与的主要方式包括合格境外机构投资者参与特定商品期货品种、境外特殊经纪参与者等。上海国际能源交易中心的一些品种允许境外特殊经纪参与者直接入场。交易所持仓排名中会显示会员名称但这些名称并不直接标注“外资”两个字需要结合会员资格和公开信息判断。在境外市场比如 COMEX 黄金和铜可以参考美国商品期货交易委员会发布的持仓报告Commitments of TradersCOT。COT 把持仓分成商业持仓和非商业持仓市场通常把非商业持仓理解为投机资金或机构资金。不同口径对“加多”的判断结果可能完全不同。分析之前一定要先确认自己用的是哪一套口径。市场常见数据外资/机构口径更新频率注意点上期所每日持仓排名境外特殊经纪参与者等每日需要核对会员名称上海国际能源交易中心每日持仓排名境外特殊经纪参与者、境外中介每日可参与品种有限COMEX/CFTCCOT 报告非商业持仓每周数据滞后第三方终端自定义席位数据自行分类不定口径要先核实1.3 为什么市场关注外资席位加多外资席位加多之所以受关注有三个现实原因。第一机构资金体量较大其调仓可能对短期价格产生影响。第二机构的研究能力和信息获取能力通常强于普通投资者持仓变化被视为“聪明钱”的方向参考。第三“持续加多”比“单日加多”包含更多信息连续多日净多增加往往说明资金不是临时起意。但同样要理解这个信号只反映期货市场的持仓变化不反映现货采购、库存变化和最终的价格方向。把它当成一个分析因子可以把它当成买卖指令就危险了。2. 数据来源和分析前的环境准备2.1 公开数据源和字段实际分析时数据可以来自交易所官方网站的每日持仓排名也可以从 Wind、Choice、文华财经等终端导出。不同来源的字段名不完全一致常见字段包括合约代码、会员名称、成交量、持买单量、持卖单量。建议在分析前先做字段统一。否则合并数据时会出现列名对不上、单位不一致、缺失值过多等问题。下面给出一个标准化的字段定义后续代码都按这个口径处理。字段名含义示例date交易日2024-08-07exchange交易所SHFEproduct品种CU、AL、AUcontract合约cu2409member会员/席位名称外资席位Along_position持买单量12000short_position持卖单量3000turnover成交量80002.2 准备 Python 分析环境分析脚本建议使用 Python 3.9 及以上版本核心依赖是 pandas、numpy 和 matplotlib。只算表格指标时pandas 就够用如果需要画持仓变化图再引入 matplotlib。安装依赖pip install pandas numpy matplotlib验证安装结果python -c import pandas as pd; print(pd.__version__)如果是在 Jupyter Notebook 中运行建议把日期字段统一为 datetime 类型避免后面做 diff 时因为字符串格式不同而报错。2.3 准备两个交易日的持仓数据要计算“加多”的增量至少需要两个交易日的数据。以标题中的 8 月 7 日为例需要 8 月 7 日的数据以及它之前最近一个交易日的数据。注意上一个交易日不一定是 8 月 6 日遇到周末和节假日要按交易日历对齐。下面是一份演示用 CSV 数据保存为 positions.csvdate,exchange,product,contract,member,long_position,short_position,turnover 2024-08-06,SHFE,CU,cu2409,外资席位A,11000,3500,7500 2024-08-07,SHFE,CU,cu2409,外资席位A,12000,3000,8000 2024-08-06,SHFE,AU,au2410,外资席位B,4000,1000,3200 2024-08-07,SHFE,AU,au2410,外资席位B,5000,1000,4500 2024-08-07,SHFE,AL,al2409,外资席位C,6000,2000,3000这份数据只是为了演示代码逻辑不是真实交易所数据。实际项目中会员名称、合约代码和数值单位都要以交易所发布为准。学习阶段可以用这种演示数据跑通流程真实项目要接入交易所每日正式数据并增加字段校验、来源记录和结果复核步骤。3. 用 Python 计算席位加多的核心指标3.1 读取数据并做基础清洗先用 pandas 读取 CSV并确认列名和数据类型import pandas as pd df pd.read_csv(positions.csv, parse_dates[date]) print(df.head()) print(df.dtypes)输出结果会显示 date 是否被正确解析为 datetimelong_position、short_position 是否为数值类型。如果原始数据里带有千分位逗号或者空格直接算减法会报错需要先用 to_numeric 做转换for col in [long_position, short_position, turnover]: df[col] pd.to_numeric(df[col], errorscoerce) df df.dropna(subset[long_position, short_position])errorscoerce 的作用是把无法转换的字符串变成 NaN再通过 dropna 去掉无效行。这样可以避免脏数据污染后续计算。3.2 计算净多单、多空比和环比增量在标准化字段之后计算三个最常用的指标净多单、多空比、环比增量。df[net_position] df[long_position] - df[short_position] df[long_short_ratio] df[long_position] / df[short_position]净多单是判断多空倾向的基础。多空比大于 1 表示持买单量大于持卖单量但要注意这个比值只反映持仓结构不反映价格方向。接下来计算两个交易日之间的变化。先把数据按日期拆开再以“交易所 品种 合约 席位”为维度做连接df_prev df[df[date] df[date].min()].copy() df_curr df[df[date] df[date].max()].copy() merged pd.merge( df_curr, df_prev, on[exchange, product, contract, member], suffixes(, _prev) ) merged[net_change] merged[net_position] - merged[net_position_prev] merged[ratio_change] merged[long_short_ratio] - merged[long_short_ratio_prev] print(merged[[date, product, contract, member, net_position, net_position_prev, net_change]])suffixes 参数用来区分当前期和上一期的同名字段。net_change 大于 0 说明该席位在本期增加了净多单或者减少了净空单。3.3 筛选“持续加多”的席位单日加多不足以构成“持续加多”。更稳妥的做法是取连续多个交易日按席位和合约分组判断最近 N 期净多单是否连续增加。df_sorted df.sort_values([member, contract, date]) def is_continuous_increase(net_series, min_days3): diff net_series.diff() return (diff 0).tail(min_days - 1).all() result ( df_sorted.groupby([member, contract])[net_position] .apply(lambda s: is_continuous_increase(s, min_days3)) .reset_index(namecontinuous_increase) ) print(result[result[continuous_increase]])这段代码的关键是 diff 和 tail。diff 计算相邻两期的净多变化tail 截取最近几期all 判断是否全部为正。min_days 传 3 时要求最近两期环比都增加也就是连续三期中后两期都在加多。注意这个逻辑没有处理换月、席位更名等特殊情况。真实项目中要先做数据整理再做分组计算。3.4 按品种汇总加多信号多品种分析时可以在合并结果上按品种分组找出每个品种净多变化最大的席位def top_added(group): return group.loc[group[net_change].idxmax()] summary merged.groupby([exchange, product]).apply(top_added).reset_index(dropTrue) print(summary[[date, product, contract, member, net_change]])这样可以快速得到一张“哪个品种、哪个席位、加了多少净多单”的汇总表。后续再结合价格、成交量和库存做交叉验证。4. 以 8 月 7 日为例一套加多信号的验证流程4.1 先看净多单变化再看持续天数回到“外资机构席位持续加多有色金属和黄金”这个标题。8 月 7 日的数据出来之后正确的分析顺序是第一步确定品种范围包括铜、铝、锌、黄金等第二步找出每个品种净多单增加的席位第三步统计这些席位连续加多的天数。下面是一张演示结果表。数据为示例仅用于说明展示结构品种席位8月6日净多8月7日净多净多变化连续加多天数沪铜外资席位A7500900015004沪铝外资席位B400042002003沪锌外资席位C200026006002黄金外资席位D320036004005看到这张表只能说“净多增加”和“持续加多”这两件事都成立。但还不能说“价格一定涨”。接下来要做的是用其他市场数据做交叉验证。4.2 用持仓量、成交量、价格和基差做交叉验证净多单增加只说明期货端多了新的多头头寸。判断信号是否有效还要看几个配套指标。指标含义加多信号配合时的解读总持仓量未平仓合约总量持仓量与价格同向上升趋势更可信成交量当日成交合约数放量加多比缩量加多信息量更大主力合约价格收盘价或结算价价格同步上涨信号更顺畅基差现货价减期货价基差走弱时加多可能是期现回归库存交易所仓单或社会库存库存下降配合加多方向更一致一个相对可靠的组合是价格趋势向上、总持仓量上升、库存下降、基差没有明显异常同时席位净多持续增加。四个条件同时满足时加多信号的可信度更高。4.3 不要把“加多”直接理解为“看涨单边”这个坑在实际分析里非常常见。一个席位净多增加可能是三种完全不同的行为。第一种是单边投机多头即资金直接押注价格上涨。第二种是套期保值多头比如企业持有铜现货空头在期货上买入做保值净多增加不代表看好价格。第三种是套利头寸包括跨期套利、内外盘比价套利和期现套利。套利头寸的净多增加是为了对冲另一个市场或另一个合约的空头不能当作单边方向信号。因此看到标题之后至少要把这三类可能性过一遍再决定是否采纳这个信号。4.4 一个更稳的判断框架趋势 持仓 库存对于有色金属和黄金这类宏观属性较强的品种推荐把加多信号放进一个多因子框架里使用。框架可以参考趋势因子主力合约价格是否处于上升趋势均线是否多头排列。持仓因子总持仓量是否增加席位净多是否持续增加。库存因子交易所仓单和社会库存是否下降。宏观因子美元指数、美债实际利率、全球制造业景气度。单一持仓数据只是其中的一个因子。把四个因子组合起来看误判概率会低很多。5. 数据口径导致误判的坑和排查方法5.1 合约代码和主力合约不一致现象分析使用 cu2409 的数据但市场讨论的“沪铜”主力合约已经是 cu2410。原因持仓排名按具体合约公布不同合约的参与者差异很大。排查方式先确认当前主力合约是哪一个再看该合约上的净多变化。处理建议按主力连续合约重新汇总避免用冷门合约推断整个品种。5.2 持买单量与净多口径混用现象标题说“加多”有人按持买单量增加判断有人按净多单增加判断。如果某席位同时持有大量空单只看持买单量会误判。处理方式统一使用净多单即持买单量减持卖单量同时记录变化幅度。需要在分析代码里明确字段定义并在输出表格里标注净多口径。5.3 席位更名、合并和代理关系现象同一家机构更换会员名称历史数据断裂或者两家机构使用同一代理链路持仓被合并展示。排查方式用“会员代码 会员名称”联合匹配遇到名称变化时手工核对。处理建议建立会员名称映射表在数据加载阶段统一替换保证分组计算稳定。5.4 日期对齐与节假日问题现象8 月 7 日的上一个交易日不一定是 8 月 6 日。遇到周末、法定节假日和交易所临时休市日期对齐错误会直接导致环比增量算错。排查方式使用交易所交易日历而不是自然日。处理建议在数据中增加 trade_day 序号用序号而不是日期字符串计算 diff。下面是一张针对数据问题的排查清单可以直接用于复核问题现象可能原因检查方式处理建议净多变化异常大合约换月或跨主力检查合约代码和日期范围按主力连续合约重新汇总席位突然消失会员更名、退居次席对比历史会员列表建立会员名称映射表加多但价格下跌套利或对锁头寸查看基差、跨期价差不要直接当单边信号连续加多天数不稳定交易日历没有对齐核对节假日和夜盘用交易日序号计算多空比出现无穷大持卖单量为 0检查分母字段对 0 值做过滤或替换6. 从数据分析到交易决策中间隔着风控6.1 公开数据的局限持仓排名数据有天然的滞后性。每日数据一般在收盘后公布反映的是某个时点的静态持仓CFTC 的 COT 报告按周公布滞后更明显。另外席位持仓是会员口径不等于资金最终归属。同一笔资金可能通过多个席位分散下单单一席位数据无法看到全貌。6.2 不要把单一信号当完整策略黄金和有色金属品种的定价逻辑不同。黄金主要受美元指数、美债实际利率、央行购金和避险情绪影响有色金属还要看全球制造业周期、矿端供应和库存变化。持仓加多可能只是其中一部分资金的行为不足以构成完整交易策略。建议把席位数据当作辅助确认而不是入场依据。6.3 资金管理和止损是底线如果确实想参考这个信号参与交易至少要有清晰的风控规则。下面是一份可以直接使用的检查清单每笔交易风险控制在账户资金的 1% 到 2%先确定止损距离再反推仓位。入场前写清楚入场价、止损价、目标价缺一个就不下单。以“净多连续下降”作为信号失效条件触发后无条件离场。每周复盘持仓变化和价格的对应关系检验信号的历史胜率。杠杆倍数设置要保守避免一次反向波动击穿本金。这里要特别说明持仓数据只是辅助工具不能替代止损。任何一次交易都可能出错止损是保护账户的最后一道防线。6.4 合规与学习建议使用公开数据时要注明来源和统计日期。转载或引用时保留数据口径避免把不同市场的口径混在一起。分析输出应定位为“数据观察”而不是“投资建议”。对新手来说建议先跑通本文代码再用真实数据连续跟踪一个月记录每一次加多信号出现后的价格表现慢慢形成自己的判断框架。同时要区分学习环境和真实分析环境学习阶段可以用演示数据跑通代码逻辑真实项目要接入交易所每日正式数据并增加字段校验、来源记录和结果复核流程防止因为一处口径错误导致整张分析表失真。本文中的代码和数据均为演示示例不构成任何投资建议。实际分析请以交易所发布的官方数据为准。