256 lines
8.7 KiB
Python
256 lines
8.7 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding:utf-8 -*-
|
||
"""
|
||
Created on 2023/12/06
|
||
@author: Monday
|
||
@group : waditu
|
||
Desc: 腾讯-股票-实时行情-成交明细
|
||
成交明细-每个交易日 16:00 提供当日数据
|
||
港股报价延时 15 分钟
|
||
"""
|
||
import warnings
|
||
import pandas as pd
|
||
import requests
|
||
from io import StringIO
|
||
from tushare.util.verify_token import require_permission
|
||
from tushare.util.format_stock_code import format_stock_code
|
||
from tushare.stock.rtq_vars import zh_sina_a_stock_cookies, zh_sina_a_stock_headers
|
||
import time
|
||
import json
|
||
from typing import Optional
|
||
from tushare.util.form_date import get_current_date
|
||
from tushare.stock import rtq_vars
|
||
from tushare.util.format_stock_code import symbol_verify
|
||
|
||
headers = {
|
||
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0"
|
||
}
|
||
|
||
|
||
@require_permission(event_name="realtime_tick", event_detail="个股历史分笔数据")
|
||
def realtime_tick(ts_code: str = "000001.SZ", src: Optional[str] = "tx",
|
||
page_count: Optional[int] = None) -> pd.DataFrame:
|
||
"""
|
||
历史分笔数据
|
||
:param ts_code: 股票代码
|
||
:type ts_code: str
|
||
:param src: 来源 腾讯财经tx 新浪财经sina
|
||
:type src: str
|
||
:param page_count: 限制页数
|
||
:type page_count: str
|
||
:return: 历史分笔数据
|
||
:rtype: pandas.DataFrame
|
||
1、TIME : 成交时间
|
||
2、PRICE : 成交价格
|
||
3、PCHANGE : 涨跌幅
|
||
4、CHANGE : 价格变动
|
||
5、VOLUME : 成交量(手)
|
||
6、AMOUNT : 成交额(元)
|
||
7、TYPE : 性质
|
||
"""
|
||
symbol = symbol_verify(ts_code)
|
||
if src == "sina":
|
||
return get_stock_sina_a_divide_amount(symbol, page_count)
|
||
elif src == 'dc':
|
||
return get_stock_dc_a_divide_amount(symbol, page_count)
|
||
else:
|
||
return get_stock_tx_a_divide_amount(symbol, page_count)
|
||
|
||
|
||
def get_stock_tx_a_divide_amount(symbol: str = "sz000001", page_count: Optional[int] = None) -> pd.DataFrame:
|
||
"""
|
||
腾讯财经-历史分笔数据
|
||
https://gu.qq.com/sz300494/gp/detail
|
||
:param symbol: 股票代码
|
||
:type symbol: str
|
||
:param page_count: 限制页数
|
||
:type page_count: str
|
||
:return: 历史分笔数据
|
||
:rtype: pandas.DataFrame
|
||
"""
|
||
symbols = str(symbol).lower().split(".")
|
||
symbol = f"{symbols[1]}{symbols[0]}"
|
||
big_df = pd.DataFrame()
|
||
page = 0
|
||
warnings.warn("正在下载数据,请稍等")
|
||
while True:
|
||
try:
|
||
url = "http://stock.gtimg.cn/data/index.php"
|
||
params = {
|
||
"appn": "detail",
|
||
"action": "data",
|
||
"c": symbol,
|
||
"p": page,
|
||
}
|
||
r = requests.get(url, headers=headers, params=params)
|
||
text_data = r.text
|
||
temp_df = (
|
||
pd.DataFrame(eval(text_data[text_data.find("["):])[1].split("|"))
|
||
.iloc[:, 0]
|
||
.str.split("/", expand=True)
|
||
)
|
||
page += 1
|
||
big_df = pd.concat([big_df, temp_df], ignore_index=True)
|
||
time.sleep(0.5)
|
||
if page_count and page >= page_count:
|
||
break
|
||
except:
|
||
break
|
||
if not big_df.empty:
|
||
big_df = big_df.iloc[:, 1:].copy()
|
||
# big_df.columns = ["成交时间", "成交价格", "价格变动", "成交量", "成交金额", "性质"]
|
||
big_df.columns = rtq_vars.TICK_COLUMNS
|
||
|
||
big_df.reset_index(drop=True, inplace=True)
|
||
property_map = {
|
||
"S": "卖盘",
|
||
"B": "买盘",
|
||
"M": "中性盘",
|
||
}
|
||
# big_df["性质"] = big_df["性质"].map(property_map)
|
||
big_df["TYPE"] = big_df["TYPE"].map(property_map)
|
||
big_df = big_df.astype(
|
||
{
|
||
"TIME": str,
|
||
"PRICE": float,
|
||
"CHANGE": float,
|
||
"VOLUME": int,
|
||
"AMOUNT": int,
|
||
"TYPE": str,
|
||
}
|
||
)
|
||
return big_df
|
||
|
||
|
||
def get_stock_sina_a_divide_amount(symbol: str = "sz000001", page_count: Optional[int] = None, ) -> pd.DataFrame:
|
||
"""
|
||
腾新浪财经-历史分笔数据
|
||
https://vip.stock.finance.sina.com.cn/quotes_service/view/vMS_tradedetail.php?symbol=sh688553
|
||
:param symbol: 股票代码
|
||
:type symbol: str
|
||
:param page_count: 限制页数
|
||
:type page_count: str
|
||
:return: 历史分笔数据
|
||
:rtype: pandas.DataFrame
|
||
"""
|
||
warnings.warn("正在下载数据,请稍等")
|
||
symbols = str(symbol).lower().split(".")
|
||
symbol = f"{symbols[1]}{symbols[0]}"
|
||
page = 0
|
||
big_df = pd.DataFrame()
|
||
while True:
|
||
try:
|
||
url = "https://vip.stock.finance.sina.com.cn/quotes_service/view/vMS_tradedetail.php"
|
||
params = {
|
||
"symbol": symbol,
|
||
"date": get_current_date(date_format="%Y-%m-%d"),
|
||
"page": page
|
||
}
|
||
response = requests.get(url, headers=zh_sina_a_stock_headers, cookies=zh_sina_a_stock_cookies,
|
||
params=params)
|
||
temp_df = (pd.read_html(StringIO(response.content.decode("GBK")))[3])
|
||
big_df = pd.concat([big_df, temp_df], ignore_index=True)
|
||
page += 1
|
||
if page_count and page >= page_count:
|
||
break
|
||
except:
|
||
break
|
||
time.sleep(0.5)
|
||
if not big_df.empty:
|
||
big_df = big_df.iloc[:, 0:].copy()
|
||
# big_df.columns = ["成交时间", "成交价格", "涨跌幅", "价格变动", "成交量(手)", "成交额(元)", "性质"]
|
||
big_df.columns = rtq_vars.TODAY_TICK_COLUMNS
|
||
big_df.reset_index(drop=True, inplace=True)
|
||
# big_df = big_df.astype(
|
||
# {
|
||
# "成交时间": str,
|
||
# "成交价格": float,
|
||
# "涨跌幅": str,
|
||
# "价格变动": str,
|
||
# "成交量(手)": int,
|
||
# "成交额(元)": int,
|
||
# "性质": str,
|
||
# }
|
||
# )
|
||
big_df = big_df.astype(
|
||
{
|
||
"TIME": str,
|
||
"PRICE": float,
|
||
"PCHANGE": str,
|
||
"CHANGE": str,
|
||
"VOLUME": int,
|
||
"AMOUNT": int,
|
||
"TYPE": str,
|
||
}
|
||
)
|
||
return big_df
|
||
|
||
|
||
def __event_stream(url, params, ):
|
||
response = requests.get(url, params=params, stream=True)
|
||
event_data = ""
|
||
|
||
for line in response.iter_lines():
|
||
# 过滤掉保持连接的空行
|
||
if line:
|
||
event_data += line.decode() + "\n"
|
||
elif event_data:
|
||
yield event_data
|
||
event_data = ""
|
||
|
||
|
||
def get_stock_dc_a_divide_amount(symbol: str = "000001", page_count: Optional[int] = None) -> pd.DataFrame:
|
||
"""
|
||
东方财富-分时数据
|
||
https://quote.eastmoney.com/f1.html?newcode=0.000001
|
||
:param symbol: 股票代码
|
||
:type symbol: str
|
||
:return: 分时数据
|
||
:rtype: pandas.DataFrame
|
||
"""
|
||
symbols = str(symbol).lower().split(".")
|
||
symbol = symbols[0]
|
||
# print(symbol)
|
||
market_code = 1 if symbol.startswith("6") else 0
|
||
url = "https://70.push2.eastmoney.com/api/qt/stock/details/sse"
|
||
params = {
|
||
"fields1": "f1,f2,f3,f4",
|
||
"fields2": "f51,f52,f53,f54,f55",
|
||
"mpi": "2000",
|
||
"ut": "bd1d9ddb04089700cf9c27f6f7426281",
|
||
"fltt": "2",
|
||
"pos": "-0",
|
||
"secid": f"{market_code}.{symbol}",
|
||
"wbp2u": "|0|0|0|web",
|
||
}
|
||
|
||
big_df = pd.DataFrame() # 创建一个空的 DataFrame
|
||
|
||
for event in __event_stream(url, params):
|
||
# 从每个事件的数据行中删除 "data: ",然后解析 JSON
|
||
event_json = json.loads(event.replace("data: ", ""))
|
||
# 将 JSON 数据转换为 DataFrame,然后添加到主 DataFrame 中
|
||
temp_df = pd.DataFrame(
|
||
[item.split(",") for item in event_json["data"]["details"]]
|
||
)
|
||
big_df = pd.concat(objs=[big_df, temp_df], ignore_index=True)
|
||
break
|
||
|
||
big_df.columns = ["TIME", "PRICE", "VOLUME", "-", "TYPE"]
|
||
big_df["TYPE"] = big_df["TYPE"].map(
|
||
{"2": "买盘", "1": "卖盘", "4": "中性盘"}
|
||
)
|
||
big_df = big_df[["TIME", "PRICE", "VOLUME", "TYPE"]]
|
||
big_df["PRICE"] = pd.to_numeric(big_df["PRICE"], errors="coerce")
|
||
big_df["VOLUME"] = pd.to_numeric(big_df["VOLUME"], errors="coerce")
|
||
|
||
return big_df
|
||
|
||
|
||
if __name__ == '__main__':
|
||
df = realtime_tick(ts_code="000001.SZ", src="dc", page_count=1)
|
||
print(help(realtime_tick))
|
||
print(df)
|
||
# r = get_stock_dc_a_divide_amount()
|
||
# print(r)
|