-
Notifications
You must be signed in to change notification settings - Fork 679
/
Copy pathutils.py
103 lines (90 loc) · 4.72 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#!usr/bin/env python3
# -*- coding:utf-8 -*-
__author__ = 'mayanqiong'
from datetime import datetime
import requests
from tqsdk.calendar import TqContCalendar
from tqsdk.datetime import _timestamp_nano_to_datetime, _timestamp_nano_to_str
class TqBacktestContinuous(object):
def __init__(self, start_dt: int, end_dt: int, headers=None) -> None:
"""
为回测时提供某个交易日的主连表
start_dt 开始的交易日
end_dt 结束的交易日
"""
self._cont_calendar = TqContCalendar(start_dt=_timestamp_nano_to_datetime(start_dt).date(),
end_dt=_timestamp_nano_to_datetime(end_dt).date(),
headers=headers)
def _get_history_cont_quotes(self, trading_day: int):
df = self._cont_calendar._get_cont_underlying_on_date(trading_day=trading_day)
quotes = {k: {"underlying_symbol": df.iloc[0][k]} for k in df.columns if k.startswith("KQ.m")}
return quotes
class TqBacktestDividend(object):
def __init__(self, start_dt: int, end_dt: int, headers=None) -> None:
"""
为回测时提供分红送股信息
start_dt 开始的交易日
end_dt 结束的交易日
"""
self._headers = headers
self._start_dt = start_dt
self._end_dt = end_dt
self._start_date = _timestamp_nano_to_str(self._start_dt, fmt='%Y%m%d')
self._end_date = _timestamp_nano_to_str(self._end_dt, fmt='%Y%m%d')
self._stocks = {} # 记录全部股票合约及从 stock-dividend 服务获取的原始数据
def _get_dividend(self, quotes, trading_day):
dt = _timestamp_nano_to_str(trading_day, fmt='%Y%m%d')
self._request_stock_dividend(quotes)
rsp_quotes = {}
# self._stocks 中应该已经记录了 quotes 中全部股票合约
for symbol, stock in self._stocks.items():
if stock['request_successed'] is True: # 从 stock-dividend 服务获取的原始数据
rsp_quotes[symbol] = {
'cash_dividend_ratio': [f"{item['drdate']},{item['cash']}" for item in stock['dividend_list']
if item['recorddate'] <= dt and item['cash'] > 0], # 除权除息日,每股分红(税后)
'stock_dividend_ratio': [f"{item['drdate']},{item['share']}" for item in stock['dividend_list']
if item['recorddate'] <= dt and item['share'] > 0] # 除权除息日,每股送转股数量
}
else:
# todo: stock['request_successed'] == False 表示请求不成功, 退回到原始合约服务中的分红送股数据, 用户会收到未来数据,
# 但是 tqsim 能保证取到结算时下一个交易日的分红信息
# 此时,quotes 为 tqbacktest._data['quotes'] 应该保存了全部的合约信息
rsp_quotes[symbol] = {
'cash_dividend_ratio': quotes[symbol].get('cash_dividend_ratio', []),
'stock_dividend_ratio': quotes[symbol].get('stock_dividend_ratio', [])
}
return rsp_quotes
def _request_stock_dividend(self, quotes):
# 对于股票合约,从 stock-dividend 服务请求回测时间段的分红方案
stock_list = [s for s in quotes if quotes[s]['ins_class'] == 'STOCK' and s not in self._stocks]
if len(stock_list) == 0:
return
# 每个合约只会请求一次,请求失败就退回到原始合约服务中的分红送股数据
for s in stock_list:
self._stocks[s] = {
'request_successed': False,
'dividend_list': []
}
# https://github.com/shinnytech/stock-dividend
rsp = requests.get(url="https://stock-dividend.shinnytech.com/query",
headers=self._headers, timeout=30,
params={
"stock_list": ','.join(stock_list),
"start_date": self._start_date,
"end_date": self._end_date
})
if rsp.status_code != 200:
return
result = rsp.json().get('result')
for s in stock_list:
self._stocks[s]['request_successed'] = True
for item in result:
"""
stockcode: 证券代码
marketcode: 市场代码
share: 每股送转股数量
cash: 每股分红(税后)
recorddate: 股权登记日
drdate: 除权除息日
"""
self._stocks[f"{item['marketcode']}.{item['stockcode']}"]["dividend_list"].append(item)