[增强功能] 股票数据
This commit is contained in:
parent
78c592a118
commit
7ffc096943
31
vnpy/data/stock/README.md
Normal file
31
vnpy/data/stock/README.md
Normal file
@ -0,0 +1,31 @@
|
||||
股票类相关数据接口
|
||||
|
||||
|
||||
基础数据
|
||||
|
||||
|
||||
获取/更新股票的基本资料
|
||||
参考/下载: http://baostock.com/baostock/index.php/%E8%AF%81%E5%88%B8%E5%9F%BA%E6%9C%AC%E8%B5%84%E6%96%99
|
||||
python stock_base.py
|
||||
保存二进制对象dict{vt_symbol: dict} => stock_base.pkb2
|
||||
|
||||
|
||||
除权除息
|
||||
|
||||
更新股票除权除息信息 (2006年)
|
||||
参考/下载: http://baostock.com/baostock/index.php/%E9%99%A4%E6%9D%83%E9%99%A4%E6%81%AF%E4%BF%A1%E6%81%AF
|
||||
python stock_dividend.py
|
||||
保存csv文件=> stock_dividend.csv
|
||||
|
||||
复权因子
|
||||
|
||||
获取/更新股票复权因子(2006年开始)
|
||||
参考/下载: http://baostock.com/baostock/index.php/%E5%A4%8D%E6%9D%83%E5%9B%A0%E5%AD%90%E4%BF%A1%E6%81%AF
|
||||
python adjust_factor.py
|
||||
保存二进制对象 dict {vt_symbol, []} => stock_adjust_factor.pkb2
|
||||
|
||||
|
||||
5分钟K线数据
|
||||
|
||||
|
||||
|
123
vnpy/data/stock/adjust_factor.py
Normal file
123
vnpy/data/stock/adjust_factor.py
Normal file
@ -0,0 +1,123 @@
|
||||
# flake8: noqa
|
||||
"""
|
||||
# 追加/更新股票复权因子
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
from typing import Any
|
||||
from collections import OrderedDict
|
||||
import pandas as pd
|
||||
|
||||
vnpy_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
||||
if vnpy_root not in sys.path:
|
||||
sys.path.append(vnpy_root)
|
||||
|
||||
os.environ["VNPY_TESTING"] = "1"
|
||||
import baostock as bs
|
||||
from vnpy.trader.constant import Exchange
|
||||
from vnpy.trader.utility import load_json, load_data_from_pkb2, save_data_to_pkb2, extract_vt_symbol
|
||||
from vnpy.data.tdx.tdx_common import get_stock_type
|
||||
from vnpy.data.stock.stock_base import get_stock_base
|
||||
import baostock as bs
|
||||
import pandas as pd
|
||||
|
||||
ADJUST_FACTOR_FILE = 'stock_adjust_factor.pkb2'
|
||||
|
||||
|
||||
def get_all_adjust_factor():
|
||||
""" 获取所有股票复权因子"""
|
||||
cache_file_name = os.path.abspath(os.path.join(os.path.dirname(__file__), ADJUST_FACTOR_FILE))
|
||||
|
||||
data = load_data_from_pkb2(cache_file_name)
|
||||
if data is None:
|
||||
return download_adjust_factor()
|
||||
else:
|
||||
return data
|
||||
|
||||
def get_adjust_factor(vt_symbol: str, stock_name: str = '', need_login: bool = True):
|
||||
"""
|
||||
通过baostock,获取复权因子
|
||||
:param vt_symbol:
|
||||
:param stock_name:
|
||||
:param need_login:
|
||||
:return:
|
||||
"""
|
||||
if need_login:
|
||||
login_msg = bs.login()
|
||||
if login_msg.error_code != '0':
|
||||
print(f'证券宝登录错误代码:{login_msg.error_code}, 错误信息:{login_msg.error_msg}')
|
||||
return []
|
||||
|
||||
symbol, exchange = extract_vt_symbol(vt_symbol)
|
||||
bs_code = '.'.join(['sh' if exchange == Exchange.SSE else 'sz', symbol])
|
||||
|
||||
print(f'开始获取{stock_name} {bs_code}得复权因子')
|
||||
rs = bs.query_adjust_factor(
|
||||
code=bs_code,
|
||||
start_date='2006-01-01'
|
||||
)
|
||||
if rs.error_code != '0':
|
||||
print(f'证券宝获取沪深A股复权因子数据,错误代码:{rs.error_code}, 错误信息:{rs.error_msg}')
|
||||
return []
|
||||
|
||||
# [dict] => dataframe
|
||||
|
||||
print(f'返回字段:{rs.fields}')
|
||||
result_list = []
|
||||
while (rs.error_code == '0') and rs.next():
|
||||
row = rs.get_row_data()
|
||||
exchange_code, stock_code = row[0].split('.')
|
||||
d = {
|
||||
'exchange': exchange.value, # 证券交易所
|
||||
'code': stock_code, # 证券代码
|
||||
'name': stock_name, # 证券中文名称
|
||||
'dividOperateDate': row[1], # 除权除息日期
|
||||
'foreAdjustFactor': float(row[2]), # 向前复权因子 除权除息日前一个交易日的收盘价/除权除息日最近的一个交易日的前收盘价
|
||||
'backAdjustFactor': float(row[3]), # 向后复权因子 除权除息日最近的一个交易日的前收盘价/除权除息日前一个交易日的收盘价
|
||||
'adjustFactor': float(row[4]) # 本次复权因子
|
||||
|
||||
}
|
||||
result_list.append(d)
|
||||
|
||||
print(f'{d}')
|
||||
return result_list
|
||||
|
||||
|
||||
def download_adjust_factor():
|
||||
"""
|
||||
下载更新股票复权因子
|
||||
:return:
|
||||
"""
|
||||
|
||||
# 获取所有股票基础信息
|
||||
base_dict = get_stock_base()
|
||||
|
||||
# 尝试从本地缓存获取
|
||||
cache_file_name = os.path.abspath(os.path.join(os.path.dirname(__file__), ADJUST_FACTOR_FILE))
|
||||
factor_dict = load_data_from_pkb2(cache_file_name)
|
||||
if factor_dict is None:
|
||||
factor_dict = dict()
|
||||
|
||||
login_msg = bs.login()
|
||||
if login_msg.error_code != '0':
|
||||
print(f'证券宝登录错误代码:{login_msg.error_code}, 错误信息:{login_msg.error_msg}')
|
||||
return
|
||||
|
||||
for k, v in base_dict.items():
|
||||
if v.get('类型') != '股票':
|
||||
continue
|
||||
|
||||
factor_list = get_adjust_factor(vt_symbol=k, stock_name=v.get('name'), need_login=False)
|
||||
|
||||
if len(factor_list) > 0:
|
||||
factor_dict.update({k: factor_list})
|
||||
|
||||
if len(factor_dict) > 0:
|
||||
save_data_to_pkb2(factor_dict, cache_file_name)
|
||||
print(f'保存除权除息至文件:{cache_file_name}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
download_adjust_factor()
|
90
vnpy/data/stock/stock_base.py
Normal file
90
vnpy/data/stock/stock_base.py
Normal file
@ -0,0 +1,90 @@
|
||||
# flake8: noqa
|
||||
"""
|
||||
# 追加/更新股票基础信息
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
from typing import Any
|
||||
from collections import OrderedDict
|
||||
import pandas as pd
|
||||
|
||||
vnpy_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
||||
if vnpy_root not in sys.path:
|
||||
sys.path.append(vnpy_root)
|
||||
|
||||
os.environ["VNPY_TESTING"] = "1"
|
||||
import baostock as bs
|
||||
from vnpy.trader.constant import Exchange
|
||||
from vnpy.trader.utility import load_json, load_data_from_pkb2, save_data_to_pkb2
|
||||
from vnpy.data.tdx.tdx_common import get_stock_type
|
||||
import baostock as bs
|
||||
|
||||
stock_type_map = {
|
||||
"1": '股票', "2": "指数", "3": "其他"
|
||||
}
|
||||
STOCK_BASE_FILE = 'stock_base.pkb2'
|
||||
|
||||
|
||||
def get_stock_base():
|
||||
""" 获取股票基础信息"""
|
||||
base_file_name = os.path.abspath(os.path.join(os.path.dirname(__file__), STOCK_BASE_FILE))
|
||||
|
||||
base_data = load_data_from_pkb2(base_file_name)
|
||||
if base_data is None:
|
||||
return update_stock_base()
|
||||
else:
|
||||
return base_data
|
||||
|
||||
|
||||
def update_stock_base():
|
||||
"""
|
||||
更新股票基础信息
|
||||
:return:
|
||||
"""
|
||||
base_file_name = os.path.abspath(os.path.join(os.path.dirname(__file__), STOCK_BASE_FILE))
|
||||
|
||||
base_data = load_data_from_pkb2(base_file_name)
|
||||
|
||||
if base_data is None:
|
||||
base_data = dict()
|
||||
|
||||
login_msg = bs.login()
|
||||
if login_msg.error_code != '0':
|
||||
print(f'证券宝登录错误代码:{login_msg.error_code}, 错误信息:{login_msg.error_msg}')
|
||||
return base_data
|
||||
|
||||
rs = bs.query_stock_basic()
|
||||
if rs.error_code != '0':
|
||||
print(f'证券宝获取沪深A股历史K线数据错误代码:{rs.error_code}, 错误信息:{rs.error_msg}')
|
||||
return
|
||||
|
||||
# [dict] => dataframe
|
||||
|
||||
print(f'返回字段:{rs.fields}')
|
||||
while (rs.error_code == '0') and rs.next():
|
||||
row = rs.get_row_data()
|
||||
exchange_code, stock_code = row[0].split('.')
|
||||
exchange = Exchange.SSE if exchange_code == 'sh' else Exchange.SZSE
|
||||
d = {
|
||||
'exchange': exchange.value,
|
||||
'code': stock_code,
|
||||
'name': row[1],
|
||||
'ipo_date': row[2],
|
||||
'out_date': row[3],
|
||||
'类型': stock_type_map.get(row[4], '其他'),
|
||||
'type': get_stock_type(stock_code),
|
||||
'status': '上市' if row[5] == '1' else '退市'
|
||||
}
|
||||
base_data.update({f'{stock_code}.{exchange.value}': d})
|
||||
# print(f'{d}')
|
||||
|
||||
save_data_to_pkb2(base_data, base_file_name)
|
||||
print(f'更新完毕')
|
||||
|
||||
return base_data
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
update_stock_base()
|
101
vnpy/data/stock/stock_dividend.py
Normal file
101
vnpy/data/stock/stock_dividend.py
Normal file
@ -0,0 +1,101 @@
|
||||
# flake8: noqa
|
||||
"""
|
||||
# 追加/更新股票除权除息
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
from typing import Any
|
||||
from collections import OrderedDict
|
||||
import pandas as pd
|
||||
|
||||
vnpy_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
||||
if vnpy_root not in sys.path:
|
||||
sys.path.append(vnpy_root)
|
||||
|
||||
os.environ["VNPY_TESTING"] = "1"
|
||||
import baostock as bs
|
||||
from vnpy.trader.constant import Exchange
|
||||
from vnpy.trader.utility import load_json, load_data_from_pkb2, save_data_to_pkb2, extract_vt_symbol
|
||||
from vnpy.data.tdx.tdx_common import get_stock_type
|
||||
from vnpy.data.stock.stock_base import get_stock_base
|
||||
import baostock as bs
|
||||
import pandas as pd
|
||||
|
||||
STOCK_DIVIDEND_FILE = 'stock_dividend.csv'
|
||||
years = [str(y) for y in range(2006, 2020)]
|
||||
|
||||
def update_stock_devidend():
|
||||
"""
|
||||
更新股票除权除息信息
|
||||
:return:
|
||||
"""
|
||||
stocks_data = get_stock_base()
|
||||
|
||||
login_msg = bs.login()
|
||||
if login_msg.error_code != '0':
|
||||
print(f'证券宝登录错误代码:{login_msg.error_code}, 错误信息:{login_msg.error_msg}')
|
||||
return
|
||||
|
||||
result_list = []
|
||||
|
||||
for k, v in stocks_data.items():
|
||||
if v.get('类型') != '股票':
|
||||
continue
|
||||
symbol, exchange = extract_vt_symbol(k)
|
||||
bs_code = '.'.join(['sh' if exchange == Exchange.SSE else 'sz', symbol])
|
||||
stock_name = v.get('name')
|
||||
|
||||
print(f'开始获取{stock_name} {bs_code}得除权除息')
|
||||
|
||||
for year in years:
|
||||
rs = bs.query_dividend_data(
|
||||
code=bs_code,
|
||||
year=year
|
||||
)
|
||||
if rs.error_code != '0':
|
||||
print(f'证券宝获取沪深A股除权除息数据,错误代码:{rs.error_code}, 错误信息:{rs.error_msg}')
|
||||
continue
|
||||
|
||||
# [dict] => dataframe
|
||||
|
||||
#print(f'返回字段:{rs.fields}')
|
||||
while (rs.error_code == '0') and rs.next():
|
||||
row = rs.get_row_data()
|
||||
exchange_code, stock_code = row[0].split('.')
|
||||
exchange = Exchange.SSE if exchange_code == 'sh' else Exchange.SZSE
|
||||
d = {
|
||||
'exchange': exchange.value,
|
||||
'code': stock_code,
|
||||
'name': stock_name,
|
||||
'dividPreNoticeDate': row[1], # 预批露公告日
|
||||
'dividAgmPumDate': row[2], # 股东大会公告日期
|
||||
'dividPlanAnnounceDate': row[3], # 预案公告日
|
||||
'dividPlanDate': row[4], # 分红实施公告日
|
||||
'dividRegistDate': row[5], # 股权登记告日
|
||||
'dividOperateDate': row[6], # 除权除息日期
|
||||
'dividPayDate': row[7], # 派息日
|
||||
'dividStockMarketDate': row[8], # 红股上市交易日
|
||||
'dividCashPsBeforeTax': row[9], # 每股股利税前
|
||||
'dividCashPsAfterTax': row[10], # 每股股利税后
|
||||
'dividStocksPs': row[11], # 每股红股
|
||||
'dividCashStock': row[12], # 分红送转
|
||||
'dividReserveToStockPs': row[13] # 每股转增资本
|
||||
}
|
||||
result_list.append(d)
|
||||
|
||||
print(f'{d}')
|
||||
|
||||
if len(result_list) > 0:
|
||||
df = pd.DataFrame(result_list)
|
||||
|
||||
export_file_name = os.path.abspath(os.path.join(os.path.dirname(__file__), STOCK_DIVIDEND_FILE))
|
||||
|
||||
df.to_csv(export_file_name)
|
||||
|
||||
print(f'保存除权除息至文件:{export_file_name}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
update_stock_devidend()
|
Loading…
Reference in New Issue
Block a user