[增强功能] 股票数据

This commit is contained in:
msincenselee 2020-04-12 15:02:01 +08:00
parent 78c592a118
commit 7ffc096943
4 changed files with 345 additions and 0 deletions

31
vnpy/data/stock/README.md Normal file
View 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线数据

View 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()

View 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()

View 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()