modify src dir.

This commit is contained in:
2024-10-23 12:11:11 +08:00
parent a746b323aa
commit 593c6ce419
28 changed files with 4626 additions and 29 deletions

33
stockapp/src/config.py Normal file
View File

@ -0,0 +1,33 @@
import logging
import os
import inspect
import datetime
# MySQL 配置
db_config = {
'host': '172.18.0.3',
'user': 'root',
'password': 'mysqlpw',
'database': 'stockdb'
}
log_dir_prefix = '../log'
# 设置日志配置
def setup_logging(log_filename=None):
# 如果未传入 log_filename则使用当前脚本名称作为日志文件名
if log_filename is None:
# 获取调用 setup_logging 的脚本文件名
caller_frame = inspect.stack()[1]
caller_filename = os.path.splitext(os.path.basename(caller_frame.filename))[0]
# 获取当前日期,格式为 yyyymmdd
current_date = datetime.now().strftime('%Y%m%d')
# 拼接 log 文件名,将日期加在扩展名前
log_filename = f'{log_dir_prefix}/{caller_filename}_{current_date}.log'
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s [%(filename)s:%(lineno)d] (%(funcName)s) - %(message)s',
handlers=[
logging.FileHandler(log_filename),
logging.StreamHandler()
])

View File

View File

@ -0,0 +1,360 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2023/1/4 12:18
Desc: 东方财富-ETF 行情
https://quote.eastmoney.com/sh513500.html
"""
from functools import lru_cache
import pandas as pd
import requests
def fund_etf_spot_em() -> pd.DataFrame:
"""
东方财富-ETF 实时行情
https://quote.eastmoney.com/center/gridlist.html#fund_etf
:return: ETF 实时行情
:rtype: pandas.DataFrame
"""
url = "http://88.push2.eastmoney.com/api/qt/clist/get"
params = {
"pn": "1",
"pz": "2000",
"po": "1",
"np": "1",
"ut": "bd1d9ddb04089700cf9c27f6f7426281",
"fltt": "2",
"invt": "2",
"wbp2u": "|0|0|0|web",
"fid": "f3",
"fs": "b:MK0021,b:MK0022,b:MK0023,b:MK0024",
"fields": "f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f12,f13,f14,f15,f16,f17,f18,f20,f21,f23,f24,f25,f22,f11,f62,f128,f136,f115,f152",
"_": "1672806290972",
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(data_json["data"]["diff"])
temp_df.rename(
columns={
"f12": "代码",
"f14": "名称",
"f2": "最新价",
"f3": "涨跌幅",
"f4": "涨跌额",
"f5": "成交量",
"f6": "成交额",
"f17": "开盘价",
"f15": "最高价",
"f16": "最低价",
"f18": "昨收",
"f8": "换手率",
"f21": "流通市值",
"f20": "总市值",
},
inplace=True,
)
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")
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")
return temp_df
@lru_cache()
def _fund_etf_code_id_map_em() -> dict:
"""
东方财富-ETF 代码和市场标识映射
https://quote.eastmoney.com/center/gridlist.html#fund_etf
:return: ETF 代码和市场标识映射
:rtype: pandas.DataFrame
"""
url = "http://88.push2.eastmoney.com/api/qt/clist/get"
params = {
"pn": "1",
"pz": "5000",
"po": "1",
"np": "1",
"ut": "bd1d9ddb04089700cf9c27f6f7426281",
"fltt": "2",
"invt": "2",
"wbp2u": "|0|0|0|web",
"fid": "f3",
"fs": "b:MK0021,b:MK0022,b:MK0023,b:MK0024",
"fields": "f12,f13",
"_": "1672806290972",
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(data_json["data"]["diff"])
temp_dict = dict(zip(temp_df["f12"], temp_df["f13"]))
return temp_dict
def fund_etf_hist_em(
symbol: str = "159707",
period: str = "daily",
start_date: str = "19700101",
end_date: str = "20500101",
adjust: str = "",
) -> pd.DataFrame:
"""
东方财富-ETF 行情
https://quote.eastmoney.com/sz159707.html
:param symbol: ETF 代码
: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
:param adjust: choice of {"qfq": "前复权", "hfq": "后复权", "": "不复权"}
:type adjust: str
:return: 每日行情
:rtype: pandas.DataFrame
"""
code_id_dict = _fund_etf_code_id_map_em()
adjust_dict = {"qfq": "1", "hfq": "2", "": "0"}
period_dict = {"daily": "101", "weekly": "102", "monthly": "103"}
url = "http://push2his.eastmoney.com/api/qt/stock/kline/get"
params = {
"fields1": "f1,f2,f3,f4,f5,f6",
"fields2": "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61,f116",
"ut": "7eea3edcaed734bea9cbfc24409ed989",
"klt": period_dict[period],
"fqt": adjust_dict[adjust],
"secid": f"{code_id_dict[symbol]}.{symbol}",
"beg": start_date,
"end": end_date,
"_": "1623766962675",
}
r = requests.get(url, params=params)
data_json = r.json()
if not (data_json["data"] and data_json["data"]["klines"]):
return pd.DataFrame()
temp_df = pd.DataFrame([item.split(",") for item in data_json["data"]["klines"]])
temp_df.columns = [
"日期",
"开盘",
"收盘",
"最高",
"最低",
"成交量",
"成交额",
"振幅",
"涨跌幅",
"涨跌额",
"换手率",
]
temp_df.index = pd.to_datetime(temp_df["日期"])
temp_df.reset_index(inplace=True, drop=True)
temp_df["开盘"] = pd.to_numeric(temp_df["开盘"])
temp_df["收盘"] = pd.to_numeric(temp_df["收盘"])
temp_df["最高"] = pd.to_numeric(temp_df["最高"])
temp_df["最低"] = pd.to_numeric(temp_df["最低"])
temp_df["成交量"] = pd.to_numeric(temp_df["成交量"])
temp_df["成交额"] = pd.to_numeric(temp_df["成交额"])
temp_df["振幅"] = pd.to_numeric(temp_df["振幅"])
temp_df["涨跌幅"] = pd.to_numeric(temp_df["涨跌幅"])
temp_df["涨跌额"] = pd.to_numeric(temp_df["涨跌额"])
temp_df["换手率"] = pd.to_numeric(temp_df["换手率"])
return temp_df
def fund_etf_hist_min_em(
symbol: str = "159707",
start_date: str = "1979-09-01 09:32:00",
end_date: str = "2222-01-01 09:32:00",
period: str = "5",
adjust: str = "",
) -> pd.DataFrame:
"""
东方财富-ETF 行情
https://quote.eastmoney.com/sz159707.html
:param symbol: ETF 代码
:type symbol: str
:param start_date: 开始日期
:type start_date: str
:param end_date: 结束日期
:type end_date: str
:param period: choice of {'1', '5', '15', '30', '60'}
:type period: str
:param adjust: choice of {'', 'qfq', 'hfq'}
:type adjust: str
:return: 每日分时行情
:rtype: pandas.DataFrame
"""
code_id_dict = _fund_etf_code_id_map_em()
adjust_map = {
"": "0",
"qfq": "1",
"hfq": "2",
}
if period == "1":
url = "https://push2his.eastmoney.com/api/qt/stock/trends2/get"
params = {
"fields1": "f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13",
"fields2": "f51,f52,f53,f54,f55,f56,f57,f58",
"ut": "7eea3edcaed734bea9cbfc24409ed989",
"ndays": "5",
"iscr": "0",
"secid": f"{code_id_dict[symbol]}.{symbol}",
"_": "1623766962675",
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(
[item.split(",") for item in data_json["data"]["trends"]]
)
temp_df.columns = [
"时间",
"开盘",
"收盘",
"最高",
"最低",
"成交量",
"成交额",
"最新价",
]
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["开盘"])
temp_df["收盘"] = pd.to_numeric(temp_df["收盘"])
temp_df["最高"] = pd.to_numeric(temp_df["最高"])
temp_df["最低"] = pd.to_numeric(temp_df["最低"])
temp_df["成交量"] = pd.to_numeric(temp_df["成交量"])
temp_df["成交额"] = pd.to_numeric(temp_df["成交额"])
temp_df["最新价"] = pd.to_numeric(temp_df["最新价"])
temp_df["时间"] = pd.to_datetime(temp_df["时间"]).astype(str)
return temp_df
else:
url = "http://push2his.eastmoney.com/api/qt/stock/kline/get"
params = {
"fields1": "f1,f2,f3,f4,f5,f6",
"fields2": "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61",
"ut": "7eea3edcaed734bea9cbfc24409ed989",
"klt": period,
"fqt": adjust_map[adjust],
"secid": f"{code_id_dict[symbol]}.{symbol}",
"beg": "0",
"end": "20500000",
"_": "1630930917857",
}
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 = [
"时间",
"开盘",
"收盘",
"最高",
"最低",
"成交量",
"成交额",
"振幅",
"涨跌幅",
"涨跌额",
"换手率",
]
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["开盘"])
temp_df["收盘"] = pd.to_numeric(temp_df["收盘"])
temp_df["最高"] = pd.to_numeric(temp_df["最高"])
temp_df["最低"] = pd.to_numeric(temp_df["最低"])
temp_df["成交量"] = pd.to_numeric(temp_df["成交量"])
temp_df["成交额"] = pd.to_numeric(temp_df["成交额"])
temp_df["振幅"] = pd.to_numeric(temp_df["振幅"])
temp_df["涨跌幅"] = pd.to_numeric(temp_df["涨跌幅"])
temp_df["涨跌额"] = pd.to_numeric(temp_df["涨跌额"])
temp_df["换手率"] = pd.to_numeric(temp_df["换手率"])
temp_df["时间"] = pd.to_datetime(temp_df["时间"]).astype(str)
temp_df = temp_df[
[
"时间",
"开盘",
"收盘",
"最高",
"最低",
"涨跌幅",
"涨跌额",
"成交量",
"成交额",
"振幅",
"换手率",
]
]
return temp_df
if __name__ == "__main__":
fund_etf_spot_em_df = fund_etf_spot_em()
print(fund_etf_spot_em_df)
fund_etf_hist_hfq_em_df = fund_etf_hist_em(
symbol="513500",
period="daily",
start_date="20000101",
end_date="20230201",
adjust="hfq",
)
print(fund_etf_hist_hfq_em_df)
fund_etf_hist_qfq_em_df = fund_etf_hist_em(
symbol="513500",
period="daily",
start_date="20000101",
end_date="20230201",
adjust="qfq",
)
print(fund_etf_hist_qfq_em_df)
fund_etf_hist_em_df = fund_etf_hist_em(
symbol="513500",
period="daily",
start_date="20000101",
end_date="20230201",
adjust="",
)
print(fund_etf_hist_em_df)
fund_etf_hist_min_em_df = fund_etf_hist_min_em(
symbol="513500",
period="5",
adjust="hfq",
start_date="2023-01-01 09:32:00",
end_date="2023-01-04 14:40:00",
)
print(fund_etf_hist_min_em_df)

View File

@ -0,0 +1,139 @@
# -*- coding:utf-8 -*-
# !/usr/bin/env python
import pandas as pd
import requests
import instock.core.tablestructure as tbs
__author__ = 'myh '
__date__ = '2023/5/7 '
def stock_cpbd_em(symbol: str = "688041") -> pd.DataFrame:
"""
东方财富网-个股-操盘必读
https://emweb.securities.eastmoney.com/PC_HSF10/OperationsRequired/Index?type=web&code=SH688041#
:param symbol: 带市场标识的股票代码
:type symbol: str
:return: 操盘必读
:rtype: pandas.DataFrame
"""
url = "https://emweb.securities.eastmoney.com/PC_HSF10/OperationsRequired/PageAjax"
if symbol.startswith("6"):
symbol = f"SH{symbol}"
else:
symbol = f"SZ{symbol}"
params = {"code": symbol}
r = requests.get(url, params=params)
data_json = r.json()
zxzb = data_json["zxzb"] # 主要指标
if len(zxzb) < 1:
return None
data_dict = zxzb[0]
zxzbOther = data_json["zxzbOther"] # 其它指标,计算出来
if len(zxzbOther) > 0:
zxzbOther = zxzbOther[0]
data_dict = {**data_dict, **zxzbOther}
# zxzbhq = data_json["zxzbhq"] # 其它指标,计算出来
# if len(zxzbhq) > 0:
# data_dict = {**data_dict, **zxzbhq}
_ssbks = data_json["ssbk"] # 所属板块
ssbk = None
for s in _ssbks:
_v = s.get('BOARD_NAME')
if _v is not None:
if ssbk is None:
ssbk = f"{_v}"
else:
ssbk = f"{ssbk}{_v}"
data_dict["BOARD_NAME"] = ssbk
gdrs = data_json["gdrs"] # 股东分析
if len(gdrs) > 0:
gdrs = gdrs[0]
data_dict = {**data_dict, **gdrs}
lhbd = data_json["lhbd"] # 龙虎榜单
if len(lhbd) > 0:
lhbd = lhbd[0]
lhbd["LHBD_DATE"] = lhbd.pop("TRADE_DATE")
data_dict = {**data_dict, **lhbd}
dzjy = data_json["dzjy"] # 大宗交易
if len(dzjy) > 0:
dzjy = dzjy[0]
dzjy["DZJY_DATE"] = dzjy.pop("TRADE_DATE")
data_dict = {**data_dict, **dzjy}
rzrq = data_json["rzrq"] # 融资融券
if len(rzrq) > 0:
rzrq = rzrq[0]
rzrq["RZRQ_DATE"] = rzrq.pop("TRADE_DATE")
data_dict = {**data_dict, **rzrq}
tbs.CN_STOCK_CPBD
# 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")
# 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_numeric(temp_df["扣非净利润同比增长"], errors="coerce")
# temp_df["总股本"] = pd.to_numeric(temp_df["总股本"], errors="coerce")
# temp_df["已流通股份"] = pd.to_numeric(temp_df["已流通股份"], errors="coerce")
def stock_zjlx_em(symbol: str = "688041") -> pd.DataFrame:
"""
东方财富网-个股-资金流向
https://data.eastmoney.com/zjlx/688041.html
:param symbol: 带市场标识的股票代码
:type symbol: str
:return: 操盘必读
:rtype: pandas.DataFrame
"""
url = "https://push2his.eastmoney.com/api/qt/stock/fflow/daykline/get"
if symbol.startswith("6"):
symbol = f"1.{symbol}"
else:
symbol = f"0.{symbol}"
params = {
"lmt": "0",
"klt": "1",
"fields1": "f1,f2,f3,f7",
"fields2": "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61,f62,f63,f64,f65",
"ut": "b2884a393a59ad64002292a3e90d46a5",
"secid": symbol
}
r = requests.get(url, params=params)
data_json = r.json()
klines = data_json["klines"] # 主要指标
"日期","主力净流入额","小单净流入额","中单净流入额","大单净流入额","超大单净流入额","主力净流入占比", "小单净流入占比", "中单净流入占比", "大单净流入占比", "超大单净流入占比"
"收盘价","涨跌幅"
if len(klines) < 1:
return None
if __name__ == "__main__":
stock_cpbd_em_df = stock_cpbd_em(symbol="688041")
print(stock_cpbd_em_df)

View File

@ -0,0 +1,535 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2022/5/16 15:31
Desc: 东方财富网-数据中心-大宗交易-市场统计
http://data.eastmoney.com/dzjy/dzjy_sctj.aspx
"""
import pandas as pd
import requests
def stock_dzjy_sctj() -> pd.DataFrame:
"""
东方财富网-数据中心-大宗交易-市场统计
http://data.eastmoney.com/dzjy/dzjy_sctj.aspx
:return: 市场统计表
:rtype: pandas.DataFrame
"""
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
'sortColumns': 'TRADE_DATE',
'sortTypes': '-1',
'pageSize': '500',
'pageNumber': '1',
'reportName': 'PRT_BLOCKTRADE_MARKET_STA',
'columns': 'TRADE_DATE,SZ_INDEX,SZ_CHANGE_RATE,BLOCKTRADE_DEAL_AMT,PREMIUM_DEAL_AMT,PREMIUM_RATIO,DISCOUNT_DEAL_AMT,DISCOUNT_RATIO',
'source': 'WEB',
'client': 'WEB',
}
r = requests.get(url, params=params)
data_json = r.json()
total_page = int(data_json['result']["pages"])
big_df = pd.DataFrame()
for page in range(1, total_page+1):
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([big_df, temp_df], ignore_index=True)
big_df.reset_index(inplace=True)
big_df['index'] = big_df['index'] + 1
big_df.columns = [
"序号",
"交易日期",
"上证指数",
"上证指数涨跌幅",
"大宗交易成交总额",
"溢价成交总额",
"溢价成交总额占比",
"折价成交总额",
"折价成交总额占比",
]
big_df["交易日期"] = pd.to_datetime(big_df["交易日期"]).dt.date
big_df["上证指数"] = pd.to_numeric(big_df["上证指数"])
big_df["上证指数涨跌幅"] = pd.to_numeric(big_df["上证指数涨跌幅"])
big_df["大宗交易成交总额"] = pd.to_numeric(big_df["大宗交易成交总额"])
big_df["溢价成交总额"] = pd.to_numeric(big_df["溢价成交总额"])
big_df["溢价成交总额占比"] = pd.to_numeric(big_df["溢价成交总额占比"])
big_df["折价成交总额"] = pd.to_numeric(big_df["折价成交总额"])
big_df["折价成交总额占比"] = pd.to_numeric(big_df["折价成交总额占比"])
return big_df
def stock_dzjy_mrmx(symbol: str = '基金', start_date: str = '20220104', end_date: str = '20220104') -> pd.DataFrame:
"""
东方财富网-数据中心-大宗交易-每日明细
http://data.eastmoney.com/dzjy/dzjy_mrmxa.aspx
:param symbol: choice of {'A股', 'B股', '基金', '债券'}
:type symbol: str
:param start_date: 开始日期
:type start_date: str
:param end_date: 结束日期
:type end_date: str
:return: 每日明细
:rtype: pandas.DataFrame
"""
symbol_map = {
'A股': '1',
'B股': '2',
'基金': '3',
'债券': '4',
}
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
'sortColumns': 'SECURITY_CODE',
'sortTypes': '1',
'pageSize': '5000',
'pageNumber': '1',
'reportName': 'RPT_DATA_BLOCKTRADE',
'columns': 'TRADE_DATE,SECURITY_CODE,SECUCODE,SECURITY_NAME_ABBR,CHANGE_RATE,CLOSE_PRICE,DEAL_PRICE,PREMIUM_RATIO,DEAL_VOLUME,DEAL_AMT,TURNOVER_RATE,BUYER_NAME,SELLER_NAME,CHANGE_RATE_1DAYS,CHANGE_RATE_5DAYS,CHANGE_RATE_10DAYS,CHANGE_RATE_20DAYS,BUYER_CODE,SELLER_CODE',
'source': 'WEB',
'client': 'WEB',
'filter': f"""(SECURITY_TYPE_WEB={symbol_map[symbol]})(TRADE_DATE>='{'-'.join([start_date[:4], start_date[4:6], start_date[6:]])}')(TRADE_DATE<='{'-'.join([end_date[:4], end_date[4:6], end_date[6:]])}')"""
}
r = requests.get(url, params=params)
data_json = r.json()
if not data_json['result']["data"]:
return pd.DataFrame()
temp_df = pd.DataFrame(data_json['result']["data"])
temp_df.reset_index(inplace=True)
temp_df['index'] = temp_df.index + 1
if symbol in {'A股'}:
temp_df.columns = [
"序号",
"交易日期",
"证券代码",
"-",
"证券简称",
"涨跌幅",
"收盘价",
"成交价",
"折溢率",
"成交量",
"成交额",
"成交额/流通市值",
"买方营业部",
"卖方营业部",
"_",
"_",
"_",
"_",
"_",
"_",
]
temp_df["交易日期"] = pd.to_datetime(temp_df["交易日期"]).dt.date
temp_df = temp_df[[
"序号",
"交易日期",
"证券代码",
"证券简称",
"涨跌幅",
"收盘价",
"成交价",
"折溢率",
"成交量",
"成交额",
"成交额/流通市值",
"买方营业部",
"卖方营业部",
]]
temp_df['涨跌幅'] = pd.to_numeric(temp_df['涨跌幅'])
temp_df['收盘价'] = pd.to_numeric(temp_df['收盘价'])
temp_df['成交价'] = pd.to_numeric(temp_df['成交价'])
temp_df['折溢率'] = pd.to_numeric(temp_df['折溢率'])
temp_df['成交量'] = pd.to_numeric(temp_df['成交量'])
temp_df['成交额'] = pd.to_numeric(temp_df['成交额'])
temp_df['成交额/流通市值'] = pd.to_numeric(temp_df['成交额/流通市值'])
if symbol in {'B股', '基金', '债券'}:
temp_df.columns = [
"序号",
"交易日期",
"证券代码",
"-",
"证券简称",
"-",
"-",
"成交价",
"-",
"成交量",
"成交额",
"-",
"买方营业部",
"卖方营业部",
"_",
"_",
"_",
"_",
"_",
"_",
]
temp_df["交易日期"] = pd.to_datetime(temp_df["交易日期"]).dt.date
temp_df = temp_df[[
"序号",
"交易日期",
"证券代码",
"证券简称",
"成交价",
"成交量",
"成交额",
"买方营业部",
"卖方营业部",
]]
temp_df['成交价'] = pd.to_numeric(temp_df['成交价'])
temp_df['成交量'] = pd.to_numeric(temp_df['成交量'])
temp_df['成交额'] = pd.to_numeric(temp_df['成交额'])
return temp_df
def stock_dzjy_mrtj(start_date: str = '20220105', end_date: str = '20220105') -> pd.DataFrame:
"""
东方财富网-数据中心-大宗交易-每日统计
http://data.eastmoney.com/dzjy/dzjy_mrtj.aspx
:param start_date: 开始日期
:type start_date: str
:param end_date: 结束日期
:type end_date: str
:return: 每日统计
:rtype: pandas.DataFrame
"""
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
'sortColumns': 'TURNOVERRATE',
'sortTypes': '-1',
'pageSize': '5000',
'pageNumber': '1',
'reportName': 'RPT_BLOCKTRADE_STA',
'columns': 'TRADE_DATE,SECURITY_CODE,SECUCODE,SECURITY_NAME_ABBR,CHANGE_RATE,CLOSE_PRICE,AVERAGE_PRICE,PREMIUM_RATIO,DEAL_NUM,VOLUME,DEAL_AMT,TURNOVERRATE,D1_CLOSE_ADJCHRATE,D5_CLOSE_ADJCHRATE,D10_CLOSE_ADJCHRATE,D20_CLOSE_ADJCHRATE',
'source': 'WEB',
'client': 'WEB',
'filter': f"(TRADE_DATE>='{'-'.join([start_date[:4], start_date[4:6], start_date[6:]])}')(TRADE_DATE<='{'-'.join([end_date[:4], end_date[4:6], end_date[6:]])}')"
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(data_json['result']["data"])
temp_df.reset_index(inplace=True)
temp_df['index'] = temp_df.index + 1
temp_df.columns = [
"序号",
"交易日期",
"证券代码",
"-",
"证券简称",
"涨跌幅",
"收盘价",
"成交价",
"折溢率",
"成交笔数",
"成交总量",
"成交总额",
"成交总额/流通市值",
"_",
"_",
"_",
"_",
]
temp_df["交易日期"] = pd.to_datetime(temp_df["交易日期"]).dt.date
temp_df = temp_df[[
"序号",
"交易日期",
"证券代码",
"证券简称",
"收盘价",
"涨跌幅",
"成交价",
"折溢率",
"成交笔数",
"成交总量",
"成交总额",
"成交总额/流通市值",
]]
temp_df['涨跌幅'] = pd.to_numeric(temp_df['涨跌幅'])
temp_df['收盘价'] = pd.to_numeric(temp_df['收盘价'])
temp_df['成交价'] = pd.to_numeric(temp_df['成交价'])
temp_df['折溢率'] = pd.to_numeric(temp_df['折溢率'])
temp_df['成交笔数'] = pd.to_numeric(temp_df['成交笔数'])
temp_df['成交总量'] = pd.to_numeric(temp_df['成交总量'])
temp_df['成交总额'] = pd.to_numeric(temp_df['成交总额'])
temp_df['成交总额/流通市值'] = pd.to_numeric(temp_df['成交总额/流通市值'])
return temp_df
def stock_dzjy_hygtj(symbol: str = '近三月') -> pd.DataFrame:
"""
东方财富网-数据中心-大宗交易-活跃 A 股统计
http://data.eastmoney.com/dzjy/dzjy_hygtj.aspx
:param symbol: choice of {'近一月', '近三月', '近六月', '近一年'}
:type symbol: str
:return: 活跃 A 股统计
:rtype: pandas.DataFrame
"""
period_map = {
'近一月': '1',
'近三月': '3',
'近六月': '6',
'近一年': '12',
}
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
'sortColumns': 'DEAL_NUM,SECURITY_CODE',
'sortTypes': '-1,-1',
'pageSize': '5000',
'pageNumber': '1',
'reportName': 'RPT_BLOCKTRADE_ACSTA',
'columns': 'SECURITY_CODE,SECUCODE,SECURITY_NAME_ABBR,CLOSE_PRICE,CHANGE_RATE,TRADE_DATE,DEAL_AMT,PREMIUM_RATIO,SUM_TURNOVERRATE,DEAL_NUM,PREMIUM_TIMES,DISCOUNT_TIMES,D1_AVG_ADJCHRATE,D5_AVG_ADJCHRATE,D10_AVG_ADJCHRATE,D20_AVG_ADJCHRATE,DATE_TYPE_CODE',
'source': 'WEB',
'client': 'WEB',
'filter': f'(DATE_TYPE_CODE={period_map[symbol]})',
}
r = requests.get(url, params=params)
data_json = r.json()
total_page = data_json['result']["pages"]
big_df = pd.DataFrame()
for page in range(1, int(total_page)+1):
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([big_df, temp_df], ignore_index=True)
big_df.reset_index(inplace=True)
big_df['index'] = big_df.index + 1
big_df.columns = [
"序号",
"证券代码",
"_",
"证券简称",
"最新价",
"涨跌幅",
"最近上榜日",
"总成交额",
"折溢率",
"成交总额/流通市值",
"上榜次数-总计",
"上榜次数-溢价",
"上榜次数-折价",
"上榜日后平均涨跌幅-1日",
"上榜日后平均涨跌幅-5日",
"上榜日后平均涨跌幅-10日",
"上榜日后平均涨跌幅-20日",
"_",
]
big_df = big_df[[
"序号",
"证券代码",
"证券简称",
"最新价",
"涨跌幅",
"最近上榜日",
"上榜次数-总计",
"上榜次数-溢价",
"上榜次数-折价",
"总成交额",
"折溢率",
"成交总额/流通市值",
"上榜日后平均涨跌幅-1日",
"上榜日后平均涨跌幅-5日",
"上榜日后平均涨跌幅-10日",
"上榜日后平均涨跌幅-20日",
]]
big_df["最近上榜日"] = pd.to_datetime(big_df["最近上榜日"]).dt.date
big_df["最新价"] = pd.to_numeric(big_df["最新价"])
big_df["涨跌幅"] = pd.to_numeric(big_df["涨跌幅"])
big_df["上榜次数-总计"] = pd.to_numeric(big_df["上榜次数-总计"])
big_df["上榜次数-溢价"] = pd.to_numeric(big_df["上榜次数-溢价"])
big_df["上榜次数-折价"] = pd.to_numeric(big_df["上榜次数-折价"])
big_df["总成交额"] = pd.to_numeric(big_df["总成交额"])
big_df["折溢率"] = pd.to_numeric(big_df["折溢率"])
big_df["成交总额/流通市值"] = pd.to_numeric(big_df["成交总额/流通市值"])
big_df["上榜日后平均涨跌幅-1日"] = pd.to_numeric(big_df["上榜日后平均涨跌幅-1日"])
big_df["上榜日后平均涨跌幅-5日"] = pd.to_numeric(big_df["上榜日后平均涨跌幅-5日"])
big_df["上榜日后平均涨跌幅-10日"] = pd.to_numeric(big_df["上榜日后平均涨跌幅-10日"])
big_df["上榜日后平均涨跌幅-20日"] = pd.to_numeric(big_df["上榜日后平均涨跌幅-20日"])
return big_df
def stock_dzjy_hyyybtj(symbol: str = '近3日') -> pd.DataFrame:
"""
东方财富网-数据中心-大宗交易-活跃营业部统计
https://data.eastmoney.com/dzjy/dzjy_hyyybtj.html
:param symbol: choice of {'当前交易日', '近3日', '近5日', '近10日', '近30日'}
:type symbol: str
:return: 活跃营业部统计
:rtype: pandas.DataFrame
"""
period_map = {
'当前交易日': '1',
'近3日': '3',
'近5日': '5',
'近10日': '10',
'近30日': '30',
}
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
'sortColumns': 'BUYER_NUM,TOTAL_BUYAMT',
'sortTypes': '-1,-1',
'pageSize': '5000',
'pageNumber': '1',
'reportName': 'RPT_BLOCKTRADE_OPERATEDEPTSTATISTICS',
'columns': 'OPERATEDEPT_CODE,OPERATEDEPT_NAME,ONLIST_DATE,STOCK_DETAILS,BUYER_NUM,SELLER_NUM,TOTAL_BUYAMT,TOTAL_SELLAMT,TOTAL_NETAMT,N_DATE',
'source': 'WEB',
'client': 'WEB',
'filter': f'(N_DATE=-{period_map[symbol]})',
}
r = requests.get(url, params=params)
data_json = r.json()
total_page = data_json['result']["pages"]
big_df = pd.DataFrame()
for page in range(1, int(total_page)+1):
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([big_df, temp_df], ignore_index=True)
big_df.reset_index(inplace=True)
big_df['index'] = big_df.index + 1
big_df.columns = [
"序号",
"_",
"营业部名称",
"最近上榜日",
"买入的股票",
"次数总计-买入",
"次数总计-卖出",
"成交金额统计-买入",
"成交金额统计-卖出",
"成交金额统计-净买入额",
"_",
]
big_df = big_df[[
"序号",
"最近上榜日",
"营业部名称",
"次数总计-买入",
"次数总计-卖出",
"成交金额统计-买入",
"成交金额统计-卖出",
"成交金额统计-净买入额",
"买入的股票",
]]
big_df["最近上榜日"] = pd.to_datetime(big_df["最近上榜日"]).dt.date
big_df["次数总计-买入"] = pd.to_numeric(big_df["次数总计-买入"])
big_df["次数总计-卖出"] = pd.to_numeric(big_df["次数总计-卖出"])
big_df["成交金额统计-买入"] = pd.to_numeric(big_df["成交金额统计-买入"])
big_df["成交金额统计-卖出"] = pd.to_numeric(big_df["成交金额统计-卖出"])
big_df["成交金额统计-净买入额"] = pd.to_numeric(big_df["成交金额统计-净买入额"])
return big_df
def stock_dzjy_yybph(symbol: str = '近三月') -> pd.DataFrame:
"""
东方财富网-数据中心-大宗交易-营业部排行
http://data.eastmoney.com/dzjy/dzjy_yybph.aspx
:param symbol: choice of {'近一月', '近三月', '近六月', '近一年'}
:type symbol: str
:return: 营业部排行
:rtype: pandas.DataFrame
"""
period_map = {
'近一月': '30',
'近三月': '90',
'近六月': '120',
'近一年': '360',
}
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
'sortColumns': 'D5_BUYER_NUM,D1_AVERAGE_INCREASE',
'sortTypes': '-1,-1',
'pageSize': '5000',
'pageNumber': '1',
'reportName': 'RPT_BLOCKTRADE_OPERATEDEPT_RANK',
'columns': 'OPERATEDEPT_CODE,OPERATEDEPT_NAME,D1_BUYER_NUM,D1_AVERAGE_INCREASE,D1_RISE_PROBABILITY,D5_BUYER_NUM,D5_AVERAGE_INCREASE,D5_RISE_PROBABILITY,D10_BUYER_NUM,D10_AVERAGE_INCREASE,D10_RISE_PROBABILITY,D20_BUYER_NUM,D20_AVERAGE_INCREASE,D20_RISE_PROBABILITY,N_DATE,RELATED_ORG_CODE',
'source': 'WEB',
'client': 'WEB',
'filter': f'(N_DATE=-{period_map[symbol]})',
}
r = requests.get(url, params=params)
data_json = r.json()
total_page = data_json['result']["pages"]
big_df = pd.DataFrame()
for page in range(1, int(total_page)+1):
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([big_df, temp_df], ignore_index=True)
big_df.reset_index(inplace=True)
big_df['index'] = big_df.index + 1
big_df.columns = [
"序号",
"_",
"营业部名称",
"上榜后1天-买入次数",
"上榜后1天-平均涨幅",
"上榜后1天-上涨概率",
"上榜后5天-买入次数",
"上榜后5天-平均涨幅",
"上榜后5天-上涨概率",
"上榜后10天-买入次数",
"上榜后10天-平均涨幅",
"上榜后10天-上涨概率",
"上榜后20天-买入次数",
"上榜后20天-平均涨幅",
"上榜后20天-上涨概率",
"_",
"_",
]
big_df = big_df[[
"序号",
"营业部名称",
"上榜后1天-买入次数",
"上榜后1天-平均涨幅",
"上榜后1天-上涨概率",
"上榜后5天-买入次数",
"上榜后5天-平均涨幅",
"上榜后5天-上涨概率",
"上榜后10天-买入次数",
"上榜后10天-平均涨幅",
"上榜后10天-上涨概率",
"上榜后20天-买入次数",
"上榜后20天-平均涨幅",
"上榜后20天-上涨概率",
]]
big_df['上榜后1天-买入次数'] = pd.to_numeric(big_df['上榜后1天-买入次数'])
big_df['上榜后1天-平均涨幅'] = pd.to_numeric(big_df['上榜后1天-平均涨幅'])
big_df['上榜后1天-上涨概率'] = pd.to_numeric(big_df['上榜后1天-上涨概率'])
big_df['上榜后5天-买入次数'] = pd.to_numeric(big_df['上榜后5天-买入次数'])
big_df['上榜后5天-平均涨幅'] = pd.to_numeric(big_df['上榜后5天-平均涨幅'])
big_df['上榜后5天-上涨概率'] = pd.to_numeric(big_df['上榜后5天-上涨概率'])
big_df['上榜后10天-买入次数'] = pd.to_numeric(big_df['上榜后10天-买入次数'])
big_df['上榜后10天-平均涨幅'] = pd.to_numeric(big_df['上榜后10天-平均涨幅'])
big_df['上榜后10天-上涨概率'] = pd.to_numeric(big_df['上榜后10天-上涨概率'])
big_df['上榜后20天-买入次数'] = pd.to_numeric(big_df['上榜后20天-买入次数'])
big_df['上榜后20天-平均涨幅'] = pd.to_numeric(big_df['上榜后20天-平均涨幅'])
big_df['上榜后20天-上涨概率'] = pd.to_numeric(big_df['上榜后20天-上涨概率'])
return big_df
if __name__ == "__main__":
stock_dzjy_sctj_df = stock_dzjy_sctj()
print(stock_dzjy_sctj_df)
stock_dzjy_mrmx_df = stock_dzjy_mrmx(symbol='债券', start_date='20201204', end_date='20201204')
print(stock_dzjy_mrmx_df)
stock_dzjy_mrtj_df = stock_dzjy_mrtj(start_date='20201204', end_date='20201204')
print(stock_dzjy_mrtj_df)
stock_dzjy_hygtj_df = stock_dzjy_hygtj(symbol='近三月')
print(stock_dzjy_hygtj_df)
stock_dzjy_hyyybtj_df = stock_dzjy_hyyybtj(symbol='近3日')
print(stock_dzjy_hyyybtj_df)
stock_dzjy_yybph_df = stock_dzjy_yybph(symbol='近三月')
print(stock_dzjy_yybph_df)

