diff --git a/HISTORY.md b/HISTORY.md index 4e9b7f8..4257ad3 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -9,6 +9,11 @@ master 专注股票量化数据,为Ai(爱)发电,向阳而生。 +2.1.0 (2024-05-05) +------------------ +1. 新增:舆情:人气榜单接口。 +2. 新增:债券:债券行情接口。 + 2.0.0 (2024-04-24) ------------------ 1. 新增:基金ETF行情接口。 @@ -19,39 +24,6 @@ master 1. 修复:修复概念返回为空bug。 2. flag:保卫3000点失败,继续保卫2500点。 -1.2.3 (2023-12-29) ------------------- -1. 修复:修复指数行情接口bug。 - -1.2.2 (2023-12-26) ------------------- -1. 更新:更新2024年交易日码表缓存文件。突发公告,除夕停止交易。 - -1.2.1 (2023-12-11) ------------------- -1. 更新:更新2024年交易日码表缓存文件。 - - -1.2.0 (2023-12-04) ------------------- -1. 新增:根据股票代码获取单只股票所属概念的接口。 - - -1.1.0 (2023-10-18) ------------------- -1. 更新:股票代码列表增加 list_date:股票上市日期字段 -2. 修复部分已知bug。 - -1.0.1 (2023-10-10) ------------------- -1. 兼容python3.6:支持qmt python3.6版本导入 -2. 依赖版本降低,扩大兼容性。 - -1.0.0 (2023-09-13) ------------------- -1. 更新:正式发布1.0.0正式版本 -2. 新增:五档和分时成交行情接口。 - ...... ------------------ diff --git a/README.md b/README.md index 3046cd6..253125a 100644 --- a/README.md +++ b/README.md @@ -193,10 +193,10 @@ print(res_df) ### (3)债券-Bond -| 数据 | API | 说明 | 备注 | -| -------------- | ---------------------------- | ----------------------------------- | ------------------------------------------------------ | -| 可转债代码 | bond.info.all_convert_code() | 获取所有A股市场的可转换债券代码信息 | 来源:1. [同花顺](http://data.10jqka.com.cn/ipo/bond/) | -| 其它数据排期中 | TODO | 若您有相关资源可以一起参与贡献 | | +| 数据 | API | 说明 | 备注 | +| ---------- | --------------------------------- | ----------------------------------- | ------------------------------------------------------ | +| 可转债代码 | bond.info.all_convert_code() | 获取所有A股市场的可转换债券代码信息 | 来源:1. [同花顺](http://data.10jqka.com.cn/ipo/bond/) | +| 可转债行情 | bond.market.list_market_current() | 获取A股市场的可转换债券最新行情 | 来源:新浪 | ### (4)舆情 @@ -208,6 +208,9 @@ print(res_df) | | sentiment.north.north_flow_current() | 获取北向资金(沪深港通)当前流入资金的行情 | 来源:1.[东方财富](https://data.eastmoney.com/hsgt/index.html) | | | sentiment.north.north_flow_min() | 获取北向资金分时行情 | | | | sentiment.north.north_flow() | 获取北向资金历史流入行情 | | +| **热度榜单** | sentiment.hot.pop_rank_100_east | 东方财富人气100榜单 | 来源:[东方财富](http://guba.eastmoney.com/rank/) | +| | sentiment.hot.hot_rank_100_ths() | 同花顺热度100排行榜 | 来源:[同花顺](https://dq.10jqka.com.cn/fuyao/hot_list_data/out/hot_list/v1/stock?stock_type=a&type=hour&list_type=normal) | +| | sentiment.hot.hot_concept_20_ths() | 同花顺热门概念板块20排行榜 | 来源:[同花顺](https://dq.10jqka.com.cn/fuyao/hot_list_data/out/hot_list/v1/stock?stock_type=a&type=hour&list_type=normal) | | 其它数据排期中 | TODO | 若您有相关资源可以一起参与贡献 | | ## 三、[数据源](https://adata.30006124.xyz/dataSource.html) @@ -263,9 +266,9 @@ print(res_df) > 对于项目有支持,包括但不仅限:内容贡献,bug提交,思想交流等等,对项目有影响的个人和机构 -| Simon | [bigbigbigfish](https://github.com/bigbigbigfish) | [LuneZ99](https://github.com/LuneZ99) | 匿名用户 | thue | [Triones009](https://github.com/Triones009) | **[adaaaaaa](https://github.com/adaaaaaa)** | **[LeslieWuboy](https://github.com/LeslieWuboy)** | -| ----- | ------------------------------------------------- | ------------------------------------- | -------- | ---- | ------------------------------------------- | ------------------------------------------- | ------------------------------------------------- | -| | | | | | | | | +| Simon | [bigbigbigfish](https://github.com/bigbigbigfish) | [LuneZ99](https://github.com/LuneZ99) | 匿名用户 | thue | [Triones009](https://github.com/Triones009) | **[adaaaaaa](https://github.com/adaaaaaa)** | **[LeslieWuboy](https://github.com/LeslieWuboy)** | [yinzhengxin](https://github.com/yinzhengxin) | +| ------------------------------------- | ------------------------------------------------- | --------------------------------------------- | -------- | ---- | ------------------------------------------- | ------------------------------------------- | ------------------------------------------------- | --------------------------------------------- | +| [yxm0513](https://github.com/yxm0513) | [hanxuanliang](https://github.com/hanxuanliang) | [akihara-sam](https://github.com/akihara-sam) | | | | | | | ---------------------------------------------------------------------- diff --git a/adata/__version__.py b/adata/__version__.py index ee9db7c..3a5396d 100644 --- a/adata/__version__.py +++ b/adata/__version__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -VERSION = (2, 0, 0) +VERSION = (2, 1, 0) PRERELEASE = None # alpha, beta or rc REVISION = None diff --git a/adata/bond/__init__.py b/adata/bond/__init__.py index 0b06bff..d9d702f 100644 --- a/adata/bond/__init__.py +++ b/adata/bond/__init__.py @@ -6,12 +6,14 @@ @log: change log """ from adata.bond.info import info +from adata.bond.market import market class Bond(object): def __init__(self) -> None: self.info = info + self.market = market bond = Bond() diff --git a/adata/bond/market/__init__.py b/adata/bond/market/__init__.py index 19aa1d8..5a5fde7 100644 --- a/adata/bond/market/__init__.py +++ b/adata/bond/market/__init__.py @@ -5,3 +5,13 @@ @time: 2023/5/31 @log: change log """ +from adata.bond.market.bond_market import BondMarket + + +class Market(BondMarket): + + def __init__(self) -> None: + super().__init__() + + +market = Market() diff --git a/adata/bond/market/bond_market.py b/adata/bond/market/bond_market.py index da527d8..a79a721 100644 --- a/adata/bond/market/bond_market.py +++ b/adata/bond/market/bond_market.py @@ -7,6 +7,7 @@ @time:2023/4/5 @log: """ +from adata.bond.market.bond_market_sina import BondMarketSina class BondMarket(object): @@ -14,3 +15,18 @@ class BondMarket(object): def __init__(self) -> None: super().__init__() + self.sina = BondMarketSina() + + def list_market_current(self, code_list=None): + """ + 获取多个可转债的最新行情信息 + :param code_list: 可转债代码 + :return: 当前最新的行情价格信息 + _MARKET_CURRENT_COLUMNS + """ + return self.sina.list_market_current(code_list) + + +if __name__ == '__main__': + print(BondMarket().list_market_current()) + print(BondMarket().list_market_current(code_list=['110044'])) diff --git a/adata/bond/market/bond_market_sina.py b/adata/bond/market/bond_market_sina.py new file mode 100644 index 0000000..7117c6c --- /dev/null +++ b/adata/bond/market/bond_market_sina.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +""" +@desc: 新浪 +https://vip.stock.finance.sina.com.cn/mkt/#hskzz_z + +@author: 1nchaos +@time:2023/4/5 +@log: +""" +import pandas as pd + +from adata.bond.market.bond_market_template import BondMarketTemplate +from adata.common.utils import requests + + +class BondMarketSina(BondMarketTemplate): + """bond 行情""" + + def __init__(self) -> None: + super().__init__() + + def list_market_current(self, code_list=None): + """ + 获取新浪的最新可转债行情 + url : http://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQNodeDataSimple + :param code_list: 可转债代码列表 + :return: 最新行情数据 + """ + # 0.进行参数拼接处理 + api_url = f"http://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQNodeDataSimple" + + # 2.循环请求 + data = [] + for i in range(100): + # 1.请求接口 + params = {"page": {i+1}, "num": "80", "sort": "symbol", + "asc": "1", "node": "hskzz_z", "_s_r_a": "page"} + res = requests.request('get', api_url, params=params) + res = res.json() + data.extend(res) + if len(res) < 80: + break + # 3. 结果筛选 + if code_list is not None: + new_data = [] + for d in data: + if d['code'] in code_list: + new_data.append(d) + data = new_data + # 4. 封装数据 + rename = {'code': 'bond_code', 'name': 'bond_name', 'pricechange': 'change', 'changepercent': 'change_pct', + 'settlement': 'pre_close', 'ticktime': 'time', 'trade': 'price'} + result_df = pd.DataFrame(data=data).rename(columns=rename) + columns_to_convert = ['price', 'open', 'high', 'low', 'pre_close', 'change', 'change_pct', 'volume', 'amount'] + result_df[columns_to_convert] = result_df[columns_to_convert].astype(float) + result_df_unique = result_df.drop_duplicates(keep='last', subset=['bond_code']) + return result_df_unique[self._MARKET_CURRENT_COLUMNS] + + +if __name__ == '__main__': + df = BondMarketSina().list_market_current(code_list=['110044', '127103']) + print(df) diff --git a/adata/bond/market/bond_market_template.py b/adata/bond/market/bond_market_template.py new file mode 100644 index 0000000..17d257c --- /dev/null +++ b/adata/bond/market/bond_market_template.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +""" +@desc: readme +@author: 1nchaos +@time: 2024/05/05 +@log: change log +""" + + +class BondMarketTemplate(object): + """ + 债券行情 + """ + _MARKET_CURRENT_COLUMNS = ['bond_code', 'bond_name', 'price', 'open', 'high', 'low', 'pre_close', 'change', + 'change_pct', 'volume', 'amount', 'time'] + + def list_market_current(self, code_list=None): + """ + 获取多个可转债的最新行情信息 + :param code_list: 可转债代码 + :return: 当前最新的行情价格信息 + _MARKET_CURRENT_COLUMNS + """ + pass diff --git a/adata/sentiment/__init__.py b/adata/sentiment/__init__.py index d279384..3fc968a 100644 --- a/adata/sentiment/__init__.py +++ b/adata/sentiment/__init__.py @@ -5,6 +5,7 @@ @time:2023/04/06 @log: """ +from adata.sentiment.hot import Hot from adata.sentiment.north_flow import NorthFlow from adata.sentiment.securities_margin import SecuritiesMargin from adata.sentiment.stock_lifting import StockLifting @@ -15,6 +16,8 @@ class Sentiment(StockLifting, SecuritiesMargin): def __init__(self) -> None: super().__init__() self.north = NorthFlow() + self.hot = Hot() sentiment = Sentiment() + diff --git a/adata/sentiment/hot.py b/adata/sentiment/hot.py new file mode 100644 index 0000000..0d54947 --- /dev/null +++ b/adata/sentiment/hot.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +""" +@desc: 热点榜单 TODO + +同花顺热点榜单 +https://eq.10jqka.com.cn/frontend/thsTopRank/index.html?fontzoom=no&client_userid=ceZLR&share_hxapp=gsc&share_action=webpage_share.hot_list_1714369375634&back_source=wxhy#/ + +@author: 1nchaos +@time: 2024/4/29 +@log: change log +""" +import pandas as pd + +from adata.common.base.base_ths import BaseThs +from adata.common.headers import ths_headers +from adata.common.utils import requests + + +class Hot(BaseThs): + """热门榜单""" + + # 东方财富人气榜 + def pop_rank_100_east(self): + """ + 东方财富人气榜100 + http://guba.eastmoney.com/rank/ + """ + # 1.url + url = "https://emappdata.eastmoney.com/stockrank/getAllCurrentList" + + # 2. 请求数据 + params = {"appId": "appId01", "globalId": "786e4c21-70dc-435a-93bb-38", + "marketType": "", "pageNo": 1, "pageSize": 100, } + res = requests.request(method='post', url=url, json=params).json() + df = pd.DataFrame(res["data"]) + + df["mark"] = ["0" + "." + item[2:] if "SZ" in item else "1" + "." + item[2:] + for item in df["sc"]] + ",".join(df["mark"]) + "?v=08926209912590994" + params = {"ut": "f057cbcbce2a86e2866ab8877db1d059", + "fltt": "2", "invt": "2", "fields": "f14,f3,f12,f2", + "secids": ",".join(df["mark"]) + ",?v=08926209912590994", } + url = "https://push2.eastmoney.com/api/qt/ulist.np/get" + res = requests.request(method='get', url=url, params=params) + + # 3. 解析封装数据 + data = res.json()["data"]["diff"] + rename = {'f2': 'price', 'f3': 'change_pct', 'f12': 'stock_code', 'f14': 'short_name', } + rank_df = pd.DataFrame(data).rename(columns=rename) + rank_df["change_pct"] = pd.to_numeric(rank_df["change_pct"], errors="coerce") + rank_df["price"] = pd.to_numeric(rank_df["price"], errors="coerce") + rank_df["change"] = rank_df["price"] * rank_df["change_pct"] / 100 + rank_df["rank"] = range(1, len(rank_df) + 1) + return rank_df[["rank", "stock_code", "short_name", "price", "change", "change_pct"]] + + def hot_rank_100_ths(self): + """ + 同花顺热股100 + https://dq.10jqka.com.cn/fuyao/hot_list_data/out/hot_list/v1/stock?stock_type=a&type=hour&list_type=normal + """ + api_url = 'https://dq.10jqka.com.cn/fuyao/hot_list_data/out/hot_list/v1/stock?stock_type=a&type=hour&list_type=normal' + headers = ths_headers.json_headers + headers['Host'] = 'dq.10jqka.com.cn' + res = requests.request(method='get', url=api_url, params={}, headers=headers) + data = res.json()['data']['stock_list'] + data_list = [] + for d in data: + d['concept_tag'] = ";".join(d['tag']['concept_tag']) + if 'popularity_tag' in d['tag']: + d['pop_tag'] = d['tag']['popularity_tag'].replace('\n', '') + data_list.append(d) + rename = {'order': 'rank', 'rise_and_fall': 'change_pct', 'code': 'stock_code', 'name': 'short_name', + 'rate': 'hot_value', 'concept_tag': 'concept_tag'} + rank_df = pd.DataFrame(data).rename(columns=rename) + rank_df = rank_df[["rank", "stock_code", "short_name", "change_pct", "hot_value", "pop_tag", "concept_tag"]] + return rank_df + + def hot_concept_20_ths(self, plate_type=1): + """ + 同花热门概念板块 + :param plate_type: 1.概念板块,2.行业板块;默认:概念板块 + """ + plate_type = 'concept' if plate_type == 1 else 'industry' + api_url = f'https://dq.10jqka.com.cn/fuyao/hot_list_data/out/hot_list/v1/plate?type={plate_type}' + headers = ths_headers.json_headers + headers['Host'] = 'dq.10jqka.com.cn' + res = requests.request(method='get', url=api_url, params={}, headers=headers) + data = res.json()['data']['plate_list'] + data_list = [] + for d in data: + data_list.append(d) + rename = {'order': 'rank', 'rise_and_fall': 'change_pct', 'rate': 'hot_value', 'code': 'concept_code', + 'name': 'concept_name'} + rank_df = pd.DataFrame(data).rename(columns=rename) + rank_df = rank_df[["rank", "concept_code", "concept_name", "change_pct", "hot_value", "hot_tag"]] + return rank_df + + +if __name__ == '__main__': + print(Hot().hot_rank_100_ths()) + print(Hot().pop_rank_100_east()) + print(Hot().hot_concept_20_ths(plate_type=1)) + print(Hot().hot_concept_20_ths(plate_type=2)) diff --git a/adata/stock/market/stock_market/stock_market.py b/adata/stock/market/stock_market/stock_market.py index 67df7dc..3609f68 100644 --- a/adata/stock/market/stock_market/stock_market.py +++ b/adata/stock/market/stock_market/stock_market.py @@ -88,7 +88,7 @@ def get_market_bar(self, stock_code: str = '000001'): if __name__ == '__main__': - print(StockMarket().get_market(stock_code='000001', start_date='2021-01-01', k_type=1)) + print(StockMarket().get_market(stock_code='300416', start_date='2021-01-01', k_type=1)) print(StockMarket().get_market_min(stock_code='000001')) print(StockMarket().list_market_current(code_list=['000001', '600001', '000795', '872925'])) print(StockMarket().get_market_five(stock_code='000001')) diff --git a/tests/adata_test/bond/bond_test.py b/tests/adata_test/bond/bond_test.py index 2ba1cb1..d74fceb 100644 --- a/tests/adata_test/bond/bond_test.py +++ b/tests/adata_test/bond/bond_test.py @@ -32,6 +32,12 @@ def test_all_convert_code(self): print(df) self.assertEqual(True, len(df) > 200) + def test_list_market_current(self): + print("开始测试:list_market_current") + df = adata.bond.market.list_market_current() + print(df) + self.assertEqual(True, len(df) > 200) + if __name__ == '__main__': unittest.main() diff --git a/tests/adata_test/sentiment/sentiment_test.py b/tests/adata_test/sentiment/sentiment_test.py index 63a70a8..3d47b95 100644 --- a/tests/adata_test/sentiment/sentiment_test.py +++ b/tests/adata_test/sentiment/sentiment_test.py @@ -31,6 +31,24 @@ def test_securities_margin(self): print(df) self.assertEqual(True, len(df) > 250) + def test_hot_rank_100_ths(self): + print("开始测试:hot_rank_100_ths") + df = adata.sentiment.hot.hot_rank_100_ths() + print(df) + self.assertEqual(True, len(df) == 100) + + def test_pop_rank_100_east(self): + print("开始测试:pop_rank_100_east") + df = adata.sentiment.hot.pop_rank_100_east() + print(df) + self.assertEqual(True, len(df) == 100) + + def test_hot_concept_20_ths(self): + print("开始测试:hot_concept_20_ths") + df = adata.sentiment.hot.hot_concept_20_ths() + print(df) + self.assertEqual(True, len(df) == 20) + if __name__ == '__main__': unittest.main()