Files
MoFin/venv/lib/python3.12/site-packages/akshare/futures/futures_settle.py
T
知微 fa45d8aa5f fix: 小果地址统一node122(兼容LAN+EasyTier)
- health_checklist.json: 192.168.1.122→node122
- ocr_client.py: docstring IP→node122
- docs/market-data-requirements.md: IP→node122
- 所有API调用通过ProxyHandler({})绕过系统代理
  Privoxy对node122:18003返回500,直连正常
2026-06-30 02:56:35 +08:00

416 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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: 结算参数日期 formatYYYY-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: 结算参数日期 formatYYYY-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: 结算参数日期 formatYYYY-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("<script") or "function" in r.text[:100]:
return pd.DataFrame()
try:
json_data = r.json()
if json_data.get("code") != "0":
return pd.DataFrame()
data_list = json_data.get("data", [])
except: # noqa: E722
return pd.DataFrame()
if not data_list:
return pd.DataFrame()
# 过滤掉期权合约,只保留期货合约
data_list = [
item for item in data_list if "-" not in item.get("contractId", "")]
if not data_list:
return pd.DataFrame()
data_df = pd.DataFrame(data_list)
data_df.columns = [
"symbol", "spec_buy_rate", "spec_buy", "hedge_buy_rate", "hedge_buy",
"rise_limit_rate", "rise_limit", "fall_limit", "agent_tot_buy_posi_quota",
"self_tot_buy_posi_quota", "client_buy_posi_quota", "self_tot_buy_ser_limit",
"client_buy_ser_limit", "trade_type"
]
data_df["variety"] = data_df["symbol"].str.extract(r"([A-Za-z]+)")
data_df["date"] = date
data_df = data_df[
["date", "symbol", "variety", "spec_buy_rate", "spec_buy", "hedge_buy_rate",
"hedge_buy", "rise_limit_rate", "rise_limit", "fall_limit",
"agent_tot_buy_posi_quota", "self_tot_buy_posi_quota", "client_buy_posi_quota"]
]
return data_df
def futures_settle_shfe(date: str = "20260119") -> pd.DataFrame:
"""
上海期货交易所-结算参数
https://www.shfe.com.cn/reports/tradedata/dailyandweeklydata/
:param date: 结算参数日期 formatYYYY-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: 结算参数日期 formatYYYY-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: 结算日期 formatYYYY-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)