View File

@ -0,0 +1,126 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2023/4/7 15:22
Desc: 东方财富网-数据中心-年报季报-分红送配
https://data.eastmoney.com/yjfp/
"""
import pandas as pd
import requests
from tqdm import tqdm
__author__ = 'myh '
__date__ = '2023/6/27 '
def stock_fhps_em(date: str = "20210630") -> pd.DataFrame:
"""
东方财富网-数据中心-年报季报-分红送配
https://data.eastmoney.com/yjfp/
:param date: 分红送配报告期
:type date: str
:return: 分红送配
:rtype: pandas.DataFrame
"""
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
"sortColumns": "PLAN_NOTICE_DATE",
"sortTypes": "-1",
"pageSize": "500",
"pageNumber": "1",
"reportName": "RPT_SHAREBONUS_DET",
"columns": "ALL",
"quoteColumns": "",
"js": '{"data":(x),"pages":(tp)}',
"source": "WEB",
"client": "WEB",
"filter": f"""(REPORT_DATE='{"-".join([date[:4], date[4:6], date[6:]])}')""",
}
r = requests.get(url, params=params)
data_json = r.json()
total_pages = int(data_json["result"]["pages"])
big_df = pd.DataFrame()
for page in tqdm(range(1, total_pages + 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([big_df, temp_df], ignore_index=True)
big_df.columns = [
"_",
"名称",
"_",
"_",
"代码",
"送转股份-送转总比例",
"送转股份-送转比例",
"送转股份-转股比例",
"现金分红-现金分红比例",
"预案公告日",
"股权登记日",
"除权除息日",
"_",
"方案进度",
"_",
"最新公告日期",
"_",
"_",
"_",
"每股收益",
"每股净资产",
"每股公积金",
"每股未分配利润",
"净利润同比增长",
"总股本",
"_",
"现金分红-股息率",
"-",
"-",
"-",
]
big_df = big_df[
[
"代码",
"名称",
"送转股份-送转总比例",
"送转股份-送转比例",
"送转股份-转股比例",
"现金分红-现金分红比例",
"现金分红-股息率",
"每股收益",
"每股净资产",
"每股公积金",
"每股未分配利润",
"净利润同比增长",
"总股本",
"预案公告日",
"股权登记日",
"除权除息日",
"方案进度",
"最新公告日期",
]
]
big_df["送转股份-送转总比例"] = pd.to_numeric(big_df["送转股份-送转总比例"])
big_df["送转股份-送转比例"] = pd.to_numeric(big_df["送转股份-送转比例"])
big_df["送转股份-转股比例"] = pd.to_numeric(big_df["送转股份-转股比例"])
big_df["现金分红-现金分红比例"] = pd.to_numeric(big_df["现金分红-现金分红比例"])
big_df["现金分红-股息率"] = pd.to_numeric(big_df["现金分红-股息率"])
big_df["每股收益"] = pd.to_numeric(big_df["每股收益"])
big_df["每股净资产"] = pd.to_numeric(big_df["每股净资产"])
big_df["每股公积金"] = pd.to_numeric(big_df["每股公积金"])
big_df["每股未分配利润"] = pd.to_numeric(big_df["每股未分配利润"])
big_df["净利润同比增长"] = pd.to_numeric(big_df["净利润同比增长"])
big_df["总股本"] = pd.to_numeric(big_df["总股本"])
big_df["预案公告日"] = pd.to_datetime(big_df["预案公告日"], errors="coerce").dt.date
big_df["股权登记日"] = pd.to_datetime(big_df["股权登记日"], errors="coerce").dt.date
big_df["除权除息日"] = pd.to_datetime(big_df["除权除息日"], errors="coerce").dt.date
big_df["最新公告日期"] = pd.to_datetime(big_df["最新公告日期"], errors="coerce").dt.date
return big_df
if __name__ == "__main__":
stock_fhps_em_df = stock_fhps_em(date="20221231")
print(stock_fhps_em_df)

View File

@ -0,0 +1,419 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2023/5/16 15:30
Desc: 东方财富网-数据中心-资金流向
https://data.eastmoney.com/zjlx/detail.html
"""
import json
import time
from functools import lru_cache
import pandas as pd
import requests
__author__ = 'myh '
__date__ = '2023/6/12 '
def stock_individual_fund_flow_rank(indicator: str = "5日") -> pd.DataFrame:
"""
东方财富网-数据中心-资金流向-排名
https://data.eastmoney.com/zjlx/detail.html
:param indicator: choice of {"今日", "3日", "5日", "10日"}
:type indicator: str
:return: 指定 indicator 资金流向排行
:rtype: pandas.DataFrame
"""
indicator_map = {
"今日": [
"f62",
"f12,f14,f2,f3,f62,f184,f66,f69,f72,f75,f78,f81,f84,f87,f204,f205,f124",
],
"3日": [
"f267",
"f12,f14,f2,f127,f267,f268,f269,f270,f271,f272,f273,f274,f275,f276,f257,f258,f124",
],
"5日": [
"f164",
"f12,f14,f2,f109,f164,f165,f166,f167,f168,f169,f170,f171,f172,f173,f257,f258,f124",
],
"10日": [
"f174",
"f12,f14,f2,f160,f174,f175,f176,f177,f178,f179,f180,f181,f182,f183,f260,f261,f124",
],
}
url = "http://push2.eastmoney.com/api/qt/clist/get"
params = {
"fid": indicator_map[indicator][0],
"po": "1",
"pz": "10000",
"pn": "1",
"np": "1",
"fltt": "2",
"invt": "2",
"ut": "b2884a393a59ad64002292a3e90d46a5",
"fs": "m:0+t:6+f:!2,m:0+t:13+f:!2,m:0+t:80+f:!2,m:1+t:2+f:!2,m:1+t:23+f:!2,m:0+t:7+f:!2,m:1+t:3+f:!2",
"fields": indicator_map[indicator][1],
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(data_json["data"]["diff"])
if indicator == "今日":
temp_df.columns = [
"最新价",
"今日涨跌幅",
"代码",
"名称",
"今日主力净流入-净额",
"今日超大单净流入-净额",
"今日超大单净流入-净占比",
"今日大单净流入-净额",
"今日大单净流入-净占比",
"今日中单净流入-净额",
"今日中单净流入-净占比",
"今日小单净流入-净额",
"今日小单净流入-净占比",
"_",
"今日主力净流入-净占比",
"_",
"_",
"_",
]
temp_df = temp_df[
[
"代码",
"名称",
"最新价",
"今日涨跌幅",
"今日主力净流入-净额",
"今日主力净流入-净占比",
"今日超大单净流入-净额",
"今日超大单净流入-净占比",
"今日大单净流入-净额",
"今日大单净流入-净占比",
"今日中单净流入-净额",
"今日中单净流入-净占比",
"今日小单净流入-净额",
"今日小单净流入-净占比",
]
]
elif indicator == "3日":
temp_df.columns = [
"最新价",
"代码",
"名称",
"_",
"3日涨跌幅",
"_",
"_",
"_",
"3日主力净流入-净额",
"3日主力净流入-净占比",
"3日超大单净流入-净额",
"3日超大单净流入-净占比",
"3日大单净流入-净额",
"3日大单净流入-净占比",
"3日中单净流入-净额",
"3日中单净流入-净占比",
"3日小单净流入-净额",
"3日小单净流入-净占比",
]
temp_df = temp_df[
[
"代码",
"名称",
"最新价",
"3日涨跌幅",
"3日主力净流入-净额",
"3日主力净流入-净占比",
"3日超大单净流入-净额",
"3日超大单净流入-净占比",
"3日大单净流入-净额",
"3日大单净流入-净占比",
"3日中单净流入-净额",
"3日中单净流入-净占比",
"3日小单净流入-净额",
"3日小单净流入-净占比",
]
]
elif indicator == "5日":
temp_df.columns = [
"最新价",
"代码",
"名称",
"5日涨跌幅",
"_",
"5日主力净流入-净额",
"5日主力净流入-净占比",
"5日超大单净流入-净额",
"5日超大单净流入-净占比",
"5日大单净流入-净额",
"5日大单净流入-净占比",
"5日中单净流入-净额",
"5日中单净流入-净占比",
"5日小单净流入-净额",
"5日小单净流入-净占比",
"_",
"_",
"_",
]
temp_df = temp_df[
[
"代码",
"名称",
"最新价",
"5日涨跌幅",
"5日主力净流入-净额",
"5日主力净流入-净占比",
"5日超大单净流入-净额",
"5日超大单净流入-净占比",
"5日大单净流入-净额",
"5日大单净流入-净占比",
"5日中单净流入-净额",
"5日中单净流入-净占比",
"5日小单净流入-净额",
"5日小单净流入-净占比",
]
]
elif indicator == "10日":
temp_df.columns = [
"最新价",
"代码",
"名称",
"_",
"10日涨跌幅",
"10日主力净流入-净额",
"10日主力净流入-净占比",
"10日超大单净流入-净额",
"10日超大单净流入-净占比",
"10日大单净流入-净额",
"10日大单净流入-净占比",
"10日中单净流入-净额",
"10日中单净流入-净占比",
"10日小单净流入-净额",
"10日小单净流入-净占比",
"_",
"_",
"_",
]
temp_df = temp_df[
[
"代码",
"名称",
"最新价",
"10日涨跌幅",
"10日主力净流入-净额",
"10日主力净流入-净占比",
"10日超大单净流入-净额",
"10日超大单净流入-净占比",
"10日大单净流入-净额",
"10日大单净流入-净占比",
"10日中单净流入-净额",
"10日中单净流入-净占比",
"10日小单净流入-净额",
"10日小单净流入-净占比",
]
]
return temp_df
def stock_sector_fund_flow_rank(
indicator: str = "10日", sector_type: str = "行业资金流"
) -> pd.DataFrame:
"""
东方财富网-数据中心-资金流向-板块资金流-排名
https://data.eastmoney.com/bkzj/hy.html
:param indicator: choice of {"今日", "5日", "10日"}
:type indicator: str
:param sector_type: choice of {"行业资金流", "概念资金流", "地域资金流"}
:type sector_type: str
:return: 指定参数的资金流排名数据
:rtype: pandas.DataFrame
"""
sector_type_map = {"行业资金流": "2", "概念资金流": "3", "地域资金流": "1"}
indicator_map = {
"今日": [
"f62",
"1",
"f12,f14,f2,f3,f62,f184,f66,f69,f72,f75,f78,f81,f84,f87,f204,f205,f124",
],
"5日": [
"f164",
"5",
"f12,f14,f2,f109,f164,f165,f166,f167,f168,f169,f170,f171,f172,f173,f257,f258,f124",
],
"10日": [
"f174",
"10",
"f12,f14,f2,f160,f174,f175,f176,f177,f178,f179,f180,f181,f182,f183,f260,f261,f124",
],
}
url = "http://push2.eastmoney.com/api/qt/clist/get"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36",
}
params = {
"pn": "1",
"pz": "5000",
"po": "1",
"np": "1",
"ut": "b2884a393a59ad64002292a3e90d46a5",
"fltt": "2",
"invt": "2",
"fid0": indicator_map[indicator][0],
"fs": f"m:90 t:{sector_type_map[sector_type]}",
"stat": indicator_map[indicator][1],
"fields": indicator_map[indicator][2],
"rt": "52975239",
"cb": "jQuery18308357908311220152_1589256588824",
"_": int(time.time() * 1000),
}
r = requests.get(url, params=params, headers=headers)
text_data = r.text
json_data = json.loads(text_data[text_data.find("{") : -2])
temp_df = pd.DataFrame(json_data["data"]["diff"])
if indicator == "今日":
temp_df.columns = [
"-",
"今日涨跌幅",
"_",
"名称",
"今日主力净流入-净额",
"今日超大单净流入-净额",
"今日超大单净流入-净占比",
"今日大单净流入-净额",
"今日大单净流入-净占比",
"今日中单净流入-净额",
"今日中单净流入-净占比",
"今日小单净流入-净额",
"今日小单净流入-净占比",
"-",
"今日主力净流入-净占比",
"今日主力净流入最大股",
"今日主力净流入最大股代码",
"是否净流入",
]
temp_df = temp_df[
[
"名称",
"今日涨跌幅",
"今日主力净流入-净额",
"今日主力净流入-净占比",
"今日超大单净流入-净额",
"今日超大单净流入-净占比",
"今日大单净流入-净额",
"今日大单净流入-净占比",
"今日中单净流入-净额",
"今日中单净流入-净占比",
"今日小单净流入-净额",
"今日小单净流入-净占比",
"今日主力净流入最大股",
]
]
elif indicator == "5日":
temp_df.columns = [
"-",
"_",
"名称",
"5日涨跌幅",
"_",
"5日主力净流入-净额",
"5日主力净流入-净占比",
"5日超大单净流入-净额",
"5日超大单净流入-净占比",
"5日大单净流入-净额",
"5日大单净流入-净占比",
"5日中单净流入-净额",
"5日中单净流入-净占比",
"5日小单净流入-净额",
"5日小单净流入-净占比",
"5日主力净流入最大股",
"_",
"_",
]
temp_df = temp_df[
[
"名称",
"5日涨跌幅",
"5日主力净流入-净额",
"5日主力净流入-净占比",
"5日超大单净流入-净额",
"5日超大单净流入-净占比",
"5日大单净流入-净额",
"5日大单净流入-净占比",
"5日中单净流入-净额",
"5日中单净流入-净占比",
"5日小单净流入-净额",
"5日小单净流入-净占比",
"5日主力净流入最大股",
]
]
elif indicator == "10日":
temp_df.columns = [
"-",
"_",
"名称",
"_",
"10日涨跌幅",
"10日主力净流入-净额",
"10日主力净流入-净占比",
"10日超大单净流入-净额",
"10日超大单净流入-净占比",
"10日大单净流入-净额",
"10日大单净流入-净占比",
"10日中单净流入-净额",
"10日中单净流入-净占比",
"10日小单净流入-净额",
"10日小单净流入-净占比",
"10日主力净流入最大股",
"_",
"_",
]
temp_df = temp_df[
[
"名称",
"10日涨跌幅",
"10日主力净流入-净额",
"10日主力净流入-净占比",
"10日超大单净流入-净额",
"10日超大单净流入-净占比",
"10日大单净流入-净额",
"10日大单净流入-净占比",
"10日中单净流入-净额",
"10日中单净流入-净占比",
"10日小单净流入-净额",
"10日小单净流入-净占比",
"10日主力净流入最大股",
]
]
return temp_df
if __name__ == "__main__":
stock_individual_fund_flow_rank_df = stock_individual_fund_flow_rank(indicator="今日")
print(stock_individual_fund_flow_rank_df)
stock_individual_fund_flow_rank_df = stock_individual_fund_flow_rank(indicator="3日")
print(stock_individual_fund_flow_rank_df)
stock_individual_fund_flow_rank_df = stock_individual_fund_flow_rank(indicator="5日")
print(stock_individual_fund_flow_rank_df)
stock_individual_fund_flow_rank_df = stock_individual_fund_flow_rank(
indicator="10日"
)
print(stock_individual_fund_flow_rank_df)
stock_sector_fund_flow_rank_df = stock_sector_fund_flow_rank(
indicator="5日", sector_type="概念资金流"
)
print(stock_sector_fund_flow_rank_df)
stock_sector_fund_flow_rank_df = stock_sector_fund_flow_rank(
indicator="今日", sector_type="行业资金流"
)
print(stock_sector_fund_flow_rank_df)

