stock-tracker

This commit is contained in:
C菌
2026-07-04 00:17:11 +08:00
commit 6087341a48
6463 changed files with 1929869 additions and 0 deletions
@@ -0,0 +1,6 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2019/9/30 13:58
Desc:
"""
@@ -0,0 +1,637 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2025/7/21 15:00
Desc: 期货配置文件
"""
import datetime
import json
import os
import pickle
import re
futures_inventory_em_symbol_dict = {
"a": "A", # 豆一
"ag": "AG", # 沪银
"al": "AL", # 沪铝
"ao": "AO", # 氧化铝
"AP": "AP", # 苹果
"au": "AU", # 沪金
"b": "B", # 豆二
"bb": None, # 胶合板 (new中没有对应)
"bc": None, # 国际铜 (new中没有对应)
"br": "BR", # BR橡胶
"bu": "BU", # 沥青
"c": "C", # 玉米
"CF": "CF", # 棉花/郑棉
"CJ": "CJ", # 红枣
"cs": "CS", # 淀粉/玉米淀粉
"cu": "CU", # 沪铜
"CY": "CY", # 棉纱
"eb": "EB", # 苯乙烯
"ec": "ec", # 集运欧线/集运指数(欧线)
"eg": "EG", # 乙二醇
"fb": None, # 纤维板 (new中没有对应)
"FG": "FG", # 玻璃
"PL": "PL", # 丙烯
"fu": "FU", # 燃料油/燃油
"hc": "HC", # 热卷
"i": "I", # 铁矿石
"IC": "IC", # 中证500
"IF": "IF", # 沪深300
"IH": "IH", # 上证50
"IM": "IM", # 中证1000
"j": "J", # 焦炭
"jd": "JD", # 鸡蛋
"jm": "JM", # 焦煤
"JR": None, # 粳稻 (new中没有对应)
"l": "L", # 塑料
"lc": "lc", # 碳酸锂
"lh": "LH", # 生猪
"LR": None, # 晚籼稻 (new中没有对应)
"lu": "lu", # LU燃油/低硫燃料油
"m": "M", # 豆粕
"MA": "MA", # 甲醇
"ni": "NI", # 沪镍/镍
"nr": "nr", # 20号胶
"OI": "OI", # 菜籽油/菜油
"p": "P", # 棕榈油/棕榈
"pb": "PB", # 沪铅
"PF": "PF", # 短纤
"pg": "PG", # 液化气/液化石油气
"PK": "PK", # 花生
"PM": None, # 普麦 (new中没有对应)
"pp": "PP", # 聚丙烯
"PX": "PX", # 对二甲苯
"rb": "RB", # 螺纹钢
"RI": None, # 早籼稻 (new中没有对应)
"RM": "RM", # 菜籽粕/菜粕
"rr": None, # 粳米 (new中没有对应)
"RS": "RS", # 油菜籽/菜籽
"ru": "RU", # 橡胶
"SA": "SA", # 纯碱
"sc": None, # 原油 (new中没有对应)
"SF": "SF", # 硅铁
"SH": "SH", # 烧碱
"si": "si", # 工业硅
"SM": "SM", # 锰硅
"sn": "SN", # 沪锡/锡
"sp": "SP", # 纸浆
"SR": "SR", # 白糖
"ss": "SS", # 不锈钢
"T": "T", # 十年国债/10年期国债
"TA": "TA", # PTA
"TF": "TF", # 五年国债/5年期国债
"TL": "TL", # 三十年国债/30年期国债期货
"TS": "TS", # 二年国债/2年期国债
"UR": "UR", # 尿素
"v": "V", # PVC
"WH": None, # 强麦 (new中没有对应)
"wr": None, # 线材 (new中没有对应)
"y": "Y", # 豆油
"ZC": None, # 动力煤 (new中没有对应)
"zn": "ZN", # 沪锌
}
hq_sina_spot_headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,"
"image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Host": "finance.sina.com.cn",
"Pragma": "no-cache",
"Referer": "https://finance.sina.com.cn/futuremarket/",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36",
}
# zh_sina_spot
zh_subscribe_exchange_symbol_url = (
"http://vip.stock.finance.sina.com.cn/quotes_service/view/js/qihuohangqing.js"
)
zh_match_main_contract_url = (
"http://vip.stock.finance.sina.com.cn/quotes_service/"
"api/json_v2.php/Market_Center.getHQFuturesData"
)
zh_match_main_contract_payload = {
"page": "1",
"num": "5",
"sort": "position",
"asc": "0",
"node": "001",
"base": "futures",
}
zh_sina_spot_headers = {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Host": "hq.sinajs.cn",
"Pragma": "no-cache",
"Referer": "https://finance.sina.com.cn/futuremarket/",
"Sec-Fetch-Mode": "no-cors",
"Sec-Fetch-Site": "cross-site",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/78.0.3904.97 Safari/537.36",
}
# 99 期货
inventory_temp_headers = {
"Accept": "image/webp,image/apng,image/*,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Connection": "keep-alive",
"Content-Type": "application/x-www-form-urlencoded",
"Cookie": "UM_distinctid=16c378978de5cc-02cfeac5f7869b-c343162-1fa400-16c378978df8d7; "
"__utmz=181566328.1570520149.3.2.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; "
"ASP.NET_SessionId=wj5gxuzl3fvvr25503tquq55; __utmc=181566328; _fxaid=1D9A634AB9F5D026585"
"6F7E85E7BC196%1D%2BOOl1inxPE7181fmKs5HCs%2BdLO%2Fq%2FbSvf46UVjo%2BE7w%3D%1DPYphpUa9OlzW"
"UzatrOQTXLPOVillbwMhTIJas%2ByfkyVL2Hd5XA1GOSslksqDkMTccXvQ2duLNsc0CHT4789JrYNbakJrpzrxL"
"nwtBC5GCTssKHGEpor6EwAZfWJgBUlCs4JYFcGUnh3jIO69A4LsOlRMOGf4c9cd%2FbohSjTx3VA%3D; __utma"
"=181566328.1348268634.1564299852.1571066568.1571068391.7; tgw_l7_route=eb1311426274fc07"
"631b2135a6431f7d; __utmt=1; __utmb=181566328.7.10.1571068391",
"Host": "service.99qh.com",
"Referer": "http://service.99qh.com/Storage/Storage.aspx?page=99qh",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36",
}
# 奇货可查
QHKC_INDEX_URL = "https://www.qhkch.com/ajax/index_show.php"
QHKC_INDEX_TREND_URL = "https://qhkch.com/ajax/indexes_trend.php"
QHKC_INDEX_PROFIT_LOSS_URL = "https://qhkch.com/ajax/indexes_profit_loss.php"
QHKC_FUND_BS_URL = "https://qhkch.com/ajax/fund_bs_pie.php"
QHKC_FUND_POSITION_URL = "https://qhkch.com/ajax/fund_position_pie.php"
QHKC_FUND_POSITION_CHANGE_URL = "https://qhkch.com/ajax/fund_position_chge_pie.php"
QHKC_FUND_DEAL_URL = "https://qhkch.com/ajax/fund_deal_pie.php"
QHKC_FUND_BIG_CHANGE_URL = "https://qhkch.com/ajax/fund_big_chge.php"
QHKC_TOOL_FOREIGN_URL = "https://qhkch.com/ajax/toolbox_foreign.php"
QHKC_TOOL_GDP_URL = "https://qhkch.com/dist/views/toolbox/gdp.html?v=1.10.7.1"
# 键值对: 键为交易所代码, 值为具体合约代码
market_exchange_symbols = {
"cffex": ["IF", "IC", "IM", "IH", "T", "TF", "TS", "TL"],
"dce": [
"C",
"CS",
"A",
"B",
"M",
"Y",
"P",
"FB",
"BB",
"JD",
"L",
"V",
"PP",
"J",
"JM",
"I",
"EG",
"RR",
"EB", # 20191009
"PG",
"LH", # 20210108 生猪期货
"LG", # 20241118 原木期货
"BZ", # 20250708 纯苯期货
],
"czce": [
"WH",
"PM",
"CF",
"SR",
"TA",
"OI",
"RI",
"MA",
"ME",
"FG",
"RS",
"RM",
"ZC",
"JR",
"LR",
"SF",
"SM",
"WT",
"TC",
"GN",
"RO",
"ER",
"SRX",
"SRY",
"WSX",
"WSY",
"CY",
"AP",
"UR",
"CJ", # 红枣期货
"SA", # 纯碱期货
"PK", # 20210201 花生期货
"PF", # 短纤
"PX", # 对二甲苯
"SH", # 烧碱
"PR", # 瓶片
"PL", # 丙烯
],
"shfe": [
"CU",
"AL",
"ZN",
"PB",
"NI",
"SN",
"AU",
"AG",
"RB",
"WR",
"HC",
"FU",
"BU",
"RU",
"SC",
"NR",
"SP",
"SS",
"LU",
"BC",
"AO",
"BR",
"EC", # 集运指数
"AD", # 铸造铝合金期货
"OP", # 胶版印刷纸期货
],
"gfex": ["SI", "LC", "PS"],
}
contract_symbols = []
[contract_symbols.extend(i) for i in market_exchange_symbols.values()]
headers = {
"Host": "www.czce.com.cn",
"Connection": "keep-alive",
"Cache-Control": "max-age=0",
"Accept": "text/html, */*; q=0.01",
"X-Requested-With": "XMLHttpRequest",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/56.0.2924.87 Safari/537.36",
"DNT": "1",
"Referer": "http://www.super-ping.com/?ping=www.google.com&locale=sc",
"Accept-Encoding": "gzip, deflate, sdch",
"Accept-Language": "zh-CN,zh;q=0.8,ja;q=0.6",
}
shfe_headers = {"User-Agent": "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)"}
dce_headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,"
"*/*;q=0.8,application/signed-exchange;v=b3",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "max-age=0",
"Content-Length": "71",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "www.dce.com.cn",
"Origin": "http://www.dce.com.cn",
"Proxy-Connection": "keep-alive",
"Referer": "http://www.dce.com.cn/publicweb/quotesdata/weekQuotesCh.html",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/77.0.3865.90 Safari/537.36",
}
SYS_SPOT_PRICE_URL = "http://www.100ppi.com/sf/day-{}.html"
SYS_SPOT_PRICE_LATEST_URL = "http://www.100ppi.com/sf/"
SHFE_VOL_RANK_URL = "https://tsite.shfe.com.cn/data/dailydata/kx/pm%s.dat"
SHFE_VOL_RANK_URL_20250701 = (
"https://www.shfe.com.cn/data/tradedata/future/dailydata/pm%s.dat"
)
CFFEX_VOL_RANK_URL = "http://www.cffex.com.cn/sj/ccpm/%s/%s/%s_1.csv"
DCE_VOL_RANK_URL_1 = (
"http://portal.dce.com.cn/publicweb/quotesdata/exportMemberDealPosiQuotesData.html?"
"memberDealPosiQuotes.variety=%s&memberDealPosiQuotes.trade_type=0&contract.cont"
"ract_id=%s&contract.variety_id=%s&year=%s&month=%s&day=%s&exportFlag=txt"
)
DCE_VOL_RANK_URL_2 = (
"http://portal.dce.com.cn/publicweb/quotesdata/memberDealPosiQuotes.html?memberDeal"
"PosiQuotes.variety=%s&memberDealPosiQuotes.trade_type=0&contract.contract_id="
"all&contract.variety_id=%s&year=%s&month=%s&day=%s"
)
CZCE_VOL_RANK_URL_1 = "http://www.czce.com.cn/cn/exchange/jyxx/pm/pm%s.html"
CZCE_VOL_RANK_URL_2 = "http://www.czce.com.cn/cn/exchange/%s/datatradeholding/%s.htm"
CZCE_VOL_RANK_URL_3 = (
"http://www.czce.com.cn/cn/DFSStaticFiles/Future/%s/%s/FutureDataHolding.htm"
)
DCE_RECEIPT_URL = "http://portal.dce.com.cn/publicweb/quotesdata/wbillWeeklyQuotes.html"
SHFE_RECEIPT_URL_1 = "http://tsite.shfe.com.cn/data/dailydata/%sdailystock.html"
SHFE_RECEIPT_URL_2 = "http://tsite.shfe.com.cn/data/dailydata/%sdailystock.dat"
SHFE_RECEIPT_URL_20250701 = (
"https://www.shfe.com.cn/data/tradedata/future/dailydata/%sdailystock.dat"
)
CZCE_RECEIPT_URL_1 = "http://www.czce.com.cn/cn/exchange/jyxx/sheet/sheet%s.html"
CZCE_RECEIPT_URL_2 = "http://www.czce.com.cn/cn/exchange/%s/datawhsheet/%s.htm"
CZCE_RECEIPT_URL_3 = (
"http://www.czce.com.cn/cn/DFSStaticFiles/Future/%s/%s/FutureDataWhsheet.htm"
)
CFFEX_DAILY_URL = "http://www.cffex.com.cn/fzjy/mrhq/{}/{}/{}_1.csv"
SHFE_DAILY_URL = "http://tsite.shfe.com.cn/data/dailydata/kx/kx%s.dat"
SHFE_DAILY_URL_20250630 = (
"https://www.shfe.com.cn/data/tradedata/future/dailydata/kx%s.dat"
)
SHFE_V_WAP_URL = "http://tsite.shfe.com.cn/data/dailydata/ck/%sdailyTimePrice.dat"
DCE_DAILY_URL = "http://www.dce.com.cn//publicweb/quotesdata/dayQuotesCh.html"
CZCE_DAILY_URL_1 = "http://www.czce.com.cn/cn/exchange/jyxx/hq/hq%s.html"
CZCE_DAILY_URL_2 = "http://www.czce.com.cn/cn/exchange/%s/datadaily/%s.txt"
CZCE_DAILY_URL_3 = (
"http://www.czce.com.cn/cn/DFSStaticFiles/Future/%s/%s/FutureDataDaily.txt"
)
DATE_PATTERN = re.compile(r"^([0-9]{4})[-/]?([0-9]{2})[-/]?([0-9]{2})")
FUTURES_SYMBOL_PATTERN = re.compile(r"(^[A-Za-z]{1,2})[0-9]+")
CFFEX_COLUMNS = [
"open",
"high",
"low",
"volume",
"turnover",
"open_interest",
"close",
"settle",
"change1",
"change2",
]
CZCE_COLUMNS = [
"pre_settle",
"open",
"high",
"low",
"close",
"settle",
"change1",
"change2",
"volume",
"open_interest",
"oi_chg",
"turnover",
"final_settle",
]
CZCE_COLUMNS_2 = [
"pre_settle",
"open",
"high",
"low",
"close",
"settle",
"change1",
"volume",
"open_interest",
"oi_chg",
"turnover",
"final_settle",
]
SHFE_COLUMNS = {
"CLOSEPRICE": "close",
"HIGHESTPRICE": "high",
"LOWESTPRICE": "low",
"OPENINTEREST": "open_interest",
"OPENPRICE": "open",
"PRESETTLEMENTPRICE": "pre_settle",
"SETTLEMENTPRICE": "settle",
"VOLUME": "volume",
}
SHFE_V_WAP_COLUMNS = {
":B1": "date",
"INSTRUMENT_ID": "symbol",
"TIME": "time_range",
"REF_SETTLEMENT_PRICE": "v_wap",
}
DCE_COLUMNS = [
"open",
"high",
"low",
"close",
"pre_settle",
"settle",
"change1",
"change2",
"volume",
"open_interest",
"oi_chg",
"turnover",
]
DCE_OPTION_COLUMNS = [
"open",
"high",
"low",
"close",
"pre_settle",
"settle",
"change1",
"change2",
"delta",
"volume",
"open_interest",
"oi_chg",
"turnover",
"exercise_volume",
]
OUTPUT_COLUMNS = [
"symbol",
"date",
"open",
"high",
"low",
"close",
"volume",
"open_interest",
"turnover",
"settle",
"pre_settle",
"variety",
]
OPTION_OUTPUT_COLUMNS = [
"symbol",
"date",
"open",
"high",
"low",
"close",
"pre_settle",
"settle",
"delta",
"volume",
"open_interest",
"oi_chg",
"turnover",
"implied_volatility",
"exercise_volume",
"variety",
]
DCE_MAP = {
"大豆": "A",
"豆一": "A",
"豆二": "B",
"豆粕": "M",
"豆油": "Y",
"棕榈油": "P",
"玉米": "C",
"玉米淀粉": "CS",
"鸡蛋": "JD",
"纤维板": "FB",
"胶合板": "BB",
"聚乙烯": "L",
"聚氯乙烯": "V",
"聚丙烯": "PP",
"焦炭": "J",
"焦煤": "JM",
"铁矿石": "I",
"乙二醇": "EG",
"粳米": "RR",
"苯乙烯": "EB",
"液化石油气": "PG",
"生猪": "LH",
"原木": "LG",
"纯苯": "BZ",
"聚氯乙烯月均价": "VF",
"聚丙烯月均价": "PPF",
"聚乙烯月均价": "LF",
}
def convert_date(date):
"""
transform a date string to datetime.date object
:param date, string, e.g. 2016-01-01, 20160101 or 2016/01/01
:return: object of datetime.date(such as 2016-01-01) or None
"""
if isinstance(date, datetime.date):
return date
elif isinstance(date, str):
match = DATE_PATTERN.match(date)
if match:
groups = match.groups()
if len(groups) == 3:
return datetime.date(
year=int(groups[0]),
month=int(groups[1]),
day=int(groups[2]),
)
return None
def get_json_path(name, module_file):
"""
获取 JSON 配置文件的路径(从模块所在目录查找)
:param name: 文件名
:param module_file: filename
:return: str json_file_path
"""
module_folder = os.path.abspath(os.path.dirname(os.path.dirname(module_file)))
module_json_path = os.path.join(module_folder, "file_fold", name)
return module_json_path
def get_pk_path(name, module_file):
"""
获取 pickle 配置文件的路径(从模块所在目录查找)
:param name: 文件名
:param module_file: filename
:return: str json_file_path
"""
module_folder = os.path.abspath(os.path.dirname(os.path.dirname(module_file)))
module_json_path = os.path.join(module_folder, "file_fold", name)
return module_json_path
def get_pk_data(file_name):
"""
获取交易日历至 2019 年结束, 这里的交易日历需要按年更新
:return: json
"""
setting_file_name = file_name
setting_file_path = get_pk_path(setting_file_name, __file__)
return pickle.load(open(setting_file_path, "rb"))
def get_calendar():
"""
获取交易日历, 这里的交易日历需要按年更新, 主要是从新浪获取的
:return: 交易日历
:rtype: json
"""
setting_file_name = "calendar.json"
setting_file_path = get_json_path(setting_file_name, __file__)
with open(setting_file_path, "r", encoding="utf-8") as f:
data_json = json.load(f)
return data_json
def last_trading_day(day):
"""
获取前一个交易日
:param day: "%Y%m%d" or datetime.date()
:return last_day: "%Y%m%d" or datetime.date()
"""
calendar = get_calendar()
if isinstance(day, str):
if day not in calendar:
print("Today is not trading day" + day)
return False
pos = calendar.index(day)
last_day = calendar[pos - 1]
return last_day
elif isinstance(day, datetime.date):
d_str = day.strftime("%Y%m%d")
if d_str not in calendar:
print("Today is not working day" + d_str)
return False
pos = calendar.index(d_str)
last_day = calendar[pos - 1]
last_day = datetime.datetime.strptime(last_day, "%Y%m%d").date()
return last_day
def get_latest_data_date(day):
"""
获取最新的有数据的交易日
:param day: datetime.datetime
:return string YYYYMMDD
"""
calendar = get_calendar()
if day.strftime("%Y%m%d") in calendar:
if day.time() > datetime.time(17, 0, 0):
return day.strftime("%Y%m%d")
else:
return last_trading_day(day.strftime("%Y%m%d"))
else:
while day.strftime("%Y%m%d") not in calendar:
day = day - datetime.timedelta(days=1)
return day.strftime("%Y%m%d")
if __name__ == "__main__":
d = datetime.datetime(2018, 10, 5, 17, 1, 0)
print(get_latest_data_date(d))
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,386 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2024/12/12 17:00
Desc: 生意社网站采集大宗商品现货价格及相应基差数据, 数据时间段从 20110104-至今
备注:现期差 = 现货价格 - 期货价格(这里的期货价格为结算价)
黄金为 元/克, 白银为 元/千克, 玻璃现货为 元/平方米, 鸡蛋现货为 元/公斤, 鸡蛋期货为 元/500千克, 其余为 元/吨.
焦炭现货规格是: 一级冶金焦; 焦炭期货规格: 介于一级和二级之间, 焦炭现期差仅供参考.
铁矿石现货价格是: 湿吨, 铁矿石期货价格是: 干吨
网页地址: https://www.100ppi.com/sf/
历史数据可以通过修改 url 地址来获取, 比如: https://www.100ppi.com/sf/day-2017-09-12.html
发现生意社的 bugs:
1. 2018-09-12 周三 数据缺失是因为生意社源数据在该交易日缺失: https://www.100ppi.com/sf/day-2018-09-12.html
"""
import datetime
import re
import time
import warnings
from typing import List
import pandas as pd
from akshare.futures import cons
from akshare.futures.requests_fun import pandas_read_html_link
from akshare.futures.symbol_var import chinese_to_english
calendar = cons.get_calendar()
def futures_spot_price_daily(
start_day: str = "20210201",
end_day: str = "20210208",
vars_list: list = cons.contract_symbols,
):
"""
指定时间段内大宗商品现货价格及相应基差
https://www.100ppi.com/sf/
:param start_day: str 开始日期 formatYYYY-MM-DD 或 YYYYMMDD 或 datetime.date对象; 默认为当天
:param end_day: str 结束数据 formatYYYY-MM-DD 或 YYYYMMDD 或 datetime.date对象; 默认为当天
:param vars_list: list 合约品种如 [RB, AL]; 默认参数为所有商品
:return: 基差
:rtype: pandas.DataFrame
展期收益率数据:
var 商品品种 string
sp 现货价格 float
near_symbol 临近交割合约 string
near_price 临近交割合约结算价 float
dom_symbol 主力合约 string
dom_price 主力合约结算价 float
near_basis 临近交割合约相对现货的基差 float
dom_basis 主力合约相对现货的基差 float
near_basis_rate 临近交割合约相对现货的基差率 float
dom_basis_rate 主力合约相对现货的基差率 float
date 日期 string YYYYMMDD
"""
start_day = (
cons.convert_date(start_day) if start_day is not None else datetime.date.today()
)
end_day = (
cons.convert_date(end_day)
if end_day is not None
else cons.convert_date(cons.get_latest_data_date(datetime.datetime.now()))
)
df_list = []
while start_day <= end_day:
temp_df = futures_spot_price(start_day, vars_list)
if temp_df is False:
return pd.concat(df_list).reset_index(drop=True)
elif temp_df is not None:
df_list.append(temp_df)
start_day += datetime.timedelta(days=1)
if len(df_list) > 0:
temp_df = pd.concat(df_list)
temp_df.reset_index(drop=True, inplace=True)
return temp_df
def futures_spot_price(
date: str = "20240430", vars_list: list = cons.contract_symbols
) -> pd.DataFrame:
"""
指定交易日大宗商品现货价格及相应基差
https://www.100ppi.com/sf/day-2017-09-12.html
:param date: 开始日期 format: YYYY-MM-DD 或 YYYYMMDD 或 datetime.date 对象; 为空时为当天
:param vars_list: 合约品种如 RB、AL 等列表 为空时为所有商品
:return: pandas.DataFrame
展期收益率数据:
var 商品品种 string
sp 现货价格 float
near_symbol 临近交割合约 string
near_price 临近交割合约结算价 float
dom_symbol 主力合约 string
dom_price 主力合约结算价 float
near_basis 临近交割合约相对现货的基差 float
dom_basis 主力合约相对现货的基差 float
near_basis_rate 临近交割合约相对现货的基差率 float
dom_basis_rate 主力合约相对现货的基差率 float
date 日期 string YYYYMMDD
"""
date = cons.convert_date(date) if date is not None else datetime.date.today()
if date < datetime.date(2011, 1, 4):
raise Exception(
"数据源开始日期为 20110104, 请将获取数据时间点设置在 20110104 后"
)
if date.strftime("%Y%m%d") not in calendar:
warnings.warn(f"{date.strftime('%Y%m%d')}非交易日")
return pd.DataFrame()
u1 = "https://www.100ppi.com/sf/"
u2 = f"https://www.100ppi.com/sf/day-{date.strftime('%Y-%m-%d')}.html"
i = 1
while True:
for url in [u2, u1]:
try:
# url = u2
headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,"
"image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"
}
r = pandas_read_html_link(url, headers=headers)
string = r[0].loc[1, 1]
news = "".join(re.findall(r"[0-9]", string))
if news[3:11] == date.strftime("%Y%m%d"):
records = _check_information(r[1], date)
records.index = records["symbol"]
var_list_in_market = [i for i in vars_list if i in records.index]
temp_df = records.loc[var_list_in_market, :]
temp_df.reset_index(drop=True, inplace=True)
return temp_df
else:
time.sleep(3)
except Exception as e: # noqa: E722
print(
f"{date.strftime('%Y-%m-%d')}日生意社数据连接失败[错误信息:{e}],第{str(i)}次尝试,最多5次"
)
i += 1
if i > 5:
print(
f"{date.strftime('%Y-%m-%d')}日生意社数据连接失败, 如果当前交易日是 2018-09-12, "
f"由于生意社源数据缺失, 无法访问, 否则为重复访问已超过5次,您的地址被网站墙了,"
f"请保存好返回数据,稍后从该日期起重试"
)
return pd.DataFrame()
def _check_information(df_data, date):
"""
数据验证和计算模块
:param df_data: pandas.DataFrame 采集的数据
:param date: datetime.date 具体某一天 YYYYMMDD
:return: pandas.DataFrame
中间数据
symbol spot_price near_contract ... near_basis_rate dom_basis_rate date
CU 49620.00 cu1811 ... -0.002418 -0.003426 20181108
RB 4551.54 rb1811 ... -0.013521 -0.134359 20181108
ZN 22420.00 zn1811 ... -0.032114 -0.076271 20181108
AL 13900.00 al1812 ... 0.005396 0.003957 20181108
AU 274.10 au1811 ... 0.005655 0.020430 20181108
WR 4806.25 wr1903 ... -0.180026 -0.237035 20181108
RU 10438.89 ru1811 ... -0.020969 0.084406 20181108
PB 18600.00 pb1811 ... -0.001344 -0.010215 20181108
AG 3542.67 ag1811 ... -0.000754 0.009408 20181108
BU 4045.53 bu1811 ... -0.129904 -0.149679 20181108
HC 4043.33 hc1811 ... -0.035449 -0.088128 20...
"""
df_data = df_data.loc[:, [0, 1, 2, 3, 5, 6]]
df_data.columns = [
"symbol",
"spot_price",
"near_contract",
"near_contract_price",
"dominant_contract",
"dominant_contract_price",
]
records = pd.DataFrame()
for string in df_data["symbol"].tolist():
news = "".join(re.findall(r"[\u4e00-\u9fa5]", string))
if news == "":
news = string.strip()
"""
if string == "PTA":
news = "PTA"
else:
news = "".join(re.findall(r"[\u4e00-\u9fa5]", string))
"""
if news != "" and news not in [
"商品",
"价格",
"上海期货交易所",
"郑州商品交易所",
"大连商品交易所",
"广州期货交易所",
# 某些天网站没有数据,比如 20180912,此时返回"暂无数据",但并不是网站被墙了
"暂无数据",
]:
symbol = chinese_to_english(news)
record = pd.DataFrame(df_data[df_data["symbol"] == string])
record.loc[:, "symbol"] = symbol
record["spot_price"] = record["spot_price"].astype(float)
if (
symbol == "JD"
): # 鸡蛋现货为元/公斤, 鸡蛋期货为元/500千克, 其余元/吨(http://www.100ppi.com/sf/)
record.loc[:, "spot_price"] = float(record["spot_price"].iloc[0]) * 500
elif (
symbol == "FG"
): # 上表中现货单位为元/平方米, 期货单位为元/吨. 换算公式:元/平方米*80=元/吨(http://www.100ppi.com/sf/959.html)
record.loc[:, "spot_price"] = float(record["spot_price"].iloc[0]) * 80
elif (
symbol == "LH"
): # 上表中现货单位为元/公斤, 期货单位为元/吨. 换算公式:元/公斤*1000=元/吨(http://www.100ppi.com/sf/959.html)
record.loc[:, "spot_price"] = float(record["spot_price"].iloc[0]) * 1000
records = pd.concat([records, record])
# 20241129:如果某日没有数据,直接返回返回空表
if records.empty:
records = df_data.iloc[0:0]
records["near_basis"] = pd.Series(dtype="float")
records["dom_basis"] = pd.Series(dtype="float")
records["near_basis_rate"] = pd.Series(dtype="float")
records["dom_basis_rate"] = pd.Series(dtype="float")
records["date"] = pd.Series(dtype="object")
return records
records[["near_contract_price", "dominant_contract_price", "spot_price"]] = (
records[["near_contract_price", "dominant_contract_price", "spot_price"]
].astype("float")
)
records["near_contract"] = records["near_contract"].replace(
r"[^0-9]*(\d*)$", r"\g<1>", regex=True
)
records["dominant_contract"] = records["dominant_contract"].replace(
r"[^0-9]*(\d*)$", r"\g<1>", regex=True
)
records["near_month"] = records.loc[:, "near_contract"]
records["near_contract"] = records["symbol"] + records.loc[
:, "near_contract"
].astype("int").astype("str")
records["dominant_month"] = records.loc[:, "dominant_contract"]
records["dominant_contract"] = records["symbol"] + records.loc[
:, "dominant_contract"
].astype("int").astype("str")
records["near_contract"] = records["near_contract"].apply(
lambda x: (
x.lower()
if x[:-4]
in cons.market_exchange_symbols["shfe"]
+ cons.market_exchange_symbols["dce"]
else x
)
)
records["dominant_contract"] = records["dominant_contract"].apply(
lambda x: (
x.lower()
if x[:-4]
in cons.market_exchange_symbols["shfe"]
+ cons.market_exchange_symbols["dce"]
else x
)
)
records["near_contract"] = records["near_contract"].apply(
lambda x: (
x[:-4] + x[-3:] if x[:-4] in cons.market_exchange_symbols["czce"] else x
)
)
records["dominant_contract"] = records["dominant_contract"].apply(
lambda x: (
x[:-4] + x[-3:] if x[:-4] in cons.market_exchange_symbols["czce"] else x
)
)
records["near_basis"] = records["near_contract_price"] - records["spot_price"]
records["dom_basis"] = records["dominant_contract_price"] - records["spot_price"]
records["near_basis_rate"] = (
records["near_contract_price"] / records["spot_price"] - 1
)
records["dom_basis_rate"] = (
records["dominant_contract_price"] / records["spot_price"] - 1
)
# records.loc[:, "date"] = date.strftime("%Y%m%d")
records.insert(0, "date", date.strftime("%Y%m%d"))
records.reset_index(inplace=True, drop=True)
return records
def _join_head(content: pd.DataFrame) -> List:
headers = []
for s1, s2 in zip(content.iloc[0], content.iloc[1]):
if s1 != s2:
s = f"{s1}{s2}"
else:
s = s1
headers.append(s)
return headers
def futures_spot_price_previous(date: str = "20240430") -> pd.DataFrame:
"""
具体交易日大宗商品现货价格及相应基差
https://www.100ppi.com/sf/day-2017-09-12.html
:param date: 交易日; 历史日期
:type date: str
:return: 现货价格及相应基差
:rtype: pandas.DataFrame
"""
date = cons.convert_date(date) if date is not None else datetime.date.today()
if date < datetime.date(2011, 1, 4):
raise Exception(
"数据源开始日期为 20110104, 请将获取数据时间点设置在 20110104 后"
)
if date.strftime("%Y%m%d") not in calendar:
warnings.warn(f"{date.strftime('%Y%m%d')}非交易日")
return pd.DataFrame()
url = date.strftime("https://www.100ppi.com/sf2/day-%Y-%m-%d.html")
headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,"
"image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"
}
content = pandas_read_html_link(url, headers=headers)
main = content[1]
# Header
header = _join_head(main)
# Values
values = main[main[4].str.endswith("%")]
values.columns = header
# Basis
# 对于没有数据的天,xml文件中没有数据,所以content[2:-1]可能为空
if len(content[2:-1]) > 0:
basis = pd.concat(content[2:-1])
else:
basis = pd.DataFrame(columns=["主力合约基差", "主力合约基差(%)"])
basis.columns = ["主力合约基差", "主力合约基差(%)"]
# 20241125(jasonudu):因为部分日期,存在多个品种的现货价格,比如20151125的白糖、豆粕、豆油等,
# 如果用商品名来merge,会出现重复列名,所以改用index来merge
# basis["商品"] = values["商品"].tolist()
basis.index = values.index
basis = pd.merge(
values[["商品", "现货价格", "主力合约代码", "主力合约价格"]],
basis,
left_index=True,
right_index=True,
)
basis = pd.merge(
basis,
values[
[
"180日内主力基差最高",
"180日内主力基差最低",
"180日内主力基差平均",
]
],
left_index=True,
right_index=True,
)
basis.columns = [
"商品",
"现货价格",
"主力合约代码",
"主力合约价格",
"主力合约基差",
"主力合约变动百分比",
"180日内主力基差最高",
"180日内主力基差最低",
"180日内主力基差平均",
]
basis["主力合约变动百分比"] = basis["主力合约变动百分比"].str.strip("%")
basis.reset_index(inplace=True, drop=True)
return basis
if __name__ == "__main__":
futures_spot_price_daily_df = futures_spot_price_daily(
start_day="20260303", end_day="20260303", vars_list=['PL']
)
print(futures_spot_price_daily_df)
futures_spot_price_df = futures_spot_price(date="20260303")
print(futures_spot_price_df)
futures_spot_price_previous_df = futures_spot_price_previous(date="20240430")
print(futures_spot_price_previous_df)
@@ -0,0 +1,100 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2023/11/15 18:00
Desc: 东方财富网-数据中心-期货期权-COMEX库存数据
https://data.eastmoney.com/pmetal/comex/by.html
"""
import pandas as pd
import requests
from akshare.utils.tqdm import get_tqdm
def futures_comex_inventory(symbol: str = "黄金") -> pd.DataFrame:
"""
东方财富网-数据中心-期货期权-COMEX库存数据
https://data.eastmoney.com/pmetal/comex/by.html
:param symbol: choice of {"黄金", "白银"}
:type symbol: str
:return: COMEX库存数据
:rtype: pandas.DataFrame
"""
symbol_map = {
"黄金": "EMI00069026",
"白银": "EMI00069027",
}
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
"sortColumns": "REPORT_DATE",
"sortTypes": "-1",
"pageSize": "500",
"pageNumber": "1",
"reportName": "RPT_FUTUOPT_GOLDSIL",
"columns": "ALL",
"quoteColumns": "",
"source": "WEB",
"client": "WEB",
"filter": f'(INDICATOR_ID1="{symbol_map[symbol]}")(@STORAGE_TON<>"NULL")',
}
r = requests.get(url, params=params)
data_json = r.json()
total_page = data_json["result"]["pages"]
big_df = pd.DataFrame()
tqdm = get_tqdm()
for page in tqdm(range(1, total_page + 1), leave=False):
params.update(
{
"pageNumber": page,
}
)
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(data_json["result"]["data"])
big_df = pd.concat(objs=[big_df, temp_df], axis=0, ignore_index=True)
big_df.reset_index(inplace=True)
big_df["index"] = big_df["index"] + 1
big_df.rename(
columns={
"index": "序号",
"REPORT_DATE": "日期",
"INDICATOR_NAME": "-",
"INDICATOR_ID1": "-",
"STORAGE_TON": f"COMEX{symbol}库存量-吨",
"STORAGE_OUNCE": f"COMEX{symbol}库存量-盎司",
"INDICATOR_ID2": "-",
"NETPOSITION_TON": "-",
"NETPOSITION_OUNCE": "-",
"NETPOSITION_DOLLAR": "-",
"INDICATOR_ID3": "-",
"OPENPOSI_STOCK": "-",
"OPENPOSTOCK_WECHANGE": "-",
"OPENPOSI_STOCK_SUM": "-",
},
inplace=True,
)
big_df = big_df[
[
"序号",
"日期",
f"COMEX{symbol}库存量-吨",
f"COMEX{symbol}库存量-盎司",
]
]
big_df[f"COMEX{symbol}库存量-吨"] = pd.to_numeric(
big_df[f"COMEX{symbol}库存量-吨"], errors="coerce"
)
big_df[f"COMEX{symbol}库存量-盎司"] = pd.to_numeric(
big_df[f"COMEX{symbol}库存量-盎司"], errors="coerce"
)
big_df["日期"] = pd.to_datetime(big_df["日期"], errors="coerce").dt.date
big_df.sort_values(["日期"], inplace=True, ignore_index=True)
big_df["序号"] = range(1, len(big_df) + 1)
return big_df
if __name__ == "__main__":
futures_comex_inventory_df = futures_comex_inventory(symbol="黄金")
print(futures_comex_inventory_df)
@@ -0,0 +1,37 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2024/7/6 18:00
Desc: openctp 期货交易费用参照表
http://openctp.cn/fees.html
"""
from datetime import datetime
from io import StringIO
import pandas as pd
import requests
from bs4 import BeautifulSoup
def futures_fees_info() -> pd.DataFrame:
"""
openctp 期货交易费用参照表
http://openctp.cn/fees.html
:return: 期货交易费用参照表
:rtype: pandas.DataFrame
"""
url = "http://openctp.cn/fees.html"
r = requests.get(url)
r.encoding = "utf-8"
soup = BeautifulSoup(r.text, features="lxml")
datetime_str = soup.find("p").string.strip("Generated at ").strip(".")
datetime_raw = datetime.strptime(datetime_str, "%Y-%m-%d %H:%M:%S")
temp_df = pd.read_html(StringIO(r.text))[0]
temp_df["更新时间"] = datetime_raw.strftime("%Y-%m-%d %H:%M:%S")
return temp_df
if __name__ == "__main__":
futures_fees_info_df = futures_fees_info()
print(futures_fees_info_df)
@@ -0,0 +1,78 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2026/2/22 15:45
Desc: 金十数据-期货手续费
https://www.jin10.com/
"""
import json
import pandas as pd
import requests
def futures_comm_js(date: str = "20260213") -> pd.DataFrame:
"""
金十财经-期货手续费
https://www.jin10.com/
:param date: 日期; 格式为 YYYYMMDD,例如 "20250213"
:type date: str
:return: 期货手续费数据
:rtype: pandas.DataFrame
"""
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/107.0.0.0 Safari/537.36",
"x-app-id": "fiXF2nOnDycGutVA",
"x-version": "1.0",
"referer": "https://www.jin10.com/",
"origin": "https://www.jin10.com",
}
url = "https://mp-api.jin10.com/api/dynamic-data/child"
formatted_date = "-".join([date[:4], date[4:6], date[6:]])
params = {
"tb_name": "_vir_26",
"search": json.dumps({"range,date": f"{formatted_date},{formatted_date}", "status": 1}),
"order": "date,desc",
}
r = requests.get(url, params=params, headers=headers)
data_json = r.json()
temp_df = pd.DataFrame(data_json["data"])
temp_df = temp_df.rename(
columns={
"date": "日期",
"heyue_name": "合约品种",
"heyue_code": "合约代码",
"pub_date_commission": "手续费公布时间",
"pub_date_price": "价格公布时间",
"heyue_price": "现价",
"up_limit_num": "涨停板",
"down_limit_num": "跌停板",
"buy_ratio": "保证金/买开",
"sell_ratio": "保证金/卖开",
"per_lot_price": "保证金/每手",
"per_ratio": "每手跳数",
"buy_commission": "开仓",
"sell_yesterday_commission": "平昨",
"sell_cur_commission": "平今",
"per_commission_price": "每跳毛利",
"per_net_profit": "每跳净利",
"jys": "交易所",
}
)
temp_df = temp_df.drop(
columns=["id", "status", "created_at", "updated_at", "_date", "_pub_date_commission", "_pub_date_price"],
errors="ignore")
temp_df['日期'] = pd.to_datetime(temp_df['日期'], errors="coerce").dt.date
temp_df['现价'] = pd.to_numeric(temp_df['现价'], errors="coerce")
temp_df['涨停板'] = pd.to_numeric(temp_df['涨停板'], errors="coerce")
temp_df['跌停板'] = pd.to_numeric(temp_df['跌停板'], errors="coerce")
temp_df['每手跳数'] = pd.to_numeric(temp_df['每手跳数'], errors="coerce")
temp_df['每跳毛利'] = pd.to_numeric(temp_df['每跳毛利'], errors="coerce")
temp_df['每跳净利'] = pd.to_numeric(temp_df['每跳净利'], errors="coerce")
return temp_df
if __name__ == "__main__":
futures_comm_js_df = futures_comm_js(date="20260213")
print(futures_comm_js_df)
@@ -0,0 +1,284 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2024/4/11 17:00
Desc: 九期网-期货手续费
https://www.9qihuo.com/qihuoshouxufei
"""
from io import StringIO
import pandas as pd
import requests
from bs4 import BeautifulSoup
def _futures_comm_qihuo_process(df: pd.DataFrame, name: str = None) -> pd.DataFrame:
"""
期货手续费数据细节处理函数
https://www.9qihuo.com/qihuoshouxufei
:param df: 获取到的 pandas.DataFrame 数据
:type df: pandas.DataFrame
:param name: 交易所名称
:type name: str
:return: 处理后的数据
:rtype: pandas.DataFrame
"""
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
common_temp_df = df.copy()
common_temp_df["合约名称"] = (
common_temp_df["合约品种"].str.split("(", expand=True).iloc[:, 0].str.strip()
)
common_temp_df["合约代码"] = (
common_temp_df["合约品种"].str.split("(", expand=True).iloc[:, 1].str.strip(")")
)
common_temp_df["涨停板"] = (
common_temp_df["涨/跌停板"].str.split("/", expand=True).iloc[:, 0].str.strip()
)
common_temp_df["跌停板"] = (
common_temp_df["涨/跌停板"].str.split("/", expand=True).iloc[:, 1].str.strip()
)
common_temp_df["保证金-买开"] = common_temp_df["保证金-买开"].str.strip("%")
common_temp_df["保证金-卖开"] = common_temp_df["保证金-卖开"].str.strip("%")
common_temp_df["保证金-每手"] = common_temp_df["保证金-保证金/每手"].str.strip("")
common_temp_df["手续费"] = common_temp_df["手续费(开+平)"].str.strip("")
try:
temp_df_ratio = (
common_temp_df["手续费标准-开仓"][
common_temp_df["手续费标准-开仓"].str.contains("万分之")
]
.str.split("/", expand=True)
.iloc[:, 0]
.astype(float)
/ 10000
)
except IndexError:
temp_df_ratio = pd.NA
temp_df_yuan = common_temp_df["手续费标准-开仓"][
common_temp_df["手续费标准-开仓"].str.contains("")
]
common_temp_df["手续费标准-开仓-万分之"] = temp_df_ratio
common_temp_df["手续费标准-开仓-元"] = temp_df_yuan.str.strip("")
try:
temp_df_ratio = (
common_temp_df["手续费标准-平昨"][
common_temp_df["手续费标准-平昨"].str.contains("万分之")
]
.str.split("/", expand=True)
.iloc[:, 0]
.astype(float)
/ 10000
)
except IndexError:
temp_df_ratio = pd.NA
temp_df_yuan = common_temp_df["手续费标准-平昨"][
common_temp_df["手续费标准-平昨"].str.contains("")
]
common_temp_df["手续费标准-平昨-万分之"] = temp_df_ratio
common_temp_df["手续费标准-平昨-元"] = temp_df_yuan.str.strip("")
try:
temp_df_ratio = (
common_temp_df["手续费标准-平今"][
common_temp_df["手续费标准-平今"].str.contains("万分之")
]
.str.split("/", expand=True)
.iloc[:, 0]
.astype(float)
/ 10000
)
except IndexError:
temp_df_ratio = pd.NA
temp_df_yuan = common_temp_df["手续费标准-平今"][
common_temp_df["手续费标准-平今"].str.contains("")
]
common_temp_df["手续费标准-平今-万分之"] = temp_df_ratio
common_temp_df["手续费标准-平今-元"] = temp_df_yuan.str.strip("")
del common_temp_df["手续费标准-开仓"]
del common_temp_df["手续费标准-平昨"]
del common_temp_df["手续费标准-平今"]
del common_temp_df["合约品种"]
del common_temp_df["涨/跌停板"]
del common_temp_df["手续费(开+平)"]
del common_temp_df["保证金-保证金/每手"]
common_temp_df["交易所名称"] = name
common_temp_df = common_temp_df[
[
"交易所名称",
"合约名称",
"合约代码",
"现价",
"涨停板",
"跌停板",
"保证金-买开",
"保证金-卖开",
"保证金-每手",
"手续费标准-开仓-万分之",
"手续费标准-开仓-元",
"手续费标准-平昨-万分之",
"手续费标准-平昨-元",
"手续费标准-平今-万分之",
"手续费标准-平今-元",
"每跳毛利",
"手续费",
"每跳净利",
"备注",
]
]
common_temp_df["现价"] = pd.to_numeric(common_temp_df["现价"])
common_temp_df["涨停板"] = pd.to_numeric(common_temp_df["涨停板"])
common_temp_df["跌停板"] = pd.to_numeric(common_temp_df["跌停板"])
common_temp_df["保证金-买开"] = pd.to_numeric(common_temp_df["保证金-买开"])
common_temp_df["保证金-卖开"] = pd.to_numeric(common_temp_df["保证金-卖开"])
common_temp_df["保证金-每手"] = pd.to_numeric(common_temp_df["保证金-每手"])
# common_temp_df["手续费标准-开仓-元"] = pd.to_numeric(common_temp_df["手续费标准-开仓-元"])
# common_temp_df["手续费标准-平昨-元"] = pd.to_numeric(common_temp_df["手续费标准-平昨-元"])
# common_temp_df["手续费标准-平今-元"] = pd.to_numeric(common_temp_df["手续费标准-平今-元"])
common_temp_df["每跳毛利"] = pd.to_numeric(common_temp_df["每跳毛利"])
common_temp_df["手续费"] = pd.to_numeric(common_temp_df["手续费"])
common_temp_df["每跳净利"] = pd.to_numeric(common_temp_df["每跳净利"])
session = requests.Session()
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/125.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive",
"Referer": "https://www.9qihuo.com/",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "same-origin",
"Sec-Fetch-User": "?1",
"Upgrade-Insecure-Requests": "1",
"Cache-Control": "max-age=0",
}
session.get("https://www.9qihuo.com/", headers=headers, timeout=10)
r = session.get(
"https://www.9qihuo.com/qihuoshouxufei", headers=headers, timeout=10
)
soup = BeautifulSoup(r.text, features="lxml")
raw_date_text = soup.find(name="a", attrs={"id": "dlink"}).previous
comm_update_time = raw_date_text.split("")[0].strip("(手续费更新时间:")
price_update_time = (
raw_date_text.split("")[1].strip("价格更新时间:").strip("。)")
)
common_temp_df["手续费更新时间"] = comm_update_time
common_temp_df["价格更新时间"] = price_update_time
return common_temp_df
def futures_comm_info(symbol: str = "所有") -> pd.DataFrame:
"""
九期网-期货手续费
https://www.9qihuo.com/qihuoshouxufei
:param symbol: choice of {"所有", "上海期货交易所", "大连商品交易所", "郑州商品交易所", "上海国际能源交易中心", "中国金融期货交易所", "广州期货交易所"}
:type symbol: str
:return: 期货手续费
:rtype: pandas.DataFrame
"""
session = requests.Session()
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/125.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive",
"Referer": "https://www.9qihuo.com/",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "same-origin",
"Sec-Fetch-User": "?1",
"Upgrade-Insecure-Requests": "1",
"Cache-Control": "max-age=0",
}
session.get("https://www.9qihuo.com/", headers=headers, timeout=10)
r = session.get(
"https://www.9qihuo.com/qihuoshouxufei", headers=headers, timeout=10
)
temp_df = pd.read_html(StringIO(r.text))[0]
temp_df.columns = [
"合约品种",
"现价",
"涨/跌停板",
"保证金-买开",
"保证金-卖开",
"保证金-保证金/每手",
"手续费标准-开仓",
"手续费标准-平昨",
"手续费标准-平今",
"每跳毛利",
"手续费(开+平)",
"每跳净利",
"备注",
"-",
"-",
]
df_0 = temp_df[temp_df["合约品种"].str.contains("上海期货交易所")].index.values[0]
df_1 = temp_df[temp_df["合约品种"].str.contains("大连商品交易所")].index.values[0]
df_2 = temp_df[temp_df["合约品种"].str.contains("郑州商品交易所")].index.values[0]
df_3 = temp_df[
temp_df["合约品种"].str.contains("上海国际能源交易中心")
].index.values[0]
df_4 = temp_df[temp_df["合约品种"].str.contains("广州期货交易所")].index.values[0]
df_5 = temp_df[temp_df["合约品种"].str.contains("中国金融期货交易所")].index.values[
0
]
shfe_df = temp_df.iloc[df_0 + 3 : df_1, :].reset_index(drop=True)
dce_df = temp_df.iloc[df_1 + 3 : df_2, :].reset_index(drop=True)
czce_df = temp_df.iloc[df_2 + 3 : df_3, :].reset_index(drop=True)
ine_df = temp_df.iloc[df_3 + 3 : df_4, :].reset_index(drop=True)
gfex_df = temp_df.iloc[df_4 + 3 : df_5, :].reset_index(drop=True)
cffex_df = temp_df.iloc[df_5 + 3 :, :].reset_index(drop=True)
if symbol == "上海期货交易所":
return _futures_comm_qihuo_process(shfe_df, name="上海期货交易所")
elif symbol == "大连商品交易所":
return _futures_comm_qihuo_process(dce_df, name="大连商品交易所")
elif symbol == "郑州商品交易所":
return _futures_comm_qihuo_process(czce_df, name="郑州商品交易所")
elif symbol == "上海国际能源交易中心":
return _futures_comm_qihuo_process(ine_df, name="上海国际能源交易中心")
elif symbol == "广州期货交易所":
return _futures_comm_qihuo_process(gfex_df, name="广州期货交易所")
elif symbol == "中国金融期货交易所":
return _futures_comm_qihuo_process(cffex_df, name="中国金融期货交易所")
else:
big_df = pd.DataFrame()
big_df = pd.concat(
objs=[big_df, _futures_comm_qihuo_process(shfe_df, name="上海期货交易所")],
ignore_index=True,
)
big_df = pd.concat(
objs=[big_df, _futures_comm_qihuo_process(dce_df, name="大连商品交易所")],
ignore_index=True,
)
big_df = pd.concat(
objs=[big_df, _futures_comm_qihuo_process(czce_df, name="郑州商品交易所")],
ignore_index=True,
)
big_df = pd.concat(
objs=[
big_df,
_futures_comm_qihuo_process(ine_df, name="上海国际能源交易中心"),
],
ignore_index=True,
)
big_df = pd.concat(
objs=[big_df, _futures_comm_qihuo_process(gfex_df, name="广州期货交易所")],
ignore_index=True,
)
big_df = pd.concat(
objs=[
big_df,
_futures_comm_qihuo_process(cffex_df, name="中国金融期货交易所"),
],
ignore_index=True,
)
return big_df
if __name__ == "__main__":
futures_comm_info_df = futures_comm_info(symbol="所有")
print(futures_comm_info_df)
@@ -0,0 +1,90 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2025/10/30 17:00
Desc: 查询期货合约当前时刻的详情
https://finance.sina.com.cn/futures/quotes/V2101.shtml
"""
from io import StringIO
import pandas as pd
import requests
from bs4 import BeautifulSoup
def futures_contract_detail(symbol: str = "AP2101") -> pd.DataFrame:
"""
查询期货合约详情
https://finance.sina.com.cn/futures/quotes/V2101.shtml
:param symbol: 合约
:type symbol: str
:return: 期货合约详情
:rtype: pandas.DataFrame
"""
url = f"https://finance.sina.com.cn/futures/quotes/{symbol}.shtml"
r = requests.get(url)
r.encoding = "gb2312"
temp_df = pd.read_html(StringIO(r.text))[6]
data_one = temp_df.iloc[:, :2]
data_one.columns = ["item", "value"]
data_two = temp_df.iloc[:, 2:4]
data_two.columns = ["item", "value"]
data_three = temp_df.iloc[:, 4:]
data_three.columns = ["item", "value"]
temp_df = pd.concat(
objs=[data_one, data_two, data_three], axis=0, ignore_index=True
)
return temp_df
def futures_contract_detail_em(symbol: str = "v2602F") -> pd.DataFrame:
"""
查询期货合约详情
https://quote.eastmoney.com/qihuo/v2602F.html
:param symbol: 合约
:type symbol: str
:return: 期货合约详情
:rtype: pandas.DataFrame
"""
url = f"https://quote.eastmoney.com/qihuo/{symbol}.html"
r = requests.get(url)
soup = BeautifulSoup(r.text, features="lxml")
url_text = (
soup.find(name="div", attrs={"class": "sidertabbox_tsplit"})
.find(name="div", attrs={"class": "onet"})
.find("a")["href"]
)
inner_symbol = url_text.split("#")[-1].strip("futures_")
url = f"https://futsse-static.eastmoney.com/redis?msgid={inner_symbol}_info"
r = requests.get(url)
data_json = r.json()
temp_df = pd.DataFrame.from_dict(data_json, orient="index")
column_mapping = {
"vname": "交易品种",
"vcode": "交易代码",
"jydw": "交易单位",
"bjdw": "报价单位",
"market": "上市交易所",
"zxbddw": "最小变动价格",
"zdtbfd": "跌涨停板幅度",
"hyjgyf": "合约交割月份",
"jysj": "交易时间",
"zhjyr": "最后交易日",
"zhjgr": "最后交割日",
"jgpj": "交割品级",
"zcjybzj": "最初交易保证金",
"jgfs": "交割方式",
}
temp_df.rename(index=column_mapping, inplace=True)
temp_df.reset_index(drop=False, inplace=True)
temp_df.columns = ["item", "value"]
return temp_df
if __name__ == "__main__":
futures_contract_detail_df = futures_contract_detail(symbol="V2101")
print(futures_contract_detail_df)
futures_contract_detail_em_df = futures_contract_detail_em(symbol="l2602F")
print(futures_contract_detail_em_df)
@@ -0,0 +1,779 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2024/11/30 18:00
Desc: 期货日线行情
"""
import datetime
import json
import re
import zipfile
from io import BytesIO, StringIO
import numpy as np
import pandas as pd
import requests
from akshare.futures import cons
from akshare.futures.requests_fun import requests_link
calendar = cons.get_calendar()
def _futures_daily_czce(
date: str = "20100824", dataset: str = "datahistory2010"
) -> pd.DataFrame:
"""
郑州商品交易所-交易数据-历史行情下载
http://www.czce.com.cn/cn/jysj/lshqxz/H770319index_1.htm
:param date: 需要的日期
:type date: str
:param dataset: 数据集的名称; 此处只需要替换 datahistory2010 中的 2010 即可
:type dataset: str
:return: 指定日期的所有品种行情数据
:rtype: pandas.DataFrame
"""
url = f"http://www.czce.com.cn/cn/exchange/{dataset}.zip"
r = requests.get(url)
with zipfile.ZipFile(BytesIO(r.content)) as file:
with file.open(f"{dataset}.txt") as my_file:
data = my_file.read().decode("gb2312")
data_df = pd.read_table(StringIO(data), sep=r"|", header=1)
data_df.columns = [item.strip() for item in data_df.columns]
data_df.dropna(axis=1, inplace=True)
for column in data_df.columns:
try:
data_df[column] = data_df[column].str.strip("\t")
data_df[column] = data_df[column].str.replace(",", "")
except: # noqa: E722
data_df[column] = data_df[column]
data_df["昨结算"] = pd.to_numeric(data_df["昨结算"])
data_df["今开盘"] = pd.to_numeric(data_df["今开盘"])
data_df["最高价"] = pd.to_numeric(data_df["最高价"])
data_df["最低价"] = pd.to_numeric(data_df["最低价"])
data_df["今收盘"] = pd.to_numeric(data_df["今收盘"])
data_df["今结算"] = pd.to_numeric(data_df["今结算"])
data_df["涨跌1"] = pd.to_numeric(data_df["涨跌1"])
data_df["涨跌2"] = pd.to_numeric(data_df["涨跌2"])
data_df["成交量(手)"] = pd.to_numeric(data_df["成交量(手)"])
data_df["空盘量"] = pd.to_numeric(data_df["空盘量"])
data_df["增减量"] = pd.to_numeric(data_df["增减量"])
data_df["成交额(万元)"] = pd.to_numeric(data_df["成交额(万元)"])
data_df["交割结算价"] = pd.to_numeric(data_df["交割结算价"])
data_df["交易日期"] = pd.to_datetime(data_df["交易日期"])
data_df.columns = [
"date",
"symbol",
"pre_settle",
"open",
"high",
"low",
"close",
"settle",
"-",
"-",
"volume",
"open_interest",
"-",
"turnover",
"-",
]
variety_list = [
re.compile(r"[a-zA-Z_]+").findall(item)[0] for item in data_df["symbol"]
]
data_df["variety"] = variety_list
data_df = data_df[
[
"symbol",
"date",
"open",
"high",
"low",
"close",
"volume",
"open_interest",
"turnover",
"settle",
"pre_settle",
"variety",
]
]
temp_df = data_df[data_df["date"] == pd.Timestamp(date)].copy()
temp_df["date"] = date
temp_df.reset_index(inplace=True, drop=True)
return temp_df
def get_cffex_daily(date: str = "20100416") -> pd.DataFrame:
"""
中国金融期货交易所-日频率交易数据
http://www.cffex.com.cn/rtj/
:param date: 交易日; 数据开始时间为 20100416
:type date: str
:return: 日频率交易数据
:rtype: pandas.DataFrame
"""
day = cons.convert_date(date) if date is not None else datetime.date.today()
if day.strftime("%Y%m%d") not in calendar:
# warnings.warn("%s非交易日" % day.strftime("%Y%m%d"))
return pd.DataFrame()
url = f"http://www.cffex.com.cn/sj/historysj/{date[:-2]}/zip/{date[:-2]}.zip"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/108.0.0.0 Safari/537.36",
}
r = requests.get(url, headers=headers)
try:
with zipfile.ZipFile(BytesIO(r.content)) as file:
with file.open(f"{date}_1.csv") as my_file:
data = my_file.read().decode("gb2312")
data_df = pd.read_csv(StringIO(data))
except: # noqa: E722
return pd.DataFrame()
data_df = data_df[data_df["合约代码"] != "小计"]
data_df = data_df[data_df["合约代码"] != "合计"]
data_df = data_df[~data_df["合约代码"].str.contains("IO")]
data_df = data_df[~data_df["合约代码"].str.contains("MO")]
data_df = data_df[~data_df["合约代码"].str.contains("HO")]
data_df.reset_index(inplace=True, drop=True)
data_df["合约代码"] = data_df["合约代码"].str.strip()
symbol_list = data_df["合约代码"].to_list()
variety_list = [re.compile(r"[a-zA-Z_]+").findall(item)[0] for item in symbol_list]
if data_df.shape[1] == 15:
data_df.columns = [
"symbol",
"open",
"high",
"low",
"volume",
"turnover",
"open_interest",
"_",
"close",
"settle",
"pre_settle",
"_",
"_",
"_",
"_",
]
else:
data_df.columns = [
"symbol",
"open",
"high",
"low",
"volume",
"turnover",
"open_interest",
"_",
"close",
"settle",
"pre_settle",
"_",
"_",
"_",
]
data_df["date"] = date
data_df["variety"] = variety_list
data_df = data_df[
[
"symbol",
"date",
"open",
"high",
"low",
"close",
"volume",
"open_interest",
"turnover",
"settle",
"pre_settle",
"variety",
]
]
return data_df
def get_gfex_daily(date: str = "20221223") -> pd.DataFrame:
"""
广州期货交易所-日频率-量价数据
广州期货交易所: 工业硅(上市时间: 20221222)
http://www.gfex.com.cn/gfex/rihq/hqsj_tjsj.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()
if day.strftime("%Y%m%d") not in calendar:
# warnings.warn(f"{day.strftime('%Y%m%d')}非交易日")
return pd.DataFrame()
url = "http://www.gfex.com.cn/u/interfacesWebTiDayQuotes/loadList"
payload = {"trade_date": date, "trade_type": "0"}
headers = {
"Accept": "application/json, text/javascript, */*; q=0.01",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "no-cache",
"Content-Length": "32",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Host": "www.gfex.com.cn",
"Origin": "http://www.gfex.com.cn",
"Pragma": "no-cache",
"Proxy-Connection": "keep-alive",
"Referer": "http://www.gfex.com.cn/gfex/rihq/hqsj_tjsj.shtml",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/108.0.0.0 Safari/537.36",
"X-Requested-With": "XMLHttpRequest",
"content-type": "application/x-www-form-urlencoded",
}
r = requests.post(url, data=payload, headers=headers)
try:
data_json = r.json()
except: # noqa: E722
return pd.DataFrame()
result_df = pd.DataFrame(data_json["data"])
result_df = result_df[~result_df["variety"].str.contains("小计")]
result_df = result_df[~result_df["variety"].str.contains("总计")]
result_df["symbol"] = (
result_df["varietyOrder"].str.upper() + result_df["delivMonth"]
)
result_df["date"] = date
result_df["open"] = pd.to_numeric(result_df["open"], errors="coerce")
result_df["high"] = pd.to_numeric(result_df["high"], errors="coerce")
result_df["low"] = pd.to_numeric(result_df["low"], errors="coerce")
result_df["close"] = pd.to_numeric(result_df["close"], errors="coerce")
result_df["volume"] = pd.to_numeric(result_df["volumn"], errors="coerce")
result_df["open_interest"] = pd.to_numeric(
result_df["openInterest"], errors="coerce"
)
result_df["turnover"] = pd.to_numeric(result_df["turnover"], errors="coerce")
result_df["settle"] = pd.to_numeric(result_df["clearPrice"], errors="coerce")
result_df["pre_settle"] = pd.to_numeric(result_df["lastClear"], errors="coerce")
result_df["variety"] = result_df["varietyOrder"].str.upper()
result_df = result_df[
[
"symbol",
"date",
"open",
"high",
"low",
"close",
"volume",
"open_interest",
"turnover",
"settle",
"pre_settle",
"variety",
]
]
return result_df
def get_ine_daily(date: str = "20241129") -> pd.DataFrame:
"""
上海国际能源交易中心-日频率-量价数据
上海国际能源交易中心: 原油期货(上市时间: 20180326); 20号胶期货(上市时间: 20190812)
trade_price: https://www.ine.cn/statements/daily/?paramid=kx
trade_note: https://www.ine.cn/data/datanote.dat
:param date: 日期 formatYYYY-MM-DD 或 YYYYMMDD 或 datetime.date对象,默认为当前交易日
:type date: str or datetime.date
:return: 上海国际能源交易中心-日频率-量价数据
:rtype: pandas.DataFrame or None
"""
day = cons.convert_date(date) if date is not None else datetime.date.today()
if day.strftime("%Y%m%d") not in calendar:
# warnings.warn(f"{day.strftime('%Y%m%d')}非交易日")
return pd.DataFrame()
url = f"https://www.ine.cn/data/tradedata/future/dailydata/kx{day.strftime('%Y%m%d')}.dat"
r = requests.get(url, headers=cons.shfe_headers)
result_df = pd.DataFrame()
try:
data_json = r.json()
except: # noqa: E722
return pd.DataFrame()
temp_df = pd.DataFrame(data_json["o_curinstrument"]).iloc[:-1, :]
temp_df = temp_df[temp_df["DELIVERYMONTH"] != "小计"]
temp_df = temp_df[~temp_df["PRODUCTNAME"].str.contains("总计")]
try:
result_df["symbol"] = (
temp_df["PRODUCTGROUPID"].str.upper().str.strip() + temp_df["DELIVERYMONTH"]
)
except: # noqa: E722
result_df["symbol"] = (
temp_df["PRODUCTID"]
.str.upper()
.str.strip()
.str.split("_", expand=True)
.iloc[:, 0]
+ temp_df["DELIVERYMONTH"]
)
result_df["date"] = day.strftime("%Y%m%d")
result_df["open"] = temp_df["OPENPRICE"]
result_df["high"] = temp_df["HIGHESTPRICE"]
result_df["low"] = temp_df["LOWESTPRICE"]
result_df["close"] = temp_df["CLOSEPRICE"]
result_df["volume"] = temp_df["VOLUME"]
result_df["open_interest"] = temp_df["OPENINTEREST"]
try:
result_df["turnover"] = temp_df["TURNOVER"]
except: # noqa: E722
result_df["turnover"] = 0
result_df["settle"] = temp_df["SETTLEMENTPRICE"]
result_df["pre_settle"] = temp_df["PRESETTLEMENTPRICE"]
try:
result_df["variety"] = temp_df["PRODUCTGROUPID"].str.upper().str.strip()
except: # noqa: E722
result_df["variety"] = (
temp_df["PRODUCTID"]
.str.upper()
.str.strip()
.str.split("_", expand=True)
.iloc[:, 0]
)
result_df = result_df[result_df["symbol"] != "总计"]
result_df = result_df[~result_df["symbol"].str.contains("efp")]
return result_df
def get_czce_daily(date: str = "20050525") -> pd.DataFrame:
"""
郑州商品交易所-日频率-量价数据
http://www.czce.com.cn/cn/jysj/mrhq/H770301index_1.htm
:param date: 日期 formatYYYY-MM-DD 或 YYYYMMDD 或 datetime.date 对象,默认为当前交易日; 日期需要大于 20100824
:type date: str or datetime.date
:return: 郑州商品交易所-日频率-量价数据
:rtype: pandas.DataFrame
"""
day = cons.convert_date(date) if date is not None else datetime.date.today()
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/108.0.0.0 Safari/537.36"
}
url = ""
if day.strftime("%Y%m%d") not in calendar:
# warnings.warn(f"{day.strftime('%Y%m%d')}非交易日")
return pd.DataFrame()
if day > datetime.date(2010, 8, 24):
if day > datetime.date(2015, 11, 11):
u = cons.CZCE_DAILY_URL_3
url = u % (day.strftime("%Y"), day.strftime("%Y%m%d"))
elif day <= datetime.date(2015, 11, 11):
u = cons.CZCE_DAILY_URL_2
url = u % (day.strftime("%Y"), day.strftime("%Y%m%d"))
listed_columns = cons.CZCE_COLUMNS
output_columns = cons.OUTPUT_COLUMNS
try:
r = requests.get(url, headers=headers)
if datetime.date(2015, 11, 12) <= day <= datetime.date(2017, 12, 27):
html = str(r.content, encoding="gbk")
else:
html = r.text
except requests.exceptions.HTTPError as reason:
if reason.response.status_code != 404:
print(
cons.CZCE_DAILY_URL_3
% (day.strftime("%Y"), day.strftime("%Y%m%d")),
reason,
)
return pd.DataFrame()
if html.find("您的访问出错了") >= 0 or html.find("无期权每日行情交易记录") >= 0:
return pd.DataFrame()
html = [
i.replace(" ", "").split("|")
for i in html.split("\n")[:-3]
if i[0][0] != ""
]
if day > datetime.date(2015, 11, 11):
if html[1][0] not in ["品种月份", "品种代码", "合约代码"]:
return pd.DataFrame()
dict_data = list()
day_const = int(day.strftime("%Y%m%d"))
for row in html[2:]:
m = cons.FUTURES_SYMBOL_PATTERN.match(row[0])
if not m:
continue
row_dict = {
"date": day_const,
"symbol": row[0],
"variety": m.group(1),
}
for i, field in enumerate(listed_columns):
if row[i + 1] == "\r" or row[i + 1] == "":
row_dict[field] = 0.0
elif field in [
"volume",
"open_interest",
"oi_chg",
"exercise_volume",
]:
row[i + 1] = row[i + 1].replace(",", "")
row_dict[field] = int(row[i + 1])
else:
row[i + 1] = row[i + 1].replace(",", "")
row_dict[field] = float(row[i + 1])
dict_data.append(row_dict)
return pd.DataFrame(dict_data)[output_columns]
elif day <= datetime.date(2015, 11, 11):
dict_data = list()
day_const = int(day.strftime("%Y%m%d"))
for row in html[1:]:
row = row[0].split(",")
m = cons.FUTURES_SYMBOL_PATTERN.match(row[0])
if not m:
continue
row_dict = {
"date": day_const,
"symbol": row[0],
"variety": m.group(1),
}
for i, field in enumerate(listed_columns):
if row[i + 1] == "\r":
row_dict[field] = 0.0
elif field in [
"volume",
"open_interest",
"oi_chg",
"exercise_volume",
]:
row_dict[field] = int(float(row[i + 1]))
else:
row_dict[field] = float(row[i + 1])
dict_data.append(row_dict)
return pd.DataFrame(dict_data)[output_columns]
if day <= datetime.date(2010, 8, 24):
_futures_daily_czce_df = _futures_daily_czce(date)
return _futures_daily_czce_df
def get_shfe_daily(date: str = "20220415") -> pd.DataFrame:
"""
上海期货交易所-日频率-量价数据
https://tsite.shfe.com.cn/statements/dataview.html?paramid=kx
:param date: 日期 formatYYYY-MM-DD 或 YYYYMMDD 或 datetime.date对象, 默认为当前交易日
:type date: str or datetime.date
:return: 上海期货交易所-日频率-量价数据
:rtype: pandas.DataFrame or None
上期所日交易数据(DataFrame):
symbol 合约代码
date 日期
open 开盘价
high 最高价
low 最低价
close 收盘价
volume 成交量
open_interest 持仓量
turnover 成交额
settle 结算价
pre_settle 前结算价
variety 合约类别
或 None(给定交易日没有交易数据)
"""
day = cons.convert_date(date) if date is not None else datetime.date.today()
if day.strftime("%Y%m%d") not in calendar:
# warnings.warn("%s非交易日" % day.strftime("%Y%m%d"))
return pd.DataFrame()
try:
json_data = json.loads(
requests_link(
cons.SHFE_DAILY_URL_20250630 % (day.strftime("%Y%m%d")),
headers=cons.shfe_headers,
).text
)
except requests.HTTPError as reason:
if reason.response != 404:
print(cons.SHFE_DAILY_URL_20250630 % (day.strftime("%Y%m%d")), reason)
return pd.DataFrame()
if len(json_data["o_curinstrument"]) == 0:
return pd.DataFrame()
df = pd.DataFrame(
[
row
for row in json_data["o_curinstrument"]
if row["DELIVERYMONTH"] not in ["小计", "合计"]
and row["DELIVERYMONTH"] != ""
]
)
try:
df["variety"] = df["PRODUCTGROUPID"].str.upper().str.strip()
except KeyError:
df["variety"] = (
df["PRODUCTID"]
.str.upper()
.str.split("_", expand=True)
.iloc[:, 0]
.str.strip()
)
df["symbol"] = df["variety"] + df["DELIVERYMONTH"]
df["date"] = day.strftime("%Y%m%d")
df["VOLUME"] = df["VOLUME"].apply(lambda x: 0 if x == "" else x)
try:
df["turnover"] = df["TURNOVER"].apply(lambda x: 0 if x == "" else x)
except KeyError:
df["turnover"] = np.nan
df.rename(columns=cons.SHFE_COLUMNS, inplace=True)
df = df[~df["symbol"].str.contains("efp")]
df = df[cons.OUTPUT_COLUMNS]
df.reset_index(inplace=True)
return df
def get_dce_daily(date: str = "20251027") -> pd.DataFrame:
"""
大连商品交易所日交易数据
http://www.dce.com.cn/dalianshangpin/xqsj/tjsj26/rtj/rxq/index.html
:param date: 交易日, e.g., 20200416
:type date: str
:return: 具体交易日的个品种行情数据
:rtype: pandas.DataFrame
"""
day = cons.convert_date(date) if date is not None else datetime.date.today()
if day.strftime("%Y%m%d") not in calendar:
# warnings.warn("%s非交易日" % day.strftime("%Y%m%d"))
return pd.DataFrame()
url = "http://www.dce.com.cn/dcereport/publicweb/dailystat/dayQuotes"
payload = {
"contractId": "",
"lang": "zh",
"optionSeries": "",
"statisticsType": "0",
"tradeDate": date,
"tradeType": "1",
"varietyId": "all",
}
r = requests.post(url, json=payload)
data_json = r.json()
temp_df = pd.DataFrame(data_json["data"])
temp_df.rename(
columns={
"variety": "品种名称",
"contractId": "合约",
"open": "开盘价",
"high": "最高价",
"low": "最低价",
"close": "收盘价",
"lastClear": "前结算价",
"clearPrice": "结算价",
"diff": "涨跌",
"diff1": "涨跌1",
"volumn": "成交量",
"openInterest": "持仓量",
"diffI": "持仓量变化",
"turnover": "成交额",
},
inplace=True,
)
temp_df = temp_df[~temp_df["品种名称"].str.contains("小计")]
temp_df = temp_df[~temp_df["品种名称"].str.contains("总计")]
temp_df["variety"] = temp_df["品种名称"].map(lambda x: cons.DCE_MAP[x])
temp_df["symbol"] = temp_df["合约"]
del temp_df["品种名称"]
del temp_df["合约"]
temp_df.columns = [
"open",
"high",
"low",
"close",
"pre_settle",
"settle",
"_",
"_",
"_",
"volume",
"open_interest",
"_",
"turnover",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"variety",
"symbol",
]
temp_df["date"] = date
temp_df = temp_df[
[
"symbol",
"date",
"open",
"high",
"low",
"close",
"volume",
"open_interest",
"turnover",
"settle",
"pre_settle",
"variety",
]
]
temp_df = temp_df.astype(
{
"open": "float",
"high": "float",
"low": "float",
"close": "float",
"volume": "float",
"open_interest": "float",
"turnover": "float",
"settle": "float",
"pre_settle": "float",
}
)
temp_df.reset_index(inplace=True, drop=True)
return temp_df
def get_futures_daily(
start_date: str = "20220208",
end_date: str = "20220208",
market: str = "CFFEX",
) -> pd.DataFrame:
"""
交易所日交易数据
:param start_date: 开始日期 formatYYYY-MM-DD 或 YYYYMMDD 或 datetime.date对象 为空时为当天
:type start_date: str
:param end_date: 结束数据 formatYYYY-MM-DD 或 YYYYMMDD 或 datetime.date对象 为空时为当天
:type end_date: str
:param market: 'CFFEX' 中金所, 'CZCE' 郑商所, 'SHFE' 上期所, 'DCE' 大商所 之一, 'INE' 上海国际能源交易中心, "GFEX" 广州期货交易所。默认为中金所
:type market: str
:return: 交易所日交易数据
:rtype: pandas.DataFrame
"""
if market.upper() == "CFFEX":
f = get_cffex_daily
elif market.upper() == "CZCE":
f = get_czce_daily
elif market.upper() == "SHFE":
f = get_shfe_daily
elif market.upper() == "DCE":
f = get_dce_daily
elif market.upper() == "INE":
f = get_ine_daily
elif market.upper() == "GFEX":
f = get_gfex_daily
else:
print("Invalid Market Symbol")
return pd.DataFrame()
start_date = (
cons.convert_date(start_date)
if start_date is not None
else datetime.date.today()
)
end_date = (
cons.convert_date(end_date)
if end_date is not None
else cons.convert_date(cons.get_latest_data_date(datetime.datetime.now()))
)
df_list = list()
while start_date <= end_date:
df = f(date=str(start_date).replace("-", ""))
if not df.empty:
df_list.append(df)
start_date += datetime.timedelta(days=1)
if len(df_list) == 0:
return pd.DataFrame()
elif len(df_list) > 0:
temp_df = pd.concat(df_list).reset_index(drop=True)
temp_df = temp_df[~temp_df["symbol"].str.contains("efp")]
return temp_df
else:
return pd.DataFrame()
def futures_hist_daily_cffex(date: str = "20260403") -> pd.DataFrame:
"""
中国金融期货交易所-交易所日交易数据
http://www.cffex.com.cn/cn/rtj.html
:param date: 交易日
:type date: str
:return: 交易所日交易数据
:rtype: pandas.DataFrame
"""
url = f"http://www.cffex.com.cn/sj/hqsj/rtj/{date[:6]}/{date[6:]}/{date}_1.csv"
data_df = pd.read_csv(url, encoding="gbk")
data_df = data_df[data_df["合约代码"] != "小计"]
data_df = data_df[data_df["合约代码"] != "合计"]
data_df = data_df[~data_df["合约代码"].str.contains("IO")]
data_df = data_df[~data_df["合约代码"].str.contains("MO")]
data_df = data_df[~data_df["合约代码"].str.contains("HO")]
data_df.reset_index(inplace=True, drop=True)
data_df["合约代码"] = data_df["合约代码"].str.strip()
symbol_list = data_df["合约代码"].to_list()
variety_list = [re.compile(r"[a-zA-Z_]+").findall(item)[0] for item in symbol_list]
data_df.columns = [
"symbol",
"open",
"high",
"low",
"volume",
"turnover",
"open_interest",
"_",
"close",
"settle",
"pre_settle",
"_",
"_",
"_",
]
data_df["date"] = date
data_df["variety"] = variety_list
data_df = data_df[
[
"symbol",
"date",
"open",
"high",
"low",
"close",
"volume",
"open_interest",
"turnover",
"settle",
"pre_settle",
"variety",
]
]
return data_df
if __name__ == "__main__":
get_futures_daily_df = get_futures_daily(
start_date="20250708", end_date="20250708", market="DCE"
)
print(get_futures_daily_df)
get_dce_daily_df = get_dce_daily(date="20251029")
print(get_dce_daily_df)
get_cffex_daily_df = get_cffex_daily(date="20260401")
print(get_cffex_daily_df)
get_ine_daily_df = get_ine_daily(date="20230818")
print(get_ine_daily_df)
get_czce_daily_df = get_czce_daily(date="20210513")
print(get_czce_daily_df)
get_shfe_daily_df = get_shfe_daily(date="20250630")
print(get_shfe_daily_df)
get_gfex_daily_df = get_gfex_daily(date="20221228")
print(get_gfex_daily_df)
futures_hist_daily_cffex_df = futures_hist_daily_cffex(date="20260302")
print(futures_hist_daily_cffex_df)
@@ -0,0 +1,73 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2025/3/5 18:00
Desc: 外盘期货-历史行情数据-日频率
https://finance.sina.com.cn/money/future/hf.html
"""
from datetime import datetime
from io import StringIO
import pandas as pd
import requests
from akshare.futures.futures_hq_sina import (
futures_foreign_commodity_subscribe_exchange_symbol,
)
def futures_foreign_hist(symbol: str = "ZSD") -> pd.DataFrame:
"""
外盘期货-历史行情数据-日频率
https://finance.sina.com.cn/money/future/hf.html
:param symbol: 外盘期货代码, 可以通过 ak.futures_foreign_commodity_subscribe_exchange_symbol() 来获取所有品种代码
:type symbol: str
:return: 历史行情数据-日频率
:rtype: pandas.DataFrame
"""
today = f"{datetime.today().year}_{datetime.today().month}_{datetime.today().day}"
url = (
f"https://stock2.finance.sina.com.cn/futures/api/jsonp.php/var%20_S{today}=/"
f"GlobalFuturesService.getGlobalFuturesDailyKLine"
)
params = {
"symbol": symbol,
"_": today,
"source": "web",
}
r = requests.get(url, params=params)
data_text = r.text
data_df = pd.read_json(StringIO(data_text[data_text.find("[") : -2]))
return data_df
def futures_foreign_detail(symbol: str = "ZSD") -> pd.DataFrame:
"""
foreign futures contract detail data
:param symbol: futures symbol, you can get it from hf_subscribe_exchange_symbol function
:type symbol: str
:return: contract detail
:rtype: pandas.DataFrame
"""
url = f"https://finance.sina.com.cn/futures/quotes/{symbol}.shtml"
r = requests.get(url)
r.encoding = "gbk"
data_text = r.text
data_df = pd.read_html(StringIO(data_text))[6]
return data_df
if __name__ == "__main__":
futures_foreign_hist_df = futures_foreign_hist(symbol="JY")
print(futures_foreign_hist_df)
subscribes = futures_foreign_commodity_subscribe_exchange_symbol()
for item in subscribes:
futures_foreign_detail_df = futures_foreign_detail(symbol=item)
print(futures_foreign_detail_df)
for item in subscribes:
futures_foreign_hist_df = futures_foreign_hist(symbol=item)
print(futures_foreign_hist_df)
@@ -0,0 +1,252 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2025/3/9 22:00
Desc: 东方财富网-行情中心-期货市场-国际期货
https://quote.eastmoney.com/center/gridlist.html#futures_global
"""
import math
from typing import Optional
import pandas as pd
import requests
from akshare.utils.tqdm import get_tqdm
def __futures_global_hist_market_code(symbol: str = "HG00Y") -> Optional[int]:
"""
东方财富网-行情中心-期货市场-国际期货-品种市场对照表
https://quote.eastmoney.com/center/gridlist.html#futures_global
:param symbol: HG00Y, 品种代码可以通过 ak.futures_global_spot_em() 来获取所有可获取历史行情数据的品种代码
:type symbol: str
:return: 品种所属于的市场
:rtype: str
"""
# 提取品种代码(去掉年份和月份部分)
base_symbol = ""
i = 0
while i < len(symbol) and not symbol[i].isdigit():
base_symbol += symbol[i]
i += 1
# 如果代码中没有数字(异常情况),则返回整个代码作为基础品种代码
if not base_symbol and i == len(symbol):
base_symbol = symbol
# 金属和贵金属品种 - 101
if base_symbol in ["HG", "GC", "SI", "QI", "QO", "MGC", "LTH"]:
return 101
# 能源品种 - 102
if base_symbol in ["CL", "NG", "RB", "HO", "PA", "PL", "QM"]:
return 102
# 农产品和金融品种 - 103
if base_symbol in [
"ZW",
"ZM",
"ZS",
"ZC",
"XC",
"XK",
"XW",
"YM",
"TY",
"US",
"EH",
"ZL",
"ZR",
"ZO",
"FV",
"TU",
"UL",
"NQ",
"ES",
]:
return 103
# 中国市场特有品种 - 104
if base_symbol in ["TF", "RT", "CN"]:
return 104
# 软商品期货 - 108
if base_symbol in ["SB", "CT", "SF"]:
return 108
# 特殊L开头品种 - 109
if base_symbol in ["LCPT", "LZNT", "LALT", "LTNT", "LLDT", "LNKT"]:
return 109
# MPM开头品种 - 110
if base_symbol == "MPM":
return 110
# 日本市场品种 - 111
if base_symbol.startswith("J"):
return 111
# 单字母代码品种 - 112
if base_symbol in ["M", "B", "G"]:
return 112
# 如果没有匹配到任何规则,返回一个默认值或者错误
return None
def futures_global_spot_em() -> pd.DataFrame:
"""
东方财富网-行情中心-期货市场-国际期货
https://quote.eastmoney.com/center/gridlist.html#futures_global
:return: 行情数据
:rtype: pandas.DataFrame
"""
url = "https://futsseapi.eastmoney.com/list/COMEX,NYMEX,COBOT,SGX,NYBOT,LME,MDEX,TOCOM,IPE"
params = {
"orderBy": "dm",
"sort": "desc",
"pageSize": "20",
"pageIndex": "0",
"token": "58b2fa8f54638b60b87d69b31969089c",
"field": "dm,sc,name,p,zsjd,zde,zdf,f152,o,h,l,zjsj,vol,wp,np,ccl",
"blockName": "callback",
}
r = requests.get(url, params=params)
data_json = r.json()
total_num = data_json["total"]
total_page = math.ceil(total_num / 20) - 1
tqdm = get_tqdm()
big_df = pd.DataFrame()
for page in tqdm(range(total_page), leave=False):
params.update({"pageIndex": page})
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(data_json["list"])
big_df = pd.concat(objs=[big_df, temp_df], ignore_index=True)
big_df.reset_index(inplace=True)
big_df["index"] = big_df["index"] + 1
big_df.rename(
columns={
"index": "序号",
"np": "卖盘",
"h": "最高",
"dm": "代码",
"zsjd": "-",
"l": "最低",
"ccl": "持仓量",
"o": "今开",
"p": "最新价",
"sc": "-",
"vol": "成交量",
"name": "名称",
"wp": "买盘",
"zde": "涨跌额",
"zdf": "涨跌幅",
"zjsj": "昨结",
},
inplace=True,
)
big_df = big_df[
[
"序号",
"代码",
"名称",
"最新价",
"涨跌额",
"涨跌幅",
"今开",
"最高",
"最低",
"昨结",
"成交量",
"买盘",
"卖盘",
"持仓量",
]
]
big_df["最新价"] = pd.to_numeric(big_df["最新价"], errors="coerce")
big_df["涨跌额"] = pd.to_numeric(big_df["涨跌额"], errors="coerce")
big_df["涨跌幅"] = pd.to_numeric(big_df["涨跌幅"], errors="coerce")
big_df["今开"] = pd.to_numeric(big_df["今开"], errors="coerce")
big_df["最高"] = pd.to_numeric(big_df["最高"], errors="coerce")
big_df["最低"] = pd.to_numeric(big_df["最低"], errors="coerce")
big_df["昨结"] = pd.to_numeric(big_df["昨结"], errors="coerce")
big_df["成交量"] = pd.to_numeric(big_df["成交量"], errors="coerce")
big_df["买盘"] = pd.to_numeric(big_df["买盘"], errors="coerce")
big_df["卖盘"] = pd.to_numeric(big_df["卖盘"], errors="coerce")
big_df["持仓量"] = pd.to_numeric(big_df["持仓量"], errors="coerce")
return big_df
def futures_global_hist_em(symbol: str = "HG00Y") -> pd.DataFrame:
"""
东方财富网-行情中心-期货市场-国际期货-历史行情数据
https://quote.eastmoney.com/globalfuture/HG25J.html
:param symbol: 品种代码可以通过 ak.futures_global_spot_em() 来获取所有可获取历史行情数据的品种代码
:type symbol: str
:return: 历史行情数据
:rtype: pandas.DataFrame
"""
url = "https://push2his.eastmoney.com/api/qt/stock/kline/get"
market_code = __futures_global_hist_market_code(symbol)
params = {
"secid": f"{market_code}.{symbol}",
"klt": "101",
"fqt": "1",
"lmt": "6600",
"end": "20500000",
"iscca": "1",
"fields1": "f1,f2,f3,f4,f5,f6,f7,f8",
"fields2": "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61,f62,f63,f64",
"ut": "f057cbcbce2a86e2866ab8877db1d059",
"forcect": "1",
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame([item.split(",") for item in data_json["data"]["klines"]])
temp_df["code"] = data_json["data"]["code"]
temp_df["name"] = data_json["data"]["name"]
temp_df.columns = [
"日期",
"开盘",
"最新价",
"最高",
"最低",
"总量",
"-",
"-",
"涨幅",
"-",
"-",
"-",
"持仓",
"日增",
"代码",
"名称",
]
temp_df = temp_df[
[
"日期",
"代码",
"名称",
"开盘",
"最新价",
"最高",
"最低",
"总量",
"涨幅",
"持仓",
"日增",
]
]
temp_df["日期"] = pd.to_datetime(temp_df["日期"], errors="coerce").dt.date
temp_df["开盘"] = pd.to_numeric(temp_df["开盘"], errors="coerce")
temp_df["最新价"] = pd.to_numeric(temp_df["最新价"], errors="coerce")
temp_df["最高"] = pd.to_numeric(temp_df["最高"], errors="coerce")
temp_df["最低"] = pd.to_numeric(temp_df["最低"], errors="coerce")
temp_df["总量"] = pd.to_numeric(temp_df["总量"], errors="coerce")
temp_df["涨幅"] = pd.to_numeric(temp_df["涨幅"], errors="coerce")
temp_df["日增"] = pd.to_numeric(temp_df["日增"], errors="coerce")
# 日增修复为有符号32位整数值
unsigned_max, signed_max = (2**32) - 1, (2**31) - 1
mask = temp_df["日增"] > signed_max
temp_df.loc[mask, "日增"] = temp_df.loc[mask, "日增"] - (unsigned_max + 1)
return temp_df
if __name__ == "__main__":
futures_global_spot_em_df = futures_global_spot_em()
print(futures_global_spot_em_df)
futures_global_hist_em_df = futures_global_hist_em(symbol="HG00Y")
print(futures_global_hist_em_df)
@@ -0,0 +1,192 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2024/2/20 17:00
Desc: 东方财富网-期货行情
https://qhweb.eastmoney.com/quote
"""
import re
from functools import lru_cache
from typing import Tuple, Dict
import pandas as pd
import requests
def __futures_hist_separate_char_and_numbers_em(symbol: str = "焦煤2506") -> tuple:
"""
东方财富网-期货行情-交易所品种对照表原始数据
https://quote.eastmoney.com/qihuo/al2505.html
:param symbol: 股票代码
:type symbol: str
:return: 交易所品种对照表原始数据
:rtype: pandas.DataFrame
"""
char = re.findall(pattern="[\u4e00-\u9fa5a-zA-Z]+", string=symbol)
numbers = re.findall(pattern=r"\d+", string=symbol)
return char[0], numbers[0]
@lru_cache()
def __fetch_exchange_symbol_raw_em() -> list:
"""
东方财富网-期货行情-交易所品种对照表原始数据
https://quote.eastmoney.com/qihuo/al2505.html
:return: 交易所品种对照表原始数据
:rtype: pandas.DataFrame
"""
url = "https://futsse-static.eastmoney.com/redis"
params = {"msgid": "gnweb"}
r = requests.get(url, params=params)
data_json = r.json()
all_exchange_symbol_list = []
for item in data_json:
params = {"msgid": str(item["mktid"])}
r = requests.get(url, params=params)
inner_data_json = r.json()
for num in range(1, len(inner_data_json) + 1):
params = {"msgid": str(item["mktid"]) + f"_{num}"}
r = requests.get(url, params=params)
inner_data_json = r.json()
all_exchange_symbol_list.extend(inner_data_json)
return all_exchange_symbol_list
@lru_cache()
def __get_exchange_symbol_map() -> Tuple[Dict, Dict, Dict, Dict]:
"""
东方财富网-期货行情-交易所品种映射
https://quote.eastmoney.com/qihuo/al2505.html
:return: 交易所品种映射
:rtype: pandas.DataFrame
"""
all_exchange_symbol_list = __fetch_exchange_symbol_raw_em()
c_contract_mkt = {}
c_contract_to_e_contract = {}
e_symbol_mkt = {}
c_symbol_mkt = {}
for item in all_exchange_symbol_list:
c_contract_mkt[item["name"]] = item["mktid"]
c_contract_to_e_contract[item["name"]] = item["code"]
e_symbol_mkt[item["vcode"]] = item["mktid"]
c_symbol_mkt[item["vname"]] = item["mktid"]
return c_contract_mkt, c_contract_to_e_contract, e_symbol_mkt, c_symbol_mkt
def futures_hist_table_em() -> pd.DataFrame:
"""
东方财富网-期货行情-交易所品种对照表
https://quote.eastmoney.com/qihuo/al2505.html
:return: 交易所品种对照表
:rtype: pandas.DataFrame
"""
all_exchange_symbol_list = __fetch_exchange_symbol_raw_em()
temp_df = pd.DataFrame(all_exchange_symbol_list)
temp_df = temp_df[["mktname", "name", "code"]]
temp_df.columns = ["市场简称", "合约中文代码", "合约代码"]
return temp_df
def futures_hist_em(
symbol: str = "热卷主连",
period: str = "daily",
start_date: str = "19900101",
end_date: str = "20500101",
) -> pd.DataFrame:
"""
东方财富网-期货行情-行情数据
https://qhweb.eastmoney.com/quote
:param symbol: 期货代码
:type symbol: str
:param period: choice of {'daily', 'weekly', 'monthly'}
:type period: str
:param start_date: 开始日期
:type start_date: str
:param end_date: 结束日期
:type end_date: str
:return: 行情数据
:rtype: pandas.DataFrame
"""
url = "https://push2his.eastmoney.com/api/qt/stock/kline/get"
period_dict = {"daily": "101", "weekly": "102", "monthly": "103"}
c_contract_mkt, c_contract_to_e_contract, e_symbol_mkt, c_symbol_mkt = (
__get_exchange_symbol_map()
)
try:
sec_id = f"{c_contract_mkt[symbol]}.{c_contract_to_e_contract[symbol]}"
except KeyError:
symbol_char, numbers = __futures_hist_separate_char_and_numbers_em(symbol)
if re.match(pattern="^[\u4e00-\u9fa5]+$", string=symbol_char):
sec_id = str(c_symbol_mkt[symbol_char]) + "." + symbol
else:
sec_id = str(e_symbol_mkt[symbol_char]) + "." + symbol
params = {
"secid": sec_id,
"klt": period_dict[period],
"fqt": "1",
"lmt": "10000",
"end": "20500000",
"iscca": "1",
"fields1": "f1,f2,f3,f4,f5,f6,f7,f8",
"fields2": "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61,f62,f63,f64",
"ut": "7eea3edcaed734bea9cbfc24409ed989",
"forcect": "1",
}
r = requests.get(url, timeout=15, params=params)
data_json = r.json()
temp_df = pd.DataFrame([item.split(",") for item in data_json["data"]["klines"]])
if temp_df.empty:
return temp_df
temp_df.columns = [
"时间",
"开盘",
"收盘",
"最高",
"最低",
"成交量",
"成交额",
"-",
"涨跌幅",
"涨跌",
"_",
"_",
"持仓量",
"_",
]
temp_df = temp_df[
[
"时间",
"开盘",
"最高",
"最低",
"收盘",
"涨跌",
"涨跌幅",
"成交量",
"成交额",
"持仓量",
]
]
temp_df.index = pd.to_datetime(temp_df["时间"])
temp_df = temp_df[start_date:end_date]
temp_df.reset_index(drop=True, inplace=True)
temp_df["开盘"] = pd.to_numeric(temp_df["开盘"], errors="coerce")
temp_df["收盘"] = pd.to_numeric(temp_df["收盘"], errors="coerce")
temp_df["最高"] = pd.to_numeric(temp_df["最高"], errors="coerce")
temp_df["最低"] = pd.to_numeric(temp_df["最低"], errors="coerce")
temp_df["成交量"] = pd.to_numeric(temp_df["成交量"], errors="coerce")
temp_df["成交额"] = pd.to_numeric(temp_df["成交额"], errors="coerce")
temp_df["涨跌"] = pd.to_numeric(temp_df["涨跌"], errors="coerce")
temp_df["涨跌幅"] = pd.to_numeric(temp_df["涨跌幅"], errors="coerce")
temp_df["持仓量"] = pd.to_numeric(temp_df["持仓量"], errors="coerce")
temp_df["时间"] = pd.to_datetime(temp_df["时间"], errors="coerce").dt.date
return temp_df
if __name__ == "__main__":
futures_hist_table_em_df = futures_hist_table_em()
print(futures_hist_table_em_df)
futures_hist_em_df = futures_hist_em(symbol="热卷主连", period="daily")
print(futures_hist_em_df)
@@ -0,0 +1,298 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2025/3/5 18:00
Desc: 新浪财经-外盘期货
https://finance.sina.com.cn/money/future/hf.html
"""
import time
from typing import Union, List
import pandas as pd
import requests
from bs4 import BeautifulSoup
from akshare.utils import demjson
def _get_real_name_list() -> list:
"""
新浪-外盘期货所有品种的中文名称
https://finance.sina.com.cn/money/future/hf.html
:return: 外盘期货所有品种的中文名称
:rtype: list
"""
url = "https://finance.sina.com.cn/money/future/hf.html"
r = requests.get(url)
r.encoding = "gb2312"
data_text = r.text
need_text = data_text[
data_text.find("var oHF_1 = ") + 12 : data_text.find("var oHF_2") - 2
].replace("\n\t", "")
data_json = demjson.decode(need_text)
name_list = [item[0].strip() for item in data_json.values()]
return name_list
def futures_foreign_commodity_subscribe_exchange_symbol() -> list:
"""
需要订阅的行情的代码
https://finance.sina.com.cn/money/future/hf.html
:return: 需要订阅的行情的代码
:rtype: list
"""
url = "https://finance.sina.com.cn/money/future/hf.html"
r = requests.get(url)
r.encoding = "gb2312"
data_text = r.text
data_json = demjson.decode(
data_text[
data_text.find("var oHF_1 = ") + 12 : data_text.find("var oHF_2 = ") - 2
]
)
code_list = list(data_json.keys())
return code_list
def futures_hq_subscribe_exchange_symbol() -> pd.DataFrame:
"""
将品种字典转化为 pandas.DataFrame
https://finance.sina.com.cn/money/future/hf.html
:return: 品种对应表
:rtype: pandas.DataFrame
"""
inner_dict = {
"新加坡铁矿石": "FEF",
"马棕油": "FCPO",
"日橡胶": "RSS3",
"美国原糖": "RS",
"CME比特币期货": "BTC",
"NYBOT-棉花": "CT",
"LME镍3个月": "NID",
"LME铅3个月": "PBD",
"LME锡3个月": "SND",
"LME锌3个月": "ZSD",
"LME铝3个月": "AHD",
"LME铜3个月": "CAD",
"CBOT-黄豆": "S",
"CBOT-小麦": "W",
"CBOT-玉米": "C",
"CBOT-黄豆油": "BO",
"CBOT-黄豆粉": "SM",
"日本橡胶": "TRB",
"COMEX铜": "HG",
"NYMEX天然气": "NG",
"NYMEX原油": "CL",
"COMEX白银": "SI",
"COMEX黄金": "GC",
"CME-瘦肉猪": "LHC",
"布伦特原油": "OIL",
"伦敦金": "XAU",
"伦敦银": "XAG",
"伦敦铂金": "XPT",
"伦敦钯金": "XPD",
"欧洲碳排放": "EUA",
}
temp_df = pd.DataFrame.from_dict(inner_dict, orient="index")
temp_df.reset_index(inplace=True)
temp_df.columns = ["symbol", "code"]
return temp_df
def futures_foreign_commodity_realtime(symbol: Union[str, List[str]]) -> pd.DataFrame:
"""
新浪-外盘期货-行情数据
https://finance.sina.com.cn/money/future/hf.html
:param symbol: 通过调用 ak.futures_hq_subscribe_exchange_symbol() 函数来获取
:type symbol: list or str
:return: 行情数据
:rtype: pandas.DataFrame
"""
if isinstance(symbol, list):
payload = "?list=" + ",".join(["hf_" + item for item in symbol])
else:
symbol = symbol.split(",")
payload = "?list=" + ",".join(["hf_" + item for item in symbol])
url = "https://hq.sinajs.cn/" + payload
headers = {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Host": "hq.sinajs.cn",
"Pragma": "no-cache",
"Referer": "https://finance.sina.com.cn/",
"sec-ch-ua": '" Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"Sec-Fetch-Dest": "script",
"Sec-Fetch-Mode": "no-cors",
"Sec-Fetch-Site": "cross-site",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/97.0.4692.71 Safari/537.36",
}
r = requests.get(url, headers=headers)
data_text = r.text
data_df = pd.DataFrame(
[
item.strip().split("=")[1].split(",")
for item in data_text.split(";")
if item.strip() != ""
]
)
data_df.iloc[:, 0] = data_df.iloc[:, 0].str.replace('"', "")
data_df.iloc[:, -1] = data_df.iloc[:, -1].str.replace('"', "")
# 处理伦敦金 XAU 的情况
if len(data_df.columns) == 14:
data_df["temp"] = None
data_df.columns = [
"current_price",
"-",
"bid",
"ask",
"high",
"low",
"time",
"last_settle_price",
"open",
"hold",
"-",
"-",
"date",
"symbol",
"current_price_rmb",
]
temp_symbol_code_df = futures_hq_subscribe_exchange_symbol()
temp_symbol_code_dict = dict(
zip(temp_symbol_code_df["code"], temp_symbol_code_df["symbol"])
)
data_df["symbol"] = [temp_symbol_code_dict[subscribe] for subscribe in symbol]
data_df = data_df[
[
"symbol",
"current_price",
"current_price_rmb",
"bid",
"ask",
"high",
"low",
"time",
"last_settle_price",
"open",
"hold",
"date",
]
]
data_df.columns = [
"名称",
"最新价",
"人民币报价",
"买价",
"卖价",
"最高价",
"最低价",
"行情时间",
"昨日结算价",
"开盘价",
"持仓量",
"日期",
]
data_df.dropna(how="all", inplace=True)
data_df["最新价"] = pd.to_numeric(data_df["最新价"], errors="coerce")
data_df["人民币报价"] = pd.to_numeric(data_df["人民币报价"], errors="coerce")
data_df["买价"] = pd.to_numeric(data_df["买价"], errors="coerce")
data_df["卖价"] = pd.to_numeric(data_df["卖价"], errors="coerce")
data_df["最高价"] = pd.to_numeric(data_df["最高价"], errors="coerce")
data_df["最低价"] = pd.to_numeric(data_df["最低价"], errors="coerce")
data_df["昨日结算价"] = pd.to_numeric(data_df["昨日结算价"], errors="coerce")
data_df["开盘价"] = pd.to_numeric(data_df["开盘价"], errors="coerce")
data_df["持仓量"] = pd.to_numeric(data_df["持仓量"], errors="coerce")
data_df["涨跌额"] = data_df["最新价"] - data_df["昨日结算价"]
data_df["涨跌幅"] = (
(data_df["最新价"] - data_df["昨日结算价"]) / data_df["昨日结算价"] * 100
)
data_df = data_df[
[
"名称",
"最新价",
"人民币报价",
"涨跌额",
"涨跌幅",
"开盘价",
"最高价",
"最低价",
"昨日结算价",
"持仓量",
"买价",
"卖价",
"行情时间",
"日期",
]
]
# 获取转换比例数据
url = "https://finance.sina.com.cn/money/future/hf.html"
r = requests.get(url)
r.encoding = "utf-8"
soup = BeautifulSoup(r.text, features="lxml")
data_text = soup.find_all(name="script", attrs={"type": "text/javascript"})[
-2
].string.strip()
raw_text = data_text[data_text.find("oHF_1 = ") : data_text.find("oHF_2")]
need_text = raw_text[raw_text.find("{") : raw_text.rfind("}") + 1]
data_json = demjson.decode(need_text)
price_mul = pd.DataFrame(
[
[item[0] for item in data_json.values()],
[item[1][0] for item in data_json.values()],
]
).T
price_mul.columns = ["symbol", "price"]
price_mul = price_mul[price_mul["symbol"].isin(data_df["名称"])]
price_mul.reset_index(inplace=True, drop=True)
price_mul["price"] = pd.to_numeric(price_mul["price"], errors="coerce")
# 获取汇率数据
url = "https://hq.sinajs.cn/?list=USDCNY"
r = requests.get(url, headers=headers)
data_text = r.text
usd_rmb = float(
data_text[data_text.find('"') + 1 : data_text.find(",美元人民币")].split(",")[
-1
]
)
# 计算人民币报价
data_df["最新价"] = pd.to_numeric(data_df["最新价"], errors="coerce")
data_df["人民币报价"] = data_df["最新价"] * price_mul["price"] * float(usd_rmb)
data_df.dropna(thresh=4, inplace=True)
return data_df
if __name__ == "__main__":
futures_hq_subscribe_exchange_symbol_df = futures_hq_subscribe_exchange_symbol()
print(futures_hq_subscribe_exchange_symbol_df)
print("开始接收实时行情, 每秒刷新一次")
subscribes = futures_foreign_commodity_subscribe_exchange_symbol()
futures_foreign_commodity_realtime_df = futures_foreign_commodity_realtime(
symbol="CT,NID"
)
print(futures_foreign_commodity_realtime_df)
futures_foreign_commodity_realtime_df = futures_foreign_commodity_realtime(
symbol=["XAU"]
)
print(futures_foreign_commodity_realtime_df)
while True:
futures_foreign_commodity_realtime_df = futures_foreign_commodity_realtime(
symbol=subscribes
)
print(futures_foreign_commodity_realtime_df)
time.sleep(3)
@@ -0,0 +1,57 @@
# -*- coding:utf-8 -*-
# !/usr/bin/env python
"""
Date: 2026/4/28 15:00
Desc: 中证商品指数
http://www.ccidx.com/
"""
import pandas as pd
import requests
def futures_index_ccidx(symbol: str = "中证商品期货指数") -> pd.DataFrame:
"""
中证商品指数-商品指数-日频率
http://www.ccidx.com/index.html
:param symbol: choice of {"中证商品期货指数", "中证商品期货价格指数"}
:type symbol: str
:return: 商品指数-日频率
:rtype: pandas.DataFrame
"""
futures_index_map = {
"中证商品期货指数": "100001.CCI",
"中证商品期货价格指数": "000001.CCI",
}
url = "http://www.ccidx.com/CCI-ZZZS/index/getDateLine"
params = {"indexId": futures_index_map[symbol]}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(
[item for item in data_json["data"]["dateLineJson"]]
)
temp_df.rename(
columns={
"tradeDate": "日期",
"indexId": "指数代码",
"closingPrice": "收盘点位",
"settlePrice": "结算点位",
"dailyIncreaseAndDecrease": "涨跌",
"dailyIncreaseAndDecreasePercentage": "涨跌幅",
},
inplace=True,
)
temp_df["日期"] = pd.to_datetime(temp_df["日期"], errors="coerce").dt.date
temp_df["收盘点位"] = pd.to_numeric(temp_df["收盘点位"], errors="coerce")
temp_df["结算点位"] = pd.to_numeric(temp_df["结算点位"], errors="coerce")
temp_df["涨跌"] = pd.to_numeric(temp_df["涨跌"], errors="coerce")
temp_df["涨跌幅"] = pd.to_numeric(temp_df["涨跌幅"], errors="coerce")
temp_df.sort_values(by=["日期"], inplace=True)
temp_df.reset_index(inplace=True, drop=True)
return temp_df
if __name__ == "__main__":
futures_index_ccidx_df = futures_index_ccidx(symbol="中证商品期货指数")
print(futures_index_ccidx_df)
@@ -0,0 +1,99 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2025/11/25 18:00
Desc: 99 期货网-大宗商品库存数据
https://www.99qh.com/
"""
import json
from datetime import datetime
from functools import lru_cache
import pandas as pd
import requests
from bs4 import BeautifulSoup
@lru_cache(maxsize=32)
def __get_99_symbol_map() -> pd.DataFrame:
"""
99 期货网-品种代码对照表
https://www.99qh.com/data/stockIn?productId=12
:return: 品种代码对照表
:rtype: pandas.DataFrame
"""
import warnings
warnings.filterwarnings("ignore")
url = "https://www.99qh.com/data/stockIn"
r = requests.get(url, verify=False)
soup = BeautifulSoup(r.text, features="lxml")
raw_data = soup.find(attrs={"id": "__NEXT_DATA__"}).text
data_json = json.loads(raw_data)
df_list = []
for i, item in enumerate(
data_json["props"]["pageProps"]["data"]["varietyListData"]
):
temp_df = pd.DataFrame(
data_json["props"]["pageProps"]["data"]["varietyListData"][i]["productList"]
)
df_list.append(temp_df)
big_df = pd.concat(df_list, ignore_index=True)
return big_df
def futures_inventory_99(symbol: str = "豆一") -> pd.DataFrame:
"""
99 期货网-大宗商品库存数据
https://www.99qh.com/data/stockIn?productId=12
:param symbol: 交易所对应的具体品种; 大连商品交易所的 豆一
:type symbol: str
:return: 大宗商品库存数据
:rtype: pandas.DataFrame
"""
import warnings
warnings.filterwarnings("ignore")
temp_df = __get_99_symbol_map()
symbol_name_map = dict(zip(temp_df["name"], temp_df["productId"]))
symbol_code_map = dict(zip(temp_df["code"], temp_df["productId"]))
if symbol in symbol_name_map: # 如果输入的是中文名称
product_id = symbol_name_map[symbol]
elif symbol in symbol_code_map: # 如果输入的是代码
product_id = symbol_code_map[symbol]
else:
raise ValueError(f"未找到品种 {symbol} 对应的编号")
url = "https://centerapi.fx168api.com/app/qh/api/stock/trend"
headers = {
"Content-Type": "application/json;charset=UTF-8",
"_pcc": "J7Dwju3vSeTlLLfTOLBnMXMtc9+PI1GWJR82GTEemXB9ORwBKCyPNDNVUQQv8p1jL3mLpZJ0PHt8"
"HZ57YtInOoeRj900V6EBBuvPTDAD9bghKWx4sNHiZNJhkzb4cSjlSO9ZcyZPHXuCLp2szfvtZSgCGQSbTFLUnHJsMrUFxJw=",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/58.0.3029.110 Safari/537.3",
"referer": "https://www.99qh.com",
"origin": "https://www.99qh.com",
}
params = {
"productId": product_id,
"type": "1",
"pageNo": "1",
"pageSize": "5000",
"startDate": "",
"endDate": f"{datetime.now().date().isoformat()}",
"appCategory": "web",
}
r = requests.get(url, params, headers=headers, verify=False)
data_json = r.json()
temp_df = pd.DataFrame(data_json["data"]["list"])
temp_df.columns = ["日期", "收盘价", "库存"]
temp_df.sort_values(by=["日期"], ignore_index=True, inplace=True)
temp_df["日期"] = pd.to_datetime(temp_df["日期"], errors="coerce").dt.date
temp_df["收盘价"] = pd.to_numeric(temp_df["收盘价"], errors="coerce")
temp_df["库存"] = pd.to_numeric(temp_df["库存"], errors="coerce")
return temp_df
if __name__ == "__main__":
futures_inventory_99_df = futures_inventory_99(symbol="豆一")
print(futures_inventory_99_df)
@@ -0,0 +1,69 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2025/3/5 17:30
Desc: 东方财富网-数据中心-期货库存数据
https://data.eastmoney.com/ifdata/kcsj.html
"""
import pandas as pd
import requests
from akshare.futures.cons import futures_inventory_em_symbol_dict
def futures_inventory_em(symbol: str = "a") -> pd.DataFrame:
"""
东方财富网-数据中心-期货库存数据
https://data.eastmoney.com/ifdata/kcsj.html
:param symbol: 支持品种代码和中文名称中文名称参见https://data.eastmoney.com/ifdata/kcsj.html
:type symbol: str
:return: 指定品种的库存数据
:rtype: pandas.DataFrame
"""
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
"reportName": "RPT_FUTU_POSITIONCODE",
"columns": "TRADE_MARKET_CODE,TRADE_CODE,TRADE_TYPE",
"filter": '(IS_MAINCODE="1")',
"pageNumber": "1",
"pageSize": "500",
"source": "WEB",
"client": "WEB",
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(data_json["result"]["data"])
symbol_dict = dict(zip(temp_df["TRADE_TYPE"], temp_df["TRADE_CODE"]))
if symbol in symbol_dict.keys():
product_id = symbol_dict[symbol]
elif symbol in futures_inventory_em_symbol_dict.keys(): # 如果输入的是代码
product_id = futures_inventory_em_symbol_dict[symbol]
else:
raise ValueError(f"请输入正确的 symbol, 可选项为: {symbol_dict}")
params = {
"reportName": "RPT_FUTU_STOCKDATA",
"columns": "SECURITY_CODE,TRADE_DATE,ON_WARRANT_NUM,ADDCHANGE",
"filter": f"""(SECURITY_CODE="{product_id}")(TRADE_DATE>='2020-10-28')""",
"pageNumber": "1",
"pageSize": "500",
"sortTypes": "-1",
"sortColumns": "TRADE_DATE",
"source": "WEB",
"client": "WEB",
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(data_json["result"]["data"])
temp_df.columns = ["-", "日期", "库存", "增减"]
temp_df = temp_df[["日期", "库存", "增减"]]
temp_df.sort_values(["日期"], inplace=True)
temp_df.reset_index(inplace=True, drop=True)
temp_df["库存"] = pd.to_numeric(temp_df["库存"], errors="coerce")
temp_df["增减"] = pd.to_numeric(temp_df["增减"], errors="coerce")
temp_df["日期"] = pd.to_datetime(temp_df["日期"], errors="coerce").dt.date
return temp_df
if __name__ == "__main__":
futures_inventory_em_df = futures_inventory_em(symbol="a")
print(futures_inventory_em_df)
@@ -0,0 +1,100 @@
# -*- coding:utf-8 -*-
# !/usr/bin/env python
"""
Date: 2024/12/26 18:00
Desc: 上海金属网-快讯
https://www.shmet.com/newsFlash/newsFlash.html?searchKeyword=
"""
import pandas as pd
import requests
def futures_news_shmet(symbol: str = "全部") -> pd.DataFrame:
"""
上海金属网-快讯
https://www.shmet.com/newsFlash/newsFlash.html?searchKeyword=
:param symbol: choice of {"全部", "要闻", "VIP", "财经", "", "", "", "", "", "", "贵金属", "小金属"}
:type symbol: str
:return: 上海金属网-快讯
:rtype: pandas.DataFrame
"""
url = "https://www.shmet.com/api/rest/news/queryNewsflashList"
if symbol == "全部":
payload = {"currentPage": 1, "pageSize": 100}
else:
symbol_map = {
"要闻": "0",
"VIP": "100",
"财经": "999",
"": "1002",
"": "1003",
"": "1005",
"": "1004",
"": "1006",
"": "1007",
"贵金属": "1008",
"小金属": "1009",
}
payload = {
"currentPage": 1,
"pageSize": 2000,
"content": "",
"flashTag": symbol_map[symbol],
}
r = requests.post(url, json=payload)
data_json = r.json()
temp_df = pd.DataFrame(data_json["data"]["dataList"])
temp_df.columns = [
"-",
"-",
"-",
"发布时间",
"-",
"内容",
"-",
"-",
"-",
"-",
"-",
"-",
"-",
"-",
"-",
"-",
"-",
]
temp_df = temp_df[
[
"发布时间",
"内容",
]
]
temp_df["发布时间"] = pd.to_datetime(
temp_df["发布时间"], unit="ms", utc=True
).dt.tz_convert("Asia/Shanghai")
temp_df.sort_values(["发布时间"], inplace=True)
temp_df.reset_index(inplace=True, drop=True)
return temp_df
if __name__ == "__main__":
futures_news_shmet_df = futures_news_shmet(symbol="")
print(futures_news_shmet_df)
for item in [
"全部",
"要闻",
"VIP",
"财经",
"",
"",
"",
"",
"",
"",
"贵金属",
"小金属",
]:
futures_news_shmet_df = futures_news_shmet(symbol=item)
print(futures_news_shmet_df)
@@ -0,0 +1,179 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2025/7/16 17:40
Desc: 中国期货各合约展期收益率
日线数据从 daily_bar 函数获取, 需要在收盘后运行
"""
import datetime
import re
import warnings
import math
import pandas as pd
from akshare.futures import cons
from akshare.futures.futures_daily_bar import get_futures_daily
from akshare.futures.symbol_var import symbol_market, symbol_varieties
calendar = cons.get_calendar()
def get_roll_yield(date=None, var="BB", symbol1=None, symbol2=None, df=None):
"""
指定交易日指定品种主力和次主力或任意两个合约的展期收益率
Parameters
------
date: string 某一天日期 format YYYYMMDD
var: string 合约品种如 RBAL
symbol1: string 合约 1 rb1810
symbol2: string 合约 2 rb1812
df: DataFrame或None 从dailyBar得到合约价格如果为空就在函数内部抓dailyBar直接喂给数据可以让计算加快
"""
# date = "20100104"
date = cons.convert_date(date) if date is not None else datetime.date.today()
if date.strftime("%Y%m%d") not in calendar:
warnings.warn("%s非交易日" % date.strftime("%Y%m%d"))
return None
if symbol1:
var = symbol_varieties(symbol1)
if not isinstance(df, pd.DataFrame):
market = symbol_market(var)
df = get_futures_daily(start_date=date, end_date=date, market=market)
if var:
df = df[
~df["symbol"].str.contains("efp")
] # 20200304 由于交易所获取的数据中会有比如 "CUefp",所以在这里过滤
df = df[df["variety"] == var].sort_values(by=["open_interest"], ascending=False)
# df["close"] = df["close"].astype("float")
df["close"] = pd.to_numeric(df["close"])
if len(df["close"]) < 2:
return None
symbol1 = df["symbol"].tolist()[0]
symbol2 = df["symbol"].tolist()[1]
close1 = df["close"][df["symbol"] == symbol1].tolist()[0]
close2 = df["close"][df["symbol"] == symbol2].tolist()[0]
a = re.sub(r"\D", "", symbol1)
a_1 = int(a[:-2])
a_2 = int(a[-2:])
b = re.sub(r"\D", "", symbol2)
b_1 = int(b[:-2])
b_2 = int(b[-2:])
c = (a_1 - b_1) * 12 + (a_2 - b_2)
if close1 == 0 or close2 == 0:
return False
if c > 0:
return math.log(close2 / close1) / c * 12, symbol2, symbol1
else:
return math.log(close2 / close1) / c * 12, symbol1, symbol2
def get_roll_yield_bar(
type_method: str = "var",
var: str = "RB",
date: str = "20201030",
start_day: str = None,
end_day: str = None,
):
"""
展期收益率
:param type_method: 'symbol': 获取指定交易日指定品种所有交割月合约的收盘价; 'var': 获取指定交易日所有品种两个主力合约的展期收益率(展期收益率横截面); 'date': 获取指定品种每天的两个主力合约的展期收益率(展期收益率时间序列)
:param var: 合约品种如 "RB", "AL"
:param date: 指定交易日 format YYYYMMDD
:param start_day: 开始日期 formatYYYYMMDD
:param end_day: 结束日期 formatYYYYMMDD
:return: pandas.DataFrame
展期收益率数据(DataFrame)
ry 展期收益率
index 日期或品种
"""
date = cons.convert_date(date) if date is not None else datetime.date.today()
start_day = (
cons.convert_date(start_day) if start_day is not None else datetime.date.today()
)
end_day = (
cons.convert_date(end_day)
if end_day is not None
else cons.convert_date(cons.get_latest_data_date(datetime.datetime.now()))
)
if type_method == "symbol":
df = get_futures_daily(
start_date=date, end_date=date, market=symbol_market(var)
)
df = df[df["variety"] == var]
return df
if type_method == "var":
df = pd.DataFrame()
for market in ["dce", "cffex", "shfe", "czce", "gfex"]:
df = pd.concat(
[
df,
get_futures_daily(start_date=date, end_date=date, market=market),
]
)
var_list = list(set(df["variety"]))
for i_remove in ["IO", "MO", "HO"]:
if i_remove in var_list:
var_list.remove(i_remove)
df_l = pd.DataFrame()
for var in var_list:
ry = get_roll_yield(date, var, df=df)
if ry:
df_l = pd.concat(
[
df_l,
pd.DataFrame(
[ry],
index=[var],
columns=["roll_yield", "near_by", "deferred"],
),
]
)
df_l["date"] = date
df_l = df_l.sort_values("roll_yield")
return df_l
if type_method == "date":
df_l = pd.DataFrame()
while start_day <= end_day:
try:
ry = get_roll_yield(start_day, var)
if ry:
df_l = pd.concat(
[
df_l,
pd.DataFrame(
[ry],
index=[start_day],
columns=["roll_yield", "near_by", "deferred"],
),
]
)
except: # noqa: E722
pass
start_day += datetime.timedelta(days=1)
return df_l
if __name__ == "__main__":
get_roll_yield_bar_range_df = get_roll_yield_bar(
type_method="date",
var="RB",
start_day="20230801",
end_day="20230810",
)
print(get_roll_yield_bar_range_df)
get_roll_yield_bar_range_df = get_roll_yield_bar(
type_method="var",
date="20191008",
)
print(get_roll_yield_bar_range_df)
get_roll_yield_bar_symbol = get_roll_yield_bar(type_method="var", date="20210201")
print(get_roll_yield_bar_symbol)
@@ -0,0 +1,45 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2025/3/31 18:00
Desc: 国泰君安期货-交易日历数据表
https://www.gtjaqh.com/pc/calendar.html
"""
from io import StringIO
import pandas as pd
import requests
def futures_rule(date: str = "20231205") -> pd.DataFrame:
"""
国泰君安期货-交易日历数据表
https://www.gtjaqh.com/pc/calendar.html
:param date: 需要指定为交易日, 且是近期的日期
:type date: str
:return: 交易日历数据
:rtype: pandas.DataFrame
"""
import urllib3
urllib3.disable_warnings()
url = " https://www.gtjaqh.com/pc/calendar"
params = {"date": f"{date}"}
r = requests.get(url, params=params, verify=False)
big_df = pd.read_html(StringIO(r.text), header=1)[0]
big_df["交易保证金比例"] = big_df["交易保证金比例"].str.strip("%")
big_df["交易保证金比例"] = pd.to_numeric(big_df["交易保证金比例"], errors="coerce")
big_df["涨跌停板幅度"] = big_df["涨跌停板幅度"].str.strip("%")
big_df["涨跌停板幅度"] = pd.to_numeric(big_df["涨跌停板幅度"], errors="coerce")
big_df["合约乘数"] = pd.to_numeric(big_df["合约乘数"], errors="coerce")
big_df["最小变动价位"] = pd.to_numeric(big_df["最小变动价位"], errors="coerce")
big_df["限价单每笔最大下单手数"] = pd.to_numeric(
big_df["限价单每笔最大下单手数"], errors="coerce"
)
return big_df
if __name__ == "__main__":
futures_rule_df = futures_rule(date="20250328")
print(futures_rule_df)
@@ -0,0 +1,38 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2024/1/17 19:30
Desc: 东方财富网-期货行情-品种及交易规则
https://portal.eastmoneyfutures.com/pages/service/jyts.html#jyrl
"""
import pandas as pd
import requests
from akshare.utils.cons import headers
def futures_rule_em() -> pd.DataFrame:
"""
东方财富网-期货行情-品种及交易规则
https://portal.eastmoneyfutures.com/pages/service/jyts.html#jyrl
:return: 品种及交易规则
:rtype: pandas.DataFrame
"""
url = "https://eastmoneyfutures.com/api/ComManage/GetPZJYInfo"
r = requests.get(url, headers=headers)
data_json = r.json()
temp_df = pd.DataFrame(data_json["Data"])
return temp_df
def futures_trading_hours_em():
"""
东方财富网-期货交易时间
https://qhweb.eastmoney.com/tradinghours
"""
pass
if __name__ == "__main__":
futures_rule_em_df = futures_rule_em()
print(futures_rule_em_df)
@@ -0,0 +1,415 @@
#!/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)
@@ -0,0 +1,87 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2024/1/18 16:25
Desc: 新加坡交易所-衍生品-历史数据-历史结算价格
https://www.sgx.com/zh-hans/research-education/derivatives
https://links.sgx.com/1.0.0/derivatives-daily/5888/FUTURE.zip
"""
import zipfile
from io import BytesIO
from io import StringIO
import pandas as pd
import requests
def __fetch_ftse_index_futu(date: str = "20231108") -> int:
"""
新加坡交易所-日历计算
https://wap.eastmoney.com/quote/stock/100.STI.html
:param date: 交易日
:type date: str
:return: 日期计算结果
:rtype: int
"""
url = "https://push2his.eastmoney.com/api/qt/stock/kline/get"
params = {
"secid": "100.STI",
"klt": "101",
"fqt": "0",
"lmt": "10000",
"end": date,
"iscca": "1",
"fields1": "f1,f2,f3,f4,f5,f6,f7,f8",
"fields2": "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61,f62,f63,f64",
"ut": "f057cbcbce2a86e2866ab8877db1d059",
"forcect": "1",
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame([item.split(",") for item in data_json["data"]["klines"]])
temp_df.columns = [
"date",
"-",
"open",
"close",
"high",
"low",
"volume",
"amount",
"_",
"-",
"open",
"close",
"high",
"low",
]
num = temp_df["date"].index[-1] + 791
return num
def futures_settlement_price_sgx(date: str = "20231107") -> pd.DataFrame:
"""
新加坡交易所-衍生品-历史数据-历史结算价格
https://www.sgx.com/zh-hans/research-education/derivatives
:param date: 交易日
:type date: str
:return: 所有期货品种的在指定交易日的历史结算价格
:rtype: pandas.DataFrame
"""
num = __fetch_ftse_index_futu(date)
url = f"https://links.sgx.com/1.0.0/derivatives-daily/{num}/FUTURE.zip"
r = requests.get(url)
with zipfile.ZipFile(BytesIO(r.content)) as file:
with file.open(file.namelist()[0]) as my_file:
data = my_file.read().decode()
if file.namelist()[0].endswith("txt"):
data_df = pd.read_table(StringIO(data))
else:
data_df = pd.read_csv(StringIO(data))
return data_df
if __name__ == "__main__":
futures_settlement_price_sgx_df = futures_settlement_price_sgx(date="20240110")
print(futures_settlement_price_sgx_df)
@@ -0,0 +1,100 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2024/3/21 12:00
Desc: 东方财富网-数据中心-现货与股票
https://data.eastmoney.com/ifdata/xhgp.html
"""
import pandas as pd
import requests
from akshare.utils import demjson
def futures_spot_stock(symbol: str = "能源") -> pd.DataFrame:
"""
东方财富网-数据中心-现货与股票
https://data.eastmoney.com/ifdata/xhgp.html
:param symbol: choice of {'能源', '化工', '塑料', '纺织', '有色', '钢铁', '建材', '农副'}
:type symbol: str
:return: 现货与股票上下游对应数据
:rtype: pandas.DataFrame
"""
map_dict = {
"能源": 0,
"化工": 1,
"塑料": 2,
"纺织": 3,
"有色": 4,
"钢铁": 5,
"建材": 6,
"农副": 7,
}
url = "https://data.eastmoney.com/ifdata/xhgp.html"
headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,"
"image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Host": "data.eastmoney.com",
"Pragma": "no-cache",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
}
r = requests.get(url, headers=headers)
data_text = r.text
temp_json = demjson.decode(
data_text[
data_text.find("pagedata") : data_text.find(
"/newstatic/js/common/emdataview.js"
)
]
.strip("pagedata= ")
.strip(';\n </script>\n <script src="')
)
date_list = list(temp_json["dates"].values())
temp_json = temp_json["datas"]
temp_df = temp_json[map_dict.get(symbol)]
temp_df = pd.DataFrame(temp_df["list"])
xyyh_list = [
"-" if item == [] else ", ".join([inner_item["name"] for inner_item in item])
for item in temp_df["xyyhs"].tolist()
]
scs_list = [
"-" if item == [] else ", ".join([inner_item["name"] for inner_item in item])
for item in temp_df["scss"].tolist()
]
temp_df["scss"] = scs_list
temp_df["xyyhs"] = xyyh_list
temp_df.columns = [
"商品名称",
date_list[0],
date_list[1],
date_list[2],
date_list[3],
date_list[4],
"最新价格",
"近半年涨跌幅",
"生产商",
"下游用户",
]
temp_df[date_list[0]] = pd.to_numeric(temp_df[date_list[0]], errors="coerce")
temp_df[date_list[1]] = pd.to_numeric(temp_df[date_list[1]], errors="coerce")
temp_df[date_list[2]] = pd.to_numeric(temp_df[date_list[2]], errors="coerce")
temp_df[date_list[3]] = pd.to_numeric(temp_df[date_list[3]], errors="coerce")
temp_df["最新价格"] = pd.to_numeric(temp_df["最新价格"], errors="coerce")
temp_df["近半年涨跌幅"] = pd.to_numeric(temp_df["近半年涨跌幅"], errors="coerce")
return temp_df
if __name__ == "__main__":
futures_spot_stock_df = futures_spot_stock(symbol="能源")
print(futures_spot_stock_df)
for sector in ["能源", "化工", "塑料", "纺织", "有色", "钢铁", "建材", "农副"]:
futures_spot_stock_df = futures_spot_stock(symbol=sector)
print(futures_spot_stock_df)
@@ -0,0 +1,47 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2024/4/24 18:10
Desc: 上海期货交易所指定交割仓库库存周报
https://datacenter.jin10.com/reportType/dc_shfe_weekly_stock
https://tsite.shfe.com.cn/statements/dataview.html?paramid=kx
"""
import pandas as pd
import requests
def futures_stock_shfe_js(date: str = "20240419") -> pd.DataFrame:
"""
金十财经-上海期货交易所指定交割仓库库存周报
https://datacenter.jin10.com/reportType/dc_shfe_weekly_stock
:param date: 交易日; 库存周报只在每周的最后一个交易日公布数据
:type date: str
:return: 库存周报
:rtype: pandas.Series
"""
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/107.0.0.0 Safari/537.36",
"x-app-id": "rU6QIu7JHe2gOUeR",
"x-csrf-token": "x-csrf-token",
"x-version": "1.0.0",
}
url = "https://datacenter-api.jin10.com/reports/list"
params = {
"category": "stock",
"date": "-".join([date[:4], date[4:6], date[6:]]),
"attr_id": "1",
}
r = requests.get(url, params=params, headers=headers)
data_json = r.json()
columns_list = [item["name"] for item in data_json["data"]["keys"]]
temp_df = pd.DataFrame(data_json["data"]["values"], columns=columns_list)
for item in columns_list[1:]:
temp_df[item] = pd.to_numeric(temp_df[item], errors="coerce")
return temp_df
if __name__ == "__main__":
futures_stock_shfe_js_df = futures_stock_shfe_js(date="20240419")
print(futures_stock_shfe_js_df)
@@ -0,0 +1,340 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2024/1/22 20:30
Desc: 期货-期转现-交割
"""
from io import StringIO, BytesIO
import pandas as pd
import requests
def futures_to_spot_shfe(date: str = "202312") -> pd.DataFrame:
"""
上海期货交易所-期转现
https://tsite.shfe.com.cn/statements/dataview.html?paramid=kx
1(BC)螺纹钢线材热轧卷板天然橡胶20号胶低硫燃料油燃料油石油沥青纸浆不锈钢的数量单位为黄金的数量单位为白银的数量单位为千克原油的数量单位为
2交割量期转现量为单向计算
:param date: 年月
:type date: str
:return: 上海期货交易所期转现
:rtype: pandas.DataFrame
"""
url = f"https://tsite.shfe.com.cn/data/instrument/ExchangeDelivery{date}.dat"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/100.0.4896.127 Safari/537.36",
}
r = requests.get(url, headers=headers)
data_json = r.json()
temp_df = pd.DataFrame(data_json["ExchangeDelivery"])
temp_df.columns = [
"_",
"日期",
"交割量",
"_",
"期转现量",
"合约",
"_",
"_",
]
temp_df = temp_df[
[
"日期",
"合约",
"交割量",
"期转现量",
]
]
temp_df["日期"] = pd.to_datetime(temp_df["日期"], errors="coerce").dt.date
temp_df["交割量"] = pd.to_numeric(temp_df["交割量"], errors="coerce")
temp_df["期转现量"] = pd.to_numeric(temp_df["期转现量"], errors="coerce")
return temp_df
def futures_delivery_dce(date: str = "202312") -> pd.DataFrame:
"""
大连商品交易所-交割统计
http://www.dce.com.cn/dalianshangpin/xqsj/tjsj26/jgtj/jgsj/index.html
:param date: 交割日期
:type date: str
:return: 大连商品交易所-交割统计
:rtype: pandas.DataFrame
"""
url = "http://www.dce.com.cn/publicweb/quotesdata/delivery.html"
params = {
"deliveryQuotes.variety": "all",
"year": "",
"month": "",
"deliveryQuotes.begin_month": date,
"deliveryQuotes.end_month": str(int(date) + 1),
}
headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Pragma": "no-cache",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36",
}
r = requests.post(url, params=params, headers=headers)
temp_df = pd.read_html(StringIO(r.text))[0]
temp_df["交割日期"] = (
temp_df["交割日期"].astype(str).str.split(".", expand=True).iloc[:, 0]
)
temp_df = temp_df[~temp_df["品种"].str.contains("小计|总计")]
temp_df.reset_index(inplace=True, drop=True)
temp_df["交割日期"] = pd.to_datetime(temp_df["交割日期"], errors="coerce").dt.date
temp_df["交割量"] = pd.to_numeric(temp_df["交割量"], errors="coerce")
temp_df["交割金额"] = pd.to_numeric(temp_df["交割金额"], errors="coerce")
return temp_df
def futures_to_spot_dce(date: str = "202312") -> pd.DataFrame:
"""
大连商品交易所-期转现
http://www.dce.com.cn/dalianshangpin/xqsj/tjsj26/jgtj/qzxcx/index.html
:param date: 期转现日期
:type date: str
:return: 大连商品交易所-期转现
:rtype: pandas.DataFrame
"""
url = "http://www.dce.com.cn/publicweb/quotesdata/ftsDeal.html"
params = {
"ftsDealQuotes.variety": "all",
"year": "",
"month": "",
"ftsDealQuotes.begin_month": date,
"ftsDealQuotes.end_month": date,
}
r = requests.post(url, params=params)
temp_df = pd.read_html(StringIO(r.text))[0]
temp_df["期转现发生日期"] = (
temp_df["期转现发生日期"].astype(str).str.split(".", expand=True).iloc[:, 0]
)
temp_df = temp_df[~temp_df["合约代码"].str.contains("小计|总计")]
temp_df.reset_index(inplace=True, drop=True)
temp_df["期转现发生日期"] = pd.to_datetime(
temp_df["期转现发生日期"], errors="coerce"
).dt.date
temp_df["期转现数量"] = pd.to_numeric(temp_df["期转现数量"], errors="coerce")
return temp_df
def futures_delivery_match_dce(symbol: str = "a") -> pd.DataFrame:
"""
大连商品交易所-交割配对表
http://www.dce.com.cn/dalianshangpin/xqsj/tjsj26/jgtj/jgsj/index.html
:param symbol: 交割品种
:type symbol: str
:return: 大连商品交易所-交割配对表
:rtype: pandas.DataFrame
"""
url = "http://www.dce.com.cn/publicweb/quotesdata/deliveryMatch.html"
params = {
"deliveryMatchQuotes.variety": symbol,
"contract.contract_id": "all",
"contract.variety_id": symbol,
}
r = requests.post(url, params=params)
temp_df = pd.read_html(StringIO(r.text))[0]
temp_df["配对日期"] = (
temp_df["配对日期"].astype(str).str.split(".", expand=True).iloc[:, 0]
)
temp_df = temp_df.iloc[:-1, :]
temp_df["配对日期"] = pd.to_datetime(temp_df["配对日期"], errors="coerce").dt.date
temp_df["配对手数"] = pd.to_numeric(temp_df["配对手数"], errors="coerce")
temp_df["交割结算价"] = pd.to_numeric(temp_df["交割结算价"], errors="coerce")
return temp_df
def futures_to_spot_czce(date: str = "20231228") -> pd.DataFrame:
"""
郑州商品交易所-期转现统计
http://www.czce.com.cn/cn/jysj/qzxtj/H770311index_1.htm
:param date: 年月日
:type date: str
:return: 郑州商品交易所-期转现统计
:rtype: pandas.DataFrame
"""
url = f"http://www.czce.com.cn/cn/DFSStaticFiles/Future/{date[:4]}/{date}/FutureDataTrdtrades.xls"
headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Host": "www.czce.com.cn",
"Pragma": "no-cache",
"Referer": "http://www.czce.com.cn/",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36",
}
r = requests.get(url, headers=headers)
r.encoding = "utf-8"
temp_df = pd.read_excel(BytesIO(r.content), skiprows=1)
temp_df.columns = [
"合约代码",
"合约数量",
]
temp_df = temp_df[
[
"合约代码",
"合约数量",
]
]
temp_df["合约数量"] = temp_df["合约数量"].astype(str).str.replace(",", "")
temp_df["合约数量"] = pd.to_numeric(temp_df["合约数量"], errors="coerce")
temp_df = temp_df[~temp_df["合约代码"].str.contains("小计|合计")]
temp_df.reset_index(inplace=True, drop=True)
return temp_df
def futures_delivery_match_czce(date: str = "20210106") -> pd.DataFrame:
"""
郑州商品交易所-交割配对
http://www.czce.com.cn/cn/jysj/jgpd/H770308index_1.htm
:param date: 年月日
:type date: str
:return: 郑州商品交易所-交割配对
:rtype: pandas.DataFrame
"""
url = f"http://www.czce.com.cn/cn/DFSStaticFiles/Future/{date[:4]}/{date}/FutureDataDelsettle.xls"
r = requests.get(url)
r.encoding = "utf-8"
temp_df = pd.read_excel(BytesIO(r.content), skiprows=0)
index_flag = temp_df[temp_df.iloc[:, 0].str.contains("配对日期")].index.values
big_df = pd.DataFrame()
for i, item in enumerate(index_flag):
try:
temp_inner_df = temp_df[index_flag[i] + 1 : index_flag[i + 1]]
except: # noqa: E722
temp_inner_df = temp_df[index_flag[i] + 1 :]
temp_inner_df.columns = temp_inner_df.iloc[0, :]
temp_inner_df = temp_inner_df.iloc[1:-1, :]
temp_inner_df.reset_index(drop=True, inplace=True)
date_contract_str = (
temp_df[temp_df.iloc[:, 0].str.contains("配对日期")].iloc[:, 0].values[i]
)
inner_date = date_contract_str.split("")[1].split(" ")[0]
symbol = date_contract_str.split("")[-1]
temp_inner_df["配对日期"] = inner_date
temp_inner_df["合约代码"] = symbol
big_df = pd.concat([big_df, temp_inner_df], ignore_index=True)
big_df.columns = [
"卖方会员",
"卖方会员-会员简称",
"买方会员",
"买方会员-会员简称",
"交割量",
"配对日期",
"合约代码",
]
big_df["交割量"] = big_df["交割量"].str.replace(",", "")
big_df["交割量"] = pd.to_numeric(big_df["交割量"])
return big_df
def futures_delivery_czce(date: str = "20210112") -> pd.DataFrame:
"""
郑州商品交易所-月度交割查询
http://www.czce.com.cn/cn/jysj/ydjgcx/H770316index_1.htm
:param date: 年月日
:type date: str
:return: 郑州商品交易所-月度交割查询
:rtype: pandas.DataFrame
"""
url = f"http://www.czce.com.cn/cn/DFSStaticFiles/Future/{date[:4]}/{date}/FutureDataSettlematched.xls"
r = requests.get(url)
r.encoding = "utf-8"
temp_df = pd.read_excel(BytesIO(r.content), skiprows=1)
temp_df.columns = [
"品种",
"交割数量",
"交割额",
]
temp_df["交割数量"] = temp_df["交割数量"].astype(str).str.replace(",", "")
temp_df["交割额"] = temp_df["交割额"].astype(str).str.replace(",", "")
temp_df["交割数量"] = pd.to_numeric(temp_df["交割数量"], errors="coerce")
temp_df["交割额"] = pd.to_numeric(temp_df["交割额"], errors="coerce")
return temp_df
def futures_delivery_shfe(date: str = "202312") -> pd.DataFrame:
"""
上海期货交易所-交割情况表
https://tsite.shfe.com.cn/statements/dataview.html?paramid=kx
注意: 日期 -> 月度统计 -> 下拉到交割情况表
:param date: 年月日
:type date: str
:return: 上海期货交易所-交割情况表
:rtype: pandas.DataFrame
"""
url = f"https://tsite.shfe.com.cn/data/dailydata/{date}monthvarietystatistics.dat"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/100.0.4896.127 Safari/537.36",
}
r = requests.get(url, headers=headers)
r.encoding = "utf-8"
data_json = r.json()
temp_df = pd.DataFrame(data_json["o_curdelivery"])
temp_df.columns = [
"品种",
"品种代码",
"_",
"交割量-本月",
"交割量-比重",
"交割量-本年累计",
"交割量-累计同比",
]
temp_df = temp_df[
[
"品种",
"交割量-本月",
"交割量-比重",
"交割量-本年累计",
"交割量-累计同比",
]
]
temp_df["交割量-本月"] = pd.to_numeric(temp_df["交割量-本月"], errors="coerce")
temp_df["交割量-比重"] = pd.to_numeric(temp_df["交割量-比重"], errors="coerce")
temp_df["交割量-本年累计"] = pd.to_numeric(
temp_df["交割量-本年累计"], errors="coerce"
)
temp_df["交割量-累计同比"] = pd.to_numeric(
temp_df["交割量-累计同比"], errors="coerce"
)
return temp_df
if __name__ == "__main__":
futures_to_spot_dce_df = futures_to_spot_dce(date="202312")
print(futures_to_spot_dce_df)
futures_to_spot_shfe_df = futures_to_spot_shfe(date="202312")
print(futures_to_spot_shfe_df)
futures_to_spot_czce_df = futures_to_spot_czce(date="20210112")
print(futures_to_spot_czce_df)
futures_delivery_dce_df = futures_delivery_dce(date="202101")
print(futures_delivery_dce_df)
futures_delivery_monthly_czce_df = futures_delivery_czce(date="20251014")
print(futures_delivery_monthly_czce_df)
futures_delivery_shfe_df = futures_delivery_shfe(date="202312")
print(futures_delivery_shfe_df)
futures_delivery_match_dce_df = futures_delivery_match_dce(symbol="a")
print(futures_delivery_match_dce_df)
futures_delivery_match_czce_df = futures_delivery_match_czce(date="20210106")
print(futures_delivery_match_czce_df)
@@ -0,0 +1,247 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2025/7/1 16:30
Desc: 期货-仓单日报
上海期货交易所-仓单日报
https://tsite.shfe.com.cn/statements/dataview.html?paramid=dailystock
郑州商品交易所-交易数据-仓单日报
http://www.czce.com.cn/cn/jysj/cdrb/H770310index_1.htm
大连商品交易所-行情数据-统计数据-日统计-仓单日报
http://www.dce.com.cn/dalianshangpin/xqsj/tjsj26/rtj/cdrb/index.html
广州期货交易所-行情数据-仓单日报
http://www.gfex.com.cn/gfex/cdrb/hqsj_tjsj.shtml
"""
import re
from io import BytesIO, StringIO
import pandas as pd
import requests
def futures_warehouse_receipt_czce(date: str = "20251103") -> dict:
"""
郑州商品交易所-交易数据-仓单日报
http://www.czce.com.cn/cn/jysj/cdrb/H770310index_1.htm
:param date: 交易日, e.g., "20200702"
:type date: str
:return: 指定日期的仓单日报数据
:rtype: dict
"""
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
if int(date) > 20251101:
url = f"http://www.czce.com.cn/cn/DFSStaticFiles/Future/{date[:4]}/{date}/FutureDataWhsheet.xlsx"
else:
url = f"http://www.czce.com.cn/cn/DFSStaticFiles/Future/{date[:4]}/{date}/FutureDataWhsheet.xls"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/83.0.4103.116 Safari/537.36"
}
r = requests.get(url, verify=False, headers=headers)
temp_df = pd.read_excel(BytesIO(r.content))
index_list = temp_df[temp_df.iloc[:, 0].str.find("品种") == 0.0].index.to_list()
index_list.append(len(temp_df))
big_dict = {}
for inner_index in range(len(index_list) - 1):
inner_df = temp_df[index_list[inner_index] : index_list[inner_index + 1]]
inner_key = re.findall(pattern=r"[a-zA-Z]+", string=inner_df.iloc[0, 0])[0]
inner_df = inner_df.iloc[1:, :]
inner_df.dropna(axis=0, how="all", inplace=True)
inner_df.dropna(axis=1, how="all", inplace=True)
inner_df.columns = inner_df.iloc[0, :].to_list()
inner_df = inner_df.iloc[1:, :]
inner_df.reset_index(inplace=True, drop=True)
big_dict[inner_key] = inner_df
return big_dict
def futures_warehouse_receipt_dce(date: str = "20251027") -> pd.DataFrame:
"""
大连商品交易所-行情数据-统计数据-日统计-仓单日报
http://www.dce.com.cn/dce/channel/list/187.html
:param date: 交易日, e.g., "20200702"
:type date: str
:return: 指定日期的仓单日报数据
:rtype: dict
"""
url = "http://www.dce.com.cn/dcereport/publicweb/dailystat/wbillWeeklyQuotes"
payload = {
"tradeDate": date,
"varietyId": "all",
}
r = requests.post(url, json=payload)
data_json = r.json()
temp_df = pd.DataFrame(data_json["data"]["entityList"])
temp_df.rename(
columns={
"variety": "品种名称",
"whAbbr": "仓库/分库",
"deliveryAbbr": "可选提货地点/分库-数量",
"lastWbillQty": "昨日仓单量(手)",
"wbillQty": "今日仓单量(手)",
"diff": "增减(手)",
"varietyOrder": "品种代码",
},
inplace=True,
)
temp_df = temp_df[
[
"品种代码",
"品种名称",
"仓库/分库",
"可选提货地点/分库-数量",
"昨日仓单量(手)",
"今日仓单量(手)",
"增减(手)",
]
]
return temp_df
def futures_shfe_warehouse_receipt(date: str = "20200702") -> dict:
"""
上海期货交易所指定交割仓库期货仓单日报
https://tsite.shfe.com.cn/statements/dataview.html?paramid=dailystock&paramdate=20200703
:param date: 交易日, e.g., "20200702"
:type date: str
:return: 指定日期的仓单日报数据
:rtype: dict
"""
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/83.0.4103.116 Safari/537.36"
}
url = (
f"https://www.shfe.com.cn/data/tradedata/future/dailydata/{date}dailystock.dat"
)
if date >= "20140519":
r = requests.get(url, headers=headers)
data_json = r.json()
temp_df = pd.DataFrame(data_json["o_cursor"])
temp_df["VARNAME"] = temp_df["VARNAME"].str.split(r"$", expand=True).iloc[:, 0]
temp_df["REGNAME"] = temp_df["REGNAME"].str.split(r"$", expand=True).iloc[:, 0]
temp_df["WHABBRNAME"] = (
temp_df["WHABBRNAME"].str.split(r"$", expand=True).iloc[:, 0]
)
big_dict = {}
for item in set(temp_df["VARNAME"]):
big_dict[item] = temp_df[temp_df["VARNAME"] == item]
else:
url = f"https://www.shfe.com.cn/data/tradedata/future/dailydata/{date}dailystock.html"
r = requests.get(url, headers=headers)
temp_df = pd.read_html(StringIO(r.text))[0]
index_list = temp_df[
temp_df.iloc[:, 3].str.contains("单位:") == 1
].index.to_list()
big_dict = {}
for inner_index in range(len(index_list)):
temp_index_start = index_list[inner_index]
if (inner_index + 1) >= len(index_list):
if temp_df.iloc[-1, 0].startswith("注:"):
temp_index_end = len(temp_df) - 1
else:
temp_index_end = len(temp_df)
else:
temp_index_end = index_list[inner_index + 1]
inner_df = temp_df[temp_index_start:temp_index_end]
inner_df.reset_index(inplace=True, drop=True)
inner_key = inner_df.iloc[0, 0]
inner_df.columns = inner_df.iloc[1].to_list()
inner_df = inner_df[2:]
inner_df.reset_index(inplace=True, drop=True)
big_dict[inner_key] = inner_df
return big_dict
def futures_gfex_warehouse_receipt(date: str = "20240122") -> dict:
"""
广州期货交易所-行情数据-仓单日报
http://www.gfex.com.cn/gfex/cdrb/hqsj_tjsj.shtml
:param date: 交易日, e.g., "20240122"
:type date: str
:return: 指定日期的仓单日报数据
:rtype: dict
"""
url = "http://www.gfex.com.cn/u/interfacesWebTdWbillWeeklyQuotes/loadList"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/83.0.4103.116 Safari/537.36"
}
payload = {"gen_date": date}
r = requests.post(url=url, data=payload, headers=headers)
data_json = r.json()
temp_df = pd.DataFrame(data_json["data"])
symbol_list = list(
set([item.upper() for item in temp_df["varietyOrder"].tolist() if item != ""])
)
temp_df.rename(
columns={
"varietyOrder": "symbol",
"variety": "品种",
"whAbbr": "仓库/分库",
"lastWbillQty": "昨日仓单量",
"wbillQty": "今日仓单量",
"regWbillQty": "增减",
},
inplace=True,
)
temp_df = temp_df[
[
"symbol",
"whType",
"品种",
"仓库/分库",
"昨日仓单量",
"今日仓单量",
"增减",
]
]
temp_df["whType"] = pd.to_numeric(temp_df["whType"], errors="coerce")
temp_df.dropna(
subset=["whType"], how="any", axis=0, ignore_index=True, inplace=True
)
big_dict = dict()
for symbol in symbol_list:
inner_temp_df = temp_df[temp_df["symbol"] == symbol.lower()].copy()
inner_temp_df = inner_temp_df[
[
"品种",
"仓库/分库",
"昨日仓单量",
"今日仓单量",
"增减",
]
]
inner_temp_df["昨日仓单量"] = pd.to_numeric(
inner_temp_df["昨日仓单量"], errors="coerce"
)
inner_temp_df["今日仓单量"] = pd.to_numeric(
inner_temp_df["今日仓单量"], errors="coerce"
)
inner_temp_df["增减"] = pd.to_numeric(inner_temp_df["增减"], errors="coerce")
inner_temp_df.reset_index(inplace=True, drop=True)
big_dict[symbol] = inner_temp_df
return big_dict
if __name__ == "__main__":
futures_warehouse_receipt_czce_df = futures_warehouse_receipt_czce(date="20251014")
print(futures_warehouse_receipt_czce_df)
futures_warehouse_receipt_dce_df = futures_warehouse_receipt_dce(date="20251014")
print(futures_warehouse_receipt_dce_df)
futures_shfe_warehouse_receipt_df = futures_shfe_warehouse_receipt(date="20200702")
print(futures_shfe_warehouse_receipt_df)
futures_shfe_warehouse_receipt_df = futures_shfe_warehouse_receipt(date="20140516")
print(futures_shfe_warehouse_receipt_df)
futures_gfex_warehouse_receipt_df = futures_gfex_warehouse_receipt(date="20240122")
print(futures_gfex_warehouse_receipt_df)
futures_gfex_warehouse_receipt_df = futures_gfex_warehouse_receipt(date="20260226")
print(futures_gfex_warehouse_receipt_df)
@@ -0,0 +1,728 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2024/3/20 16:00
Desc: 新浪财经-国内期货-实时数据获取
https://vip.stock.finance.sina.com.cn/quotes_service/view/qihuohangqing.html#titlePos_3
P.S. 注意采集速度, 容易封禁 IP, 如果不能访问请稍后再试
"""
import json
import time
from functools import lru_cache
import pandas as pd
import requests
import py_mini_racer
from akshare.futures.cons import (
zh_subscribe_exchange_symbol_url,
zh_match_main_contract_url,
zh_match_main_contract_payload,
)
from akshare.futures.futures_contract_detail import futures_contract_detail
from akshare.utils import demjson
@lru_cache()
def futures_symbol_mark() -> pd.DataFrame:
"""
期货的品种和代码映射
https://vip.stock.finance.sina.com.cn/quotes_service/view/js/qihuohangqing.js
:return: 期货的品种和代码映射
:rtype: pandas.DataFrame
"""
url = (
"https://vip.stock.finance.sina.com.cn/quotes_service/view/js/qihuohangqing.js"
)
r = requests.get(url)
r.encoding = "gb2312"
data_text = r.text
raw_json = data_text[data_text.find("{") : data_text.find("}") + 1]
data_json = demjson.decode(raw_json)
czce_mark_list = [item[1] for item in data_json["czce"][1:]]
dce_mark_list = [item[1] for item in data_json["dce"][1:]]
shfe_mark_list = [item[1] for item in data_json["shfe"][1:]]
cffex_mark_list = [item[1] for item in data_json["cffex"][1:]]
gfex_mark_list = [item[1] for item in data_json["gfex"][1:]]
all_mark_list = (
czce_mark_list
+ dce_mark_list
+ shfe_mark_list
+ cffex_mark_list
+ gfex_mark_list
)
czce_market_name_list = [data_json["czce"][0]] * len(czce_mark_list)
dce_market_name_list = [data_json["dce"][0]] * len(dce_mark_list)
shfe_market_name_list = [data_json["shfe"][0]] * len(shfe_mark_list)
cffex_market_name_list = [data_json["cffex"][0]] * len(cffex_mark_list)
gfex_market_name_list = [data_json["gfex"][0]] * len(gfex_mark_list)
all_market_name_list = (
czce_market_name_list
+ dce_market_name_list
+ shfe_market_name_list
+ cffex_market_name_list
+ gfex_market_name_list
)
czce_symbol_list = [item[0] for item in data_json["czce"][1:]]
dce_symbol_list = [item[0] for item in data_json["dce"][1:]]
shfe_symbol_list = [item[0] for item in data_json["shfe"][1:]]
cffex_symbol_list = [item[0] for item in data_json["cffex"][1:]]
gfex_symbol_list = [item[0] for item in data_json["gfex"][1:]]
all_symbol_list = (
czce_symbol_list
+ dce_symbol_list
+ shfe_symbol_list
+ cffex_symbol_list
+ gfex_symbol_list
)
temp_df = pd.DataFrame([all_market_name_list, all_symbol_list, all_mark_list]).T
temp_df.columns = [
"exchange",
"symbol",
"mark",
]
return temp_df
def futures_zh_realtime(symbol: str = "PTA") -> pd.DataFrame:
"""
期货品种当前时刻所有可交易的合约实时数据
https://vip.stock.finance.sina.com.cn/quotes_service/view/qihuohangqing.html#titlePos_1
:param symbol: 品种名称可以通过 ak.futures_symbol_mark() 获取所有品种命名表
:type symbol: str
:return: 期货品种当前时刻所有可交易的合约实时数据
:rtype: pandas.DataFrame
"""
_futures_symbol_mark_df = futures_symbol_mark()
symbol_mark_map = dict(
zip(_futures_symbol_mark_df["symbol"], _futures_symbol_mark_df["mark"])
)
url = "https://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQFuturesData"
params = {
"page": "1",
"sort": "position",
"asc": "0",
"node": symbol_mark_map[symbol],
"base": "futures",
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(data_json)
temp_df["trade"] = pd.to_numeric(temp_df["trade"], errors="coerce")
temp_df["settlement"] = pd.to_numeric(temp_df["settlement"], errors="coerce")
temp_df["presettlement"] = pd.to_numeric(temp_df["presettlement"], errors="coerce")
temp_df["open"] = pd.to_numeric(temp_df["open"], errors="coerce")
temp_df["high"] = pd.to_numeric(temp_df["high"], errors="coerce")
temp_df["low"] = pd.to_numeric(temp_df["low"], errors="coerce")
temp_df["close"] = pd.to_numeric(temp_df["close"], errors="coerce")
temp_df["bidprice1"] = pd.to_numeric(temp_df["bidprice1"], errors="coerce")
temp_df["askprice1"] = pd.to_numeric(temp_df["askprice1"], errors="coerce")
temp_df["bidvol1"] = pd.to_numeric(temp_df["bidvol1"], errors="coerce")
temp_df["askvol1"] = pd.to_numeric(temp_df["askvol1"], errors="coerce")
temp_df["volume"] = pd.to_numeric(temp_df["volume"], errors="coerce")
temp_df["position"] = pd.to_numeric(temp_df["position"], errors="coerce")
temp_df["preclose"] = pd.to_numeric(temp_df["preclose"], errors="coerce")
temp_df["changepercent"] = pd.to_numeric(temp_df["changepercent"], errors="coerce")
temp_df["bid"] = pd.to_numeric(temp_df["bid"], errors="coerce")
temp_df["ask"] = pd.to_numeric(temp_df["ask"], errors="coerce")
temp_df["prevsettlement"] = pd.to_numeric(
temp_df["prevsettlement"], errors="coerce"
)
return temp_df
def zh_subscribe_exchange_symbol(symbol: str = "cffex") -> pd.DataFrame:
"""
交易所具体的可交易品种
https://vip.stock.finance.sina.com.cn/quotes_service/view/qihuohangqing.html#titlePos_1
:param symbol: choice of {'czce', 'dce', 'shfe', 'cffex', 'gfex'}
:type symbol: str
:return: 交易所具体的可交易品种
:rtype: dict
"""
r = requests.get(zh_subscribe_exchange_symbol_url)
r.encoding = "gbk"
data_text = r.text
data_json = demjson.decode(
data_text[data_text.find("{") : data_text.find("};") + 1]
)
if symbol == "czce":
data_json["czce"].remove("郑州商品交易所")
return pd.DataFrame(data_json["czce"])
if symbol == "dce":
data_json["dce"].remove("大连商品交易所")
return pd.DataFrame(data_json["dce"])
if symbol == "shfe":
data_json["shfe"].remove("上海期货交易所")
return pd.DataFrame(data_json["shfe"])
if symbol == "cffex":
data_json["cffex"].remove("中国金融期货交易所")
return pd.DataFrame(data_json["cffex"])
if symbol == "gfex":
data_json["gfex"].remove("广州期货交易所")
return pd.DataFrame(data_json["gfex"])
def match_main_contract(symbol: str = "cffex") -> str:
"""
新浪财经-期货-主力合约
https://vip.stock.finance.sina.com.cn/quotes_service/view/qihuohangqing.html#titlePos_1
:param symbol: choice of {'czce', 'dce', 'shfe', 'cffex', 'gfex'}
:type symbol: str
:return: 主力合约的字符串
:rtype: str
"""
subscribe_exchange_list = []
exchange_symbol_list = zh_subscribe_exchange_symbol(symbol).iloc[:, 1].tolist()
for item in exchange_symbol_list:
# item = 'sngz_qh'
zh_match_main_contract_payload.update({"node": item})
res = requests.get(
zh_match_main_contract_url, params=zh_match_main_contract_payload
)
data_json = demjson.decode(res.text)
data_df = pd.DataFrame(data_json)
try:
main_contract = data_df[data_df.iloc[:, 3:].duplicated()]
print(main_contract["symbol"].values[0])
subscribe_exchange_list.append(main_contract["symbol"].values[0])
except: # noqa: E722
if len(data_df) == 1:
subscribe_exchange_list.append(data_df["symbol"].values[0])
print(data_df["symbol"].values[0])
else:
print(item, "无主力合约")
continue
print(f"{symbol}主力合约获取成功")
return ",".join([item for item in subscribe_exchange_list])
def futures_zh_spot(
symbol: str = "V2309",
market: str = "CF",
adjust: str = "0",
) -> pd.DataFrame:
"""
期货的实时行情数据
https://vip.stock.finance.sina.com.cn/quotes_service/view/qihuohangqing.html#titlePos_1
:param symbol: 合约名称的字符串组合
:type symbol: str
:param market: CF 为商品期货
:type market: str
:param adjust: '1' or '0'字符串的 0 1返回合约交易所和最小变动单位的实时数据, 返回数据会变慢
:type adjust: str
:return: 期货的实时行情数据
:rtype: pandas.DataFrame
"""
file_data = "Math.round(Math.random() * 2147483648).toString(16)"
ctx = py_mini_racer.MiniRacer()
rn_code = ctx.eval(file_data)
subscribe_list = ",".join(["nf_" + item.strip() for item in symbol.split(",")])
url = f"https://hq.sinajs.cn/rn={rn_code}&list={subscribe_list}"
headers = {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "no-cache",
"Host": "hq.sinajs.cn",
"Pragma": "no-cache",
"Proxy-Connection": "keep-alive",
"Referer": "https://vip.stock.finance.sina.com.cn/",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/97.0.4692.71 Safari/537.36",
}
r = requests.get(url, headers=headers)
data_df = pd.DataFrame(
[
item.strip().split("=")[1].split(",")
for item in r.text.split(";")
if item.strip() != ""
]
)
data_df.iloc[:, 0] = data_df.iloc[:, 0].str.replace('"', "")
data_df.iloc[:, -1] = data_df.iloc[:, -1].str.replace('"', "")
if adjust == "1":
contract_name_list = [item.split("_")[1] for item in subscribe_list.split(",")]
contract_min_list = []
contract_exchange_list = []
for contract_name in contract_name_list:
temp_df = futures_contract_detail(symbol=contract_name)
exchange_name = temp_df[temp_df["item"] == "上市交易所"]["value"].values[0]
contract_exchange_list.append(exchange_name)
contract_min = temp_df[temp_df["item"] == "最小变动价位"]["value"].values[0]
contract_min_list.append(contract_min)
if market == "CF":
data_df.columns = [
"symbol",
"time",
"open",
"high",
"low",
"last_close",
"bid_price",
"ask_price",
"current_price",
"avg_price",
"last_settle_price",
"buy_vol",
"sell_vol",
"hold",
"volume",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
]
data_df = data_df[
[
"symbol",
"time",
"open",
"high",
"low",
"current_price",
"bid_price",
"ask_price",
"buy_vol",
"sell_vol",
"hold",
"volume",
"avg_price",
"last_close",
"last_settle_price",
]
]
data_df["exchange"] = contract_exchange_list
data_df["contract"] = contract_name_list
data_df["contract_min_change"] = contract_min_list
data_df["open"] = pd.to_numeric(data_df["open"], errors="coerce")
data_df["high"] = pd.to_numeric(data_df["high"], errors="coerce")
data_df["low"] = pd.to_numeric(data_df["low"], errors="coerce")
data_df["current_price"] = pd.to_numeric(
data_df["current_price"], errors="coerce"
)
data_df["bid_price"] = pd.to_numeric(data_df["bid_price"], errors="coerce")
data_df["ask_price"] = pd.to_numeric(data_df["ask_price"], errors="coerce")
data_df["buy_vol"] = pd.to_numeric(data_df["buy_vol"], errors="coerce")
data_df["sell_vol"] = pd.to_numeric(data_df["sell_vol"], errors="coerce")
data_df["hold"] = pd.to_numeric(data_df["hold"], errors="coerce")
data_df["volume"] = pd.to_numeric(data_df["volume"], errors="coerce")
data_df["avg_price"] = pd.to_numeric(data_df["avg_price"], errors="coerce")
data_df["last_close"] = pd.to_numeric(
data_df["last_close"], errors="coerce"
)
data_df["last_settle_price"] = pd.to_numeric(
data_df["last_settle_price"], errors="coerce"
)
data_df.dropna(subset=["current_price"], ignore_index=True, inplace=True)
return data_df
else:
data_df.columns = [
"open",
"high",
"low",
"current_price",
"volume",
"amount",
"hold",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"__",
"time",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"symbol",
]
data_df = data_df[
[
"symbol",
"time",
"open",
"high",
"low",
"current_price",
"hold",
"volume",
"amount",
]
]
data_df["exchange"] = contract_exchange_list
data_df["contract"] = contract_name_list
data_df["contract_min_change"] = contract_min_list
data_df["open"] = pd.to_numeric(data_df["open"], errors="coerce")
data_df["high"] = pd.to_numeric(data_df["high"], errors="coerce")
data_df["low"] = pd.to_numeric(data_df["low"], errors="coerce")
data_df["current_price"] = pd.to_numeric(
data_df["current_price"], errors="coerce"
)
data_df["hold"] = pd.to_numeric(data_df["hold"], errors="coerce")
data_df["volume"] = pd.to_numeric(data_df["volume"], errors="coerce")
data_df["amount"] = pd.to_numeric(data_df["amount"], errors="coerce")
data_df.dropna(subset=["current_price"], ignore_index=True, inplace=True)
return data_df
else:
if market == "CF":
# 此处由于 20220601 接口变动,增加了字段,此处增加异常判断,except 后为新代码
try:
data_df.columns = [
"symbol",
"time",
"open",
"high",
"low",
"last_close",
"bid_price",
"ask_price",
"current_price",
"avg_price",
"last_settle_price",
"buy_vol",
"sell_vol",
"hold",
"volume",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
]
except: # noqa: E722
data_df.columns = [
"symbol",
"time",
"open",
"high",
"low",
"last_close",
"bid_price",
"ask_price",
"current_price",
"avg_price",
"last_settle_price",
"buy_vol",
"sell_vol",
"hold",
"volume",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
]
data_df = data_df[
[
"symbol",
"time",
"open",
"high",
"low",
"current_price",
"bid_price",
"ask_price",
"buy_vol",
"sell_vol",
"hold",
"volume",
"avg_price",
"last_close",
"last_settle_price",
]
]
data_df["open"] = pd.to_numeric(data_df["open"], errors="coerce")
data_df["high"] = pd.to_numeric(data_df["high"], errors="coerce")
data_df["low"] = pd.to_numeric(data_df["low"], errors="coerce")
data_df["current_price"] = pd.to_numeric(
data_df["current_price"], errors="coerce"
)
data_df["bid_price"] = pd.to_numeric(data_df["bid_price"], errors="coerce")
data_df["ask_price"] = pd.to_numeric(data_df["ask_price"], errors="coerce")
data_df["buy_vol"] = pd.to_numeric(data_df["buy_vol"], errors="coerce")
data_df["sell_vol"] = pd.to_numeric(data_df["sell_vol"], errors="coerce")
data_df["hold"] = pd.to_numeric(data_df["hold"], errors="coerce")
data_df["volume"] = pd.to_numeric(data_df["volume"], errors="coerce")
data_df["avg_price"] = pd.to_numeric(data_df["avg_price"], errors="coerce")
data_df["last_close"] = pd.to_numeric(
data_df["last_close"], errors="coerce"
)
data_df["last_settle_price"] = pd.to_numeric(
data_df["last_settle_price"], errors="coerce"
)
data_df.dropna(subset=["current_price"], ignore_index=True, inplace=True)
return data_df
else:
data_df.columns = [
"open",
"high",
"low",
"current_price",
"volume",
"amount",
"hold",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"__",
"time",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"_",
"symbol",
]
data_df = data_df[
[
"symbol",
"time",
"open",
"high",
"low",
"current_price",
"hold",
"volume",
"amount",
]
]
data_df["open"] = pd.to_numeric(data_df["open"], errors="coerce")
data_df["high"] = pd.to_numeric(data_df["high"], errors="coerce")
data_df["low"] = pd.to_numeric(data_df["low"], errors="coerce")
data_df["current_price"] = pd.to_numeric(
data_df["current_price"], errors="coerce"
)
data_df["hold"] = pd.to_numeric(data_df["hold"], errors="coerce")
data_df["volume"] = pd.to_numeric(data_df["volume"], errors="coerce")
data_df["amount"] = pd.to_numeric(data_df["amount"], errors="coerce")
data_df.dropna(subset=["current_price"], inplace=True, ignore_index=True)
return data_df
def futures_zh_minute_sina(symbol: str = "IF2008", period: str = "1") -> pd.DataFrame:
"""
中国各品种期货分钟频率数据
https://vip.stock.finance.sina.com.cn/quotes_service/view/qihuohangqing.html#titlePos_3
:param symbol: 可以通过 match_main_contract(symbol="cffex") 获取, 或者访问网页获取
:type symbol: str
:param period: choice of {"1": "1分钟", "5": "5分钟", "15": "15分钟", "30": "30分钟", "60": "60分钟"}
:type period: str
:return: 指定 symbol period 的数据
:rtype: pandas.DataFrame
"""
url = "https://stock2.finance.sina.com.cn/futures/api/jsonp.php/=/InnerFuturesNewService.getFewMinLine"
params = {
"symbol": symbol,
"type": period,
}
r = requests.get(url, params=params)
temp_df = pd.DataFrame(json.loads(r.text.split("=(")[1].split(");")[0]))
temp_df.columns = [
"datetime",
"open",
"high",
"low",
"close",
"volume",
"hold",
]
temp_df["open"] = pd.to_numeric(temp_df["open"], errors="coerce")
temp_df["high"] = pd.to_numeric(temp_df["high"], errors="coerce")
temp_df["low"] = pd.to_numeric(temp_df["low"], errors="coerce")
temp_df["close"] = pd.to_numeric(temp_df["close"], errors="coerce")
temp_df["volume"] = pd.to_numeric(temp_df["volume"], errors="coerce")
temp_df["hold"] = pd.to_numeric(temp_df["hold"], errors="coerce")
return temp_df
def futures_zh_daily_sina(symbol: str = "RB0") -> pd.DataFrame:
"""
中国各品种期货日频率数据
https://finance.sina.com.cn/futures/quotes/V2105.shtml
:param symbol: 可以通过 match_main_contract(symbol="cffex") 获取, 或者访问网页获取
:type symbol: str
:return: 指定 symbol 的数据
:rtype: pandas.DataFrame
"""
date = "20210412"
url = (
"https://stock2.finance.sina.com.cn/futures/api/jsonp.php/var%20_V21052021_4_12="
"/InnerFuturesNewService.getDailyKLine"
)
params = {
"symbol": symbol,
"type": "_".join([date[:4], date[4:6], date[6:]]),
}
r = requests.get(url, params=params)
temp_df = pd.DataFrame(json.loads(r.text.split("=(")[1].split(");")[0]))
temp_df.columns = [
"date",
"open",
"high",
"low",
"close",
"volume",
"hold",
"settle",
]
temp_df["open"] = pd.to_numeric(temp_df["open"], errors="coerce")
temp_df["high"] = pd.to_numeric(temp_df["high"], errors="coerce")
temp_df["low"] = pd.to_numeric(temp_df["low"], errors="coerce")
temp_df["close"] = pd.to_numeric(temp_df["close"], errors="coerce")
temp_df["volume"] = pd.to_numeric(temp_df["volume"], errors="coerce")
temp_df["hold"] = pd.to_numeric(temp_df["hold"], errors="coerce")
temp_df["settle"] = pd.to_numeric(temp_df["settle"], errors="coerce")
return temp_df
if __name__ == "__main__":
match_main_contract_df = match_main_contract(symbol="gfex")
print(match_main_contract_df)
futures_zh_spot_df = futures_zh_spot(symbol="V2405,V2409", market="CF", adjust="0")
print(futures_zh_spot_df)
futures_zh_spot_df = futures_zh_spot(symbol="V2405", market="CF", adjust="0")
print(futures_zh_spot_df)
futures_symbol_mark_df = futures_symbol_mark()
print(futures_symbol_mark_df)
futures_zh_realtime_df = futures_zh_realtime(symbol="工业硅")
print(futures_zh_realtime_df)
futures_zh_minute_sina_df = futures_zh_minute_sina(symbol="RB0", period="1")
print(futures_zh_minute_sina_df)
futures_zh_daily_sina_df = futures_zh_daily_sina(symbol="RB0")
print(futures_zh_daily_sina_df)
futures_zh_daily_sina_df = futures_zh_daily_sina(symbol="RB2410")
print(futures_zh_daily_sina_df)
dce_text = match_main_contract(symbol="dce")
czce_text = match_main_contract(symbol="czce")
shfe_text = match_main_contract(symbol="shfe")
gfex_text = match_main_contract(symbol="gfex")
while True:
time.sleep(3)
futures_zh_spot_df = futures_zh_spot(
symbol=",".join([dce_text, czce_text, shfe_text, gfex_text]),
market="CF",
adjust="0",
)
print(futures_zh_spot_df)
@@ -0,0 +1,670 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2025/7/21 15:00
Desc: 每日注册仓单数据
大连商品交易所, 上海期货交易所, 郑州商品交易所, 广州期货交易所
"""
import datetime
import re
import warnings
from io import BytesIO
from typing import List
import pandas as pd
import requests
from akshare.futures import cons
from akshare.futures.requests_fun import requests_link, pandas_read_html_link
from akshare.futures.symbol_var import chinese_to_english
calendar = cons.get_calendar()
shfe_20100126 = pd.DataFrame(
{
"var": ["CU", "AL", "ZN", "RU", "FU", "AU", "RB", "WR"],
"receipt": [29783, 285396, 187713, 116435, 376200, 12, 145648, 0],
}
)
shfe_20101029 = pd.DataFrame(
{
"var": ["CU", "AL", "ZN", "RU", "FU", "AU", "RB", "WR"],
"receipt": [39214, 359729, 182562, 25990, 313600, 27, 36789, 0],
}
)
def get_dce_receipt(date: str = None, vars_list: List = cons.contract_symbols):
"""
大连商品交易所-注册仓单数据
http://www.dce.com.cn/dce/channel/list/187.html
:param date: 开始日期: YYYY-MM-DD YYYYMMDD datetime.date对象, 为空时为当天
:type date: str
:param vars_list: 合约品种如 RB, AL等列表, 为空时为所有商品数据从 20060106开始每周五更新仓单数据直到20090407起每交易日都更新仓单数据
:type vars_list: list
:return: 注册仓单数据
:rtype: pandas.DataFrame
"""
if not isinstance(vars_list, list):
return warnings.warn("vars_list: 必须是列表")
date = cons.convert_date(date) if date is not None else datetime.date.today()
if date.strftime("%Y%m%d") not in calendar:
warnings.warn(f"{date.strftime('%Y%m%d')}非交易日")
return None
url = "http://www.dce.com.cn/dcereport/publicweb/dailystat/wbillWeeklyQuotes"
payload = {
"tradeDate": date.strftime("%Y%m%d"),
"varietyId": "all",
}
r = requests.post(url, json=payload)
data_json = r.json()
temp_df = pd.DataFrame(data_json["data"]["entityList"])
records = pd.DataFrame()
for x in temp_df.to_dict(orient="records"):
if isinstance(x["variety"], str):
if x["variety"][-2:] == "小计":
var = x["variety"][:-2]
temp_data = {
"var": chinese_to_english(var),
"receipt": int(x["wbillQty"]),
"receipt_chg": int(x["diff"]),
"date": date.strftime("%Y%m%d"),
}
records = pd.concat([records, pd.DataFrame(temp_data, index=[0])])
if len(records.index) != 0:
records.index = records["var"]
vars_in_market = [i for i in vars_list if i in records.index]
records = records.loc[vars_in_market, :]
return records.reset_index(drop=True)
def get_shfe_receipt_1(
date: str = None, vars_list: List = cons.contract_symbols
) -> pd.DataFrame:
"""
上海期货交易所-注册仓单数据-类型1
适用 20081006 20140518(包括)2010012620101029日期交易所格式混乱直接回复脚本中 pandas.DataFrame, 2010041620130821日期交易所数据丢失
:param date: 开始日期 formatYYYY-MM-DD YYYYMMDD datetime.date对象为空时为当天
:type date: str
:param vars_list: 合约品种如RBAL等列表为空时为所有商品
:type vars_list: list
:return: 注册仓单数据-类型1
:rtype: pandas.DataFrame
"""
if not isinstance(vars_list, list):
raise warnings.warn("symbol_list: 必须是列表")
date = (
cons.convert_date(date).strftime("%Y%m%d")
if date is not None
else datetime.date.today()
)
if date not in calendar:
warnings.warn(f"{date.strftime('%Y%m%d')}非交易日")
return pd.DataFrame()
if date == "20100126":
shfe_20100126["date"] = date
return shfe_20100126
elif date == "20101029":
shfe_20101029["date"] = date
return shfe_20101029
elif date in ["20100416", "20130821"]:
print("20100416、20130821交易所数据丢失")
return pd.DataFrame()
else:
var_list = [
"天然橡胶",
"沥青仓库",
"沥青厂库",
"热轧卷板",
"燃料油",
"白银",
"线材",
"螺纹钢",
"",
"",
"",
"",
"黄金",
"",
"",
]
url = cons.SHFE_RECEIPT_URL_1 % date
data = pandas_read_html_link(url)[0]
indexes = [x for x in data.index if (data[0].tolist()[x] in var_list)]
last_index = [x for x in data.index if "" in str(data[0].tolist()[x])][0] - 1
records = pd.DataFrame()
for i in list(range(len(indexes))):
if i != len(indexes) - 1:
data_cut = data.loc[indexes[i] : indexes[i + 1] - 1, :]
else:
data_cut = data.loc[indexes[i] : last_index, :]
data_cut = data_cut.fillna(method="pad")
data_dict = dict()
data_dict["var"] = chinese_to_english(data_cut[0].tolist()[0])
data_dict["receipt"] = int(data_cut[2].tolist()[-1])
data_dict["receipt_chg"] = int(data_cut[3].tolist()[-1])
data_dict["date"] = date
records = pd.concat([records, pd.DataFrame(data_dict, index=[0])])
if len(records.index) != 0:
records.index = records["var"]
vars_in_market = [i for i in vars_list if i in records.index]
records = records.loc[vars_in_market, :]
return records.reset_index(drop=True)
def get_shfe_receipt_2(
date: str = None, vars_list: List = cons.contract_symbols
) -> pd.DataFrame:
"""
上海期货交易所-注册仓单数据-类型2
适用 20140519(包括)-至今
:param date: 开始日期 formatYYYY-MM-DD YYYYMMDD datetime.date对象 为空时为当天
:type date: str
:param vars_list: 合约品种如 RBAL 等列表 为空时为所有商品
:type vars_list: list
:return: 注册仓单数据
:rtype: pandas.DataFrame
"""
if not isinstance(vars_list, list):
raise warnings.warn("symbol_list: 必须是列表")
date = (
cons.convert_date(date).strftime("%Y%m%d")
if date is not None
else datetime.date.today()
)
if date not in calendar:
warnings.warn("%s 非交易日" % date.strftime("%Y%m%d"))
return pd.DataFrame()
url = cons.SHFE_RECEIPT_URL_20250701 % date
r = requests_link(url, encoding="utf-8", headers=cons.shfe_headers)
try:
context = r.json()
except: # noqa
return pd.DataFrame()
data = pd.DataFrame(context["o_cursor"])
if len(data.columns) < 1:
return pd.DataFrame()
records = pd.DataFrame()
for var in set(data["VARNAME"].tolist()):
data_cut = data[data["VARNAME"] == var]
if "BC" in var:
data_dict = {
"var": "BC",
"receipt": int(data_cut["WRTWGHTS"].tolist()[-1]),
"receipt_chg": int(data_cut["WRTCHANGE"].tolist()[-1]),
"date": date,
}
else:
data_dict = {
"var": chinese_to_english(re.sub(r"\W|[a-zA-Z]", "", var)),
"receipt": int(data_cut["WRTWGHTS"].tolist()[-1]),
"receipt_chg": int(data_cut["WRTCHANGE"].tolist()[-1]),
"date": date,
}
records = pd.concat([records, pd.DataFrame(data_dict, index=[0])])
temp_records = (
records.groupby("var")[["receipt", "receipt_chg"]].sum().reset_index()
)
temp_records["date"] = date
records = temp_records
if len(records.index) != 0:
records.index = records["var"]
vars_in_market = [i for i in vars_list if i in records.index]
records = records.loc[vars_in_market, :]
return records.reset_index(drop=True)
def get_shfe_receipt_3(
date: str = None, vars_list: List = cons.contract_symbols
) -> pd.DataFrame:
"""
上海期货交易所-注册仓单数据-类型2
适用 20140519(包括)-至今
:param date: 开始日期 formatYYYY-MM-DD YYYYMMDD datetime.date对象 为空时为当天
:type date: str
:param vars_list: 合约品种如 RBAL 等列表 为空时为所有商品
:type vars_list: list
:return: 注册仓单数据
:rtype: pandas.DataFrame
"""
if not isinstance(vars_list, list):
raise warnings.warn("symbol_list: 必须是列表")
date = (
cons.convert_date(date).strftime("%Y%m%d")
if date is not None
else datetime.date.today()
)
if date not in calendar:
warnings.warn("%s 非交易日" % date.strftime("%Y%m%d"))
return pd.DataFrame()
url = f"https://www.shfe.com.cn/data/tradedata/future/stockdata/dailystock_{date}/ZH/all.html"
r = requests.get(url, headers=cons.shfe_headers)
from io import StringIO
temp_tables = pd.read_html(StringIO(r.text))
len(temp_tables)
records = pd.DataFrame()
for table_num in range(1, len(temp_tables)):
temp_df = pd.read_html(StringIO(r.text))[table_num]
data_dict = {
"var": chinese_to_english(temp_df.iloc[0, 1]),
"receipt": int(temp_df.iloc[-1, 2]),
"receipt_chg": int(temp_df.iloc[-1, 3]),
"date": date,
}
records = pd.concat([records, pd.DataFrame(data_dict, index=[0])])
temp_records = (
records.groupby("var")[["receipt", "receipt_chg"]].sum().reset_index()
)
temp_records["date"] = date
records = temp_records
if len(records.index) != 0:
records.index = records["var"]
vars_in_market = [i for i in vars_list if i in records.index]
records = records.loc[vars_in_market, :]
return records.reset_index(drop=True)
def get_czce_receipt_1(date: str = None, vars_list: List = cons.contract_symbols):
"""
郑州商品交易所-注册仓单数据
适用 20080222 20100824(包括)
:param date: 开始日期 formatYYYY-MM-DD YYYYMMDD datetime.date对象 为空时为当天
:type date: str
:param vars_list: list
:type vars_list: 合约品种如 CFTA 等列表 为空时为所有商品
:return: 注册仓单数据
:rtype: pandas.DataFrame
"""
date = (
cons.convert_date(date).strftime("%Y%m%d")
if date is not None
else datetime.date.today()
)
if date not in calendar:
warnings.warn("%s非交易日" % date.strftime("%Y%m%d"))
return None
if date == "20090820":
return pd.DataFrame()
url = cons.CZCE_RECEIPT_URL_1 % date
r = requests_link(url, encoding="utf-8", headers=cons.shfe_headers)
context = r.text
data = pd.read_html(context)[1]
records = pd.DataFrame()
indexes = [x for x in data.index if "品种:" in str(data[0].tolist()[x])]
ends = [x for x in data.index if "总计" in str(data[0].tolist()[x])]
for i in list(range(len(indexes))):
if i != len(indexes) - 1:
data_cut = data.loc[indexes[i] : ends[i], :]
data_cut = data_cut.fillna(method="pad")
else:
data_cut = data.loc[indexes[i] :, :]
data_cut = data_cut.fillna(method="pad")
if "PTA" in data_cut[0].tolist()[0]:
var = "TA"
else:
var = chinese_to_english(re.sub(r"[A-Z]+", "", data_cut[0].tolist()[0][3:]))
if var == "CF":
receipt = data_cut[6].tolist()[-1]
receipt_chg = data_cut[7].tolist()[-1]
else:
receipt = data_cut[5].tolist()[-1]
receipt_chg = data_cut[6].tolist()[-1]
data_dict = {
"var": var,
"receipt": int(receipt),
"receipt_chg": int(receipt_chg),
"date": date,
}
records = pd.concat([records, pd.DataFrame(data_dict, index=[0])])
if len(records.index) != 0:
records.index = records["var"]
vars_in_market = [i for i in vars_list if i in records.index]
records = records.loc[vars_in_market, :]
return records.reset_index(drop=True)
def get_czce_receipt_2(date: str = None, vars_list: List = cons.contract_symbols):
"""
郑州商品交易所-注册仓单数据
http://www.czce.com.cn/cn/jysj/cdrb/H770310index_1.htm
适用 20100825(包括) - 20151111(包括)
:param date: 开始日期 formatYYYY-MM-DD YYYYMMDD datetime.date对象 为空时为当天
:type date: str
:param vars_list: 合约品种如 CFTA 等列表为空时为所有商品
:type vars_list: list
:return: 注册仓单数据
:rtype: pandas.DataFrame
"""
if not isinstance(vars_list, list):
return warnings.warn("symbol_list: 必须是列表")
date = (
cons.convert_date(date).strftime("%Y%m%d")
if date is not None
else datetime.date.today()
)
if date not in calendar:
warnings.warn("%s非交易日" % date.strftime("%Y%m%d"))
return None
url = cons.CZCE_RECEIPT_URL_2 % (date[:4], date)
r = requests.get(url)
r.encoding = "utf-8"
data = pd.read_html(r.text)[3:]
records = pd.DataFrame()
for data_cut in data:
if len(data_cut.columns) > 3:
last_indexes = [
x for x in data_cut.index if "注:" in str(data_cut[0].tolist()[x])
]
if len(last_indexes) > 0:
last_index = last_indexes[0] - 1
data_cut = data_cut.loc[:last_index, :]
if "PTA" in data_cut[0].tolist()[0]:
var = "TA"
else:
strings = data_cut[0].tolist()[0]
string = strings.split(" ")[0][3:]
var = chinese_to_english(re.sub(r"[A-Z]+", "", string))
data_cut.columns = data_cut.T[1].tolist()
receipt = data_cut["仓单数量"].tolist()[-1]
receipt_chg = data_cut["当日增减"].tolist()[-1]
data_dict = {
"var": var,
"receipt": int(receipt),
"receipt_chg": int(receipt_chg),
"date": date,
}
records = pd.concat([records, pd.DataFrame(data_dict, index=[0])])
if len(records.index) != 0:
records.index = records["var"]
vars_in_market = [i for i in vars_list if i in records.index]
records = records.loc[vars_in_market, :]
return records.reset_index(drop=True)
def get_czce_receipt_3(
date: str = None, vars_list: List = cons.contract_symbols
) -> pd.DataFrame:
"""
郑州商品交易所-注册仓单数据
适用 20151008-至今
http://www.czce.com.cn/cn/jysj/cdrb/H770310index_1.htm
:param date: 开始日期 formatYYYY-MM-DD YYYYMMDD datetime.date对象 为空时为当天
:type date: str
:param vars_list: 合约品种如 CFTA 等列表为空时为所有商品
:type vars_list: list
:return: 注册仓单数据
:rtype: pandas.DataFrame
"""
if not isinstance(vars_list, list):
print("vars_list: 必须是列表")
return pd.DataFrame()
date = (
cons.convert_date(date).strftime("%Y%m%d")
if date is not None
else datetime.date.today()
)
if date not in calendar:
warnings.warn("%s非交易日" % date.strftime("%Y%m%d"))
return pd.DataFrame()
if int(date) > 20251101:
url = f"http://www.czce.com.cn/cn/DFSStaticFiles/Future/{date[:4]}/{date}/FutureDataWhsheet.xlsx"
else:
url = f"http://www.czce.com.cn/cn/DFSStaticFiles/Future/{date[:4]}/{date}/FutureDataWhsheet.xls"
r = requests_link(url, encoding="utf-8", headers=cons.shfe_headers)
temp_df = pd.read_excel(BytesIO(r.content))
temp_df = temp_df[
[
bool(1 - item)
for item in [
item if item is not pd.NA else False
for item in temp_df.iloc[:, 0].str.contains("非农产品")
]
]
]
temp_df.reset_index(inplace=True, drop=True)
range_list_one = list(
temp_df[
[
item if not pd.isnull(item) else False
for item in temp_df.iloc[:, 0].str.contains("品种")
]
].index
)
range_list_two = list(
temp_df[
[
item if not pd.isnull(item) else False
for item in temp_df.iloc[:, 0].str.contains("品种")
]
].index
)[1:]
range_list_two.append(None)
symbol_list = []
receipt_list = []
receipt_chg_list = []
records = pd.DataFrame()
for page in range(len(range_list_one)):
inner_df = temp_df[range_list_one[page] : range_list_two[page]]
reg = re.compile(r"[A-Z]+")
try:
symbol = reg.findall(inner_df.iloc[0, 0])[0]
except: # noqa
continue
symbol_list.append(symbol)
inner_df.columns = inner_df.iloc[1, :]
inner_df = inner_df.iloc[2:, :]
inner_df = inner_df.dropna(axis=1, how="all")
if symbol == "PTA":
try:
receipt_list.append(
inner_df["仓单数量(完税)"].iloc[-1]
+ int(inner_df["仓单数量(保税)"].iloc[-1])
) # 20210316 TA 分为保税和完税
except: # noqa
receipt_list.append(0)
elif symbol == "MA":
try:
try:
receipt_list.append(
inner_df["仓单数量(完税)"].iloc[-2]
+ int(inner_df["仓单数量(保税)"].iloc[-2])
) # 20210316 MA 分为保税和完税
except: # noqa
receipt_list.append(
inner_df["仓单数量(完税)"].iloc[-2]
) # 处理 MA 的特殊格式
except: # noqa
receipt_list.append(0)
else:
try:
receipt_list.append(inner_df["仓单数量"].iloc[-1])
except: # noqa
receipt_list.append(0)
if symbol == "MA":
receipt_chg_list.append(inner_df["当日增减"].iloc[-2])
else:
receipt_chg_list.append(inner_df["当日增减"].iloc[-1])
data_df = pd.DataFrame(
[symbol_list, receipt_list, receipt_chg_list, [date] * len(receipt_chg_list)]
).T
data_df.columns = ["var", "receipt", "receipt_chg", "date"]
temp_list = data_df["var"].tolist()
data_df["var"] = [item if item != "PTA" else "TA" for item in temp_list]
if len(data_df.index) != 0:
data_df.index = data_df["var"]
vars_in_market = [i for i in vars_list if i in data_df.index]
records = data_df.loc[vars_in_market, :]
return records.reset_index(drop=True)
def get_gfex_receipt(
date: str = None, vars_list: List = cons.contract_symbols
) -> pd.DataFrame:
"""
广州期货交易所-注册仓单数据
http://www.gfex.com.cn/gfex/cdrb/hqsj_tjsj.shtml
:param date: 开始日期 formatYYYY-MM-DD YYYYMMDD datetime.date对象 为空时为当天
:type date: str
:param vars_list: 合约品种如 SI 等列表为空时为所有商品
:type vars_list: list
:return: 注册仓单数据
:rtype: pandas.DataFrame
"""
if not isinstance(vars_list, list):
raise warnings.warn("vars_list: 必须是列表")
date = cons.convert_date(date) if date is not None else datetime.date.today()
if date.strftime("%Y%m%d") not in calendar:
warnings.warn(f"{date.strftime('%Y%m%d')}非交易日")
return pd.DataFrame()
url = "http://www.gfex.com.cn/u/interfacesWebTdWbillWeeklyQuotes/loadList"
payload = {"gen_date": date.isoformat().replace("-", "")}
headers = {
"Accept": "application/json, text/javascript, */*; q=0.01",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "no-cache",
"Content-Length": "32",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Host": "www.gfex.com.cn",
"Origin": "http://www.gfex.com.cn",
"Pragma": "no-cache",
"Proxy-Connection": "keep-alive",
"Referer": "http://www.gfex.com.cn/gfex/rihq/hqsj_tjsj.shtml",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/108.0.0.0 Safari/537.36",
"X-Requested-With": "XMLHttpRequest",
"content-type": "application/x-www-form-urlencoded",
}
r = requests.post(url, data=payload, headers=headers)
data_json = r.json()
temp_df = pd.DataFrame(data_json["data"])
temp_df = temp_df[temp_df["variety"].str.contains("小计")]
result_df = temp_df[["wbillQty", "diff"]].copy()
if result_df.empty:
return pd.DataFrame()
result_df.loc[:, "date"] = date.isoformat().replace("-", "")
result_df.loc[:, "var"] = [
item.upper() for item in temp_df["varietyOrder"].tolist()
]
result_df.reset_index(drop=True, inplace=True)
result_df.rename(
columns={
"wbillQty": "receipt",
"diff": "receipt_chg",
},
inplace=True,
)
result_df = result_df[["var", "receipt", "receipt_chg", "date"]]
result_df.set_index(keys=["var"], inplace=True)
if "LC" not in result_df.index:
vars_list.remove("LC")
if "PS" not in result_df.index:
vars_list.remove("PS")
result_df = result_df.loc[vars_list, :]
result_df.reset_index(inplace=True)
return result_df
def get_receipt(
start_date: str = None,
end_date: str = None,
vars_list: List = cons.contract_symbols,
):
"""
大宗商品-注册仓单数据
:param start_date: 开始日期 formatYYYY-MM-DD YYYYMMDD datetime.date 对象 为空时为当天
:type start_date: str
:param end_date: 结束数据 formatYYYY-MM-DD YYYYMMDD datetime.date 对象 为空时为当天
:type end_date: str
:param vars_list: 合约品种如 RBAL 等列表为空时为所有商品
:type vars_list: str
:return: 注册仓单数据
:rtype: pandas.DataFrame
"""
if not isinstance(vars_list, list):
return warnings.warn("vars_list: 必须是列表")
start_date = (
cons.convert_date(start_date)
if start_date is not None
else datetime.date.today()
)
end_date = (
cons.convert_date(end_date)
if end_date is not None
else cons.convert_date(cons.get_latest_data_date(datetime.datetime.now()))
)
records = pd.DataFrame()
while start_date <= end_date:
if start_date.strftime("%Y%m%d") not in calendar:
warnings.warn(f"{start_date.strftime('%Y%m%d')} 非交易日")
else:
print(start_date)
for market, market_vars in cons.market_exchange_symbols.items():
f = None
if market == "dce":
if start_date >= datetime.date(2009, 4, 7):
f = get_dce_receipt
else:
print("20090407 起,大连商品交易所每个交易日更新仓单数据")
f = None
elif market == "shfe":
if (
datetime.date(2008, 10, 6)
<= start_date
<= datetime.date(2014, 5, 16)
):
f = get_shfe_receipt_1
elif (
datetime.date(2014, 5, 16)
<= start_date
<= datetime.date(2025, 11, 17)
):
f = get_shfe_receipt_2
elif start_date > datetime.date(2025, 11, 17):
f = get_shfe_receipt_3
else:
f = None
print("20081006 起,上海期货交易所每个交易日更新仓单数据")
elif market == "gfex":
if start_date > datetime.date(2022, 12, 22):
f = get_gfex_receipt
else:
f = None
print("20081006 起,上海期货交易所每个交易日更新仓单数据")
elif market == "czce":
if (
datetime.date(2008, 3, 3)
<= start_date
<= datetime.date(2010, 8, 24)
):
f = get_czce_receipt_1
elif (
datetime.date(2010, 8, 24)
< start_date
<= datetime.date(2015, 11, 11)
):
f = get_czce_receipt_2
elif start_date > datetime.date(2015, 11, 11):
f = get_czce_receipt_3
else:
f = None
print("20080303 起,郑州商品交易所每个交易日更新仓单数据")
get_vars = [var for var in vars_list if var in market_vars]
if market != "cffex" and get_vars != []:
if f is not None:
records = pd.concat([records, f(start_date, get_vars)])
start_date += datetime.timedelta(days=1)
records.reset_index(drop=True, inplace=True)
if records.empty:
return records
return records
if __name__ == "__main__":
get_receipt_df = get_receipt(
start_date="20260130", end_date="20260130", vars_list=["RB"]
)
print(get_receipt_df)
@@ -0,0 +1,89 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2023/9/15 19:00
Desc: 请求网站内容的函数: 在链接失败后可重复 20
"""
import time
from io import StringIO
from typing import Dict
import pandas as pd
import requests
def requests_link(
url: str,
encoding: str = "utf-8",
method: str = "get",
data: Dict = None,
headers: Dict = None,
):
"""
利用 requests 请求网站, 爬取网站内容, 如网站链接失败, 可重复爬取 20
:param url: string 网站地址
:param encoding: string 编码类型: "utf-8", "gbk", "gb2312"
:param method: string 访问方法: "get", "post"
:param data: dict 上传数据: 键值对
:param headers: dict 游览器请求头: 键值对
:return: requests.response 爬取返回内容: response
"""
i = 0
while True:
try:
if method == "get":
r = requests.get(url, timeout=20, headers=headers)
r.encoding = encoding
return r
elif method == "post":
r = requests.post(url, timeout=20, data=data, headers=headers)
r.encoding = encoding
return r
else:
raise ValueError("请提供正确的请求方式")
except: # noqa: E722
i += 1
print(f"{str(i)}次链接失败, 最多尝试 20 次")
time.sleep(5)
if i > 20:
return None
def pandas_read_html_link(
url: str,
encoding: str = "utf-8",
method: str = "get",
data: Dict = None,
headers: Dict = None,
):
"""
利用 pandas 提供的 read_html 函数来直接提取网页中的表格内容, 如网站链接失败, 可重复爬取 20
:param url: string 网站地址
:param encoding: string 编码类型: "utf-8", "gbk", "gb2312"
:param method: string 访问方法: "get", "post"
:param data: dict 上传数据: 键值对
:param headers: dict 游览器请求头: 键值对
:return: requests.response 爬取返回内容: response
"""
i = 0
while True:
try:
if method == "get":
r = requests.get(url, timeout=20, headers=headers)
r.encoding = encoding
r = pd.read_html(StringIO(r.text), encoding=encoding)
return r
elif method == "post":
r = requests.post(url, timeout=20, data=data, headers=headers)
r.encoding = encoding
r = pd.read_html(StringIO(r.text), encoding=encoding)
return r
else:
raise ValueError("请提供正确的请求方式")
except requests.exceptions.Timeout as e:
i += 1
print(f"{str(i)}次链接失败, 最多尝试20次", e)
time.sleep(5)
if i > 20:
return None
@@ -0,0 +1,359 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2025/7/21 15:00
Desc: 期货品种映射表
"""
import re
from akshare.futures import cons
def symbol_varieties(contract_code: str):
"""
查找到具体合约代码, 返回大写字母的品种名称
:param contract_code: ru1801
:return: RU
"""
symbol_detail = "".join(re.findall(r"\D", contract_code)).upper().strip()
if symbol_detail == "PTA":
symbol_detail = "TA"
return symbol_detail
def symbol_market(symbol_detail: str = "SC"):
"""
映射出市场代码
:param symbol_detail:
:return:
"""
var_item = symbol_varieties(symbol_detail)
for market_item, contract_items in cons.market_exchange_symbols.items():
if var_item in contract_items:
return market_item
def find_chinese(chinese_string: str):
"""
查找中文字符
:param chinese_string: 中文字符串
:return:
"""
p = re.compile(r"[\u4e00-\u9fa5]")
res = re.findall(p, chinese_string)
return "".join(res)
def chinese_to_english(chinese_var: str):
"""
映射期货品种中文名称和英文缩写
:param chinese_var: 期货品种中文名称
:return: 对应的英文缩写
"""
chinese_list = [
"橡胶",
"天然橡胶",
"石油沥青",
"石油沥青(仓库)",
"石油沥青(厂库)",
"沥青",
"沥青仓库",
"沥青(仓库)",
"沥青厂库",
"沥青(厂库)",
"热轧卷板",
"热轧卷板厂库",
"热轧卷板仓库",
"热轧卷板(厂库)",
"热轧卷板(仓库)",
"热轧板卷",
"燃料油",
"白银",
"线材",
"螺纹钢",
"螺纹钢(仓库)",
"螺纹钢(厂库)",
"",
"",
"",
"",
"黄金",
"钯金",
"",
"",
"纸浆",
"纸浆(仓库)",
"纸浆(厂库)",
"豆一",
"大豆",
"豆二",
"胶合板",
"玉米",
"玉米淀粉",
"聚乙烯",
"LLDPE",
"LDPE",
"豆粕",
"豆油",
"大豆油",
"棕榈油",
"纤维板",
"鸡蛋",
"聚氯乙烯",
"PVC",
"聚丙烯",
"PP",
"焦炭",
"焦煤",
"铁矿石",
"乙二醇",
"强麦",
"强筋小麦",
" 强筋小麦",
"硬冬白麦",
"普麦",
"硬白小麦",
"硬白小麦()",
"皮棉",
"棉花",
"一号棉",
"白糖",
"PTA",
"菜籽油",
"菜油",
"早籼稻",
"早籼",
"甲醇",
"柴油",
"玻璃",
"油菜籽",
"菜籽",
"菜籽粕",
"菜粕",
"动力煤",
"粳稻",
"晚籼稻",
"晚籼",
"硅铁",
"锰硅",
"硬麦",
"棉纱",
"苹果",
"原油",
"中质含硫原油",
"尿素",
"20号胶",
"苯乙烯",
"不锈钢",
"粳米",
"20号胶20",
"红枣",
"不锈钢仓库",
"不锈钢厂库",
"不锈钢(厂库)",
"不锈钢(仓库)",
"纯碱",
"液化石油气",
"低硫燃料油",
"纸浆仓库",
"石油沥青厂库",
"石油沥青仓库",
"螺纹钢仓库",
"螺纹钢厂库",
"纸浆厂库",
"低硫燃料油仓库",
"低硫燃料油厂库",
"低硫燃料油(仓库)",
"低硫燃料油(厂库)",
"短纤",
"涤纶短纤",
"生猪",
"花生",
"工业硅",
"氧化铝",
"丁二烯橡胶",
"碳酸锂",
"氧化铝仓库",
"氧化铝厂库",
"氧化铝(仓库)",
"氧化铝(厂库)",
"烧碱",
"丁二烯橡胶仓库",
"丁二烯橡胶厂库",
"丁二烯橡胶(仓库)",
"丁二烯橡胶(厂库)",
"PX",
"原木",
"瓶片期货",
"瓶片",
"纯苯",
"多晶硅",
"铸造铝合金",
"铜(BC)",
"胶版印刷纸(仓库)",
"胶版印刷纸(厂库)",
"丙烯期货",
"丙烯",
]
english_list = [
"RU",
"RU",
"BU",
"BU",
"BU",
"BU",
"BU",
"BU",
"BU2",
"BU2",
"HC",
"HC",
"HC",
"HC",
"HC",
"HC",
"FU",
"AG",
"WR",
"RB",
"RB",
"RB",
"PB",
"CU",
"AL",
"ZN",
"AU",
"AU",
"SN",
"NI",
"SP",
"SP",
"SP",
"A",
"A",
"B",
"BB",
"C",
"CS",
"L",
"L",
"L",
"M",
"Y",
"Y",
"P",
"FB",
"JD",
"V",
"V",
"PP",
"PP",
"J",
"JM",
"I",
"EG",
"WH",
"WH",
"WH",
"PM",
"PM",
"PM",
"PM",
"CF",
"CF",
"CF",
"SR",
"TA",
"OI",
"OI",
"RI",
"ER",
"MA",
"MA",
"FG",
"RS",
"RS",
"RM",
"RM",
"ZC",
"JR",
"LR",
"LR",
"SF",
"SM",
"WT",
"CY",
"AP",
"SC",
"SC",
"UR",
"NR",
"EB",
"SS",
"RR",
"NR",
"CJ",
"SS",
"SS",
"SS",
"SS",
"SA",
"PG",
"LU",
"SP",
"BU",
"BU",
"RB",
"RB",
"SP",
"LU",
"LU",
"LU",
"LU",
"PF",
"PF",
"LH",
"PK",
"SI",
"AO",
"BR",
"LC",
"AO",
"AO",
"AO",
"AO",
"SH",
"BR",
"BR",
"BR",
"BR",
"PX",
"LG",
"PR",
"PR",
"BZ",
"PS",
"AD",
"BC",
"OP",
"OP",
"PL",
"PL",
]
pos = chinese_list.index(chinese_var)
return english_list[pos]
if __name__ == "__main__":
print(chinese_to_english("苹果"))
symbol = "rb1801"
var = symbol_varieties("rb1808")
print(var)
market = symbol_market("SP")
print(market)
chi = find_chinese("a对方水电费dc大V")
print(chi)