#!/usr/bin/env python # -*- coding:utf-8 -*- """ Date: 2026/2/20 10:00 Desc: 期货结算信息 期货交易所结算参数数据 - 中金所: 结算参数(保证金、手续费等) - 已实现 - 郑商所: 结算参数 - 已实现 - 上期所: 结算参数 - 已实现 - 广期所: 结算参数 - 已实现 - 上能中心: 结算参数 - 已实现 - 大商所: 待解决(网站反爬虫保护,所有接口返回412错误) """ import datetime import pandas as pd import requests from io import StringIO from akshare.futures import cons from akshare.utils.cons import headers gfex_headers = { "Accept": "application/json, text/javascript, */*; q=0.01", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Origin": "http://www.gfex.com.cn", "Referer": "http://www.gfex.com.cn/gfex/rjycs/ywcs.shtml", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "X-Requested-With": "XMLHttpRequest", } # 统一的结算参数字段 SETTLE_OUTPUT_COLUMNS = [ "date", "symbol", "variety", "settle_price", "long_margin_ratio", "short_margin_ratio", "spec_long_margin_ratio", "spec_short_margin_ratio", "hedge_long_margin_ratio", "hedge_short_margin_ratio", "trade_fee_ratio", "close_today_fee_ratio", "delivery_fee_ratio", "is_single_market", "single_market_days", "limit_ratio", "position_limit", "trade_limit", "rise_limit_rate", "fall_limit_rate", ] def _normalize_settle_columns(df: pd.DataFrame) -> pd.DataFrame: """ 统一结算参数字段,将各交易所的字段映射到统一字段 :param df: 原始DataFrame :type df: pandas.DataFrame :return: 统一格式的DataFrame :rtype: pandas.DataFrame """ if df.empty: return pd.DataFrame(columns=SETTLE_OUTPUT_COLUMNS) # 字段映射关系 field_mapping = { # 统一字段 -> 可能的来源字段 "settle_price": ["settle_price", "SETTLEMENTPRICE", "当日结算价"], "long_margin_ratio": ["long_margin_ratio", "margin_ratio", "SPECLONGMARGINRATIO", "specBuyRate", "spec_buy_rate"], "short_margin_ratio": ["short_margin_ratio", "SPECSHORTMARGINRATIO", "hedgeBuyRate", "hedge_buy_rate"], "spec_long_margin_ratio": ["spec_long_margin_ratio", "SPECLONGMARGINRATIO", "spec_buy_rate"], "spec_short_margin_ratio": ["spec_short_margin_ratio", "SPECSHORTMARGINRATIO", "hedge_buy_rate"], "hedge_long_margin_ratio": ["hedge_long_margin_ratio", "HEDGLONGMARGINRATIO", "hedge_buy_rate"], "hedge_short_margin_ratio": ["hedge_short_margin_ratio", "HEDGSHORTMARGINRATIO", "spec_buy_rate"], "trade_fee_ratio": ["trade_fee_ratio", "TRADEFEERATIO", "交易手续费"], "close_today_fee_ratio": ["close_today_fee_ratio", "TTRADEFEERATIO", "日内平今仓交易手续费"], "delivery_fee_ratio": ["delivery_fee_ratio", "COMMODITYDELIVFEERATIO", "交割手续费"], "is_single_market": ["is_single_market", "是否单边市"], "single_market_days": ["single_market_days", "连续单边市天数"], "limit_ratio": ["limit_ratio", "涨跌停板(%)"], "position_limit": ["position_limit", "日持仓限额", "clientBuyPosiQuota", "client_buy_posi_quota"], "trade_limit": ["trade_limit", "交易限额"], "rise_limit_rate": ["rise_limit_rate", "riseLimitRate", "rise_limit_rate"], "fall_limit_rate": ["fall_limit_rate", "fallLimit", "fall_limit"], } # 确保必要的字段存在 for col in ["date", "symbol", "variety"]: if col not in df.columns: if col == "variety" and "symbol" in df.columns: df["variety"] = df["symbol"].str.extract(r"([A-Za-z]+)", expand=False) else: df[col] = None # 映射字段 for target_field, possible_sources in field_mapping.items(): if target_field not in df.columns: for source in possible_sources: if source in df.columns: df[target_field] = df[source] break else: df[target_field] = None # 返回统一格式 return df[SETTLE_OUTPUT_COLUMNS] def _parse_pipe_data(text: str) -> pd.DataFrame: """ 解析管道符分隔的数据 :param text: 原始文本数据 :type text: str :return: 解析后的DataFrame :rtype: pandas.DataFrame """ lines = text.strip().split("\n") if len(lines) < 2: return pd.DataFrame() columns = [col.strip() for col in lines[1].split("|")] data_lines = [line for line in lines[2:] if line.strip()] data_list = [] for line in data_lines: row = [col.strip() for col in line.split("|")] if len(row) >= len(columns): data_list.append(row[:len(columns)]) return pd.DataFrame(data_list, columns=columns) def futures_settle_cffex(date: str = "20260119") -> pd.DataFrame: """ 中国金融期货交易所-结算参数 http://www.cffex.com.cn/jscs/ :param date: 结算参数日期 format:YYYY-MM-DD 或 YYYYMMDD 或 datetime.date对象,默认为当前交易日 :type date: str or datetime.date :return: 结算参数数据 :rtype: pandas.DataFrame """ day = cons.convert_date(date) if date is not None else datetime.date.today() date = day.strftime("%Y%m%d") url = f"http://www.cffex.com.cn/sj/jscs/{date[:4]}{date[4:6]}/{date[6:8]}/{date}_1.csv" r = requests.get(url, headers=headers) r.encoding = "gbk" if r.status_code != 200: return pd.DataFrame() # 检查是否返回的是 HTML 页面(页面不存在或数据未发布) if r.text.strip().startswith("<") or "要查看的页面不存在" in r.text: return pd.DataFrame() try: data_df = pd.read_csv(StringIO(r.text), skiprows=1) except: # noqa: E722 return pd.DataFrame() if data_df.shape[0] < 5: return pd.DataFrame() data_df.columns = [ "symbol", "long_margin_ratio", "short_margin_ratio", "trade_fee_ratio", "delivery_fee_ratio", "close_today_fee_ratio", ] data_df = data_df[data_df["symbol"].notna()] data_df = data_df[data_df["symbol"].str.contains( r"^[A-Z]+", na=False, regex=True)] data_df["variety"] = data_df["symbol"].str.extract(r"([A-Z]+)") data_df["date"] = date data_df = data_df[ ["date", "symbol", "variety", "long_margin_ratio", "short_margin_ratio", "trade_fee_ratio", "delivery_fee_ratio", "close_today_fee_ratio"] ] return data_df def futures_settle_czce(date: str = "20260119") -> pd.DataFrame: """ 郑州商品交易所-结算参数 http://www.czce.com.cn/cn/jysj/jscs/H077003003index_1.htm :param date: 结算参数日期 format:YYYY-MM-DD 或 YYYYMMDD 或 datetime.date对象,默认为当前交易日 :type date: str or datetime.date :return: 结算参数数据 :rtype: pandas.DataFrame """ day = cons.convert_date(date) if date is not None else datetime.date.today() date = day.strftime("%Y%m%d") url = f"http://www.czce.com.cn/cn/DFSStaticFiles/Future/{date[:4]}/{date}/FutureDataClearParams.txt" r = requests.get(url, headers=headers) r.encoding = "utf-8" if r.status_code != 200: return pd.DataFrame() try: data_df = _parse_pipe_data(r.text) except: # noqa: E722 return pd.DataFrame() if data_df.shape[0] < 5: return pd.DataFrame() data_df.columns = [ "symbol", "settle_price", "is_single_market", "single_market_days", "margin_ratio", "limit_ratio", "trade_fee", "fee_type", "delivery_fee", "close_today_fee", "position_limit", "trade_limit" ] data_df = data_df[data_df["symbol"].notna()] data_df = data_df[~data_df["symbol"].str.contains("小计|合计|总计", na=False)] data_df["variety"] = data_df["symbol"].str.extract(r"([A-Za-z]+)") data_df["date"] = date data_df = data_df[ ["date", "symbol", "variety", "settle_price", "is_single_market", "single_market_days", "margin_ratio", "limit_ratio", "trade_fee", "fee_type", "delivery_fee", "close_today_fee", "position_limit", "trade_limit"] ] return data_df def futures_settle_gfex(date: str = "20260119") -> pd.DataFrame: """ 广州期货交易所-结算参数 http://www.gfex.com.cn/gfex/rjycs/ywcs.shtml :param date: 结算参数日期 format:YYYY-MM-DD 或 YYYYMMDD 或 datetime.date对象,默认为当前交易日 :type date: str or datetime.date :return: 结算参数数据 :rtype: pandas.DataFrame """ day = cons.convert_date(date) if date is not None else datetime.date.today() date = day.strftime("%Y%m%d") url = "http://www.gfex.com.cn/u/interfacesWebTtQueryTradPara/loadDayList" payload = {"trade_type": "0"} r = requests.post(url, data=payload, headers=gfex_headers) if r.status_code != 200: return pd.DataFrame() # 检查是否返回了反爬虫的 JavaScript 代码 if r.text.strip().startswith(" pd.DataFrame: """ 上海期货交易所-结算参数 https://www.shfe.com.cn/reports/tradedata/dailyandweeklydata/ :param date: 结算参数日期 format:YYYY-MM-DD 或 YYYYMMDD 或 datetime.date对象,默认为当前交易日 :type date: str or datetime.date :return: 结算参数数据 :rtype: pandas.DataFrame """ day = cons.convert_date(date) if date is not None else datetime.date.today() date = day.strftime("%Y%m%d") url = f"https://www.shfe.com.cn/data/tradedata/future/dailydata/js{date}.dat" r = requests.get(url, headers=cons.shfe_headers) if r.status_code != 200: return pd.DataFrame() try: data_json = r.json() data_list = data_json.get("o_cursor", []) except: # noqa: E722 return pd.DataFrame() if not data_list: return pd.DataFrame() data_df = pd.DataFrame(data_list) data_df.columns = [ "symbol", "trade_fee_ratio", "close_today_fee_ratio", "delivery_fee_unit", "spec_long_margin_ratio", "hedge_long_margin_ratio", "delivery_fee_ratio", "product_id", "product_name", "close_today_fee_unit", "trade_fee_unit", "hedge_short_margin_ratio", "settle_price", "uni_direction", "spec_short_margin_ratio", "is_close_today" ] data_df["variety"] = data_df["symbol"].str.extract(r"([A-Za-z]+)") data_df["date"] = date data_df = data_df[ ["date", "symbol", "variety", "settle_price", "spec_long_margin_ratio", "hedge_long_margin_ratio", "spec_short_margin_ratio", "hedge_short_margin_ratio", "trade_fee_ratio", "close_today_fee_ratio", "is_close_today"] ] return data_df def futures_settle_ine(date: str = "20260119") -> pd.DataFrame: """ 上海国际能源交易中心-结算参数 https://www.ine.cn/reports/businessdata/prmsummary/ :param date: 结算参数日期 format:YYYY-MM-DD 或 YYYYMMDD 或 datetime.date对象,默认为当前交易日 :type date: str or datetime.date :return: 结算参数数据 :rtype: pandas.DataFrame """ day = cons.convert_date(date) if date is not None else datetime.date.today() date = day.strftime("%Y%m%d") url = f"https://www.ine.cn/data/tradedata/future/dailydata/js{date}.dat" r = requests.get(url, headers=cons.shfe_headers) if r.status_code != 200: return pd.DataFrame() try: data_json = r.json() data_list = data_json.get("o_cursor", []) except: # noqa: E722 return pd.DataFrame() if not data_list: return pd.DataFrame() data_df = pd.DataFrame(data_list) data_df.columns = [ "symbol", "trade_fee_ratio", "close_today_fee_ratio", "delivery_fee_unit", "spec_long_margin_ratio", "hedge_long_margin_ratio", "delivery_fee_ratio", "product_id", "product_name", "close_today_fee_unit", "trade_fee_unit", "hedge_short_margin_ratio", "settle_price", "uni_direction", "spec_short_margin_ratio", "is_close_today" ] data_df["variety"] = data_df["symbol"].str.extract(r"([A-Za-z]+)") data_df["date"] = date data_df = data_df[ ["date", "symbol", "variety", "settle_price", "spec_long_margin_ratio", "hedge_long_margin_ratio", "spec_short_margin_ratio", "hedge_short_margin_ratio", "trade_fee_ratio", "close_today_fee_ratio", "is_close_today"] ] return data_df def futures_settle(date: str = "20260119", market: str = "CFFEX") -> pd.DataFrame: """ 期货交易所结算参数 :param date: 结算日期 format:YYYY-MM-DD 或 YYYYMMDD 或 datetime.date对象,默认为当前交易日 :type date: str or datetime.date :param market: 交易所代码: CFFEX-中金所, CZCE-郑商所, SHFE-上期所, DCE-大商所, INE-上能中心, GFEX-广期所 :type market: str :return: 结算参数数据(统一格式) :rtype: pandas.DataFrame """ if market.upper() == "CFFEX": df = futures_settle_cffex(date) elif market.upper() == "CZCE": df = futures_settle_czce(date) elif market.upper() == "SHFE": df = futures_settle_shfe(date) elif market.upper() == "GFEX": df = futures_settle_gfex(date) elif market.upper() == "INE": df = futures_settle_ine(date) else: print(f"Unsupported market: {market}") return pd.DataFrame(columns=SETTLE_OUTPUT_COLUMNS) temp_df = _normalize_settle_columns(df) return temp_df if __name__ == "__main__": futures_settle_cffex_df = futures_settle_cffex(date="20260119") print("=== 中金所结算参数 ===") print(futures_settle_cffex_df) futures_settle_czce_df = futures_settle_czce(date="20260119") print("\n=== 郑商所结算参数 ===") print(futures_settle_czce_df) futures_settle_shfe_df = futures_settle_shfe(date="20260119") print("\n=== 上期所结算参数 ===") print(futures_settle_shfe_df) futures_settle_gfex_df = futures_settle_gfex(date="20260119") print("\n=== 广期所结算参数 ===") print(futures_settle_gfex_df) futures_settle_ine_df = futures_settle_ine(date="20250117") print("\n=== 上能中心结算参数 ===") print(futures_settle_ine_df) futures_settle_df = futures_settle(date="20260119", market="CFFEX") print("\n=== 通用接口-CFFEX ===") print(futures_settle_df) futures_settle_df = futures_settle(date="20260119", market="CZCE") print("\n=== 通用接口-CZCE ===") print(futures_settle_df) futures_settle_df = futures_settle(date="20260119", market="SHFE") print("\n=== 通用接口-SHFE ===") print(futures_settle_df) futures_settle_df = futures_settle(date="20260119", market="GFEX") print("\n=== 通用接口-GFEX ===") print(futures_settle_df) futures_settle_df = futures_settle(date="20260119", market="INE") print("\n=== 通用接口-INE ===") print(futures_settle_df)