View File

@ -0,0 +1,554 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2022/6/19 15:26
Desc: 东方财富网-行情首页-沪深京 A 股
"""
import requests
import pandas as pd
from functools import lru_cache
def stock_zh_a_spot_em() -> pd.DataFrame:
"""
东方财富网-沪深京 A 股-实时行情
https://quote.eastmoney.com/center/gridlist.html#hs_a_board
:return: 实时行情
:rtype: pandas.DataFrame
"""
url = "http://82.push2.eastmoney.com/api/qt/clist/get"
params = {
"pn": "1",
"pz": "50000",
"po": "1",
"np": "1",
"ut": "bd1d9ddb04089700cf9c27f6f7426281",
"fltt": "2",
"invt": "2",
"fid": "f3",
"fs": "m:0 t:6,m:0 t:80,m:1 t:2,m:1 t:23,m:0 t:81 s:2048",
"fields": "f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f14,f15,f16,f17,f18,f20,f21,f22,f23,f24,f25,f26,f37,f38,f39,f40,f41,f45,f46,f48,f49,f57,f61,f100,f112,f113,f114,f115,f221",
"_": "1623833739532",
}
r = requests.get(url, params=params)
data_json = r.json()
if not data_json["data"]["diff"]:
return pd.DataFrame()
temp_df = pd.DataFrame(data_json["data"]["diff"])
temp_df.columns = [
"最新价",
"涨跌幅",
"涨跌额",
"成交量",
"成交额",
"振幅",
"换手率",
"市盈率动",
"量比",
"5分钟涨跌",
"代码",
"名称",
"最高",
"最低",
"今开",
"昨收",
"总市值",
"流通市值",
"涨速",
"市净率",
"60日涨跌幅",
"年初至今涨跌幅",
"上市时间",
"加权净资产收益率",
"总股本",
"已流通股份",
"营业收入",
"营业收入同比增长",
"归属净利润",
"归属净利润同比增长",
"每股未分配利润",
"毛利率",
"资产负债率",
"每股公积金",
"所处行业",
"每股收益",
"每股净资产",
"市盈率静",
"市盈率TTM",
"报告期"
]
temp_df = temp_df[
[
"代码",
"名称",
"最新价",
"涨跌幅",
"涨跌额",
"成交量",
"成交额",
"振幅",
"换手率",
"量比",
"今开",
"最高",
"最低",
"昨收",
"涨速",
"5分钟涨跌",
"60日涨跌幅",
"年初至今涨跌幅",
"市盈率动",
"市盈率TTM",
"市盈率静",
"市净率",
"每股收益",
"每股净资产",
"每股公积金",
"每股未分配利润",
"加权净资产收益率",
"毛利率",
"资产负债率",
"营业收入",
"营业收入同比增长",
"归属净利润",
"归属净利润同比增长",
"报告期",
"总股本",
"已流通股份",
"总市值",
"流通市值",
"所处行业",
"上市时间"
]
]
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_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["5分钟涨跌"] = pd.to_numeric(temp_df["5分钟涨跌"], errors="coerce")
temp_df["60日涨跌幅"] = pd.to_numeric(temp_df["60日涨跌幅"], errors="coerce")
temp_df["年初至今涨跌幅"] = pd.to_numeric(temp_df["年初至今涨跌幅"], errors="coerce")
temp_df["市盈率动"] = pd.to_numeric(temp_df["市盈率动"], errors="coerce")
temp_df["市盈率TTM"] = pd.to_numeric(temp_df["市盈率TTM"], 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_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["报告期"], format='%Y%m%d', 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["上市时间"], format='%Y%m%d', errors="coerce")
return temp_df
@lru_cache()
def code_id_map_em() -> dict:
"""
东方财富-股票和市场代码
http://quote.eastmoney.com/center/gridlist.html#hs_a_board
:return: 股票和市场代码
:rtype: dict
"""
url = "http://80.push2.eastmoney.com/api/qt/clist/get"
params = {
"pn": "1",
"pz": "50000",
"po": "1",
"np": "1",
"ut": "bd1d9ddb04089700cf9c27f6f7426281",
"fltt": "2",
"invt": "2",
"fid": "f3",
"fs": "m:1 t:2,m:1 t:23",
"fields": "f12",
"_": "1623833739532",
}
r = requests.get(url, params=params)
data_json = r.json()
if not data_json["data"]["diff"]:
return dict()
temp_df = pd.DataFrame(data_json["data"]["diff"])
temp_df["market_id"] = 1
temp_df.columns = ["sh_code", "sh_id"]
code_id_dict = dict(zip(temp_df["sh_code"], temp_df["sh_id"]))
params = {
"pn": "1",
"pz": "50000",
"po": "1",
"np": "1",
"ut": "bd1d9ddb04089700cf9c27f6f7426281",
"fltt": "2",
"invt": "2",
"fid": "f3",
"fs": "m:0 t:6,m:0 t:80",
"fields": "f12",
"_": "1623833739532",
}
r = requests.get(url, params=params)
data_json = r.json()
if not data_json["data"]["diff"]:
return dict()
temp_df_sz = pd.DataFrame(data_json["data"]["diff"])
temp_df_sz["sz_id"] = 0
code_id_dict.update(dict(zip(temp_df_sz["f12"], temp_df_sz["sz_id"])))
params = {
"pn": "1",
"pz": "50000",
"po": "1",
"np": "1",
"ut": "bd1d9ddb04089700cf9c27f6f7426281",
"fltt": "2",
"invt": "2",
"fid": "f3",
"fs": "m:0 t:81 s:2048",
"fields": "f12",
"_": "1623833739532",
}
r = requests.get(url, params=params)
data_json = r.json()
if not data_json["data"]["diff"]:
return dict()
temp_df_sz = pd.DataFrame(data_json["data"]["diff"])
temp_df_sz["bj_id"] = 0
code_id_dict.update(dict(zip(temp_df_sz["f12"], temp_df_sz["bj_id"])))
return code_id_dict
def stock_zh_a_hist(
symbol: str = "000001",
period: str = "daily",
start_date: str = "19700101",
end_date: str = "20500101",
adjust: str = "",
) -> pd.DataFrame:
"""
东方财富网-行情首页-沪深京 A 股-每日行情
https://quote.eastmoney.com/concept/sh603777.html?from=classic
: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
:param adjust: choice of {"qfq": "前复权", "hfq": "后复权", "": "不复权"}
:type adjust: str
:return: 每日行情
:rtype: pandas.DataFrame
"""
code_id_dict = code_id_map_em()
adjust_dict = {"qfq": "1", "hfq": "2", "": "0"}
period_dict = {"daily": "101", "weekly": "102", "monthly": "103"}
url = "http://push2his.eastmoney.com/api/qt/stock/kline/get"
params = {
"fields1": "f1,f2,f3,f4,f5,f6",
"fields2": "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61,f116",
"ut": "7eea3edcaed734bea9cbfc24409ed989",
"klt": period_dict[period],
"fqt": adjust_dict[adjust],
"secid": f"{code_id_dict[symbol]}.{symbol}",
"beg": start_date,
"end": end_date,
"_": "1623766962675",
}
r = requests.get(url, params=params)
data_json = r.json()
if not (data_json["data"] and data_json["data"]["klines"]):
return pd.DataFrame()
temp_df = pd.DataFrame(
[item.split(",") for item in data_json["data"]["klines"]]
)
temp_df.columns = [
"日期",
"开盘",
"收盘",
"最高",
"最低",
"成交量",
"成交额",
"振幅",
"涨跌幅",
"涨跌额",
"换手率",
]
temp_df.index = pd.to_datetime(temp_df["日期"])
temp_df.reset_index(inplace=True, drop=True)
temp_df["开盘"] = pd.to_numeric(temp_df["开盘"])
temp_df["收盘"] = pd.to_numeric(temp_df["收盘"])
temp_df["最高"] = pd.to_numeric(temp_df["最高"])
temp_df["最低"] = pd.to_numeric(temp_df["最低"])
temp_df["成交量"] = pd.to_numeric(temp_df["成交量"])
temp_df["成交额"] = pd.to_numeric(temp_df["成交额"])
temp_df["振幅"] = pd.to_numeric(temp_df["振幅"])
temp_df["涨跌幅"] = pd.to_numeric(temp_df["涨跌幅"])
temp_df["涨跌额"] = pd.to_numeric(temp_df["涨跌额"])
temp_df["换手率"] = pd.to_numeric(temp_df["换手率"])
return temp_df
def stock_zh_a_hist_min_em(
symbol: str = "000001",
start_date: str = "1979-09-01 09:32:00",
end_date: str = "2222-01-01 09:32:00",
period: str = "5",
adjust: str = "",
) -> pd.DataFrame:
"""
东方财富网-行情首页-沪深京 A 股-每日分时行情
https://quote.eastmoney.com/concept/sh603777.html?from=classic
:param symbol: 股票代码
:type symbol: str
:param start_date: 开始日期
:type start_date: str
:param end_date: 结束日期
:type end_date: str
:param period: choice of {'1', '5', '15', '30', '60'}
:type period: str
:param adjust: choice of {'', 'qfq', 'hfq'}
:type adjust: str
:return: 每日分时行情
:rtype: pandas.DataFrame
"""
code_id_dict = code_id_map_em()
adjust_map = {
"": "0",
"qfq": "1",
"hfq": "2",
}
if period == "1":
url = "https://push2his.eastmoney.com/api/qt/stock/trends2/get"
params = {
"fields1": "f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13",
"fields2": "f51,f52,f53,f54,f55,f56,f57,f58",
"ut": "7eea3edcaed734bea9cbfc24409ed989",
"ndays": "5",
"iscr": "0",
"secid": f"{code_id_dict[symbol]}.{symbol}",
"_": "1623766962675",
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(
[item.split(",") for item in data_json["data"]["trends"]]
)
temp_df.columns = [
"时间",
"开盘",
"收盘",
"最高",
"最低",
"成交量",
"成交额",
"最新价",
]
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["开盘"])
temp_df["收盘"] = pd.to_numeric(temp_df["收盘"])
temp_df["最高"] = pd.to_numeric(temp_df["最高"])
temp_df["最低"] = pd.to_numeric(temp_df["最低"])
temp_df["成交量"] = pd.to_numeric(temp_df["成交量"])
temp_df["成交额"] = pd.to_numeric(temp_df["成交额"])
temp_df["最新价"] = pd.to_numeric(temp_df["最新价"])
temp_df["时间"] = pd.to_datetime(temp_df["时间"]).astype(str)
return temp_df
else:
url = "http://push2his.eastmoney.com/api/qt/stock/kline/get"
params = {
"fields1": "f1,f2,f3,f4,f5,f6",
"fields2": "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61",
"ut": "7eea3edcaed734bea9cbfc24409ed989",
"klt": period,
"fqt": adjust_map[adjust],
"secid": f"{code_id_dict[symbol]}.{symbol}",
"beg": "0",
"end": "20500000",
"_": "1630930917857",
}
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 = [
"时间",
"开盘",
"收盘",
"最高",
"最低",
"成交量",
"成交额",
"振幅",
"涨跌幅",
"涨跌额",
"换手率",
]
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["开盘"])
temp_df["收盘"] = pd.to_numeric(temp_df["收盘"])
temp_df["最高"] = pd.to_numeric(temp_df["最高"])
temp_df["最低"] = pd.to_numeric(temp_df["最低"])
temp_df["成交量"] = pd.to_numeric(temp_df["成交量"])
temp_df["成交额"] = pd.to_numeric(temp_df["成交额"])
temp_df["振幅"] = pd.to_numeric(temp_df["振幅"])
temp_df["涨跌幅"] = pd.to_numeric(temp_df["涨跌幅"])
temp_df["涨跌额"] = pd.to_numeric(temp_df["涨跌额"])
temp_df["换手率"] = pd.to_numeric(temp_df["换手率"])
temp_df["时间"] = pd.to_datetime(temp_df["时间"]).astype(str)
temp_df = temp_df[
[
"时间",
"开盘",
"收盘",
"最高",
"最低",
"涨跌幅",
"涨跌额",
"成交量",
"成交额",
"振幅",
"换手率",
]
]
return temp_df
def stock_zh_a_hist_pre_min_em(
symbol: str = "000001",
start_time: str = "09:00:00",
end_time: str = "15:50:00",
) -> pd.DataFrame:
"""
东方财富网-行情首页-沪深京 A 股-每日分时行情包含盘前数据
http://quote.eastmoney.com/concept/sh603777.html?from=classic
:param symbol: 股票代码
:type symbol: str
:param start_time: 开始时间
:type start_time: str
:param end_time: 结束时间
:type end_time: str
:return: 每日分时行情包含盘前数据
:rtype: pandas.DataFrame
"""
code_id_dict = code_id_map_em()
url = "https://push2.eastmoney.com/api/qt/stock/trends2/get"
params = {
"fields1": "f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13",
"fields2": "f51,f52,f53,f54,f55,f56,f57,f58",
"ut": "fa5fd1943c7b386f172d6893dbfba10b",
"ndays": "1",
"iscr": "1",
"iscca": "0",
"secid": f"{code_id_dict[symbol]}.{symbol}",
"_": "1623766962675",
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(
[item.split(",") for item in data_json["data"]["trends"]]
)
temp_df.columns = [
"时间",
"开盘",
"收盘",
"最高",
"最低",
"成交量",
"成交额",
"最新价",
]
temp_df.index = pd.to_datetime(temp_df["时间"])
date_format = temp_df.index[0].date().isoformat()
temp_df = temp_df[
date_format + " " + start_time : date_format + " " + end_time
]
temp_df.reset_index(drop=True, inplace=True)
temp_df["开盘"] = pd.to_numeric(temp_df["开盘"])
temp_df["收盘"] = pd.to_numeric(temp_df["收盘"])
temp_df["最高"] = pd.to_numeric(temp_df["最高"])
temp_df["最低"] = pd.to_numeric(temp_df["最低"])
temp_df["成交量"] = pd.to_numeric(temp_df["成交量"])
temp_df["成交额"] = pd.to_numeric(temp_df["成交额"])
temp_df["最新价"] = pd.to_numeric(temp_df["最新价"])
temp_df["时间"] = pd.to_datetime(temp_df["时间"]).astype(str)
return temp_df
if __name__ == "__main__":
stock_zh_a_hist_df = stock_zh_a_hist(
symbol="000858",
period="daily",
start_date="20220516",
end_date="20220722",
adjust="",
)
print(stock_zh_a_hist_df)
exit(0)
stock_zh_a_spot_em_df = stock_zh_a_spot_em()
print(stock_zh_a_spot_em_df)
code_id_map_em_df = code_id_map_em()
print(code_id_map_em_df)
stock_zh_a_hist_df = stock_zh_a_hist(
symbol="430090",
period="daily",
start_date="20220516",
end_date="20220722",
adjust="hfq",
)
print(stock_zh_a_hist_df)
stock_zh_a_hist_min_em_df = stock_zh_a_hist_min_em(symbol="833454", period="1")
print(stock_zh_a_hist_min_em_df)
stock_zh_a_hist_pre_min_em_df = stock_zh_a_hist_pre_min_em(symbol="833454")
print(stock_zh_a_hist_pre_min_em_df)
stock_zh_a_spot_em_df = stock_zh_a_spot_em()
print(stock_zh_a_spot_em_df)
stock_zh_a_hist_min_em_df = stock_zh_a_hist_min_em(
symbol="000001", period='1'
)
print(stock_zh_a_hist_min_em_df)
stock_zh_a_hist_df = stock_zh_a_hist(
symbol="833454",
period="daily",
start_date="20170301",
end_date="20211115",
adjust="hfq",
)
print(stock_zh_a_hist_df)

View File

@ -0,0 +1,888 @@
# -*- coding:utf-8 -*-
# !/usr/bin/env python
"""
Date: 2022/3/15 17:32
Desc: 东方财富网-数据中心-龙虎榜单
https://data.eastmoney.com/stock/tradedetail.html
"""
import pandas as pd
import requests
from tqdm import tqdm
def stock_lhb_detail_em(
start_date: str = "20230403", end_date: str = "20230417"
) -> pd.DataFrame:
"""
东方财富网-数据中心-龙虎榜单-龙虎榜详情
https://data.eastmoney.com/stock/tradedetail.html
:param start_date: 开始日期
:type start_date: str
:param end_date: 结束日期
:type end_date: str
:return: 龙虎榜详情
:rtype: pandas.DataFrame
"""
start_date = "-".join([start_date[:4], start_date[4:6], start_date[6:]])
end_date = "-".join([end_date[:4], end_date[4:6], end_date[6:]])
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
"sortColumns": "SECURITY_CODE,TRADE_DATE",
"sortTypes": "1,-1",
"pageSize": "5000",
"pageNumber": "1",
"reportName": "RPT_DAILYBILLBOARD_DETAILSNEW",
"columns": "SECURITY_CODE,SECUCODE,SECURITY_NAME_ABBR,TRADE_DATE,EXPLAIN,CLOSE_PRICE,CHANGE_RATE,BILLBOARD_NET_AMT,BILLBOARD_BUY_AMT,BILLBOARD_SELL_AMT,BILLBOARD_DEAL_AMT,ACCUM_AMOUNT,DEAL_NET_RATIO,DEAL_AMOUNT_RATIO,TURNOVERRATE,FREE_MARKET_CAP,EXPLANATION,D1_CLOSE_ADJCHRATE,D2_CLOSE_ADJCHRATE,D5_CLOSE_ADJCHRATE,D10_CLOSE_ADJCHRATE,SECURITY_TYPE_CODE",
"source": "WEB",
"client": "WEB",
"filter": f"(TRADE_DATE<='{end_date}')(TRADE_DATE>='{start_date}')",
}
r = requests.get(url, params=params)
data_json = r.json()
total_page_num = data_json["result"]["pages"]
big_df = pd.DataFrame()
for page in range(1, total_page_num + 1):
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([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": "序号",
"SECURITY_CODE": "代码",
"SECUCODE": "-",
"SECURITY_NAME_ABBR": "名称",
"TRADE_DATE": "上榜日",
"EXPLAIN": "解读",
"CLOSE_PRICE": "收盘价",
"CHANGE_RATE": "涨跌幅",
"BILLBOARD_NET_AMT": "龙虎榜净买额",
"BILLBOARD_BUY_AMT": "龙虎榜买入额",
"BILLBOARD_SELL_AMT": "龙虎榜卖出额",
"BILLBOARD_DEAL_AMT": "龙虎榜成交额",
"ACCUM_AMOUNT": "市场总成交额",
"DEAL_NET_RATIO": "净买额占总成交比",
"DEAL_AMOUNT_RATIO": "成交额占总成交比",
"TURNOVERRATE": "换手率",
"FREE_MARKET_CAP": "流通市值",
"EXPLANATION": "上榜原因",
"D1_CLOSE_ADJCHRATE": "上榜后1日",
"D2_CLOSE_ADJCHRATE": "上榜后2日",
"D5_CLOSE_ADJCHRATE": "上榜后5日",
"D10_CLOSE_ADJCHRATE": "上榜后10日",
},
inplace=True,
)
big_df = big_df[
[
"序号",
"代码",
"名称",
"上榜日",
"解读",
"收盘价",
"涨跌幅",
"龙虎榜净买额",
"龙虎榜买入额",
"龙虎榜卖出额",
"龙虎榜成交额",
"市场总成交额",
"净买额占总成交比",
"成交额占总成交比",
"换手率",
"流通市值",
"上榜原因",
"上榜后1日",
"上榜后2日",
"上榜后5日",
"上榜后10日",
]
]
big_df["上榜日"] = pd.to_datetime(big_df["上榜日"]).dt.date
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")
big_df["上榜后1日"] = pd.to_numeric(big_df["上榜后1日"], errors="coerce")
big_df["上榜后2日"] = pd.to_numeric(big_df["上榜后2日"], errors="coerce")
big_df["上榜后5日"] = pd.to_numeric(big_df["上榜后5日"], errors="coerce")
big_df["上榜后10日"] = pd.to_numeric(big_df["上榜后10日"], errors="coerce")
return big_df
def stock_lhb_stock_statistic_em(symbol: str = "近一月") -> pd.DataFrame:
"""
东方财富网-数据中心-龙虎榜单-个股上榜统计
https://data.eastmoney.com/stock/tradedetail.html
:param symbol: choice of {"近一月", "近三月", "近六月", "近一年"}
:type symbol: str
:return: 个股上榜统计
:rtype: pandas.DataFrame
"""
symbol_map = {
"近一月": "01",
"近三月": "02",
"近六月": "03",
"近一年": "04",
}
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
"sortColumns": "BILLBOARD_TIMES,LATEST_TDATE,SECURITY_CODE",
"sortTypes": "-1,-1,1",
"pageSize": "500",
"pageNumber": "1",
"reportName": "RPT_BILLBOARD_TRADEALL",
"columns": "ALL",
"source": "WEB",
"client": "WEB",
"filter": f'(STATISTICS_CYCLE="{symbol_map[symbol]}")',
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(data_json["result"]["data"])
temp_df.reset_index(inplace=True)
temp_df["index"] = temp_df.index + 1
temp_df.columns = [
"序号",
"-",
"代码",
"最近上榜日",
"名称",
"近1个月涨跌幅",
"近3个月涨跌幅",
"近6个月涨跌幅",
"近1年涨跌幅",
"涨跌幅",
"收盘价",
"-",
"龙虎榜总成交额",
"龙虎榜净买额",
"-",
"-",
"机构买入净额",
"上榜次数",
"龙虎榜买入额",
"龙虎榜卖出额",
"机构买入总额",
"机构卖出总额",
"买方机构次数",
"卖方机构次数",
"-",
]
temp_df = temp_df[
[
"序号",
"代码",
"名称",
"最近上榜日",
"收盘价",
"涨跌幅",
"上榜次数",
"龙虎榜净买额",
"龙虎榜买入额",
"龙虎榜卖出额",
"龙虎榜总成交额",
"买方机构次数",
"卖方机构次数",
"机构买入净额",
"机构买入总额",
"机构卖出总额",
"近1个月涨跌幅",
"近3个月涨跌幅",
"近6个月涨跌幅",
"近1年涨跌幅",
]
]
temp_df["最近上榜日"] = pd.to_datetime(temp_df["最近上榜日"]).dt.date
return temp_df
def stock_lhb_jgmmtj_em(
start_date: str = "20220906", end_date: str = "20220906"
) -> pd.DataFrame:
"""
东方财富网-数据中心-龙虎榜单-机构买卖每日统计
https://data.eastmoney.com/stock/jgmmtj.html
:param start_date: 开始日期
:type start_date: str
:param end_date: 结束日期
:type end_date: str
:return: 机构买卖每日统计
:rtype: pandas.DataFrame
"""
start_date = "-".join([start_date[:4], start_date[4:6], start_date[6:]])
end_date = "-".join([end_date[:4], end_date[4:6], end_date[6:]])
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
"sortColumns": "NET_BUY_AMT,TRADE_DATE,SECURITY_CODE",
"sortTypes": "-1,-1,1",
"pageSize": "5000",
"pageNumber": "1",
"reportName": "RPT_ORGANIZATION_TRADE_DETAILS",
"columns": "ALL",
"source": "WEB",
"client": "WEB",
"filter": f"(TRADE_DATE>='{start_date}')(TRADE_DATE<='{end_date}')",
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(data_json["result"]["data"])
temp_df.reset_index(inplace=True)
temp_df["index"] = temp_df.index + 1
temp_df.columns = [
"序号",
"-",
"名称",
"代码",
"上榜日期",
"收盘价",
"涨跌幅",
"买方机构数",
"卖方机构数",
"机构买入总额",
"机构卖出总额",
"机构买入净额",
"市场总成交额",
"机构净买额占总成交额比",
"换手率",
"流通市值",
"上榜原因",
"-",
"-",
"-",
"-",
"-",
"-",
"-",
"-",
"-",
]
temp_df = temp_df[
[
"序号",
"代码",
"名称",
"收盘价",
"涨跌幅",
"买方机构数",
"卖方机构数",
"机构买入总额",
"机构卖出总额",
"机构买入净额",
"市场总成交额",
"机构净买额占总成交额比",
"换手率",
"流通市值",
"上榜原因",
"上榜日期",
]
]
temp_df["上榜日期"] = pd.to_datetime(temp_df["上榜日期"]).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")
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
def stock_lhb_jgstatistic_em(symbol: str = "近一月") -> pd.DataFrame:
"""
东方财富网-数据中心-龙虎榜单-机构席位追踪
https://data.eastmoney.com/stock/jgstatistic.html
:param symbol: choice of {"近一月", "近三月", "近六月", "近一年"}
:type symbol: str
:return: 机构席位追踪
:rtype: pandas.DataFrame
"""
symbol_map = {
"近一月": "01",
"近三月": "02",
"近六月": "03",
"近一年": "04",
}
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
"sortColumns": "ONLIST_TIMES,SECURITY_CODE",
"sortTypes": "-1,1",
"pageSize": "5000",
"pageNumber": "1",
"reportName": "RPT_ORGANIZATION_SEATNEW",
"columns": "ALL",
"source": "WEB",
"client": "WEB",
"filter": f'(STATISTICSCYCLE="{symbol_map[symbol]}")',
}
r = requests.get(url, params=params)
data_json = r.json()
total_page = data_json["result"]["pages"]
big_df = pd.DataFrame()
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([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": "序号",
"SECURITY_CODE": "代码",
"SECURITY_NAME_ABBR": "名称",
"CLOSE_PRICE": "收盘价",
"CHANGE_RATE": "涨跌幅",
"AMOUNT": "龙虎榜成交金额",
"ONLIST_TIMES": "上榜次数",
"BUY_AMT": "机构买入额",
"BUY_TIMES": "机构买入次数",
"SELL_AMT": "机构卖出额",
"SELL_TIMES": "机构卖出次数",
"NET_BUY_AMT": "机构净买额",
"M1_CLOSE_ADJCHRATE": "近1个月涨跌幅",
"M3_CLOSE_ADJCHRATE": "近3个月涨跌幅",
"M6_CLOSE_ADJCHRATE": "近6个月涨跌幅",
"Y1_CLOSE_ADJCHRATE": "近1年涨跌幅",
},
inplace=True,
)
big_df = big_df[
[
"序号",
"代码",
"名称",
"收盘价",
"涨跌幅",
"龙虎榜成交金额",
"上榜次数",
"机构买入额",
"机构买入次数",
"机构卖出额",
"机构卖出次数",
"机构净买额",
"近1个月涨跌幅",
"近3个月涨跌幅",
"近6个月涨跌幅",
"近1年涨跌幅",
]
]
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["近1个月涨跌幅"] = pd.to_numeric(big_df["近1个月涨跌幅"], errors="coerce")
big_df["近3个月涨跌幅"] = pd.to_numeric(big_df["近3个月涨跌幅"], errors="coerce")
big_df["近6个月涨跌幅"] = pd.to_numeric(big_df["近6个月涨跌幅"], errors="coerce")
big_df["近1年涨跌幅"] = pd.to_numeric(big_df["近1年涨跌幅"], errors="coerce")
return big_df
def stock_lhb_hyyyb_em(
start_date: str = "20220324", end_date: str = "20220324"
) -> pd.DataFrame:
"""
东方财富网-数据中心-龙虎榜单-每日活跃营业部
https://data.eastmoney.com/stock/jgmmtj.html
:param start_date: 开始日期
:type start_date: str
:param end_date: 结束日期
:type end_date: str
:return: 每日活跃营业部
:rtype: pandas.DataFrame
"""
start_date = "-".join([start_date[:4], start_date[4:6], start_date[6:]])
end_date = "-".join([end_date[:4], end_date[4:6], end_date[6:]])
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
"sortColumns": "TOTAL_NETAMT,ONLIST_DATE,OPERATEDEPT_CODE",
"sortTypes": "-1,-1,1",
"pageSize": "5000",
"pageNumber": "1",
"reportName": "RPT_OPERATEDEPT_ACTIVE",
"columns": "ALL",
"source": "WEB",
"client": "WEB",
"filter": f"(ONLIST_DATE>='{start_date}')(ONLIST_DATE<='{end_date}')",
}
r = requests.get(url, params=params)
data_json = r.json()
total_page = data_json["result"]["pages"]
big_df = pd.DataFrame()
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([big_df, temp_df], ignore_index=True)
big_df.reset_index(inplace=True)
big_df["index"] = big_df.index + 1
big_df.columns = [
"序号",
"营业部名称",
"上榜日",
"买入个股数",
"卖出个股数",
"买入总金额",
"卖出总金额",
"总买卖净额",
"-",
"-",
"买入股票",
"-",
"-",
]
big_df = big_df[
[
"序号",
"营业部名称",
"上榜日",
"买入个股数",
"卖出个股数",
"买入总金额",
"卖出总金额",
"总买卖净额",
"买入股票",
]
]
big_df["上榜日"] = pd.to_datetime(big_df["上榜日"]).dt.date
big_df["买入个股数"] = pd.to_numeric(big_df["买入个股数"])
big_df["卖出个股数"] = pd.to_numeric(big_df["卖出个股数"])
big_df["买入总金额"] = pd.to_numeric(big_df["买入总金额"])
big_df["卖出总金额"] = pd.to_numeric(big_df["卖出总金额"])
big_df["总买卖净额"] = pd.to_numeric(big_df["总买卖净额"])
return big_df
def stock_lhb_yybph_em(symbol: str = "近一月") -> pd.DataFrame:
"""
东方财富网-数据中心-龙虎榜单-营业部排行
https://data.eastmoney.com/stock/yybph.html
:param symbol: choice of {"近一月", "近三月", "近六月", "近一年"}
:type symbol: str
:return: 营业部排行
:rtype: pandas.DataFrame
"""
symbol_map = {
"近一月": "01",
"近三月": "02",
"近六月": "03",
"近一年": "04",
}
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
"sortColumns": "TOTAL_BUYER_SALESTIMES_1DAY,OPERATEDEPT_CODE",
"sortTypes": "-1,1",
"pageSize": "5000",
"pageNumber": "1",
"reportName": "RPT_RATEDEPT_RETURNT_RANKING",
"columns": "ALL",
"source": "WEB",
"client": "WEB",
"filter": f'(STATISTICSCYCLE="{symbol_map[symbol]}")',
}
r = requests.get(url, params=params)
data_json = r.json()
total_page = data_json["result"]["pages"]
big_df = pd.DataFrame()
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([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": "序号",
"OPERATEDEPT_NAME": "营业部名称",
"TOTAL_BUYER_SALESTIMES_1DAY": "上榜后1天-买入次数",
"AVERAGE_INCREASE_1DAY": "上榜后1天-平均涨幅",
"RISE_PROBABILITY_1DAY": "上榜后1天-上涨概率",
"TOTAL_BUYER_SALESTIMES_2DAY": "上榜后2天-买入次数",
"AVERAGE_INCREASE_2DAY": "上榜后2天-平均涨幅",
"RISE_PROBABILITY_2DAY": "上榜后2天-上涨概率",
"TOTAL_BUYER_SALESTIMES_3DAY": "上榜后3天-买入次数",
"AVERAGE_INCREASE_3DAY": "上榜后3天-平均涨幅",
"RISE_PROBABILITY_3DAY": "上榜后3天-上涨概率",
"TOTAL_BUYER_SALESTIMES_5DAY": "上榜后5天-买入次数",
"AVERAGE_INCREASE_5DAY": "上榜后5天-平均涨幅",
"RISE_PROBABILITY_5DAY": "上榜后5天-上涨概率",
"TOTAL_BUYER_SALESTIMES_10DAY": "上榜后10天-买入次数",
"AVERAGE_INCREASE_10DAY": "上榜后10天-平均涨幅",
"RISE_PROBABILITY_10DAY": "上榜后10天-上涨概率",
},
inplace=True,
)
big_df = big_df[
[
"序号",
"营业部名称",
"上榜后1天-买入次数",
"上榜后1天-平均涨幅",
"上榜后1天-上涨概率",
"上榜后2天-买入次数",
"上榜后2天-平均涨幅",
"上榜后2天-上涨概率",
"上榜后3天-买入次数",
"上榜后3天-平均涨幅",
"上榜后3天-上涨概率",
"上榜后5天-买入次数",
"上榜后5天-平均涨幅",
"上榜后5天-上涨概率",
"上榜后10天-买入次数",
"上榜后10天-平均涨幅",
"上榜后10天-上涨概率",
]
]
big_df["上榜后1天-买入次数"] = pd.to_numeric(big_df["上榜后1天-买入次数"], errors="coerce")
big_df["上榜后1天-平均涨幅"] = pd.to_numeric(big_df["上榜后1天-平均涨幅"], errors="coerce")
big_df["上榜后1天-上涨概率"] = pd.to_numeric(big_df["上榜后1天-上涨概率"], errors="coerce")
big_df["上榜后2天-买入次数"] = pd.to_numeric(big_df["上榜后2天-买入次数"], errors="coerce")
big_df["上榜后2天-平均涨幅"] = pd.to_numeric(big_df["上榜后2天-平均涨幅"], errors="coerce")
big_df["上榜后2天-上涨概率"] = pd.to_numeric(big_df["上榜后2天-上涨概率"], errors="coerce")
big_df["上榜后3天-买入次数"] = pd.to_numeric(big_df["上榜后3天-买入次数"], errors="coerce")
big_df["上榜后3天-平均涨幅"] = pd.to_numeric(big_df["上榜后3天-平均涨幅"], errors="coerce")
big_df["上榜后3天-上涨概率"] = pd.to_numeric(big_df["上榜后3天-上涨概率"], errors="coerce")
big_df["上榜后5天-买入次数"] = pd.to_numeric(big_df["上榜后5天-买入次数"], errors="coerce")
big_df["上榜后5天-平均涨幅"] = pd.to_numeric(big_df["上榜后5天-平均涨幅"], errors="coerce")
big_df["上榜后5天-上涨概率"] = pd.to_numeric(big_df["上榜后5天-上涨概率"], errors="coerce")
big_df["上榜后10天-买入次数"] = pd.to_numeric(big_df["上榜后10天-买入次数"], errors="coerce")
big_df["上榜后10天-平均涨幅"] = pd.to_numeric(big_df["上榜后10天-平均涨幅"], errors="coerce")
big_df["上榜后10天-上涨概率"] = pd.to_numeric(big_df["上榜后10天-上涨概率"], errors="coerce")
return big_df
def stock_lhb_traderstatistic_em(symbol: str = "近一月") -> pd.DataFrame:
"""
东方财富网-数据中心-龙虎榜单-营业部统计
https://data.eastmoney.com/stock/traderstatistic.html
:param symbol: choice of {"近一月", "近三月", "近六月", "近一年"}
:type symbol: str
:return: 营业部统计
:rtype: pandas.DataFrame
"""
symbol_map = {
"近一月": "01",
"近三月": "02",
"近六月": "03",
"近一年": "04",
}
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
"sortColumns": "AMOUNT,OPERATEDEPT_CODE",
"sortTypes": "-1,1",
"pageSize": "5000",
"pageNumber": "1",
"reportName": "RPT_OPERATEDEPT_LIST_STATISTICS",
"columns": "ALL",
"source": "WEB",
"client": "WEB",
"filter": f'(STATISTICSCYCLE="{symbol_map[symbol]}")',
}
r = requests.get(url, params=params)
data_json = r.json()
total_page = data_json["result"]["pages"]
big_df = pd.DataFrame()
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([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": "序号",
"OPERATEDEPT_NAME": "营业部名称",
"AMOUNT": "龙虎榜成交金额",
"SALES_ONLIST_TIMES": "上榜次数",
"ACT_BUY": "买入额",
"TOTAL_BUYER_SALESTIMES": "买入次数",
"ACT_SELL": "卖出额",
"TOTAL_SELLER_SALESTIMES": "卖出次数",
},
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")
return big_df
def stock_lhb_stock_detail_date_em(symbol: str = "600077") -> pd.DataFrame:
"""
东方财富网-数据中心-龙虎榜单-个股龙虎榜详情-日期
https://data.eastmoney.com/stock/tradedetail.html
:param symbol: 股票代码
:type symbol: str
:return: 个股龙虎榜详情-日期
:rtype: pandas.DataFrame
"""
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
"reportName": "RPT_LHB_BOARDDATE",
"columns": "SECURITY_CODE,TRADE_DATE,TR_DATE",
"filter": f'(SECURITY_CODE="{symbol}")',
"pageNumber": "1",
"pageSize": "1000",
"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.reset_index(inplace=True)
temp_df["index"] = temp_df.index + 1
temp_df.columns = [
"序号",
"股票代码",
"交易日",
"-",
]
temp_df = temp_df[
[
"序号",
"股票代码",
"交易日",
]
]
temp_df["交易日"] = pd.to_datetime(temp_df["交易日"]).dt.date
return temp_df
def stock_lhb_stock_detail_em(
symbol: str = "000788", date: str = "20220315", flag: str = "卖出"
) -> pd.DataFrame:
"""
东方财富网-数据中心-龙虎榜单-个股龙虎榜详情
https://data.eastmoney.com/stock/lhb/600077.html
:param symbol: 股票代码
:type symbol: str
:param date: 查询日期; 需要通过 ak.stock_lhb_stock_detail_date_em(symbol="600077") 接口获取相应股票的有龙虎榜详情数据的日期
:type date: str
:param flag: choice of {"买入", "卖出"}
:type flag: str
:return: 个股龙虎榜详情
:rtype: pandas.DataFrame
"""
flag_map = {
"买入": "BUY",
"卖出": "SELL",
}
report_map = {
"买入": "RPT_BILLBOARD_DAILYDETAILSBUY",
"卖出": "RPT_BILLBOARD_DAILYDETAILSSELL",
}
url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
params = {
"reportName": report_map[flag],
"columns": "ALL",
"filter": f"""(TRADE_DATE='{'-'.join([date[:4], date[4:6], date[6:]])}')(SECURITY_CODE="{symbol}")""",
"pageNumber": "1",
"pageSize": "500",
"sortTypes": "-1",
"sortColumns": flag_map[flag],
"source": "WEB",
"client": "WEB",
"_": "1647338693644",
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame(data_json["result"]["data"])
temp_df.reset_index(inplace=True)
temp_df["index"] = temp_df.index + 1
if flag == "买入":
temp_df.columns = [
"序号",
"-",
"-",
"-",
"-",
"交易营业部名称",
"类型",
"-",
"-",
"-",
"-",
"买入金额",
"卖出金额",
"净额",
"-",
"-",
"-",
"-",
"买入金额-占总成交比例",
"卖出金额-占总成交比例",
"-",
]
temp_df = temp_df[
[
"序号",
"交易营业部名称",
"买入金额",
"买入金额-占总成交比例",
"卖出金额",
"卖出金额-占总成交比例",
"净额",
"类型",
]
]
temp_df["买入金额"] = pd.to_numeric(temp_df["买入金额"])
temp_df["买入金额-占总成交比例"] = pd.to_numeric(temp_df["买入金额-占总成交比例"])
temp_df["卖出金额"] = pd.to_numeric(temp_df["卖出金额"])
temp_df["卖出金额-占总成交比例"] = pd.to_numeric(temp_df["卖出金额-占总成交比例"])
temp_df.sort_values("类型", inplace=True)
temp_df.reset_index(inplace=True, drop=True)
temp_df["序号"] = range(1, len(temp_df["序号"]) + 1)
else:
temp_df.columns = [
"序号",
"-",
"-",
"-",
"-",
"交易营业部名称",
"类型",
"-",
"-",
"-",
"-",
"买入金额",
"卖出金额",
"净额",
"-",
"-",
"-",
"-",
"买入金额-占总成交比例",
"卖出金额-占总成交比例",
"-",
]
temp_df = temp_df[
[
"序号",
"交易营业部名称",
"买入金额",
"买入金额-占总成交比例",
"卖出金额",
"卖出金额-占总成交比例",
"净额",
"类型",
]
]
temp_df["买入金额"] = pd.to_numeric(temp_df["买入金额"])
temp_df["买入金额-占总成交比例"] = pd.to_numeric(temp_df["买入金额-占总成交比例"])
temp_df["卖出金额"] = pd.to_numeric(temp_df["卖出金额"])
temp_df["卖出金额-占总成交比例"] = pd.to_numeric(temp_df["卖出金额-占总成交比例"])
temp_df.sort_values("类型", inplace=True)
temp_df.reset_index(inplace=True, drop=True)
temp_df["序号"] = range(1, len(temp_df["序号"]) + 1)
return temp_df
if __name__ == "__main__":
stock_lhb_detail_em_df = stock_lhb_detail_em(
start_date="20230403", end_date="20230417"
)
print(stock_lhb_detail_em_df)
stock_lhb_stock_statistic_em_df = stock_lhb_stock_statistic_em(symbol="近一月")
print(stock_lhb_stock_statistic_em_df)
stock_lhb_stock_statistic_em_df = stock_lhb_stock_statistic_em(symbol="近三月")
print(stock_lhb_stock_statistic_em_df)
stock_lhb_stock_statistic_em_df = stock_lhb_stock_statistic_em(symbol="近六月")
print(stock_lhb_stock_statistic_em_df)
stock_lhb_stock_statistic_em_df = stock_lhb_stock_statistic_em(symbol="近一年")
print(stock_lhb_stock_statistic_em_df)
stock_lhb_jgmmtj_em_df = stock_lhb_jgmmtj_em(
start_date="20220904", end_date="20220906"
)
print(stock_lhb_jgmmtj_em_df)
stock_lhb_jgstatistic_em_df = stock_lhb_jgstatistic_em(symbol="近一月")
print(stock_lhb_jgstatistic_em_df)
stock_lhb_hyyyb_em_df = stock_lhb_hyyyb_em(
start_date="20220324", end_date="20220324"
)
print(stock_lhb_hyyyb_em_df)
stock_lhb_yybph_em_df = stock_lhb_yybph_em(symbol="近一月")
print(stock_lhb_yybph_em_df)
stock_lhb_traderstatistic_em_df = stock_lhb_traderstatistic_em(symbol="近一月")
print(stock_lhb_traderstatistic_em_df)
stock_lhb_stock_detail_date_em_df = stock_lhb_stock_detail_date_em(symbol="002901")
print(stock_lhb_stock_detail_date_em_df)
stock_lhb_stock_detail_em_df = stock_lhb_stock_detail_em(
symbol="002901", date="20221012", flag="买入"
)
print(stock_lhb_stock_detail_em_df)
stock_lhb_stock_detail_em_df = stock_lhb_stock_detail_em(
symbol="600016", date="20220324", flag="买入"
)
print(stock_lhb_stock_detail_em_df)

View File

@ -0,0 +1,216 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2022/11/19 12:00
Desc: 新浪财经-龙虎榜
https://vip.stock.finance.sina.com.cn/q/go.php/vInvestConsult/kind/lhb/index.phtml
"""
import pandas as pd
import requests
from bs4 import BeautifulSoup
from tqdm import tqdm
def stock_lhb_detail_daily_sina(
trade_date: str = "20200730", symbol: str = "当日无价格涨跌幅限制的A股出现异常波动停牌的股票"
) -> pd.DataFrame:
"""
龙虎榜-每日详情
http://vip.stock.finance.sina.com.cn/q/go.php/vInvestConsult/kind/lhb/index.phtml
:param trade_date: 交易日, e.g., trade_date="20200729"
:type trade_date: str
:param symbol: 指定标题
:type symbol: str
:return: 龙虎榜-每日详情
:rtype: pandas.DataFrame
"""
trade_date = "-".join([trade_date[:4], trade_date[4:6], trade_date[6:]])
url = "http://vip.stock.finance.sina.com.cn/q/go.php/vInvestConsult/kind/lhb/index.phtml"
params = {"tradedate": trade_date}
r = requests.get(url, params=params)
soup = BeautifulSoup(r.text, "lxml")
table_name_list = [
item.get_text().strip()
for item in soup.find_all(
"span", attrs={"style": "font-weight:bold;font-size:14px;"}
)
if item.get_text().strip() != ""
]
if symbol == "返回当前交易日所有可查询的指标":
return table_name_list
else:
position_num = table_name_list.index(symbol)
if len(table_name_list) == position_num + 1:
temp_df_1 = pd.read_html(r.text, flavor='bs4', header=1)[position_num].iloc[0:, :]
temp_df_2 = pd.read_html(r.text, flavor='bs4', header=1)[position_num + 1].iloc[0:, :]
temp_df_3 = pd.read_html(r.text, flavor='bs4', header=1)[position_num + 2].iloc[0:, :]
temp_df = pd.concat([temp_df_1, temp_df_2, temp_df_3], ignore_index=True)
else:
temp_df = pd.read_html(r.text, flavor='bs4', header=1)[position_num].iloc[0:, :]
temp_df["股票代码"] = temp_df["股票代码"].astype(str).str.zfill(6)
del temp_df["查看详情"]
temp_df.columns = ["序号", "股票代码", "股票名称", "收盘价", "对应值", "成交量", "成交额"]
return temp_df
def _find_last_page(url: str = None, recent_day: str = "60"):
url = "http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/ggtj/index.phtml"
params = {
"last": recent_day,
"p": "1",
}
r = requests.get(url, params=params)
soup = BeautifulSoup(r.text, "lxml")
try:
previous_page = int(soup.find_all(attrs={"class": "page"})[-2].text)
except:
previous_page = 1
if previous_page != 1:
while True:
params = {
"last": recent_day,
"p": previous_page,
}
r = requests.get(url, params=params)
soup = BeautifulSoup(r.text, "lxml")
last_page = int(soup.find_all(attrs={"class": "page"})[-2].text)
if last_page != previous_page:
previous_page = last_page
continue
else:
break
return previous_page
def stock_lhb_ggtj_sina(recent_day: str = "30") -> pd.DataFrame:
"""
龙虎榜-个股上榜统计
http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/ggtj/index.phtml
:param recent_day: choice of {"5": 最近 5 天; "10": 最近 10 天; "30": 最近 30 天; "60": 最近 60 天;}
:type recent_day: str
:return: 龙虎榜-每日详情
:rtype: pandas.DataFrame
"""
url = "http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/ggtj/index.phtml"
last_page_num = _find_last_page(url, recent_day)
big_df = pd.DataFrame()
for page in tqdm(range(1, last_page_num + 1), leave=False):
params = {
"last": recent_day,
"p": page,
}
r = requests.get(url, params=params)
temp_df = pd.read_html(r.text)[0].iloc[0:, :]
big_df = pd.concat([big_df, temp_df], ignore_index=True)
big_df["股票代码"] = big_df["股票代码"].astype(str).str.zfill(6)
big_df.columns = ["股票代码", "股票名称", "上榜次数", "累积购买额", "累积卖出额", "净额", "买入席位数", "卖出席位数"]
return big_df
def stock_lhb_yytj_sina(recent_day: str = "5") -> pd.DataFrame:
"""
龙虎榜-营业部上榜统计
http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/yytj/index.phtml
:param recent_day: choice of {"5": 最近 5 天; "10": 最近 10 天; "30": 最近 30 天; "60": 最近 60 天;}
:type recent_day: str
:return: 龙虎榜-营业部上榜统计
:rtype: pandas.DataFrame
"""
url = "http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/yytj/index.phtml"
last_page_num = _find_last_page(url, recent_day)
big_df = pd.DataFrame()
for page in tqdm(range(1, last_page_num + 1), leave=False):
params = {
"last": "5",
"p": page,
}
r = requests.get(url, params=params)
temp_df = pd.read_html(r.text)[0].iloc[0:, :]
big_df = pd.concat([big_df, temp_df], ignore_index=True)
big_df.columns = ["营业部名称", "上榜次数", "累积购买额", "买入席位数", "累积卖出额", "卖出席位数", "买入前三股票"]
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 stock_lhb_jgzz_sina(recent_day: str = "5") -> pd.DataFrame:
"""
龙虎榜-机构席位追踪
http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/jgzz/index.phtml
:param recent_day: choice of {"5": 最近 5 天; "10": 最近 10 天; "30": 最近 30 天; "60": 最近 60 天;}
:type recent_day: str
:return: 龙虎榜-机构席位追踪
:rtype: pandas.DataFrame
"""
url = "http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/jgzz/index.phtml"
last_page_num = _find_last_page(url, recent_day)
big_df = pd.DataFrame()
for page in tqdm(range(1, last_page_num + 1), leave=False):
params = {
"last": recent_day,
"p": page,
}
r = requests.get(url, params=params)
temp_df = pd.read_html(r.text)[0].iloc[0:, :]
big_df = pd.concat([big_df, temp_df], ignore_index=True)
big_df["股票代码"] = big_df["股票代码"].astype(str).str.zfill(6)
del big_df["当前价"]
del big_df["涨跌幅"]
big_df.columns = ["股票代码", "股票名称", "累积买入额", "买入次数", "累积卖出额", "卖出次数", "净额"]
big_df['买入次数'] = pd.to_numeric(big_df['买入次数'], errors="coerce")
big_df['卖出次数'] = pd.to_numeric(big_df['卖出次数'], errors="coerce")
return big_df
def stock_lhb_jgmx_sina() -> pd.DataFrame:
"""
龙虎榜-机构席位成交明细
http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/jgmx/index.phtml
:return: 龙虎榜-机构席位成交明细
:rtype: pandas.DataFrame
"""
url = "http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/jgmx/index.phtml"
params = {
"p": "1",
}
r = requests.get(url, params=params)
soup = BeautifulSoup(r.text, "lxml")
try:
last_page_num = int(soup.find_all(attrs={"class": "page"})[-2].text)
except:
last_page_num = 1
big_df = pd.DataFrame()
for page in tqdm(range(1, last_page_num + 1), leave=False):
params = {
"p": page,
}
r = requests.get(url, params=params)
temp_df = pd.read_html(r.text)[0].iloc[0:, :]
big_df = pd.concat([big_df, temp_df], ignore_index=True)
big_df["股票代码"] = big_df["股票代码"].astype(str).str.zfill(6)
return big_df
if __name__ == "__main__":
indicator_name_list = stock_lhb_detail_daily_sina(
trade_date="20221118", symbol="返回当前交易日所有可查询的指标"
)
print(indicator_name_list)
stock_lhb_detail_daily_sina_df = stock_lhb_detail_daily_sina(
trade_date="20221118", symbol="换手率达20%的证券"
)
print(stock_lhb_detail_daily_sina_df)
stock_lhb_ggtj_sina_df = stock_lhb_ggtj_sina(recent_day="60")
print(stock_lhb_ggtj_sina_df)
stock_lhb_yytj_sina_df = stock_lhb_yytj_sina(recent_day="60")
print(stock_lhb_yytj_sina_df)
stock_lhb_jgzz_sina_df = stock_lhb_jgzz_sina(recent_day="30")
print(stock_lhb_jgzz_sina_df)
stock_lhb_jgmx_sina_df = stock_lhb_jgmx_sina()
print(stock_lhb_jgmx_sina_df)

View File

@ -0,0 +1,79 @@
# -*- coding:utf-8 -*-
# !/usr/bin/env python
import pandas as pd
import requests
import instock.core.tablestructure as tbs
__author__ = 'myh '
__date__ = '2023/5/9 '
def stock_selection() -> pd.DataFrame:
"""
东方财富网-个股-选股器
https://data.eastmoney.com/xuangu/
:return: 选股器
:rtype: pandas.DataFrame
"""
cols = tbs.TABLE_CN_STOCK_SELECTION['columns']
sty = "" # 初始值 "SECUCODE,SECURITY_CODE,SECURITY_NAME_ABBR,CHANGE_RATE"
for k in cols:
sty = f"{sty},{cols[k]['map']}"
url = "https://data.eastmoney.com/dataapi/xuangu/list"
params = {
"sty": sty[1:],
"filter": "(MARKET+in+(\"上交所主板\",\"深交所主板\",\"深交所创业板\"))(NEW_PRICE>0)",
"p": 1,
"ps": 10000,
"source": "SELECT_SECURITIES",
"client": "WEB"
}
r = requests.get(url, params=params)
data_json = r.json()
data = data_json["result"]["data"]
if not data:
return pd.DataFrame()
temp_df = pd.DataFrame(data)
mask = ~temp_df['CONCEPT'].isna()
temp_df.loc[mask, 'CONCEPT'] = temp_df.loc[mask, 'CONCEPT'].apply(lambda x: ', '.join(x))
mask = ~temp_df['STYLE'].isna()
temp_df.loc[mask, 'STYLE'] = temp_df.loc[mask, 'STYLE'].apply(lambda x: ', '.join(x))
for k in cols:
t = tbs.get_field_type_name(cols[k]["type"])
if t == 'numeric':
temp_df[cols[k]["map"]] = pd.to_numeric(temp_df[cols[k]["map"]], errors="coerce")
elif t == 'datetime':
temp_df[cols[k]["map"]] = pd.to_datetime(temp_df[cols[k]["map"]], errors="coerce").dt.date
return temp_df
def stock_selection_params():
"""
东方财富网-个股-选股器-选股指标
https://data.eastmoney.com/xuangu/
:return: 选股器-选股指标
:rtype: pandas.DataFrame
"""
url = "https://datacenter-web.eastmoney.com/wstock/selection/api/data/get"
params = {
"type": "RPTA_PCNEW_WHOLE",
"sty": "ALL",
"p": 1,
"ps": 50000,
"source": "SELECT_SECURITIES",
"client": "WEB"
}
r = requests.get(url, params=params)
data_json = r.json()
zxzb = data_json["zxzb"] # 指标
print(zxzb)
if __name__ == "__main__":
stock_selection_df = stock_selection()
print(stock_selection)

View File

@ -0,0 +1,331 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2022/10/1 19:27
Desc: 新浪财经-交易日历
https://finance.sina.com.cn/realstock/company/klc_td_sh.txt
此处可以用来更新 calendar.json 文件,注意末尾没有 ","
"""
import datetime
import pandas as pd
import requests
from py_mini_racer import py_mini_racer
hk_js_decode = """
function d(t) {
var e, i, n, r, a, o, s, l = (arguments,
864e5), u = 7657, c = [], h = [], d = ~(3 << 30), f = 1 << 30,
p = [0, 3, 5, 6, 9, 10, 12, 15, 17, 18, 20, 23, 24, 27, 29, 30], m = Math, g = function () {
var l, u;
for (l = 0; 64 > l; l++)
h[l] = m.pow(2, l),
26 > l && (c[l] = v(l + 65),
c[l + 26] = v(l + 97),
10 > l && (c[l + 52] = v(l + 48)));
for (c.push("+", "/"),
c = c.join(""),
i = t.split(""),
n = i.length,
l = 0; n > l; l++)
i[l] = c.indexOf(i[l]);
return r = {},
e = o = 0,
a = {},
u = w([12, 6]),
s = 63 ^ u[1],
{
_1479: T,
_136: _,
_200: S,
_139: k,
_197: _mi_run
}["_" + u[0]] || function () {
return []
}
}, v = String.fromCharCode, b = function (t) {
return t === {}._
}, N = function () {
var t, e;
for (t = y(),
e = 1; ;) {
if (!y())
return e * (2 * t - 1);
e++
}
}, y = function () {
var t;
return e >= n ? 0 : (t = i[e] & 1 << o,
o++,
o >= 6 && (o -= 6,
e++),
!!t)
}, w = function (t, r, a) {
var s, l, u, c, d;
for (l = [],
u = 0,
r || (r = []),
a || (a = []),
s = 0; s < t.length; s++)
if (c = t[s],
u = 0,
c) {
if (e >= n)
return l;
if (t[s] <= 0)
u = 0;
else if (t[s] <= 30) {
for (; d = 6 - o,
d = c > d ? d : c,
u |= (i[e] >> o & (1 << d) - 1) << t[s] - c,
o += d,
o >= 6 && (o -= 6,
e++),
c -= d,
!(0 >= c);)
;
r[s] && u >= h[t[s] - 1] && (u -= h[t[s]])
} else
u = w([30, t[s] - 30], [0, r[s]]),
a[s] || (u = u[0] + u[1] * h[30]);
l[s] = u
} else
l[s] = 0;
return l
}, x = function (t) {
var e, i, n;
for (t > 1 && (e = 0),
e = 0; t > e; e++)
r.d++,
n = r.d % 7,
(3 == n || 4 == n) && (r.d += 5 - n);
return i = new Date,
i.setTime((u + r.d) * l),
i
}, S = function () {
var t, i, a, o, l;
if (s >= 1)
return [];
for (r.d = w([18], [1])[0] - 1,
a = w([3, 3, 30, 6]),
r.p = a[0],
r.ld = a[1],
r.cd = a[2],
r.c = a[3],
r.m = m.pow(10, r.p),
r.pc = r.cd / r.m,
i = [],
t = 0; o = {
d: 1
},
y() && (a = w([3])[0],
0 == a ? o.d = w([6])[0] : 1 == a ? (r.d = w([18])[0],
o.d = 0) : o.d = a),
l = {
day: x(o.d)
},
y() && (r.ld += N()),
a = w([3 * r.ld], [1]),
r.cd += a[0],
l.close = r.cd / r.m,
i.push(l),
!(e >= n) && (e != n - 1 || 63 & (r.c ^ t + 1)); t++)
;
return i[0].prevclose = r.pc,
i
}, _ = function () {
var t, i, a, o, l, u, c, h, d, f, p;
if (s > 2)
return [];
for (c = [],
d = {
v: "volume",
p: "price",
a: "avg_price"
},
r.d = w([18], [1])[0] - 1,
h = {
day: x(1)
},
a = w(1 > s ? [3, 3, 4, 1, 1, 1, 5] : [4, 4, 4, 1, 1, 1, 3]),
t = 0; 7 > t; t++)
r[["la", "lp", "lv", "tv", "rv", "zv", "pp"][t]] = a[t];
for (r.m = m.pow(10, r.pp),
s >= 1 ? (a = w([3, 3]),
r.c = a[0],
a = a[1]) : (a = 5,
r.c = 2),
r.pc = w([6 * a])[0],
h.pc = r.pc / r.m,
r.cp = r.pc,
r.da = 0,
r.sa = r.sv = 0,
t = 0; !(e >= n) && (e != n - 1 || 7 & (r.c ^ t)); t++) {
for (l = {},
o = {},
f = r.tv ? y() : 1,
i = 0; 3 > i; i++)
if (p = ["v", "p", "a"][i],
(f ? y() : 0) && (a = N(),
r["l" + p] += a),
u = "v" == p && r.rv ? y() : 1,
a = w([3 * r["l" + p] + ("v" == p ? 7 * u : 0)], [!!i])[0] * (u ? 1 : 100),
o[p] = a,
"v" == p) {
if (!(l[d[p]] = a) && (s > 1 || 241 > t) && (r.zv ? !y() : 1)) {
o.p = 0;
break
}
} else
"a" == p && (r.da = (1 > s ? 0 : r.da) + o.a);
r.sv += o.v,
l[d.p] = (r.cp += o.p) / r.m,
r.sa += o.v * r.cp,
l[d.a] = b(o.a) ? t ? c[t - 1][d.a] : l[d.p] : r.sv ? ((m.floor((r.sa * (2e3 / r.m) + r.sv) / r.sv) >> 1) + r.da) / 1e3 : l[d.p] + r.da / 1e3,
c.push(l)
}
return c[0].date = h.day,
c[0].prevclose = h.pc,
c
}, T = function () {
var t, e, i, n, a, o, l;
if (s >= 1)
return [];
for (r.lv = 0,
r.ld = 0,
r.cd = 0,
r.cv = [0, 0],
r.p = w([6])[0],
r.d = w([18], [1])[0] - 1,
r.m = m.pow(10, r.p),
a = w([3, 3]),
r.md = a[0],
r.mv = a[1],
t = []; a = w([6]),
a.length;) {
if (i = {
c: a[0]
},
n = {},
i.d = 1,
32 & i.c)
for (; ;) {
if (a = w([6])[0],
63 == (16 | a)) {
l = 16 & a ? "x" : "u",
a = w([3, 3]),
i[l + "_d"] = a[0] + r.md,
i[l + "_v"] = a[1] + r.mv;
break
}
if (32 & a) {
o = 8 & a ? "d" : "v",
l = 16 & a ? "x" : "u",
i[l + "_" + o] = (7 & a) + r["m" + o];
break
}
if (o = 15 & a,
0 == o ? i.d = w([6])[0] : 1 == o ? (r.d = o = w([18])[0],
i.d = 0) : i.d = o,
!(16 & a))
break
}
n.date = x(i.d);
for (o in {
v: 0,
d: 0
})
b(i["x_" + o]) || (r["l" + o] = i["x_" + o]),
b(i["u_" + o]) && (i["u_" + o] = r["l" + o]);
for (i.l_l = [i.u_d, i.u_d, i.u_d, i.u_d, i.u_v],
l = p[15 & i.c],
1 & i.u_v && (l = 31 - l),
16 & i.c && (i.l_l[4] += 2),
e = 0; 5 > e; e++)
l & 1 << 4 - e && i.l_l[e]++,
i.l_l[e] *= 3;
i.d_v = w(i.l_l, [1, 0, 0, 1, 1], [0, 0, 0, 0, 1]),
o = r.cd + i.d_v[0],
n.open = o / r.m,
n.high = (o + i.d_v[1]) / r.m,
n.low = (o - i.d_v[2]) / r.m,
n.close = (o + i.d_v[3]) / r.m,
a = i.d_v[4],
"number" == typeof a && (a = [a, a >= 0 ? 0 : -1]),
r.cd = o + i.d_v[3],
l = r.cv[0] + a[0],
r.cv = [l & d, r.cv[1] + a[1] + !!((r.cv[0] & d) + (a[0] & d) & f)],
n.volume = (r.cv[0] & f - 1) + r.cv[1] * f,
t.push(n)
}
return t
}, k = function () {
var t, e, i, n;
if (s > 1)
return [];
for (r.l = 0,
n = -1,
r.d = w([18])[0] - 1,
i = w([18])[0]; r.d < i;)
e = x(1),
0 >= n ? (y() && (r.l += N()),
n = w([3 * r.l], [0])[0] + 1,
t || (t = [e],
n--)) : t.push(e),
n--;
return t
};
return _mi_run = function () {
var t, i, a, o;
if (s >= 1)
return [];
for (r.f = w([6])[0],
r.c = w([6])[0],
a = [],
r.dv = [],
r.dl = [],
t = 0; t < r.f; t++)
r.dv[t] = 0,
r.dl[t] = 0;
for (t = 0; !(e >= n) && (e != n - 1 || 7 & (r.c ^ t)); t++) {
for (o = [],
i = 0; i < r.f; i++)
y() && (r.dl[i] += N()),
r.dv[i] += w([3 * r.dl[i]], [1])[0],
o[i] = r.dv[i];
a.push(o)
}
return a
}
,
g()()
}
"""
def tool_trade_date_hist_sina() -> pd.DataFrame:
"""
交易日历-历史数据
https://finance.sina.com.cn/realstock/company/klc_td_sh.txt
:return: 交易日历
:rtype: pandas.DataFrame
"""
url = "https://finance.sina.com.cn/realstock/company/klc_td_sh.txt"
r = requests.get(url)
js_code = py_mini_racer.MiniRacer()
js_code.eval(hk_js_decode)
dict_list = js_code.call(
"d", r.text.split("=")[1].split(";")[0].replace('"', "")
) # 执行js解密代码
temp_df = pd.DataFrame(dict_list)
temp_df.columns = ["trade_date"]
temp_df["trade_date"] = pd.to_datetime(temp_df["trade_date"]).dt.date
temp_list = temp_df["trade_date"].to_list()
temp_list.append(datetime.date(1992, 5, 4)) # 是交易日但是交易日历缺失该日期
temp_list.sort()
temp_df = pd.DataFrame(temp_list, columns=["trade_date"])
return temp_df
if __name__ == "__main__":
tool_trade_date_hist_df = tool_trade_date_hist_sina()
print(tool_trade_date_hist_df)

View File

@ -0,0 +1,101 @@
"""
Script Name:
Description: 从富途获取复权因子数据。
参考地址: https://openapi.futunn.com/futu-api-doc/quote/get-rehab.html
Author: [Your Name]
Created Date: YYYY-MM-DD
Last Modified: YYYY-MM-DD
Version: 1.0
Modification History:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
"""
import logging
import pymysql
import time
from futu import *
import pandas as pd
import config
# 设置日志
config.setup_logging()
# 连接 MySQL 数据库
def get_mysql_connection():
return pymysql.connect(**config.db_config)
# 获取股票代码列表
def get_stock_codes(table_name):
connection = get_mysql_connection()
with connection.cursor(pymysql.cursors.DictCursor) as cursor:
cursor.execute(f"SELECT code, code_name FROM {table_name} ")
result = cursor.fetchall()
connection.close()
return result
# 插入或更新复权信息
def insert_or_update_rehab_data(connection, rehab_data, code, name):
try:
with connection.cursor() as cursor:
sql = """
INSERT INTO futu_rehab (code, name, ex_div_date, forward_adj_factorA, forward_adj_factorB, backward_adj_factorA, backward_adj_factorB)
VALUES (%s, %s, %s, %s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
forward_adj_factorA = VALUES(forward_adj_factorA),
forward_adj_factorB = VALUES(forward_adj_factorB),
backward_adj_factorA = VALUES(backward_adj_factorA),
backward_adj_factorB = VALUES(backward_adj_factorB)
"""
for row in rehab_data.itertuples(index=False):
cursor.execute(sql, (code, name, row.ex_div_date, row.forward_adj_factorA, row.forward_adj_factorB, row.backward_adj_factorA, row.backward_adj_factorB))
connection.commit()
except pymysql.MySQLError as e:
logging.error(f"Error occurred while inserting or updating rehab data: {e}", exc_info=True)
# 从 Futu API 获取复权信息
def get_rehab_data(code):
quote_ctx = OpenQuoteContext(host='127.0.0.1', port=11111)
ret, data = quote_ctx.get_rehab(code)
quote_ctx.close()
if ret == RET_OK:
return data
else:
logging.error(f"Failed to get rehab data for {code}: {data}")
return None
# 主函数
def process_stock_data(table_name, prefix=''):
stocks = get_stock_codes(table_name)
connection = get_mysql_connection()
for stock in stocks:
code = stock['code']
name = stock['code_name']
# 拼接 'US.' 前缀对于 sp500 表中的股票
full_code = f"{prefix}{code}" if prefix else code
logging.info(f"Processing {full_code} ({name})")
# 获取复权数据
rehab_data = get_rehab_data(full_code)
if rehab_data is not None:
# 插入或更新复权数据
insert_or_update_rehab_data(connection, rehab_data, full_code, name)
logging.info(f"Inserted/Updated rehab data for {full_code} ({name})")
time.sleep(3)
connection.close()
if __name__ == "__main__":
# 处理 hs300 表数据,不需要加 'US.' 前缀
process_stock_data("hs300")
# 处理 sp500 表数据,加 'US.' 前缀
process_stock_data("sp500", prefix='US.')

View File

@ -0,0 +1,122 @@
"""
Script Name:
Description: 从富途获取历史K线。通过不同变量可以获取不复权、前复权、后复权等数据。
参考地址: https://openapi.futunn.com/futu-api-doc/quote/request-history-kline.html
Author: [Your Name]
Created Date: YYYY-MM-DD
Last Modified: YYYY-MM-DD
Version: 1.0
Modification History:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
"""
import pymysql
import time
import logging
from futu import *
from datetime import datetime, timedelta
import config
config.setup_logging()
# 连接 MySQL
connection = pymysql.connect(**config.db_config)
# 复权类型,不复权
# selected_autype = AuType.NONE
# selected_table = "hs300_his_kline_none"
# 复权类型,后复权
selected_autype = AuType.HFQ
selected_table = "hs300_his_kline_hfq"
# 复权类型,默认为 AuType.QFQ ,即前复权
# selected_autype = AuType.QFQ
# selected_table = "hs300_qfq_his"
# 获取当前日期
end_date = datetime.now().strftime('%Y-%m-%d')
# 计算 start_date 为当前日期减去10年再加一天
start_date = (datetime.now() - timedelta(days=365*10-1)).strftime('%Y-%m-%d')
# 定义插入数据的函数
def insert_data(connection, data):
try:
with connection.cursor() as cursor:
for index, row in data.iterrows():
sql = f"""
INSERT INTO {selected_table} (code, name, time_key, open, close, high, low, pe_ratio, turnover_rate, volume, turnover, change_rate, last_close)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
name = VALUES(name),
open = VALUES(open),
close = VALUES(close),
high = VALUES(high),
low = VALUES(low),
pe_ratio = VALUES(pe_ratio),
turnover_rate = VALUES(turnover_rate),
volume = VALUES(volume),
turnover = VALUES(turnover),
change_rate = VALUES(change_rate),
last_close = VALUES(last_close)
"""
cursor.execute(sql, (
row['code'], row['name'], row['time_key'], row['open'], row['close'],
row['high'], row['low'], row['pe_ratio'], row['turnover_rate'],
row['volume'], row['turnover'], row['change_rate'], row['last_close']
))
connection.commit()
except pymysql.MySQLError as e:
logging.error(f"Error occurred while inserting data: {e}")
print(f"Error occurred while inserting data: {e}")
# 获取 hs300 表中的所有股票代码
def get_hs300_codes():
with connection.cursor() as cursor:
cursor.execute("SELECT code FROM hs300 ")
return cursor.fetchall()
# 初始化 futu 行情连接
quote_ctx = OpenQuoteContext(host='127.0.0.1', port=11111)
try:
hs300_codes = get_hs300_codes()
for code_row in hs300_codes:
code = code_row[0] # 从数据库行中提取 code
# 获取历史 K 线数据,设置分页请求
ret, data, page_req_key = quote_ctx.request_history_kline(code, autype=selected_autype, start=start_date, end=end_date, max_count=500)
if ret == RET_OK:
logging.info(f"成功获取 {code} 的第一页数据,共 {len(data)}")
print(f"成功获取 {code} 的第一页数据,共 {len(data)}")
# 插入第一页数据
insert_data(connection, data)
else:
logging.error(f"获取 {code} 的数据失败: {data}")
print(f"获取 {code} 的数据失败: {data}")
# 分页拉取
while page_req_key is not None:
time.sleep(1) # 休眠 5 秒
ret, data, page_req_key = quote_ctx.request_history_kline(code, autype=selected_autype, start=start_date, end=end_date, max_count=500, page_req_key=page_req_key)
if ret == RET_OK:
logging.info(f"成功获取 {code} 的分页数据,共 {len(data)}")
print(f"成功获取 {code} 的分页数据,共 {len(data)}")
# 插入分页数据
insert_data(connection, data)
else:
logging.error(f"分页数据获取失败: {data}")
print(f"分页数据获取失败: {data}")
# 每次获取完一个股票的数据后,休眠 5 秒
time.sleep(2)
finally:
quote_ctx.close() # 关闭 futu 连接
connection.close() # 关闭 MySQL 连接

View File

@ -0,0 +1,78 @@
"""
Script Name:
Description: 从富途获取历史K线。通过不同变量可以获取不复权、前复权、后复权等数据。
参考地址: https://openapi.futunn.com/futu-api-doc/quote/get-market-snapshot.html
Author: [Your Name]
Created Date: YYYY-MM-DD
Last Modified: YYYY-MM-DD
Version: 1.0
Modification History:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
"""
import pymysql
import pandas as pd
from futu import *
import logging
import config
# 设置日志
config.setup_logging()
logger = logging.getLogger()
# 数据库连接函数
def connect_to_db():
return pymysql.connect(**config.db_config)
# 从sp300表中获取所有股票代码
def fetch_sp300_codes(connection):
query = "SELECT code FROM hs300"
return pd.read_sql(query, connection)
# 获取市场快照并保存到 CSV 文件
def get_market_snapshot_and_save_to_csv(stock_codes, output_file):
quote_ctx = OpenQuoteContext(host='127.0.0.1', port=11111)
ret, data = quote_ctx.get_market_snapshot(stock_codes)
if ret == RET_OK:
logger.info(f"Successfully fetched market snapshot for {len(stock_codes)} codes.")
# 将数据写入CSV文件
data.to_csv(output_file, index=False)
logger.info(f"Snapshot data saved to {output_file}")
else:
logger.error(f"Error fetching market snapshot: {data}")
quote_ctx.close()
# 主函数
def main():
try:
# 连接数据库
connection = connect_to_db()
# 从 sp300 表中获取所有的股票代码
sp300_codes_df = fetch_sp300_codes(connection)
# 提取股票代码列表
stock_codes = sp300_codes_df['code'].tolist()
if not stock_codes:
logger.warning("No stock codes found in sp300 table.")
return
# 获取市场快照并保存到 CSV 文件
output_file = "./result/market_snapshot.csv"
get_market_snapshot_and_save_to_csv(stock_codes, output_file)
except Exception as e:
logger.error(f"An error occurred: {e}")
finally:
if connection:
connection.close()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,97 @@
"""
Script Name:
Description: 从富途获取板块列表。
参考地址: https://openapi.futunn.com/futu-api-doc/quote/get-plate-list.html
Author: [Your Name]
Created Date: YYYY-MM-DD
Last Modified: YYYY-MM-DD
Version: 1.0
Modification History:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
"""
import time
from futu import *
import pymysql
from datetime import datetime
import logging
import config
# 市场映射
market_mapping = {
'US': Market.US,
'HK': Market.HK,
'SZ': Market.SZ,
'SH': Market.SH
}
# 设置日志
config.setup_logging()
# 板块集合类型映射
plat_mapping = {
'INDUSTRY': Plate.INDUSTRY,
'ALL': Plate.ALL,
'CONCEPT': Plate.CONCEPT
}
# 建立 MySQL 连接
connection = pymysql.connect(**config.db_config)
# 定义插入或更新函数
def insert_or_update_data(connection, data, market, plat):
try:
with connection.cursor() as cursor:
for index, row in data.iterrows():
code = row['code']
plate_name = row['plate_name']
plate_id = row['plate_id']
up_date = datetime.now().strftime('%Y-%m-%d') # 当前日期
# MySQL 插入或更新语句
sql = """
INSERT INTO futu_plat_list (code, plate_name, plate_id, market, plat, up_date)
VALUES (%s, %s, %s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
plate_name = VALUES(plate_name),
plate_id = VALUES(plate_id),
market = VALUES(market),
up_date = VALUES(up_date)
"""
cursor.execute(sql, (code, plate_name, plate_id, market, plat, up_date))
# 提交事务
connection.commit()
except pymysql.MySQLError as e:
# 捕获 MySQL 错误并打印日志
print(f"Error occurred while inserting/updating data for market {market}, plat {plat}: {e}")
# 可根据需要记录到文件或其他日志工具
# 初始化行情连接
quote_ctx = OpenQuoteContext(host='127.0.0.1', port=11111)
try:
# 双重循环:市场和板块类型
for market in market_mapping:
for plat_name, plat_enum in plat_mapping.items():
# 拉取数据
ret, data = quote_ctx.get_plate_list(market_mapping[market], plat_enum)
if ret == RET_OK:
row_count = len(data) # 获取行数
print(f"成功获取 {market} 市场的 {plat_name} 板块数据,共 {row_count}")
# 插入或更新数据到 MySQL
insert_or_update_data(connection, data, market, plat_name)
else:
print(f"获取 {market} 市场的 {plat_name} 板块数据失败: {data}")
# 每次循环后休眠10秒
time.sleep(10)
finally:
quote_ctx.close() # 关闭行情连接
connection.close() # 关闭 MySQL 连接

View File

@ -0,0 +1,135 @@
"""
Script Name:
Description: 从yahoo获取美股股票的历史K线, 通过 auto_adjust 参数来控制是否获取前复权数据。默认为true, 如果设置为false, 那么结果中会自动带 adj Close.
参考地址: https://github.com/ranaroussi/yfinance
https://aroussi.com/post/python-yahoo-finance
Author: [Your Name]
Created Date: YYYY-MM-DD
Last Modified: YYYY-MM-DD
Version: 1.0
Modification History:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
"""
import yfinance as yf
import pymysql
import logging
import time
import sys
import os
from datetime import datetime
import config # 引入 config.py 中的配置
# 股票代码集合,如果属于这些股票,则使用 "max" 时间段
special_stock_codes = ('ABNB', 'CARR', 'CEG', 'GEHC', 'GEV', 'HUBB', 'KVUE', 'OTIS', 'PLTR', 'SOLV', 'VLTO')
# K线调整选项决定是否使用前复权价格
kline_adjust = True
# 根据 kline_adjust 决定使用的表名
table_name = 'sp500_qfq_his_202410' if kline_adjust else 'sp500_his_kline_none'
# 使用 config.py 中的日志配置
config.setup_logging()
logger = logging.getLogger()
# MySQL数据库连接
def connect_to_db():
try:
#return pymysql.connect(**config.db_config)
return pymysql.connect(
**config.db_config,
cursorclass=pymysql.cursors.DictCursor # 确保使用字典形式的游标
)
except pymysql.MySQLError as e:
logger.error(f"Error connecting to the database: {e}", exc_info=True)
return None
# 从MySQL读取sp500表中的股票代码和名称
def fetch_sp500_codes():
db = connect_to_db()
if db is None:
logger.error("Failed to connect to database.")
return []
try:
with db.cursor() as cursor:
cursor.execute("SELECT code_inner, code_name FROM sp500")
codes = cursor.fetchall()
return codes
finally:
db.close()
# 插入数据到指定表名
def insert_stock_data_to_db(data, code, name):
try:
db = connect_to_db()
if db is None:
return
with db.cursor() as cursor:
insert_query = f"""
INSERT INTO {table_name} (time_key, open, high, low, close, adj_close, volume, dividends, stock_splits, code, name)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
open = VALUES(open),
high = VALUES(high),
low = VALUES(low),
close = VALUES(close),
adj_close = VALUES(adj_close),
volume = VALUES(volume),
dividends = VALUES(dividends),
stock_splits = VALUES(stock_splits)
"""
# auto_adjust=True: Date,Open,High,Low,Close,Volume,Dividends,Stock Splits
# auto_adjust=False: Date,Open,High,Low,Close,Adj Close,Volume,Dividends,Stock Splits
for index, row in data.iterrows():
time_key = index.strftime('%Y-%m-%d %H:%M:%S')
# 判断 row['Adj Close'] 是否存在,若不存在则使用 0
adj_close = row['Adj Close'] if 'Adj Close' in row else 0
values = (time_key, row['Open'], row['High'], row['Low'], row['Close'], adj_close, row['Volume'], row['Dividends'], row['Stock Splits'], code, name)
cursor.execute(insert_query, values)
db.commit()
except pymysql.MySQLError as e:
logger.error(f"Error occurred while inserting data: {e}", exc_info=True)
finally:
if db:
db.close()
# 拉取股票的历史数据
def fetch_and_store_stock_data():
codes = fetch_sp500_codes()
for row in codes:
code_inner = row['code_inner']
code_name = row['code_name']
logger.info(f"Fetching data for {code_name} ({code_inner})...")
# 判断使用的时间段,特殊股票使用 max其他使用 10y
period = "max" if code_inner in special_stock_codes else "10y"
try:
stock = yf.Ticker(code_inner)
# 拉取股票历史数据,使用 kline_adjust 决定 auto_adjust 是否为 True
hist_data = stock.history(period=period, auto_adjust=kline_adjust)
if not hist_data.empty:
logger.info(f"Inserting data for {code_name} ({code_inner}) into {table_name}...")
insert_stock_data_to_db(hist_data, code_inner, code_name)
else:
logger.warning(f"No data found for {code_name} ({code_inner})")
# 每次请求完后休眠3秒
time.sleep(3)
except Exception as e:
logger.error(f"Error fetching data for {code_name} ({code_inner}): {e}", exc_info=True)
if __name__ == "__main__":
fetch_and_store_stock_data()

View File

@ -0,0 +1,218 @@
"""
Script Name: stat_adjust_kline.py
Description: 根据从数据源获取的历史K线计算股票的前复权和后复权值.
注意:
本程序只适合沪深300的前复权和后复权计算使用的是富途提供的不复权数据和复权因子。
处理sp500有问题yahoo 提供的不复权收据 + 富途提供的复权因子计算前复权与yahoo提供的前复权数据差别很大。
尚未找到原因所以目前只能用hs300
Author: [Your Name]
Created Date: YYYY-MM-DD
Last Modified: YYYY-MM-DD
Version: 1.0
Modification History:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
"""
import pymysql
import logging
import sys
import time
import config
import argparse
# 配置不同市场的表名管理
tables_mapping = {
'sp500': {
'none_his_kline': 'sp500_his_kline_none',
'adjust_his_kline': 'sp500_ajust_kline_202410',
'rehab_table': 'futu_rehab'
},
'hs300': {
'none_his_kline': 'hs300_his_kline_none',
'adjust_his_kline': 'hs300_ajust_kline_202410',
'rehab_table': 'futu_rehab'
}
}
# 日志配置
config.setup_logging()
logger = logging.getLogger()
# MySQL数据库连接
def connect_to_db():
try:
return pymysql.connect(
**config.db_config,
cursorclass=pymysql.cursors.DictCursor
)
except pymysql.MySQLError as e:
logger.error(f"Error connecting to the database: {e}", exc_info=True)
return None
# 从指定市场表中读取code和code_name字段
def fetch_codes_from_market_table(market, debug=False):
db = connect_to_db()
if db is None:
logger.error("Failed to connect to database.")
return []
try:
with db.cursor() as cursor:
query = f"SELECT code, code_name FROM {market} "
if debug:
#query += " LIMIT 2"
query += " where code in ('GE', 'WTW')"
cursor.execute(query)
codes = cursor.fetchall()
return codes
finally:
db.close()
# 读取复权因子数据
def fetch_rehab_data(db, code):
try:
with db.cursor() as cursor:
cursor.execute(f"SELECT ex_div_date, forward_adj_factorA, forward_adj_factorB, backward_adj_factorA, backward_adj_factorB FROM futu_rehab WHERE code = %s ORDER BY ex_div_date DESC", (code,))
return cursor.fetchall()
except pymysql.MySQLError as e:
logger.error(f"Error fetching rehab data for {code}: {e}", exc_info=True)
return []
# 读取不复权的股票价格数据
def fetch_kline_none_data(db, table_name, code):
try:
with db.cursor() as cursor:
cursor.execute(f"SELECT code, time_key, open, close FROM {table_name} WHERE code = %s ORDER BY time_key ASC", (code,))
return cursor.fetchall()
except pymysql.MySQLError as e:
logger.error(f"Error fetching kline none data for {code}: {e}", exc_info=True)
return []
# 插入前后复权价格到数据库
def insert_hfq_data(db, hfq_data, hfq_table):
try:
with db.cursor() as cursor:
insert_query = f"""
INSERT INTO {hfq_table} (code, name, time_key, hfq_open, hfq_close, qfq_open, qfq_close, none_open, none_close)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
hfq_open = VALUES(hfq_open),
hfq_close = VALUES(hfq_close),
qfq_open = VALUES(qfq_open),
qfq_close = VALUES(qfq_close),
none_open = VALUES(none_open),
none_close = VALUES(none_close)
"""
cursor.executemany(insert_query, hfq_data)
db.commit()
except pymysql.MySQLError as e:
logger.error(f"Error inserting hfq data: {e}", exc_info=True)
# 计算后复权价格和前复权价格
def calculate_hfq_qfq_price(market, debug=False):
db = connect_to_db()
if db is None:
return
# 获取表名
table_names = tables_mapping[market]
none_his_kline_table = table_names['none_his_kline']
adjust_kline_table = table_names['adjust_his_kline']
# 获取股票代码
codes = fetch_codes_from_market_table(market, debug)
isSP500 = True if market == 'sp500' else False
for row in codes:
code = row['code']
name = row['code_name']
# 如果是 sp500 市场,拼接 'US.' + code
rehab_code = code
if isSP500:
rehab_code = 'US.' + code
logger.info(f"Processing {code} ({name})...")
# 获取复权因子数据,没有的话就直接使用不复权值
rehab_res = fetch_rehab_data(db, rehab_code)
if not rehab_res:
logger.warning(f"No rehab data found for {code}, use non close")
rehab_res = list()
# 反转复权因子行,为了计算前复权
rehab_res_asc = list(reversed(rehab_res))
# 获取不复权的价格数据
kline_none = fetch_kline_none_data(db, none_his_kline_table, code)
if not kline_none:
logger.warning(f"No kline none data found for {code}")
continue
hfq_data = []
# 遍历kline_none计算前后复权价格
for kline_row in kline_none:
none_open = kline_row['open']
none_close = kline_row['close']
time_key = kline_row['time_key']
# 将 time_key 转换为 date 格式
time_key_date = time_key.date()
# 计算后复权价格
hfq_open = none_open
hfq_close = none_close
tmp_close = none_close
tmp_open = none_open
for rehab_row in rehab_res:
# Yahoo Finance 提供的不复权数据,已经处理了拆股;所以对于富途复权因子表里的拆股数据,要忽略
if isSP500 and rehab_row['backward_adj_factorA'] != 1 :
continue
if rehab_row['ex_div_date'] <= time_key_date:
hfq_close = (tmp_close * rehab_row['backward_adj_factorA']) + rehab_row['backward_adj_factorB']
hfq_open = (tmp_open * rehab_row['backward_adj_factorA']) + rehab_row['backward_adj_factorB']
tmp_close = hfq_close
tmp_open = hfq_open
# 计算前复权价格
qfq_close = none_close
qfq_open = none_open
tmp_close = none_close
tmp_open = none_open
for rehab_row in rehab_res_asc:
# Yahoo Finance 提供的不复权数据,已经处理了拆股;所以对于富途复权因子表里的拆股和合股数据,要忽略
if isSP500 and rehab_row['backward_adj_factorA'] != 1 :
continue
# 富途对美股的前复权价格计算,要忽略 forward_adj_factorB
# https://openapi.futunn.com/futu-api-doc/qa/quote.html
factorB = 0 if isSP500 else rehab_row['forward_adj_factorB']
if rehab_row['ex_div_date'] > time_key_date:
qfq_close = (tmp_close * rehab_row['forward_adj_factorA']) + factorB
qfq_open = (tmp_open * rehab_row['forward_adj_factorA']) + factorB
tmp_close = qfq_close
tmp_open = qfq_open
# 保存计算后的复权价格
hfq_data.append((code, name, time_key, hfq_open, hfq_close, qfq_open, qfq_close, none_open, none_close))
# 插入后复权价格数据
insert_hfq_data(db, hfq_data, adjust_kline_table)
logger.info(f"Inserted HFQ/QFQ data for {code} ({name})")
time.sleep(1)
db.close()
if __name__ == "__main__":
# 命令行参数处理
parser = argparse.ArgumentParser(description='Calculate HFQ and QFQ Prices for Market')
parser.add_argument('--market', type=str, default='hs300', help='Market to process (sp500 or hs300)')
parser.add_argument('--debug', action='store_true', help='Enable debug mode (limit records)')
args = parser.parse_args()
# 调用主函数
calculate_hfq_qfq_price(args.market, args.debug)

263
stockapp/src/stat_growth.py Normal file
View File

@ -0,0 +1,263 @@
"""
Script Name:
Description: 获取沪深300成分股的最新股价, 并计算年内涨幅, 924以来的涨幅, 市盈率, 股息率等。
需要调用futu的获取快照接口。
https://openapi.futunn.com/futu-api-doc/quote/get-market-snapshot.html
Author: [Your Name]
Created Date: YYYY-MM-DD
Last Modified: YYYY-MM-DD
Version: 1.0
Modification History:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
"""
import pymysql
import logging
import csv
import os
import config
import time
from datetime import datetime
from futu import OpenQuoteContext, RET_OK # Futu API client
# 配置日志
config.setup_logging()
# 1. 获取 hs300 表数据
def get_hs300_data():
conn = pymysql.connect(**config.db_config)
cursor = conn.cursor(pymysql.cursors.DictCursor)
cursor.execute("SELECT code, code_name FROM hs300")
hs300_data = cursor.fetchall()
cursor.close()
conn.close()
return hs300_data
# 2. 批量获取市场快照
def get_market_snapshots(codes):
quote_ctx = OpenQuoteContext(host='127.0.0.1', port=11111) # 替换为实际Futu API地址和端口
snapshot_results = []
batch_size = 350
for i in range(0, len(codes), batch_size):
code_batch = codes[i:i+batch_size]
ret, data = quote_ctx.get_market_snapshot(code_batch)
if ret == RET_OK:
snapshot_results.extend(data.to_dict('records'))
else:
logging.error(f"获取市场快照失败: {data}")
quote_ctx.close()
return snapshot_results
# 3. 插入或更新 futu_market_snapshot 表
def insert_or_update_snapshot(snapshot_data):
conn = pymysql.connect(**config.db_config)
cursor = conn.cursor()
query = """
INSERT INTO futu_market_snapshot (
code, name, update_time, last_price, open_price, high_price, low_price, prev_close_price,
volume, turnover, turnover_rate, suspension, listing_date, equity_valid, issued_shares,
total_market_val, net_asset, net_profit, earning_per_share, outstanding_shares, net_asset_per_share,
circular_market_val, ey_ratio, pe_ratio, pb_ratio, pe_ttm_ratio, dividend_ttm, dividend_ratio_ttm,
dividend_lfy, dividend_lfy_ratio
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
last_price = VALUES(last_price), open_price = VALUES(open_price), high_price = VALUES(high_price),
low_price = VALUES(low_price), prev_close_price = VALUES(prev_close_price), volume = VALUES(volume),
turnover = VALUES(turnover), turnover_rate = VALUES(turnover_rate), suspension = VALUES(suspension),
issued_shares = VALUES(issued_shares), total_market_val = VALUES(total_market_val), net_asset = VALUES(net_asset),
net_profit = VALUES(net_profit), earning_per_share = VALUES(earning_per_share), outstanding_shares = VALUES(outstanding_shares),
net_asset_per_share = VALUES(net_asset_per_share), circular_market_val = VALUES(circular_market_val),
ey_ratio = VALUES(ey_ratio), pe_ratio = VALUES(pe_ratio), pb_ratio = VALUES(pb_ratio),
pe_ttm_ratio = VALUES(pe_ttm_ratio), dividend_ttm = VALUES(dividend_ttm), dividend_ratio_ttm = VALUES(dividend_ratio_ttm),
dividend_lfy = VALUES(dividend_lfy), dividend_lfy_ratio = VALUES(dividend_lfy_ratio)
"""
try:
for record in snapshot_data:
cursor.execute(query, (
record['code'], record['name'], record['update_time'], record['last_price'], record['open_price'],
record['high_price'], record['low_price'], record['prev_close_price'], record['volume'], record['turnover'],
record['turnover_rate'], record['suspension'], record['listing_date'], record['equity_valid'], record['issued_shares'],
record['total_market_val'], record['net_asset'], record['net_profit'], record['earning_per_share'], record['outstanding_shares'],
record['net_asset_per_share'], record['circular_market_val'], record['ey_ratio'], record['pe_ratio'], record['pb_ratio'],
record['pe_ttm_ratio'], record['dividend_ttm'], record['dividend_ratio_ttm'], record['dividend_lfy'], record['dividend_lfy_ratio']
))
conn.commit()
except Exception as e:
logging.error(f"插入或更新快照数据时出错: {e}")
conn.rollback()
finally:
cursor.close()
conn.close()
def process_snapshot_data():
hs300_data = get_hs300_data()
codes = [item['code'] for item in hs300_data]
# 分批拉取市场快照数据
snapshot_data = get_market_snapshots(codes)
# 插入或更新数据到数据库
insert_or_update_snapshot(snapshot_data)
logging.info(f"Successfully get market snapshots and write to db.")
def write_to_csv(file_path, fieldnames, data):
"""
Writes data to a CSV file.
:param file_path: Path to the CSV file.
:param fieldnames: A list of field names (headers) for the CSV file.
:param data: A list of dictionaries where each dictionary represents a row.
"""
try:
# Check if file exists to determine if we need to write headers
file_exists = os.path.isfile(file_path)
# Open file in append mode ('a' means append, newline='' is needed for correct CSV formatting)
with open(file_path, mode='w+', newline='', encoding='utf-8') as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
# Write headers
writer.writeheader()
# Write the data rows
writer.writerows(data)
logging.info(f"Successfully wrote data to {file_path}")
except Exception as e:
logging.error(f"Error while writing to CSV file {file_path}: {str(e)}")
raise
def calculate_yield():
conn = pymysql.connect(**config.db_config)
cursor = conn.cursor(pymysql.cursors.DictCursor)
try:
hs300_data = get_hs300_data()
results = []
for item in hs300_data:
code = item['code']
name = item['code_name']
# 1. 获取最近快照数据
cursor.execute("SELECT * FROM futu_market_snapshot WHERE code=%s ORDER BY update_time DESC LIMIT 1", (code,))
row1 = cursor.fetchone()
row1['close'] = row1['last_price']
row1['time_key'] = row1['update_time']
# 2. 获取 2024-01-01 的年初数据
cursor.execute("SELECT * FROM hs300_his_kline_none WHERE code=%s AND time_key<'2024-01-01' ORDER BY time_key DESC LIMIT 1", (code,))
row2 = cursor.fetchone()
# 3. 获取 2024-09-24 的初始数据
cursor.execute("SELECT * FROM hs300_his_kline_none WHERE code=%s AND time_key<'2024-09-24' ORDER BY time_key DESC LIMIT 1", (code,))
row3 = cursor.fetchone()
# 3.1 获取 2021-01-01 之后的历史数据中最大值(前复权)
cursor.execute("SELECT * FROM hs300_qfq_his WHERE code=%s AND time_key>='2021-01-01' ORDER BY close DESC LIMIT 1", (code,))
row4 = cursor.fetchone()
# 3.2 获取 2021-01-01 之后的历史数据中最小值(前复权)
cursor.execute("SELECT * FROM hs300_qfq_his WHERE code=%s AND time_key>='2021-01-01' ORDER BY close ASC LIMIT 1", (code,))
row5 = cursor.fetchone()
# 3.4 获取 2021-01-01 之后的历史数据中pe最大值
cursor.execute("SELECT * FROM hs300_qfq_his WHERE code=%s AND time_key>='2021-01-01' ORDER BY pe_ratio DESC LIMIT 1", (code,))
row6 = cursor.fetchone()
# 3.5 获取 2021-01-01 之后的历史数据中pe最小值
cursor.execute("SELECT * FROM hs300_qfq_his WHERE code=%s AND time_key>='2021-01-01' ORDER BY pe_ratio ASC LIMIT 1", (code,))
row7 = cursor.fetchone()
# 4. 读取复权数据
cursor.execute("SELECT * FROM futu_rehab WHERE code=%s ORDER BY ex_div_date ASC", (code,))
rehab_res = cursor.fetchall()
# 5. 计算复权价格
for row in [row1, row2, row3]:
qfq_close = row['close']
time_key_date = row['time_key'].date() # 将 datetime 转换为 date
for rehab in rehab_res:
if rehab['ex_div_date'] >= time_key_date:
qfq_close = (qfq_close * rehab['forward_adj_factorA']) + rehab['forward_adj_factorB']
row['qfq_close'] = qfq_close
# 6. 计算收益率
year_yield = row1['qfq_close'] / row2['qfq_close'] - 1 if row1 and row2 else None
yield_0924 = row1['qfq_close'] / row3['qfq_close'] - 1 if row3 and row1 else None
# 6.1 计算当前股价是 2021 年之后最高点及最低点的百分比
max_price_pct = row1['qfq_close'] / row4['close'] if row1 and row4 and row4['close'] !=0 else None
max_price_pe_pct = row1['pe_ttm_ratio'] / row4['pe_ratio'] if row1 and row4 and row4['pe_ratio'] !=0 else None
min_price_pct = row1['qfq_close'] / row5['close'] if row1 and row5 and row5['close'] !=0 else None
min_price_pe_pct = row1['pe_ttm_ratio'] / row5['pe_ratio'] if row1 and row5 and row5['pe_ratio'] !=0 else None
max_pe_pct = row1['pe_ttm_ratio'] / row6['pe_ratio'] if row1 and row6 and row6['pe_ratio'] !=0 else None
min_pe_pct = row1['pe_ttm_ratio'] / row7['pe_ratio'] if row1 and row7 and row7['pe_ratio'] !=0 else None
# 7. 收集结果
result = {
'code': code,
'name': name,
'year_begin_date': row2['time_key'].date(),
'year_begin_close': row2['qfq_close'],
'0924_date': row3['time_key'].date(),
'0924_close': row3['qfq_close'],
'max_price_date': row4['time_key'].date(),
'max_price': row4['close'],
'max_price_pe': row4['pe_ratio'],
'max_pe_date': row6['time_key'].date(),
'max_pe': row6['pe_ratio'],
'min_price_date': row5['time_key'].date(),
'min_price': row5['close'],
'min_price_pe': row5['pe_ratio'],
'min_pe_date': row7['time_key'].date(),
'min_pe': row7['pe_ratio'],
'latest_date': row1['time_key'].date(),
'latest_close': row1['qfq_close'],
'year_yield': year_yield,
'yield_0924': yield_0924,
'total_market_val': row1.get('total_market_val', None),
'pe_ttm_ratio': row1.get('pe_ttm_ratio', None),
'dividend_ratio_ttm': row1.get('dividend_ratio_ttm', None),
'dividend_lfy_ratio': row1.get('dividend_lfy_ratio', None),
'max_price_pct': max_price_pct,
'max_price_pe_pct': max_price_pe_pct,
'min_price_pct': min_price_pct,
'min_price_pe_pct': min_price_pe_pct,
'max_pe_pct': max_pe_pct,
'min_pe_pct': min_pe_pct,
}
results.append(result)
logging.info(f"{result}")
time.sleep(0.1)
# 写入CSV
# 指定字段名称
# 获取当前日期 格式化为 yyyymmdd
current_date = datetime.now()
date_string = current_date.strftime('%Y%m%d')
fieldnames = ['code', 'name', 'year_begin_date', 'year_begin_close', '0924_date', '0924_close',
'max_price_date', 'max_price', 'max_price_pe', 'max_pe_date', 'max_pe', 'min_price_date', 'min_price', 'min_price_pe', 'min_pe_date', 'min_pe',
'latest_date', 'latest_close', 'year_yield', 'yield_0924', 'total_market_val', 'pe_ttm_ratio', 'dividend_ratio_ttm', 'dividend_lfy_ratio',
'max_price_pct', 'max_price_pe_pct', 'min_price_pct', 'min_price_pe_pct', 'max_pe_pct', 'min_pe_pct'
]
write_to_csv(f'./result/stat_growth{date_string}.csv', fieldnames, results)
except Exception as e:
logging.error(f"计算收益率时出错: {e}")
finally:
cursor.close()
conn.close()
if __name__ == "__main__":
process_snapshot_data()
calculate_yield()

View File

@ -0,0 +1,116 @@
"""
Script Name:
Description: 统计hs300的成分股在区间内的涨幅。取前复权值
Author: [Your Name]
Created Date: YYYY-MM-DD
Last Modified: YYYY-MM-DD
Version: 1.0
Modification History:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
"""
import pymysql
import pandas as pd
import time
from datetime import datetime
import logging
import config
# 设置日志
config.setup_logging()
logger = logging.getLogger()
# 数据库连接函数
def connect_to_db():
return pymysql.connect(**config.db_config)
# 获取 2024-09-23 对应的 close 值
def get_close_for_date(df, date):
filtered = df[df['time_key'] == date]
if not filtered.empty:
return filtered.iloc[0]['close']
else:
logger.warning(f"No data found for date: {date}")
return None
# 获取年内涨幅的 c1, c3 值(最早和最晚的 close 值)
def get_first_last_close(df):
df_sorted = df.sort_values(by='time_key')
c1 = df_sorted.iloc[0]['close'] # 最早的 close 值
c3 = df_sorted.iloc[-1]['close'] # 最晚的 close 值
return c1, c3
# 获取最大值和最小值的 close 值
def get_max_min_close(df):
max_close = df['close'].max()
min_close = df['close'].min()
return max_close, min_close
# 主函数
def main():
try:
connection = connect_to_db()
query = """
SELECT code, name, time_key, close
FROM hs300_qfq_his
WHERE time_key >= '2021-01-01 00:00:00'
"""
df = pd.read_sql(query, connection)
# 确定要查询的日期
target_date = '2024-09-23 00:00:00'
df['time_key'] = pd.to_datetime(df['time_key'])
results = []
for code, group in df.groupby('code'):
logger.info(f"Processing code: {code}")
# 获取 c1最早的 close和 c3最晚的 close
c1, c3 = get_first_last_close(group)
# 获取 c22024-09-23 的 close 值)
c2 = get_close_for_date(group, target_date)
if c1 is None or c2 is None or c3 is None:
logger.warning(f"Skipping code {code} due to missing close values.")
continue
# 计算年内涨幅和自2024-09-23以来的涨幅
year_growth_rate = (c3 / c1 - 1) if c1 else None
growth_since_2024_09_23 = (c3 / c2 - 1) if c2 else None
# 获取年内的最大和最小 close 值
c4, c5 = get_max_min_close(group)
year_volatility = (c4 / c5 - 1) if c4 and c5 else None
results.append({
'code': code,
'name': group['name'].iloc[0],
'year_growth_rate': year_growth_rate,
'growth_since_2024_09_23': growth_since_2024_09_23,
'year_volatility': year_volatility
})
time.sleep(1)
# 将结果转换为 DataFrame 并显示
result_df = pd.DataFrame(results)
print(result_df)
# 你可以选择将结果保存到 CSV 文件中
result_df.to_csv('./result/stat_grouth_rate_since2021.csv', index=False)
except Exception as e:
logger.error(f"Error occurred: {e}")
finally:
if connection:
connection.close()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,125 @@
"""
Script Name:
Description: 根据yahoo提供的不复权数据和分红及拆股数据来计算前复权和后复权数据。
注意:
结果对不上!
按照yahoo规则不复权数据已经处理了拆股所以只要把分红加上去就行但处理结果与它返回的前复权数据仍然对不对上
有些比如AAPL差不多可以对得上但对于KDP等差异甚大找不到原因。。
所以,这个程序暂时无法使用。。。
Author: [Your Name]
Created Date: YYYY-MM-DD
Last Modified: YYYY-MM-DD
Version: 1.0
Modification History:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
"""
import pymysql
import pandas as pd
import logging
import os
import time
import config
# 设置日志
config.setup_logging()
logger = logging.getLogger()
# 数据库连接函数
def connect_to_db():
return pymysql.connect(**config.db_config)
# 读取 sp500 表中的所有行,获取 code 和 name
def fetch_sp500_codes(connection):
query = "SELECT code, code_name as name FROM sp500 "
return pd.read_sql(query, connection)
# 读取 sp500_his_kline_none 表中的数据并按 time_key 降序排列
def fetch_sp500_his_kline_none(connection, code):
query = f"SELECT * FROM sp500_his_kline_none WHERE code = '{code}' ORDER BY time_key DESC"
return pd.read_sql(query, connection)
# 将计算结果插入到 sp500_ajust_kline_202410 表中
def insert_adjusted_kline_data(connection, data):
try:
with connection.cursor() as cursor:
insert_query = """
INSERT INTO sp500_ajust_kline_202410 (code, name, time_key, hfq_open, hfq_close, qfq_open, qfq_close, none_open, none_close)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
hfq_open = VALUES(hfq_open),
hfq_close = VALUES(hfq_close),
qfq_open = VALUES(qfq_open),
qfq_close = VALUES(qfq_close),
none_open = VALUES(none_open),
none_close = VALUES(none_close)
"""
cursor.executemany(insert_query, data)
connection.commit()
except Exception as e:
logger.error(f"Error inserting data: {e}")
# 计算前复权和后复权的价格,并插入到 sp500_ajust_kline_202410
def process_and_insert_adjusted_kline(connection, code, name, result_none):
dividends_qfq = 0
dividends_hfq = 0
dividends_total = result_none['dividends'].sum()
adjusted_data = []
for index, row in result_none.iterrows():
# 计算前复权和后复权的开盘价和收盘价
qfq_close = row['close'] - dividends_qfq
qfq_open = row['open'] - dividends_qfq
hfq_close = row['close'] + dividends_hfq
hfq_open = row['open'] + dividends_hfq
adjusted_data.append((
row['code'], row['name'], row['time_key'],
hfq_open, hfq_close, qfq_open, qfq_close,
row['open'], row['close']
))
dividends_qfq += row['dividends']
dividends_hfq = dividends_total - dividends_qfq
# 插入到 sp500_ajust_kline_202410 表中
insert_adjusted_kline_data(connection, adjusted_data)
logger.info(f"Successfully processed and inserted data for code {code}")
# 主函数
def main():
try:
connection = connect_to_db()
# 读取 sp500 表中的所有行,得到 code 和 name 字段
sp500_codes = fetch_sp500_codes(connection)
for index, row in sp500_codes.iterrows():
code = row['code']
name = row['name']
logger.info(f"Processing data for code: {code}, name: {name}")
# 读取 sp500_his_kline_none 表中的数据并按 time_key 降序排列
result_none = fetch_sp500_his_kline_none(connection, code)
if result_none.empty:
logger.warning(f"No data found for code: {code}")
continue
# 处理并插入调整后的 K 线数据
process_and_insert_adjusted_kline(connection, code, name, result_none)
except Exception as e:
logger.error(f"Error occurred: {e}")
finally:
if connection:
connection.close()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,280 @@
"""
Script Name:
Description: 统计过去十年来hs300 和 sp500成分股的投资胜率年化回报率等数据。
Author: [Your Name]
Created Date: YYYY-MM-DD
Last Modified: YYYY-MM-DD
Version: 1.0
Modification History:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
- YYYY-MM-DD [Your Name]:
"""
import pymysql
import logging
import sys
import time
import numpy as np
from datetime import datetime
import argparse
import config
# 配置日志
config.setup_logging()
# 设置默认值
default_min_stat_years = 5
allowed_min_stat_years = [3, 5] # 允许的年份统计范围
default_debug = False
default_market_key = "hs300"
allowed_market_keys = ['hs300', 'sp500']
# 配置命令行参数
def parse_arguments():
parser = argparse.ArgumentParser(description="Run stock yield statistics.")
# 添加 min_stat_years 参数
parser.add_argument('--market', type=str, choices=allowed_market_keys,
help=f'Set market key for statistics (allowed: {allowed_market_keys}). Default is {default_market_key}.')
# 添加 min_stat_years 参数
parser.add_argument('--min_stat_years', type=int, choices=allowed_min_stat_years,
help=f'Set minimum years for statistics (allowed: {allowed_min_stat_years}). Default is {default_min_stat_years}.')
# 添加 debug 参数
parser.add_argument('--debug', action='store_true', help='Enable debug mode (default: False).')
args = parser.parse_args()
# 如果没有提供 --min_stat_years使用默认值
min_stat_years = args.min_stat_years if args.min_stat_years else default_min_stat_years
debug = args.debug if args.debug else default_debug
market_key = args.market if args.market else default_market_key
return min_stat_years, debug, market_key
# 获取用户输入的参数
min_stat_years, debug, market_key = parse_arguments()
# 传入表名的映射
table_mapping = {
"hs300": {
"codes": "hs300",
"his_data": "hs300_ajust_kline_202410",
"stat_res": f"hs300_{min_stat_years}years_yield_stats_2410"
},
"sp500": {
"codes": "sp500",
"his_data": "sp500_ajust_kline_202410",
"stat_res": f"sp500_{min_stat_years}years_yield_stats_2410"
}
}
# 连接 MySQL
connection = pymysql.connect(**config.db_config)
# 获取股票代码
def get_codes(table_mapping, index_name):
try:
with connection.cursor() as cursor:
if debug:
# 如果 debug 模式开启,查询一条数据
sql = f"SELECT code, code_name FROM {table_mapping[index_name]['codes']} LIMIT 1"
else:
# 否则查询所有数据
sql = f"SELECT code, code_name FROM {table_mapping[index_name]['codes']} "
cursor.execute(sql)
return cursor.fetchall()
except pymysql.MySQLError as e:
logging.error(f"Error occurred while reading {table_mapping[index_name]['codes']} : {e}", exc_info=True)
# 获取历史行情数据
def get_historical_data(table_mapping, index_name, code):
try:
with connection.cursor(pymysql.cursors.DictCursor) as cursor:
sql = f"SELECT * FROM {table_mapping[index_name]['his_data']} WHERE code = %s ORDER BY time_key"
cursor.execute(sql, (code,))
return cursor.fetchall()
except pymysql.MySQLError as e:
logging.error(f"Error occurred while reading {table_mapping[index_name]['his_data']}: {e}", exc_info=True)
# 插入统计结果
def insert_yield_stats(connection, table_mapping, index_name, code, name, diff_year, max_entry, min_entry, avg_yield, median_yield, win_rate, annual_max_entry, annual_min_entry, annual_avg_yield, annual_median_yield, max_deficit_entry, annual_yield_variance):
try:
with connection.cursor() as cursor:
sql = f"""
INSERT INTO {table_mapping[index_name]['stat_res']}
(code, name, year_diff, max_yield_rate, max_yield_rate_start, max_yield_rate_end,
min_yield_rate, min_yield_rate_start, min_yield_rate_end, avg_yield_rate,
median_yield_rate, win_rate, annual_max_yield_rate, annual_max_yield_rate_start,
annual_max_yield_rate_end, annual_min_yield_rate, annual_min_yield_rate_start,
annual_min_yield_rate_end, annual_avg_yield_rate, annual_median_yield_rate,
max_deficit_days, max_deficit_start, max_deficit_end, annual_yield_variance)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
max_yield_rate = VALUES(max_yield_rate),
max_yield_rate_start = VALUES(max_yield_rate_start),
max_yield_rate_end = VALUES(max_yield_rate_end),
min_yield_rate = VALUES(min_yield_rate),
min_yield_rate_start = VALUES(min_yield_rate_start),
min_yield_rate_end = VALUES(min_yield_rate_end),
avg_yield_rate = VALUES(avg_yield_rate),
median_yield_rate = VALUES(median_yield_rate),
win_rate = VALUES(win_rate),
annual_max_yield_rate = VALUES(annual_max_yield_rate),
annual_max_yield_rate_start = VALUES(annual_max_yield_rate_start),
annual_max_yield_rate_end = VALUES(annual_max_yield_rate_end),
annual_min_yield_rate = VALUES(annual_min_yield_rate),
annual_min_yield_rate_start = VALUES(annual_min_yield_rate_start),
annual_min_yield_rate_end = VALUES(annual_min_yield_rate_end),
annual_avg_yield_rate = VALUES(annual_avg_yield_rate),
annual_median_yield_rate = VALUES(annual_median_yield_rate),
max_deficit_days = VALUES(max_deficit_days),
max_deficit_start = VALUES(max_deficit_start),
max_deficit_end = VALUES(max_deficit_end),
annual_yield_variance = VALUES(annual_yield_variance)
"""
cursor.execute(sql, (
code, name, int(diff_year),
float(max_entry['yield_rate']), max_entry['start_time_key'], max_entry['end_time_key'],
float(min_entry['yield_rate']), min_entry['start_time_key'], min_entry['end_time_key'],
float(avg_yield), float(median_yield), win_rate,
float(annual_max_entry['annual_yield_rate']), annual_max_entry['start_time_key'], annual_max_entry['end_time_key'],
float(annual_min_entry['annual_yield_rate']), annual_min_entry['start_time_key'], annual_min_entry['end_time_key'],
float(annual_avg_yield), float(annual_median_yield),
max_deficit_entry['max_deficit_days'], max_deficit_entry['max_deficit_start'], max_deficit_entry['max_deficit_end'],
annual_yield_variance
))
connection.commit()
except pymysql.MySQLError as e:
logging.error(f"Error occurred while inserting yield stats for code {code}: {e}", exc_info=True)
# 计算收益率并计算最长连续亏损
def calculate_yield_rate(data):
results = {}
all_entries = []
num_rows = len(data)
for i in range(num_rows):
for j in range(i + 1, num_rows):
try:
start_time_key = data[i]['time_key']
end_time_key = data[j]['time_key']
time_diff = int((end_time_key - start_time_key).days / 365.0)
if time_diff < min_stat_years:
continue
# 使用后复权数据避免前复权中出现负数0从而影响统计。
close_start = data[i]['hfq_close']
close_end = data[j]['hfq_close']
yield_rate = (close_end / close_start) - 1
annual_yield_rate = yield_rate * 365 / (end_time_key - start_time_key).days
# 找到从 data[i]['close'] 到 data[j]['close'] 之间的最大连续亏损
max_deficit_days = 0
max_deficit_start = start_time_key
max_deficit_end = end_time_key
for k in range(i + 1, j):
if data[k]['hfq_close'] > close_start:
deficit_days = (data[k]['time_key'] - start_time_key).days
max_deficit_days = deficit_days
max_deficit_end = data[k]['time_key']
break
# 如果没有找到符合条件的亏损结束点,则认为 j 是亏损结束点
if max_deficit_days == 0:
max_deficit_days = (end_time_key - start_time_key).days
max_deficit_end = end_time_key
entry = {
'diff_year': time_diff,
'start_time_key': start_time_key,
'end_time_key': end_time_key,
'yield_rate': yield_rate,
'annual_yield_rate': annual_yield_rate,
'max_deficit_days': max_deficit_days,
'max_deficit_start': max_deficit_start,
'max_deficit_end': max_deficit_end
}
all_entries.append(entry)
if time_diff not in results:
results[time_diff] = []
results[time_diff].append(entry)
except ZeroDivisionError:
logging.warning(f"Zero division error for code {data[i]['code']}")
except Exception as e:
logging.error(f"Error occurred while calculating yield rate: {e}", exc_info=True)
# 将全局最大亏损信息加入到汇总部分
results[10000] = all_entries # 汇总
return results
# 统计结果并输出
def compute_statistics(connection, table_mapping, index_name, code, name, results):
for diff_year, entries in results.items():
yield_rates = [entry['yield_rate'] for entry in entries]
annual_yield_rates = [entry['annual_yield_rate'] for entry in entries]
if yield_rates:
max_yield = max(yield_rates)
min_yield = min(yield_rates)
avg_yield = np.mean(yield_rates)
median_yield = np.median(yield_rates)
max_entry = next(entry for entry in entries if entry['yield_rate'] == max_yield)
min_entry = next(entry for entry in entries if entry['yield_rate'] == min_yield)
# 年化收益率统计
annual_max_yield = max(annual_yield_rates)
annual_min_yield = min(annual_yield_rates)
annual_avg_yield = np.mean(annual_yield_rates)
annual_median_yield = np.median(annual_yield_rates)
annual_max_entry = next(entry for entry in entries if entry['annual_yield_rate'] == annual_max_yield)
annual_min_entry = next(entry for entry in entries if entry['annual_yield_rate'] == annual_min_yield)
# 计算 win_rate
win_rate = len([r for r in yield_rates if r > 0]) / len(yield_rates)
# 计算年化收益率方差
annual_yield_variance = np.var(annual_yield_rates)
# 处理最大连续亏损
max_deficit_entry = max(entries, key=lambda x: x['max_deficit_days'])
# 插入数据库
insert_yield_stats(connection, table_mapping, index_name, code, name, diff_year,
max_entry, min_entry, avg_yield, median_yield, win_rate,
annual_max_entry, annual_min_entry, annual_avg_yield, annual_median_yield,
max_deficit_entry, annual_yield_variance)
# 主函数
def main(index_name):
try:
codes = get_codes(table_mapping, index_name)
for code_row in codes:
code, name = code_row[0], code_row[1]
logging.info(f"开始处理 {code} ({name}) 的数据")
data = get_historical_data(table_mapping, index_name, code)
if not data:
logging.warning(f"未找到 {code} 的历史数据")
continue
results = calculate_yield_rate(data)
compute_statistics(connection, table_mapping, index_name, code, name, results)
logging.info(f"完成 {code} 的处理")
time.sleep(1)
except Exception as e:
logging.error(f"处理过程中出现错误: {e}", exc_info=True)
finally:
connection.close()
if __name__ == "__main__":
main(market_key)