gjdatac-api 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gjdatac_api/__init__.py +3 -0
- gjdatac_api/data_api_class.py +1468 -0
- gjdatac_api/dict_data.py +76 -0
- gjdatac_api/dolphin_db_info.py +108 -0
- gjdatac_api-0.0.1.dist-info/METADATA +18 -0
- gjdatac_api-0.0.1.dist-info/RECORD +8 -0
- gjdatac_api-0.0.1.dist-info/WHEEL +5 -0
- gjdatac_api-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1468 @@
|
|
|
1
|
+
# 此文件用于编写数据接口---类方式实现
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
import holidays
|
|
5
|
+
import asyncio
|
|
6
|
+
import pandas as pd
|
|
7
|
+
import dolphindb as ddb
|
|
8
|
+
|
|
9
|
+
from .dict_data import get_price_frequency_dict, get_price_data_type_dict, get_instruments_type_dict
|
|
10
|
+
from .dolphin_db_info import *
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class GJDataC:
|
|
14
|
+
|
|
15
|
+
def __init__(self):
|
|
16
|
+
"""
|
|
17
|
+
用于定义一些不同接口所需的变量以及一些初始化操作
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
# 数据库参数
|
|
21
|
+
# self.host = HOST
|
|
22
|
+
# self.port = PORT
|
|
23
|
+
# self.user_id = USER_ID
|
|
24
|
+
# self.password = PASSWORD
|
|
25
|
+
|
|
26
|
+
# 连接数据库
|
|
27
|
+
# self.db_session = ddb.session()
|
|
28
|
+
# self.db_session.connect(self.host, self.port, self.user_id, self.password)
|
|
29
|
+
|
|
30
|
+
''' get_price 接口相关属性 '''
|
|
31
|
+
self.get_price_data = None # 用于存放get_price接口数据
|
|
32
|
+
|
|
33
|
+
''' get_instruments 接口相关属性 '''
|
|
34
|
+
self.get_instruments_data = None # 用于存放get_instruments接口数据
|
|
35
|
+
|
|
36
|
+
''' get_trading_dates 接口相关属性 '''
|
|
37
|
+
self.get_trading_dates_data = None # 用于存放get_trading_dates接口数据
|
|
38
|
+
|
|
39
|
+
''' get_margin_ratio 接口相关属性 '''
|
|
40
|
+
self.get_margin_ratio_data = None # 用于存放get_margin_ratio接口数据
|
|
41
|
+
|
|
42
|
+
''' get_fee 接口相关属性 '''
|
|
43
|
+
self.get_fee_data = None # 用于存放get_fee接口数据
|
|
44
|
+
|
|
45
|
+
''' get_limit_position 接口相关属性 '''
|
|
46
|
+
self.get_limit_position_data = None # 用于存放get_limit_position接口数据
|
|
47
|
+
|
|
48
|
+
''' get_activate_contract 接口相关属性 '''
|
|
49
|
+
self.get_active_contract_data = None # 用于存放get_activate_contract接口数据
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def connect_db(table_name, db_path):
|
|
53
|
+
"""
|
|
54
|
+
此方法用于根据不同的数据表及数据库获取数据,只返回Table对象,对应的数据处理在对应的数据接口处理
|
|
55
|
+
:param table_name: 数据表路径
|
|
56
|
+
:param db_path: 数据库路径
|
|
57
|
+
:return 根据数据库和表路径获取的数据(Table对象), 会话信息(db_session)
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
# 连接数据库
|
|
61
|
+
db_session = ddb.session()
|
|
62
|
+
db_session.connect(COMPANY_HOST, COMPANY_PORT, COMPANY_USER_ID, COMPANY_PASSWORD)
|
|
63
|
+
|
|
64
|
+
# 从数据库中获取数据
|
|
65
|
+
data = db_session.loadTable(tableName=table_name, dbPath=db_path)
|
|
66
|
+
|
|
67
|
+
return data, db_session
|
|
68
|
+
|
|
69
|
+
""" 通用方法 """
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def general_validate_params_required(param, param_name):
|
|
73
|
+
"""
|
|
74
|
+
校验参数是否必填
|
|
75
|
+
:param param: 参数值
|
|
76
|
+
:param param_name: 参数名称
|
|
77
|
+
:return: None (用于校验数据无需返回值)
|
|
78
|
+
"""
|
|
79
|
+
if not param:
|
|
80
|
+
raise ValueError(f"{param_name} is required")
|
|
81
|
+
|
|
82
|
+
@staticmethod
|
|
83
|
+
def general_validate_either_or(field_1_name, field_1_value, field_2_name, field_2_value):
|
|
84
|
+
"""
|
|
85
|
+
此方法用于验证二选一的参数填写情况
|
|
86
|
+
:param field_1_name: 参数1名称
|
|
87
|
+
:param field_1_value: 参数1值
|
|
88
|
+
:param field_2_name: 参数2名称
|
|
89
|
+
:param field_2_value: 参数2值
|
|
90
|
+
:return: None (用于校验数据无需返回值)
|
|
91
|
+
"""
|
|
92
|
+
if not field_1_value and not field_2_value:
|
|
93
|
+
raise ValueError(f"{field_1_name} or {field_2_name} is required")
|
|
94
|
+
if field_1_value and field_2_value:
|
|
95
|
+
raise ValueError(f"{field_1_name} and {field_2_name} cannot be both provided")
|
|
96
|
+
|
|
97
|
+
def general_validate_date(self, date_str):
|
|
98
|
+
"""
|
|
99
|
+
判断字符串是否为datetime.date, datetime.datetime格式。
|
|
100
|
+
:param date_str: 待判断的字符串。
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
True: 如果是日期格式,返回 True。
|
|
104
|
+
False: 否则返回 False。
|
|
105
|
+
"""
|
|
106
|
+
if not self.general_validate_date_str_is_datetime_type(date_str):
|
|
107
|
+
return self.general_validate_date_str_is_date_type(date_str)
|
|
108
|
+
return True
|
|
109
|
+
|
|
110
|
+
@staticmethod
|
|
111
|
+
def general_validate_date_str_is_datetime_type(date_data):
|
|
112
|
+
"""
|
|
113
|
+
此方法用于验证日期字段是否为可以转换为datetime的类型
|
|
114
|
+
:param date_data: 日期字符串
|
|
115
|
+
|
|
116
|
+
:return : 如果可以转换为datetime类型,返回 True, 否则返回 False。
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
try:
|
|
120
|
+
datetime.datetime.strptime(date_data, '%Y-%m-%d %H:%M:%S')
|
|
121
|
+
return True
|
|
122
|
+
except ValueError:
|
|
123
|
+
return False
|
|
124
|
+
|
|
125
|
+
@staticmethod
|
|
126
|
+
def general_validate_date_str_is_date_type(date_data):
|
|
127
|
+
"""
|
|
128
|
+
此方法用于验证日期字段是否为可以转换为date的类型
|
|
129
|
+
:param date_data: 日期字符串
|
|
130
|
+
|
|
131
|
+
:return : 如果可以转换为date类型,返回 True, 否则返回 False。
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
datetime.datetime.strptime(date_data, '%Y-%m-%d')
|
|
136
|
+
return True
|
|
137
|
+
except ValueError:
|
|
138
|
+
return False
|
|
139
|
+
|
|
140
|
+
@staticmethod
|
|
141
|
+
def general_validate_field_str_or_list(field_value, field_name):
|
|
142
|
+
"""
|
|
143
|
+
对参数的类型进行校验,判断是否为字符串或字符串列表。
|
|
144
|
+
:param field_value: 待校验的参数值。
|
|
145
|
+
:param field_name: 待校验的参数名称。
|
|
146
|
+
:return: None (用于校验数据无需返回值)
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
if field_value and not isinstance(field_value, (str, list)):
|
|
150
|
+
raise ValueError(f"{field_name} should be a string or a list of strings")
|
|
151
|
+
|
|
152
|
+
@staticmethod
|
|
153
|
+
def general_validate_param_is_str(param_name, param_value):
|
|
154
|
+
"""
|
|
155
|
+
校验参数是否为str类型
|
|
156
|
+
:param param_name: 参数名称
|
|
157
|
+
:param param_value: 参数值
|
|
158
|
+
|
|
159
|
+
:return: None (用于校验数据无需返回值)
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
if not isinstance(param_value, str):
|
|
163
|
+
raise ValueError(f"{param_name} type error, please input str type")
|
|
164
|
+
|
|
165
|
+
def __general_validate_asset_type(self, asset_type):
|
|
166
|
+
"""
|
|
167
|
+
对asset_type进行校验
|
|
168
|
+
:param asset_type: str, 合约类型
|
|
169
|
+
|
|
170
|
+
:return: None (用于校验数据无需返回值)
|
|
171
|
+
"""
|
|
172
|
+
self.general_validate_params_required(asset_type, "asset_type") # 校验必填参数
|
|
173
|
+
if not isinstance(asset_type, str):
|
|
174
|
+
raise ValueError("asset_type should be a string")
|
|
175
|
+
if asset_type not in ["future", "option"]:
|
|
176
|
+
raise ValueError("asset_type should be 'future' or 'option'")
|
|
177
|
+
|
|
178
|
+
def general_validate_fields(self, data, fields):
|
|
179
|
+
"""
|
|
180
|
+
根据用户选择的字段进行字段筛选
|
|
181
|
+
:param fields: 字段列表--用户传入的需要返回的字段
|
|
182
|
+
:param data: 数据
|
|
183
|
+
|
|
184
|
+
:return data: 根据用户填写的字段筛选后的数据
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
''' 校验fields '''
|
|
188
|
+
# 如果没有传入fields, 则返回所有字段
|
|
189
|
+
if not fields:
|
|
190
|
+
return data
|
|
191
|
+
self.general_validate_field_str_or_list(fields, "fields")
|
|
192
|
+
|
|
193
|
+
''' 根据fields进行处理 '''
|
|
194
|
+
# 如果传入了fields,则根据传入的fields进行处理
|
|
195
|
+
columns_list = data.columns.tolist()
|
|
196
|
+
|
|
197
|
+
if isinstance(fields, str):
|
|
198
|
+
self._deal_fields(fields, columns_list)
|
|
199
|
+
data = data[[fields]]
|
|
200
|
+
elif isinstance(fields, list):
|
|
201
|
+
for field in fields:
|
|
202
|
+
self._deal_fields(field, columns_list)
|
|
203
|
+
data = data[fields]
|
|
204
|
+
|
|
205
|
+
return data
|
|
206
|
+
|
|
207
|
+
@staticmethod
|
|
208
|
+
def _deal_fields(_field, columns_list):
|
|
209
|
+
"""
|
|
210
|
+
判断用户选择的字段是否存在
|
|
211
|
+
|
|
212
|
+
:param columns_list: 数据的所有字段
|
|
213
|
+
|
|
214
|
+
:return: None (用于校验数据无需返回值)
|
|
215
|
+
"""
|
|
216
|
+
if _field not in columns_list:
|
|
217
|
+
raise ValueError(
|
|
218
|
+
f"fields: got invalided value '{_field}', choose any in "
|
|
219
|
+
f"{columns_list}")
|
|
220
|
+
|
|
221
|
+
@staticmethod
|
|
222
|
+
def general_filter_data_by_field(data, field_name, field_value):
|
|
223
|
+
"""
|
|
224
|
+
根据指定的字段进行数据过滤
|
|
225
|
+
:param data: pandas.DataFrame, 数据
|
|
226
|
+
:param field_name: str, 过滤字段
|
|
227
|
+
:param field_value: str or list, 过滤值
|
|
228
|
+
|
|
229
|
+
:return 根据字段过滤后的数据
|
|
230
|
+
"""
|
|
231
|
+
|
|
232
|
+
return data[data[field_name].isin(field_value)] if isinstance(
|
|
233
|
+
field_value, list) else data[data[field_name] == field_value]
|
|
234
|
+
|
|
235
|
+
def _general_filter_data_by_field(self, data, field_name, field_value):
|
|
236
|
+
"""
|
|
237
|
+
根据自定字段进行类型校验以及数据筛选
|
|
238
|
+
:param data: 需要处理的数据
|
|
239
|
+
:param field_name: 字段名
|
|
240
|
+
:param field_value: 字段值
|
|
241
|
+
|
|
242
|
+
:return : 根据字段过滤后的数据
|
|
243
|
+
"""
|
|
244
|
+
self.general_validate_field_str_or_list(field_value, field_name)
|
|
245
|
+
return self.general_filter_data_by_field(data, field_name, field_value)
|
|
246
|
+
|
|
247
|
+
def general_date_str_to_date(self, date_str):
|
|
248
|
+
"""
|
|
249
|
+
将date类型的str转换成datetime.date类型
|
|
250
|
+
:param date_str: str, 日期字符串
|
|
251
|
+
"""
|
|
252
|
+
if not self.general_validate_date_str_is_date_type(date_str):
|
|
253
|
+
raise ValueError("date_str is not a valid date string, please use the format 'YYYY-MM-DD")
|
|
254
|
+
|
|
255
|
+
return datetime.datetime.strptime(date_str, "%Y-%m-%d")
|
|
256
|
+
|
|
257
|
+
""" get_price(获取行情数据接口) """
|
|
258
|
+
|
|
259
|
+
def get_price(self, order_book_ids=None, asset_type="future", frequency=None, start_date=None, end_date=None,
|
|
260
|
+
fields=None):
|
|
261
|
+
"""
|
|
262
|
+
行情数据接口
|
|
263
|
+
:param order_book_ids: 合约代码--必填
|
|
264
|
+
:param asset_type: 合约类型--必填, 默认为--'future'
|
|
265
|
+
:param frequency: 频率--必填
|
|
266
|
+
:param start_date: 开始日期--选填
|
|
267
|
+
:param end_date: 结束日期--选填
|
|
268
|
+
:param fields: 字段列表--选填
|
|
269
|
+
:return: 行情数据
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
# # 从数据库获取的数据是Table类型,需要转换为DataFrame类型, 并按照时间进行排序
|
|
273
|
+
# self.get_price_data = self.get_price_data.sort_values(by='datetime', ascending=True)
|
|
274
|
+
|
|
275
|
+
''' 数据校验 (先对必填参数进行校验)'''
|
|
276
|
+
# 对order_book_ids进行校验
|
|
277
|
+
self.__get_price_validate_order_book_ids(order_book_ids)
|
|
278
|
+
|
|
279
|
+
# 对asset_type进行校验
|
|
280
|
+
self.__general_validate_asset_type(asset_type)
|
|
281
|
+
|
|
282
|
+
# 对frequency进行校验
|
|
283
|
+
self.__get_price_validate_frequency(frequency)
|
|
284
|
+
|
|
285
|
+
# 对 start_date 和 end_date 进行校验
|
|
286
|
+
self.__get_price_validate_start_end_date(start_date, end_date)
|
|
287
|
+
|
|
288
|
+
''' 参数校验完成后,开始根据参数从服务器获取数据 '''
|
|
289
|
+
# 此处获取数据时已经根据order_book_ids筛选过一次数据了,所以后续不需要再对该字段进行筛选
|
|
290
|
+
self.__get_price_data_get_data(order_book_ids, asset_type, frequency)
|
|
291
|
+
|
|
292
|
+
''' 数据处理 '''
|
|
293
|
+
# 根据frequency进行处理
|
|
294
|
+
self.__get_price_by_type_frequency(asset_type, frequency)
|
|
295
|
+
|
|
296
|
+
# 根据start_date和end_date筛选数据
|
|
297
|
+
self.__get_price_filter_by_date(start_date, end_date, order_book_ids)
|
|
298
|
+
|
|
299
|
+
# 对fields进行处理
|
|
300
|
+
self.__get_price_validate_fields(fields)
|
|
301
|
+
|
|
302
|
+
return self.get_price_data
|
|
303
|
+
|
|
304
|
+
# @staticmethod
|
|
305
|
+
def __get_price_validate_order_book_ids(self, order_book_ids):
|
|
306
|
+
"""
|
|
307
|
+
对order_book_ids 类型 以及 是否必填 进行校验
|
|
308
|
+
:param order_book_ids: 合约类型
|
|
309
|
+
|
|
310
|
+
:return: None
|
|
311
|
+
"""
|
|
312
|
+
self.general_validate_params_required(order_book_ids, "order_book_ids") # 校验必填参数
|
|
313
|
+
self.general_validate_field_str_or_list(order_book_ids, "order_book_ids") # 校验参数类型
|
|
314
|
+
|
|
315
|
+
# def get_price_filter_by_order_book_ids(self, order_book_ids):
|
|
316
|
+
# """
|
|
317
|
+
# 根据order_book_ids筛选数据
|
|
318
|
+
# """
|
|
319
|
+
# if isinstance(order_book_ids, str):
|
|
320
|
+
# self.get_price_data = self.get_price_data[self.get_price_data["order_book_ids"] == order_book_ids]
|
|
321
|
+
# elif isinstance(order_book_ids, list):
|
|
322
|
+
# self.get_price_data = self.get_price_data[self.get_price_data["order_book_ids"].isin(order_book_ids)]
|
|
323
|
+
# return self.get_price_data
|
|
324
|
+
|
|
325
|
+
def __get_price_validate_frequency(self, frequency):
|
|
326
|
+
"""
|
|
327
|
+
对frequency进行校验
|
|
328
|
+
|
|
329
|
+
:param frequency: 频率
|
|
330
|
+
:return: None
|
|
331
|
+
"""
|
|
332
|
+
|
|
333
|
+
self.general_validate_params_required(frequency, "frequency") # 校验必填参数
|
|
334
|
+
if not isinstance(frequency, str):
|
|
335
|
+
raise ValueError("frequency should be a string")
|
|
336
|
+
|
|
337
|
+
def __get_price_validate_start_end_date(self, start_date, end_date):
|
|
338
|
+
"""
|
|
339
|
+
对 start_date 和 end_date 进行校验
|
|
340
|
+
校验 start_date 和 end_date 是否同时提供,或者都不提供。
|
|
341
|
+
|
|
342
|
+
:param start_date: 开始日期
|
|
343
|
+
:param end_date: 结束日期
|
|
344
|
+
:return: None
|
|
345
|
+
"""
|
|
346
|
+
if (start_date and not end_date) or (not start_date and end_date):
|
|
347
|
+
raise ValueError("start_date and end_date should be both provided or not provided at all")
|
|
348
|
+
if start_date and end_date:
|
|
349
|
+
# 如果提供了,则进行进一步校验
|
|
350
|
+
is_start_datetime = self._is_convertible_datetime(start_date)
|
|
351
|
+
is_end_datetime = self._is_convertible_datetime(end_date)
|
|
352
|
+
if not is_end_datetime or not is_start_datetime:
|
|
353
|
+
raise ValueError(
|
|
354
|
+
"start_date and end_date should be datetime.datetime objects or "
|
|
355
|
+
"convertible to datetime.datetime objects")
|
|
356
|
+
|
|
357
|
+
# 如果传入的数据类型符合要求,进行转换
|
|
358
|
+
start_date, end_date = self._get_price_convert_start_end_date(start_date, end_date)
|
|
359
|
+
if start_date > end_date:
|
|
360
|
+
raise ValueError("start_date should be earlier than end_date")
|
|
361
|
+
|
|
362
|
+
@staticmethod
|
|
363
|
+
def _get_price_convert_start_end_date(start_date, end_date):
|
|
364
|
+
"""
|
|
365
|
+
将 start_date 和 end_date 转换为 datetime 类型。
|
|
366
|
+
|
|
367
|
+
:param start_date: 开始日期,可以是 datetime.datetime 对象或字符串。
|
|
368
|
+
:param end_date: 结束日期,可以是 datetime.datetime 对象或字符串。
|
|
369
|
+
:return: 转换后的 start_date 和 end_date。
|
|
370
|
+
"""
|
|
371
|
+
|
|
372
|
+
start_date = datetime.datetime.strptime(start_date, '%Y-%m-%d %H:%M:%S') if isinstance(start_date, str) \
|
|
373
|
+
else start_date
|
|
374
|
+
end_date = datetime.datetime.strptime(end_date, '%Y-%m-%d %H:%M:%S') if isinstance(end_date, str) \
|
|
375
|
+
else end_date
|
|
376
|
+
|
|
377
|
+
return start_date, end_date
|
|
378
|
+
|
|
379
|
+
@staticmethod
|
|
380
|
+
def _is_convertible_datetime(date_data):
|
|
381
|
+
"""
|
|
382
|
+
判断 date_data 是否是 datetime 类型或可以转换成 datetime 类型的字符串,并精确到秒。
|
|
383
|
+
param: date_data: 要判断的值。
|
|
384
|
+
|
|
385
|
+
Returns:
|
|
386
|
+
True 如果 start_date 是 datetime 类型或可以转换成 datetime 类型的字符串,否则 False。
|
|
387
|
+
"""
|
|
388
|
+
|
|
389
|
+
if isinstance(date_data, datetime.datetime):
|
|
390
|
+
return True
|
|
391
|
+
elif isinstance(date_data, str):
|
|
392
|
+
try:
|
|
393
|
+
datetime.datetime.strptime(date_data, "%Y-%m-%d %H:%M:%S")
|
|
394
|
+
return True
|
|
395
|
+
except ValueError:
|
|
396
|
+
return False
|
|
397
|
+
else:
|
|
398
|
+
return False
|
|
399
|
+
|
|
400
|
+
def __get_price_filter_by_date(self, start_date, end_date, order_book_ids):
|
|
401
|
+
"""
|
|
402
|
+
根据start_date和end_date筛选数据
|
|
403
|
+
此处order_book_ids参数用于处理未传递start_date和end_date的情况(根据order_book_ids返回距离当前时间最近的一条数据)
|
|
404
|
+
|
|
405
|
+
:param start_date: 开始时间
|
|
406
|
+
:param end_date: 结束时间
|
|
407
|
+
:param order_book_ids: 合约代码
|
|
408
|
+
:return: None
|
|
409
|
+
"""
|
|
410
|
+
# 将'date_time'列转换为datetime类型
|
|
411
|
+
try:
|
|
412
|
+
if self.get_price_data['datetime'].dtype != 'datetime64[ns]':
|
|
413
|
+
self.get_price_data['datetime'] = pd.to_datetime(self.get_price_data['datetime'])
|
|
414
|
+
except ValueError:
|
|
415
|
+
raise ValueError("source data's datetime format is not correct")
|
|
416
|
+
|
|
417
|
+
# 如果传递了start_date 和 end_date, 则返回时间段内的数据
|
|
418
|
+
if start_date and end_date:
|
|
419
|
+
self.get_price_data = self.get_price_data[
|
|
420
|
+
(self.get_price_data['datetime'] >= start_date) & (self.get_price_data['datetime'] <= end_date)]
|
|
421
|
+
|
|
422
|
+
# 如果没有传递start_date 和 end_date, 则根据传入的order_book_ids返回每个合约距离当前时间最近的一条数据
|
|
423
|
+
elif not start_date and not end_date:
|
|
424
|
+
date_time = datetime.datetime.now()
|
|
425
|
+
self.get_price_data = self.get_price_data[
|
|
426
|
+
self.get_price_data["datetime"] <= date_time]
|
|
427
|
+
|
|
428
|
+
# 根据传入的order_book_ids进行处理
|
|
429
|
+
if isinstance(order_book_ids, str):
|
|
430
|
+
self.get_price_data = self.get_price_data.tail(1)
|
|
431
|
+
else:
|
|
432
|
+
# 将order_book_id作为分组键,并找到每个分组中距离当前时间最近的数据
|
|
433
|
+
nearest_data = self.get_price_data.groupby('order_book_ids')
|
|
434
|
+
# 使用 tail(1) 获取每个组的最后一条数据
|
|
435
|
+
self.get_price_data = nearest_data.apply(lambda x: x.tail(1)).reset_index(drop=True)
|
|
436
|
+
|
|
437
|
+
def __get_price_validate_fields(self, fields):
|
|
438
|
+
"""
|
|
439
|
+
根据用户选择的字段返回数据
|
|
440
|
+
:param fields: 字段列表 -- 用户传入的需要返回的字段
|
|
441
|
+
|
|
442
|
+
:return : None
|
|
443
|
+
|
|
444
|
+
"""
|
|
445
|
+
self.get_price_data = self.general_validate_fields(self.get_price_data, fields)
|
|
446
|
+
|
|
447
|
+
def __get_price_by_type_frequency(self, asset_type, frequency):
|
|
448
|
+
"""
|
|
449
|
+
根据合约类型和frequency筛选数据
|
|
450
|
+
|
|
451
|
+
:param asset_type: 合约类型
|
|
452
|
+
:param frequency: 频率
|
|
453
|
+
:return: None
|
|
454
|
+
"""
|
|
455
|
+
# 判断asset_type是否存在
|
|
456
|
+
if not get_price_frequency_dict.get(asset_type, None):
|
|
457
|
+
raise ValueError(
|
|
458
|
+
f"asset_type: got invalided value {asset_type}, choose any in {list(get_price_frequency_dict.keys())}")
|
|
459
|
+
|
|
460
|
+
# frequency是否存在
|
|
461
|
+
exists, suffix = self._ends_with(frequency, list(get_price_frequency_dict[asset_type].keys()))
|
|
462
|
+
if not exists:
|
|
463
|
+
raise ValueError(f"{frequency} is not a valid frequency for {asset_type} contract")
|
|
464
|
+
# frequency存在再根据频率对数据做进一步处理
|
|
465
|
+
else:
|
|
466
|
+
bar_or_tick = get_price_frequency_dict[asset_type][suffix] # 获取数据类型是bar还是tick,根据值处理字段
|
|
467
|
+
self.__get_price_data_rename_columns(bar_or_tick) # 重命名字段
|
|
468
|
+
|
|
469
|
+
@staticmethod
|
|
470
|
+
def _ends_with(variable, suffixes):
|
|
471
|
+
"""判断变量是否以列表中的元素结尾。
|
|
472
|
+
:param variable: 待判断的变量
|
|
473
|
+
:param suffixes: 列表,元素为字符串,表示后缀
|
|
474
|
+
:return: True or False
|
|
475
|
+
"""
|
|
476
|
+
for suffix in suffixes:
|
|
477
|
+
if variable.endswith(suffix):
|
|
478
|
+
return True, suffix
|
|
479
|
+
return False, ""
|
|
480
|
+
|
|
481
|
+
def __get_price_data_rename_columns(self, bar_or_tick):
|
|
482
|
+
"""
|
|
483
|
+
将从数据库中获取的数据列名重命名
|
|
484
|
+
|
|
485
|
+
:param bar_or_tick: 是bar类型数据还是tick类型(不同类型字段不同)
|
|
486
|
+
:return: None
|
|
487
|
+
"""
|
|
488
|
+
|
|
489
|
+
new_columns = get_price_data_type_dict.get(bar_or_tick)
|
|
490
|
+
self.get_price_data = self.get_price_data.rename(columns=new_columns)
|
|
491
|
+
|
|
492
|
+
def _get_price_get_data(self, order_book_ids, table_name, db_path):
|
|
493
|
+
"""
|
|
494
|
+
用于接收数据表以及数据库,获取数据
|
|
495
|
+
: params order_book_ids: 合约代码
|
|
496
|
+
: params table_name: 数据表路径
|
|
497
|
+
: params db_path: 数据库路径
|
|
498
|
+
|
|
499
|
+
: return filtered_data: 从数据库获取并根据合约代码筛选后的数据
|
|
500
|
+
"""
|
|
501
|
+
get_price_data, db_session = self.connect_db(table_name, db_path)
|
|
502
|
+
|
|
503
|
+
# 使用 DolphinDB 的 where 子句筛选数据
|
|
504
|
+
if isinstance(order_book_ids, str):
|
|
505
|
+
limit_data = get_price_data.where(f"instrument_id='{order_book_ids}'")
|
|
506
|
+
else:
|
|
507
|
+
limit_data = get_price_data.where(f"instrument_id in {order_book_ids}")
|
|
508
|
+
|
|
509
|
+
# 分批处理
|
|
510
|
+
filtered_data = self._get_price_get_data_todf(limit_data)
|
|
511
|
+
|
|
512
|
+
# 关闭数据库连接
|
|
513
|
+
db_session.close()
|
|
514
|
+
|
|
515
|
+
return filtered_data
|
|
516
|
+
|
|
517
|
+
@staticmethod
|
|
518
|
+
def _get_price_get_data_todf(data):
|
|
519
|
+
"""
|
|
520
|
+
用于接收从数据库获取的数据,并分批处理,将其转换成dataframe格式的数据返回
|
|
521
|
+
: params data: 从数据库获取的数据
|
|
522
|
+
: return : 转换成dataframe格式后的数据
|
|
523
|
+
"""
|
|
524
|
+
|
|
525
|
+
result = pd.DataFrame()
|
|
526
|
+
if data.rows > 1000000:
|
|
527
|
+
chunk_size, start = 1000000, 0
|
|
528
|
+
while start < data.rows:
|
|
529
|
+
limit_data = data.limit([start, chunk_size]).toDF()
|
|
530
|
+
result = limit_data if result.empty else pd.concat([result, limit_data], ignore_index=True)
|
|
531
|
+
start += chunk_size
|
|
532
|
+
|
|
533
|
+
return result
|
|
534
|
+
return data.toDF()
|
|
535
|
+
|
|
536
|
+
# @staticmethod
|
|
537
|
+
# def _get_price_get_data_todf_in_batches(self, data, order_book_ids):
|
|
538
|
+
# """
|
|
539
|
+
# 用于接收从数据库获取的数据,并分批处理,将其转换成dataframe格式的数据返回
|
|
540
|
+
# : params data: 从数据库获取的数据
|
|
541
|
+
# : params order_book_ids: 合约代码
|
|
542
|
+
# : return : 转换成dataframe格式后的数据
|
|
543
|
+
# """
|
|
544
|
+
|
|
545
|
+
# result = pd.DataFrame()
|
|
546
|
+
# if isinstance(order_book_ids, str):
|
|
547
|
+
# if data.rows > 1000000:
|
|
548
|
+
# chunk_size, start = 1000000, 0
|
|
549
|
+
# while start < data.rows:
|
|
550
|
+
# limit_data = data.limit([start, chunk_size]).toDF()
|
|
551
|
+
# result = limit_data if result.empty else pd.concat([result, limit_data], ignore_index=True)
|
|
552
|
+
# start += chunk_size
|
|
553
|
+
|
|
554
|
+
# return result
|
|
555
|
+
# return data.toDF()
|
|
556
|
+
# elif isinstance(order_book_ids, list):
|
|
557
|
+
# for order_book_id in order_book_ids:
|
|
558
|
+
# instrument_id_df = self._get_price_get_data_todf_by_instrument_id(data, order_book_id, result)
|
|
559
|
+
# result = instrument_id_df if result.empty else pd.concat([result, instrument_id_df], ignore_index=True)
|
|
560
|
+
# return result
|
|
561
|
+
# def _get_price_get_data_todf_by_instrument_id(self, data, order_book_id, result_df):
|
|
562
|
+
# """
|
|
563
|
+
# 此方法用于批量获取数据(数据量过大)
|
|
564
|
+
# :param data: 从dolphindb查询到的数据
|
|
565
|
+
# :param order_book_ids: 合约代码列表
|
|
566
|
+
# :param result_df: 处理后的dataframe结果集
|
|
567
|
+
# """
|
|
568
|
+
|
|
569
|
+
# data.where(f"instrument_id='{order_book_id}'")
|
|
570
|
+
|
|
571
|
+
# if data.rows > 1000000:
|
|
572
|
+
# chunk_size, start = 1000000, 0
|
|
573
|
+
# while start < data.rows:
|
|
574
|
+
# limit_data = data.limit([start, chunk_size]).toDF()
|
|
575
|
+
# result_df = limit_data if result_df.empty else pd.concat([result_df, limit_data], ignore_index=True)
|
|
576
|
+
# start += chunk_size
|
|
577
|
+
|
|
578
|
+
# return result_df
|
|
579
|
+
# return data.toDF()
|
|
580
|
+
|
|
581
|
+
def __get_price_data_get_data(self, order_book_ids, asset_type, frequency):
|
|
582
|
+
"""
|
|
583
|
+
根据参数获取数据库和表名,调用接口获取数据
|
|
584
|
+
|
|
585
|
+
:param order_book_ids: 合约代码列表
|
|
586
|
+
:param asset_type: 合约类型
|
|
587
|
+
:param frequency: 频率
|
|
588
|
+
:return: None
|
|
589
|
+
"""
|
|
590
|
+
|
|
591
|
+
''' 期货行情数据 '''
|
|
592
|
+
if asset_type == "future":
|
|
593
|
+
if frequency == "tick_l1": # 期货l1级别tick行情数据
|
|
594
|
+
self.get_price_data = self._get_price_get_data(order_book_ids, history_future_tick_db_table_name,
|
|
595
|
+
history_future_tick_db_path)
|
|
596
|
+
elif frequency == "1d": # 期货日bar行情数据
|
|
597
|
+
self.get_price_data = self._get_price_get_data(order_book_ids, history_future_day_db_table_name,
|
|
598
|
+
history_future_day_db_path)
|
|
599
|
+
elif frequency == "1min": # 期货分钟bar行情数据
|
|
600
|
+
self.get_price_data = self._get_price_get_data(order_book_ids, history_future_min_db_table_name,
|
|
601
|
+
history_future_min_db_path)
|
|
602
|
+
# 数据库暂无数据
|
|
603
|
+
# elif frequency == "1min_gtja": # 公司合成的分钟bar行情数据
|
|
604
|
+
# self.get_price_data = self._get_price_get_data(order_book_ids, history_future_min_gtja_db_table_name,
|
|
605
|
+
# history_future_min_gtja_db_path)
|
|
606
|
+
# elif frequency == "tick_l2": # 期货l2级别tick行情数据
|
|
607
|
+
# self.get_price_data = self._get_price_get_data(order_book_ids, history_future_tick_l2_db_table_name,
|
|
608
|
+
# history_future_tick_l2_db_path)
|
|
609
|
+
# else:
|
|
610
|
+
# raise Exception("frequency is not valid for future contract")
|
|
611
|
+
elif asset_type == "option":
|
|
612
|
+
if frequency == "1d": # 期权日bar行情数据
|
|
613
|
+
self.get_price_data = self._get_price_get_data(order_book_ids, history_option_day_db_table_name,
|
|
614
|
+
history_option_day_db_path)
|
|
615
|
+
elif frequency == "1min": # 期权分钟bar行情数据
|
|
616
|
+
self.get_price_data = self._get_price_get_data(order_book_ids, history_option_min_db_table_name,
|
|
617
|
+
history_option_min_db_path)
|
|
618
|
+
elif frequency == "tick": # 期权tick行情数据
|
|
619
|
+
self.get_price_data = self._get_price_get_data(order_book_ids, history_option_tick_db_table_name,
|
|
620
|
+
history_option_tick_db_path)
|
|
621
|
+
else:
|
|
622
|
+
raise Exception("frequency is not valid for option contract")
|
|
623
|
+
else:
|
|
624
|
+
raise Exception("asset_type is not valid")
|
|
625
|
+
|
|
626
|
+
""" get_instruments(合约基础信息) """
|
|
627
|
+
|
|
628
|
+
def get_instruments(self, order_book_ids=None, commodity=None, asset_type=None, fields=None):
|
|
629
|
+
"""
|
|
630
|
+
获取合约基础信息接口
|
|
631
|
+
:param order_book_ids: str or list,合约代码 和 commodity_type 必填 二选一
|
|
632
|
+
:param commodity: str or list, 合约品种 和 commodity_type 必填 二选一 若填写品种参数,则返回该品种所有合约基础信息
|
|
633
|
+
:param asset_type: str, 合约类型--必填
|
|
634
|
+
:param fields: str or list, 字段列表--选填,默认为全部字段
|
|
635
|
+
:return: 合约基础信息
|
|
636
|
+
"""
|
|
637
|
+
|
|
638
|
+
''' 数据校验 '''
|
|
639
|
+
# 对order_book_ids和commodity是否必填进行校验
|
|
640
|
+
self.__get_instruments_validate_order_book_ids_commodity(order_book_ids, commodity)
|
|
641
|
+
|
|
642
|
+
# 对asset_type进行校验
|
|
643
|
+
self.__general_validate_asset_type(asset_type)
|
|
644
|
+
|
|
645
|
+
''' 根据传入的asset_type以及order_book_ids获取数据 '''
|
|
646
|
+
self.__get_instruments_data_get_data(asset_type=asset_type, order_book_ids=order_book_ids, commodity=commodity)
|
|
647
|
+
|
|
648
|
+
# 重命名字段
|
|
649
|
+
self.__get_instruments_data_rename_columns(asset_type)
|
|
650
|
+
|
|
651
|
+
# 从交易参数中填充commodity和trading_hour的值
|
|
652
|
+
# self.get_instruments_deal_commodity_trading_hour()
|
|
653
|
+
|
|
654
|
+
''' 按照文档筛选需要返回的字段 '''
|
|
655
|
+
self.__get_instruments_data_filter_return_fileds(asset_type)
|
|
656
|
+
|
|
657
|
+
# 对fields进行校验并根据fields返回对应的字段
|
|
658
|
+
self.__get_instruments_validate_fields(fields)
|
|
659
|
+
|
|
660
|
+
return self.get_instruments_data
|
|
661
|
+
|
|
662
|
+
def __get_instruments_validate_order_book_ids_commodity(self, order_book_ids, commodity):
|
|
663
|
+
"""
|
|
664
|
+
对order_book_ids和commodity_type进行校验
|
|
665
|
+
order_book_ids和commodity_type二选一,且只能二选一
|
|
666
|
+
:param order_book_ids: str or list,合约代码
|
|
667
|
+
:param commodity: str or list, 合约品种
|
|
668
|
+
:return: None
|
|
669
|
+
"""
|
|
670
|
+
|
|
671
|
+
''' 对order_book_ids和commodity_type进行校验 '''
|
|
672
|
+
self.general_validate_either_or("order_book_ids", order_book_ids, "commodity", commodity)
|
|
673
|
+
|
|
674
|
+
if order_book_ids:
|
|
675
|
+
self.general_validate_field_str_or_list(order_book_ids, "order_book_ids")
|
|
676
|
+
if commodity:
|
|
677
|
+
self.general_validate_field_str_or_list(commodity, "commodity")
|
|
678
|
+
|
|
679
|
+
def get_instruments_filter_order_book_ids(self, order_book_ids):
|
|
680
|
+
"""
|
|
681
|
+
根据order_book_ids筛选数据
|
|
682
|
+
:param order_book_ids: str or list,合约代码
|
|
683
|
+
:return: None
|
|
684
|
+
"""
|
|
685
|
+
|
|
686
|
+
self.get_instruments_data = self.get_instruments_data[
|
|
687
|
+
self.get_instruments_data["order_book_id"].isin(order_book_ids)] if isinstance(
|
|
688
|
+
order_book_ids, list) else self.get_instruments_data[
|
|
689
|
+
self.get_instruments_data["order_book_id"] == order_book_ids]
|
|
690
|
+
|
|
691
|
+
def get_instruments_filter_commodity(self, commodity):
|
|
692
|
+
"""
|
|
693
|
+
根据commodity筛选数据
|
|
694
|
+
:param commodity: str or list, 合约品种
|
|
695
|
+
:return: None
|
|
696
|
+
|
|
697
|
+
"""
|
|
698
|
+
|
|
699
|
+
self.get_instruments_data = self.get_instruments_data[
|
|
700
|
+
self.get_instruments_data["commodity"].isin(commodity)] if isinstance(
|
|
701
|
+
commodity, list) else self.get_instruments_data[
|
|
702
|
+
self.get_instruments_data["commodity"] == commodity]
|
|
703
|
+
|
|
704
|
+
def __get_instruments_data_filter_return_fileds(self, asset_type):
|
|
705
|
+
"""
|
|
706
|
+
根据asset_type返回对应的字段(不同合约类型字段不同)
|
|
707
|
+
:param asset_type: 合约类型,"future" or "option"
|
|
708
|
+
:return: None
|
|
709
|
+
"""
|
|
710
|
+
|
|
711
|
+
if asset_type == "future":
|
|
712
|
+
self.get_instruments_data = self.get_instruments_data[get_instruments_type_dict.get("future_return_fields")]
|
|
713
|
+
elif asset_type == "option":
|
|
714
|
+
self.get_instruments_data = self.get_instruments_data[get_instruments_type_dict.get("option_return_fields")]
|
|
715
|
+
|
|
716
|
+
def __get_instruments_validate_fields(self, fields):
|
|
717
|
+
"""
|
|
718
|
+
根据用户选择的字段返回数据
|
|
719
|
+
:param fields: str or list, 字段列表
|
|
720
|
+
:return: None
|
|
721
|
+
"""
|
|
722
|
+
|
|
723
|
+
self.get_instruments_data = self.general_validate_fields(self.get_instruments_data, fields)
|
|
724
|
+
|
|
725
|
+
def _get_instruments_data_get_data(self, order_book_ids, table_name, db_path):
|
|
726
|
+
"""
|
|
727
|
+
用于接收数据表以及数据库,获取数据
|
|
728
|
+
|
|
729
|
+
:param order_book_ids: 合约代码
|
|
730
|
+
:param table_name: 数据表路径
|
|
731
|
+
:param db_path: 数据库路径
|
|
732
|
+
:return: 获取的数据
|
|
733
|
+
"""
|
|
734
|
+
get_instruments_data, db_session = self.connect_db(table_name, db_path)
|
|
735
|
+
|
|
736
|
+
filtered_data = pd.DataFrame()
|
|
737
|
+
# 使用 DolphinDB 的 where 子句筛选数据
|
|
738
|
+
if isinstance(order_book_ids, str):
|
|
739
|
+
filtered_data = get_instruments_data.where(f"instrumentid='{order_book_ids}'").toDF()
|
|
740
|
+
elif isinstance(order_book_ids, list):
|
|
741
|
+
filtered_data = get_instruments_data.where(f"instrumentid in {order_book_ids}").toDF()
|
|
742
|
+
|
|
743
|
+
# 关闭数据库连接
|
|
744
|
+
db_session.close()
|
|
745
|
+
|
|
746
|
+
return filtered_data
|
|
747
|
+
|
|
748
|
+
def __get_instruments_data_get_data(self, asset_type=None, order_book_ids=None, commodity=None):
|
|
749
|
+
"""
|
|
750
|
+
根据参数获取数据库和表名,调用接口获取数据
|
|
751
|
+
|
|
752
|
+
:param asset_type: 合约类型
|
|
753
|
+
:param order_book_ids: 合约代码
|
|
754
|
+
:param commodity: 合约品种
|
|
755
|
+
:return: None
|
|
756
|
+
"""
|
|
757
|
+
|
|
758
|
+
# 如果传入的是commodity,需要获取参数品种下所有合约代码
|
|
759
|
+
if commodity:
|
|
760
|
+
# 如果传递的是品种信息,根据品种去交易参数表中查找出对对应的数据
|
|
761
|
+
# 获取交易参数
|
|
762
|
+
trading_param_data, db_session = self.connect_db(trading_params_db_table_name, trading_params_db_path)
|
|
763
|
+
|
|
764
|
+
if isinstance(commodity, str):
|
|
765
|
+
order_book_ids = list(set(
|
|
766
|
+
trading_param_data.select("contractcode").where(f"productcode = '{commodity}'").toDF()[
|
|
767
|
+
"contractcode"].to_list()))
|
|
768
|
+
elif isinstance(commodity, list):
|
|
769
|
+
order_book_ids = list(set(
|
|
770
|
+
trading_param_data.select("contractcode").where(f"productcode in {commodity}").toDF()[
|
|
771
|
+
"contractcode"].to_list()))
|
|
772
|
+
|
|
773
|
+
# 关闭数据库连接
|
|
774
|
+
db_session.close()
|
|
775
|
+
|
|
776
|
+
''' 期货行情数据 '''
|
|
777
|
+
if asset_type == "future":
|
|
778
|
+
self.get_instruments_data = self._get_instruments_data_get_data(order_book_ids,
|
|
779
|
+
future_contract_db_table_name,
|
|
780
|
+
future_contract_db_path)
|
|
781
|
+
self.get_instruments_data["type"] = "future"
|
|
782
|
+
elif asset_type == "option":
|
|
783
|
+
self.get_instruments_data = self._get_instruments_data_get_data(order_book_ids,
|
|
784
|
+
option_contract_db_table_name,
|
|
785
|
+
option_contract_db_path)
|
|
786
|
+
self.get_instruments_data["type"] = "option"
|
|
787
|
+
self.get_instruments_data["exercise_type"] = self.get_instruments_data["optionstype"]
|
|
788
|
+
else:
|
|
789
|
+
raise Exception("asset_type is not valid")
|
|
790
|
+
self.get_instruments_data["commodity"] = ""
|
|
791
|
+
self.get_instruments_data["trading_hour"] = ""
|
|
792
|
+
|
|
793
|
+
def __get_instruments_data_rename_columns(self, asset_type):
|
|
794
|
+
"""
|
|
795
|
+
将从数据库中获取的数据列名重命名为文档要求的名字
|
|
796
|
+
|
|
797
|
+
:param asset_type: 合约类型
|
|
798
|
+
:return: None
|
|
799
|
+
"""
|
|
800
|
+
|
|
801
|
+
new_columns = get_instruments_type_dict.get(asset_type)
|
|
802
|
+
self.get_instruments_data = self.get_instruments_data.rename(columns=new_columns)
|
|
803
|
+
|
|
804
|
+
def get_instruments_deal_commodity_trading_hour(self):
|
|
805
|
+
"""
|
|
806
|
+
用于处理commodity和trading_hour
|
|
807
|
+
"""
|
|
808
|
+
|
|
809
|
+
try:
|
|
810
|
+
# 获取交易参数
|
|
811
|
+
trading_param_data, db_session = self.connect_db(trading_params_db_table_name, trading_params_db_path)
|
|
812
|
+
|
|
813
|
+
for index, row in self.get_instruments_data.iterrows():
|
|
814
|
+
match = trading_param_data.toDF()[trading_param_data.toDF()['contractcode'] == row['order_book_id']]
|
|
815
|
+
if not match.empty:
|
|
816
|
+
self.get_instruments_data.loc[index, 'commodity'] = match['productcode'].iloc[0]
|
|
817
|
+
self.get_instruments_data.loc[index, 'trading_hour'] = match['tradesection'].iloc[0]
|
|
818
|
+
db_session.close()
|
|
819
|
+
except ValueError as e:
|
|
820
|
+
print(e)
|
|
821
|
+
pass
|
|
822
|
+
|
|
823
|
+
""" get_trading_dates(交易日历) """
|
|
824
|
+
|
|
825
|
+
def get_trading_dates(self, date=datetime.date.today(), n=None, start_date=None, end_date=None):
|
|
826
|
+
"""
|
|
827
|
+
获取交易日历接口
|
|
828
|
+
:param date: str--选填, 日期
|
|
829
|
+
:param n: str--必填,根据不同值获取对应的交易日历
|
|
830
|
+
:param start_date: str(datetime.date, datetime.datetime)--选填, 开始日期
|
|
831
|
+
:param end_date: str(datetime.date, datetime.datetime)--选填, 结束日期
|
|
832
|
+
若填写【date、n】为入参,则无法填写【start_date、end_date】,反之依然
|
|
833
|
+
:return: 交易日历
|
|
834
|
+
"""
|
|
835
|
+
|
|
836
|
+
""" 校验参数 """
|
|
837
|
+
self.get_trading_dates_data = self.__get_trading_dates_validate_date_n_start_end(date, n, start_date, end_date)
|
|
838
|
+
|
|
839
|
+
return self.get_trading_dates_data
|
|
840
|
+
|
|
841
|
+
def __get_trading_dates_validate_date_n_start_end(self, date, n, start_date, end_date):
|
|
842
|
+
"""
|
|
843
|
+
校验date、n和start_date、end_date有效性
|
|
844
|
+
|
|
845
|
+
:param date: str-- 日期
|
|
846
|
+
:param n: str--根据不同值获取对应的交易日历
|
|
847
|
+
:param start_date: str(datetime.date, datetime.datetime)--开始日期
|
|
848
|
+
:param end_date: str(datetime.date, datetime.datetime)--结束日期
|
|
849
|
+
:return: None
|
|
850
|
+
"""
|
|
851
|
+
|
|
852
|
+
if (date and n) and (start_date and end_date):
|
|
853
|
+
raise ValueError("date、n and start_date、end_date can only be selected one at a time")
|
|
854
|
+
if n and (start_date or end_date):
|
|
855
|
+
raise ValueError("parameter error: cannot pass date、n and start_date、end_date at the same time")
|
|
856
|
+
elif date and n: # 根据date和n获取交易日历
|
|
857
|
+
return self.__get_trading_dates_by_date_n(date, n)
|
|
858
|
+
elif start_date and end_date: # 根据start_date和end_date获取交易日历
|
|
859
|
+
return self.__get_trading_dates_by_start_end(start_date, end_date)
|
|
860
|
+
else:
|
|
861
|
+
raise ValueError("parameter error: please pass date、n or start_date、end_date")
|
|
862
|
+
|
|
863
|
+
def __get_trading_dates_by_date_n(self, date, n):
|
|
864
|
+
"""
|
|
865
|
+
校验 date 和 n
|
|
866
|
+
:param date: str--选填, 日期
|
|
867
|
+
:param n: str--必填,根据不同值获取对应的交易日历
|
|
868
|
+
:return: 根据date和n筛选后的数据
|
|
869
|
+
"""
|
|
870
|
+
|
|
871
|
+
if not isinstance(n, str):
|
|
872
|
+
raise ValueError("n parameter error, type should be str")
|
|
873
|
+
if n not in ["0", "1", "2", "3", "4", "5", "6"]:
|
|
874
|
+
raise ValueError("n parameter error, value range should be [0, 1, 2, 3, 4, 5, 6]")
|
|
875
|
+
if not isinstance(date, (str, datetime.date)):
|
|
876
|
+
raise ValueError("date parameter error, type should be str or datetime.date")
|
|
877
|
+
|
|
878
|
+
if isinstance(date, str):
|
|
879
|
+
date = datetime.datetime.strptime(date, "%Y-%m-%d").date()
|
|
880
|
+
|
|
881
|
+
return self.get_dates_in_n(date, n)
|
|
882
|
+
|
|
883
|
+
def __get_trading_dates_by_start_end(self, start_date, end_date):
|
|
884
|
+
"""
|
|
885
|
+
根据start_date和end_date获取交易日历
|
|
886
|
+
:param start_date: str(datetime.date, datetime.datetime)--选填, 开始日期
|
|
887
|
+
:param end_date: str(datetime.date, datetime.datetime)--选填, 结束日期
|
|
888
|
+
|
|
889
|
+
:return: 根据start_date和end_date筛选后的数据
|
|
890
|
+
"""
|
|
891
|
+
|
|
892
|
+
trading_params_data = self.get_trading_dates_get_data()
|
|
893
|
+
|
|
894
|
+
# 校验日期类型
|
|
895
|
+
if self.check_date_type(start_date, end_date):
|
|
896
|
+
# 如果类型校验通过,则将start_date和end_date处理成对应的时间数据类型
|
|
897
|
+
if isinstance(start_date, str):
|
|
898
|
+
start_date = self._get_trading_dates_by_start_end(start_date)
|
|
899
|
+
if isinstance(end_date, str):
|
|
900
|
+
end_date = self._get_trading_dates_by_start_end(end_date)
|
|
901
|
+
# 筛选 tradingday 列在 start_date 和 end_date 之间的数据
|
|
902
|
+
filtered_df = trading_params_data.loc[
|
|
903
|
+
(trading_params_data['tradingday'] >= start_date) & (trading_params_data['tradingday'] <= end_date)]
|
|
904
|
+
|
|
905
|
+
# 筛选 tradeflag 列等于 T 的数据(是交易日的数据)
|
|
906
|
+
final_df = filtered_df.loc[filtered_df['tradeflag'] == 'T']
|
|
907
|
+
self.get_trading_dates_data = sorted(final_df["tradingday"].tolist())
|
|
908
|
+
else:
|
|
909
|
+
raise ValueError(
|
|
910
|
+
"start_date or end_date type error, please input str, datetime.date or datetime.datetime type")
|
|
911
|
+
|
|
912
|
+
return self.get_trading_dates_data
|
|
913
|
+
|
|
914
|
+
@staticmethod
|
|
915
|
+
def _get_trading_dates_by_start_end(time_data):
|
|
916
|
+
"""
|
|
917
|
+
将时间str数据处理成对应的时间类型(例如:date类型的str,处理成datetime.date类型)
|
|
918
|
+
|
|
919
|
+
:param time_data: 时间数据
|
|
920
|
+
:return: 转换后的时间数据类型
|
|
921
|
+
"""
|
|
922
|
+
try:
|
|
923
|
+
time_data = datetime.datetime.strptime(time_data, "%Y-%m-%d").date()
|
|
924
|
+
return time_data
|
|
925
|
+
except ValueError:
|
|
926
|
+
try:
|
|
927
|
+
time_data = datetime.datetime.strptime(time_data, "%Y-%m-%d %H:%M:%S").date()
|
|
928
|
+
return time_data
|
|
929
|
+
except ValueError:
|
|
930
|
+
raise ValueError("parameter type error")
|
|
931
|
+
|
|
932
|
+
def check_date_type(self, _start_date, _end_date):
|
|
933
|
+
"""
|
|
934
|
+
判断start_date和end_date是否为str,datetime.date, datetime.datetime三种类型,
|
|
935
|
+
其中,如果是str类型,还要判断是否是datetime.date, datetime.datetime两种类型的字符串.
|
|
936
|
+
:params _start_date: 开始日期
|
|
937
|
+
:params _end_date: 结束日期
|
|
938
|
+
|
|
939
|
+
:return: 如果类型正确,返回 True。否则返回 False,并打印错误信息
|
|
940
|
+
"""
|
|
941
|
+
if isinstance(_start_date, (str, datetime.date, datetime.datetime)) and \
|
|
942
|
+
isinstance(_end_date, (str, datetime.date, datetime.datetime)):
|
|
943
|
+
if isinstance(_start_date, str) and not self.general_validate_date(_start_date):
|
|
944
|
+
raise ValueError("start_date is not a valid date string format")
|
|
945
|
+
if isinstance(_end_date, str) and not self.general_validate_date(_end_date):
|
|
946
|
+
raise ValueError("end_date is not a valid date string format")
|
|
947
|
+
return True
|
|
948
|
+
else:
|
|
949
|
+
raise ValueError(
|
|
950
|
+
"start_date or end_date type error, please input str, datetime.date or datetime.datetime type")
|
|
951
|
+
|
|
952
|
+
def get_trading_dates_get_data(self):
|
|
953
|
+
"""
|
|
954
|
+
从dolphindb获取交易日历
|
|
955
|
+
:return: 交易日历数据
|
|
956
|
+
"""
|
|
957
|
+
|
|
958
|
+
params_data, db_session = self.connect_db(trading_dates_db_table_name, trading_dates_db_path)
|
|
959
|
+
trading_params_data = params_data.toDF()
|
|
960
|
+
trading_params_data["tradingday"] = pd.to_datetime(trading_params_data["tradingday"], format="%Y%m%d").dt.date
|
|
961
|
+
db_session.close()
|
|
962
|
+
return trading_params_data
|
|
963
|
+
|
|
964
|
+
@staticmethod
|
|
965
|
+
def get_date_get_week_month_year(data, start_date, end_date):
|
|
966
|
+
"""
|
|
967
|
+
用于获取当前日期所在周、月、年的交易日数据
|
|
968
|
+
|
|
969
|
+
:param data: 交易日历数据
|
|
970
|
+
:param start_date: 开始日期
|
|
971
|
+
:param end_date: 结束日期
|
|
972
|
+
|
|
973
|
+
:return: 交易日历数据
|
|
974
|
+
|
|
975
|
+
"""
|
|
976
|
+
|
|
977
|
+
# 获取开始日期和结束日期
|
|
978
|
+
start_date = datetime.datetime.strptime(start_date, "%Y%m%d").date()
|
|
979
|
+
end_date = datetime.datetime.strptime(end_date, "%Y%m%d").date()
|
|
980
|
+
|
|
981
|
+
# 筛选出时间段内的所有数据
|
|
982
|
+
filtered_df = data.loc[(data['tradingday'] >= start_date) & (data['tradingday'] <= end_date)]
|
|
983
|
+
# 筛选出时间段内的所有交易日
|
|
984
|
+
final_df = filtered_df.loc[filtered_df['tradeflag'] == 'T']
|
|
985
|
+
|
|
986
|
+
return sorted(final_df["tradingday"].tolist())
|
|
987
|
+
|
|
988
|
+
def get_dates_in_n(self, _date, _n):
|
|
989
|
+
"""
|
|
990
|
+
获取选定日期, 根据n值获取对应的交易日历。
|
|
991
|
+
|
|
992
|
+
:param _date: 选定的日期,可以是 datetime.date 或 datetime.datetime 对象
|
|
993
|
+
:param _n: 时间段,可以是 'week'、'month' 或 'year'
|
|
994
|
+
:return: 一个包含所有日期的列表
|
|
995
|
+
"""
|
|
996
|
+
|
|
997
|
+
trading_params_data = self.get_trading_dates_get_data()
|
|
998
|
+
|
|
999
|
+
cn_holidays = holidays.CN() # 创建中国节假日对象
|
|
1000
|
+
|
|
1001
|
+
time_period_mapping_dict = {
|
|
1002
|
+
"0": _date in cn_holidays,
|
|
1003
|
+
"1": trading_params_data.loc[trading_params_data["tradingday"] == _date]["nexttrdday"].iloc[0],
|
|
1004
|
+
"2": trading_params_data.loc[trading_params_data["tradingday"] == _date]["prevtrdday"].iloc[0],
|
|
1005
|
+
"3": self.get_date_get_week_month_year(trading_params_data,
|
|
1006
|
+
trading_params_data.loc[trading_params_data["tradingday"] == _date][
|
|
1007
|
+
"firsttrddayweek"].iloc[0],
|
|
1008
|
+
trading_params_data.loc[trading_params_data["tradingday"] == _date][
|
|
1009
|
+
"lasttrddayweek"].iloc[0]),
|
|
1010
|
+
"4": self.get_date_get_week_month_year(trading_params_data,
|
|
1011
|
+
trading_params_data.loc[trading_params_data["tradingday"] == _date][
|
|
1012
|
+
"firsttrddaymonth"].iloc[0],
|
|
1013
|
+
trading_params_data.loc[trading_params_data["tradingday"] == _date][
|
|
1014
|
+
"lasttrddaymonth"].iloc[0]),
|
|
1015
|
+
"5": self.get_date_get_week_month_year(trading_params_data,
|
|
1016
|
+
trading_params_data.loc[trading_params_data["tradingday"] == _date][
|
|
1017
|
+
"firsttrddayyear"].iloc[0],
|
|
1018
|
+
trading_params_data.loc[trading_params_data["tradingday"] == _date][
|
|
1019
|
+
"lasttrddayyear"].iloc[0]),
|
|
1020
|
+
"6": trading_params_data.loc[trading_params_data["tradingday"] == _date]["nightday"].iloc[0],
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
if _n not in time_period_mapping_dict:
|
|
1024
|
+
raise ValueError("n parameter error, value range should be [0, 1, 2, 3, 4, 5, 6]")
|
|
1025
|
+
|
|
1026
|
+
return time_period_mapping_dict[_n]
|
|
1027
|
+
|
|
1028
|
+
# @staticmethod
|
|
1029
|
+
# def get_current_week(date_data):
|
|
1030
|
+
# """
|
|
1031
|
+
# 获取选定日期的当周。
|
|
1032
|
+
|
|
1033
|
+
# Args:
|
|
1034
|
+
# date_data: 选定的日期,可以是 datetime.date 或 datetime.datetime 对象。
|
|
1035
|
+
|
|
1036
|
+
# Returns:
|
|
1037
|
+
# 一个元组,包含当前周的开始日期和结束日期,类型为 datetime.date。
|
|
1038
|
+
# """
|
|
1039
|
+
|
|
1040
|
+
# # 获取星期几 (0-6, 0代表星期一)
|
|
1041
|
+
# weekday = date_data.weekday()
|
|
1042
|
+
|
|
1043
|
+
# # 计算当周的开始日期和结束日期
|
|
1044
|
+
# start_date = date_data - datetime.timedelta(days=weekday)
|
|
1045
|
+
# end_date = start_date + datetime.timedelta(days=6)
|
|
1046
|
+
|
|
1047
|
+
# return start_date, end_date
|
|
1048
|
+
|
|
1049
|
+
""" get_margin_ratio 期货保证金 """
|
|
1050
|
+
|
|
1051
|
+
def get_margin_ratio(self, order_book_id=None, commodity=None, date=datetime.datetime.now(), exchange=None):
|
|
1052
|
+
"""
|
|
1053
|
+
获取期货保证金信息接口
|
|
1054
|
+
:param order_book_id: str--选填(和commodity二选一),合约代码
|
|
1055
|
+
:param commodity: str--选填(和order_book_id二选一),合约品种,如果入参为品种,则返回该品种条件下所有合约的保证金list
|
|
1056
|
+
:param date: datetime--必填(默认今天),日期
|
|
1057
|
+
:param exchange: str--必填,交易所
|
|
1058
|
+
:return:
|
|
1059
|
+
"""
|
|
1060
|
+
|
|
1061
|
+
""" 校验数据 """
|
|
1062
|
+
# 校验order_book_id和commodity
|
|
1063
|
+
self.get_margin_ratio_validate_order_book_id_commodity(order_book_id, commodity)
|
|
1064
|
+
|
|
1065
|
+
# 校验exchange
|
|
1066
|
+
self.get_margin_ratio_validate_exchange(exchange)
|
|
1067
|
+
|
|
1068
|
+
# 校验date
|
|
1069
|
+
self.get_margin_ratio_validate_date(date)
|
|
1070
|
+
|
|
1071
|
+
""" 处理数据 """
|
|
1072
|
+
# 根据date筛选数据
|
|
1073
|
+
self.get_margin_ratio_data_by_date(date)
|
|
1074
|
+
|
|
1075
|
+
# 根据exchange筛选数据
|
|
1076
|
+
self.get_margin_ratio_data_by_exchange(exchange)
|
|
1077
|
+
|
|
1078
|
+
return self.get_margin_ratio_data[["order_book_id", "commodity", "date", "exchange"]]
|
|
1079
|
+
|
|
1080
|
+
def get_margin_ratio_validate_exchange(self, exchange):
|
|
1081
|
+
""" 校验exchange """
|
|
1082
|
+
|
|
1083
|
+
self.general_validate_params_required(exchange, "exchange") # 校验必填参数
|
|
1084
|
+
|
|
1085
|
+
if not isinstance(exchange, str):
|
|
1086
|
+
raise ValueError("exchange should be str")
|
|
1087
|
+
|
|
1088
|
+
def get_margin_ratio_validate_order_book_id_commodity(self, order_book_id, commodity):
|
|
1089
|
+
""" 校验order_book_id和commodity """
|
|
1090
|
+
|
|
1091
|
+
''' 对order_book_ids和commodity_type进行校验 '''
|
|
1092
|
+
self.general_validate_either_or("order_book_id", order_book_id, "commodity", commodity)
|
|
1093
|
+
|
|
1094
|
+
''' 根据order_book_ids和commodity_type进行筛选 '''
|
|
1095
|
+
# 因为前面已经对数据进行校验了,所以直接根据不同的参数进行筛选即可
|
|
1096
|
+
if order_book_id:
|
|
1097
|
+
self.get_margin_ratio_data = self._general_filter_data_by_field(self.get_margin_ratio_data, "order_book_id",
|
|
1098
|
+
order_book_id)
|
|
1099
|
+
if commodity:
|
|
1100
|
+
self.get_margin_ratio_data = self._general_filter_data_by_field(self.get_margin_ratio_data, "commodity",
|
|
1101
|
+
commodity)
|
|
1102
|
+
|
|
1103
|
+
def get_margin_ratio_validate_date(self, date):
|
|
1104
|
+
""" 校验date """
|
|
1105
|
+
|
|
1106
|
+
if isinstance(date, (str, datetime.date, datetime.datetime)):
|
|
1107
|
+
if isinstance(date, str) and not self.general_validate_date(date):
|
|
1108
|
+
raise ValueError("date 不是有效的日期字符串格式")
|
|
1109
|
+
return True
|
|
1110
|
+
else:
|
|
1111
|
+
raise ValueError("date 类型错误,请传入 str,datetime.date 或 datetime.datetime 类型")
|
|
1112
|
+
|
|
1113
|
+
def get_margin_ratio_data_by_date(self, date):
|
|
1114
|
+
"""
|
|
1115
|
+
根据date筛选数据
|
|
1116
|
+
"""
|
|
1117
|
+
|
|
1118
|
+
if isinstance(date, str):
|
|
1119
|
+
date = datetime.datetime.strptime(date, "%Y-%m-%d %H:%M:%S")
|
|
1120
|
+
self.get_margin_ratio_data = self.get_margin_ratio_data[self.get_margin_ratio_data["date"] == date]
|
|
1121
|
+
|
|
1122
|
+
def get_margin_ratio_data_by_exchange(self, exchange):
|
|
1123
|
+
"""
|
|
1124
|
+
根据exchange筛选数据
|
|
1125
|
+
"""
|
|
1126
|
+
|
|
1127
|
+
self.get_margin_ratio_data = self.get_margin_ratio_data[self.get_margin_ratio_data["exchange"] == exchange]
|
|
1128
|
+
|
|
1129
|
+
""" get_fee 期货交割手续费 """
|
|
1130
|
+
|
|
1131
|
+
def get_fee(self, order_book_id=None, commodity=None, date=datetime.datetime.now(), exchange=None):
|
|
1132
|
+
"""
|
|
1133
|
+
获取期货交割手续费信息接口
|
|
1134
|
+
:param order_book_id: str--选填(和commodity二选一),合约代码
|
|
1135
|
+
:param commodity: str--选填(和order_book_id二选一),合约品种,如果入参为品种,则返回该品种条件下所有合约的交割手续费list
|
|
1136
|
+
:param date: datetime--必填(默认今天),日期
|
|
1137
|
+
:param exchange: str--必填,交易所
|
|
1138
|
+
:return:
|
|
1139
|
+
"""
|
|
1140
|
+
|
|
1141
|
+
""" 校验数据 """
|
|
1142
|
+
# 校验order_book_id和commodity
|
|
1143
|
+
self.get_fee_validate_order_book_id_commodity(order_book_id, commodity)
|
|
1144
|
+
|
|
1145
|
+
# 校验exchange
|
|
1146
|
+
self.get_fee_validate_exchange(exchange)
|
|
1147
|
+
|
|
1148
|
+
# 校验date
|
|
1149
|
+
self.get_fee_validate_date(date)
|
|
1150
|
+
|
|
1151
|
+
""" 处理数据 """
|
|
1152
|
+
# 根据date筛选数据
|
|
1153
|
+
self.get_fee_data_by_date(date)
|
|
1154
|
+
|
|
1155
|
+
# 根据exchange筛选数据
|
|
1156
|
+
self.get_fee_data_by_exchange(exchange)
|
|
1157
|
+
|
|
1158
|
+
return self.get_fee_data[["order_book_id", "commodity", "date", "exchange"]]
|
|
1159
|
+
|
|
1160
|
+
def get_fee_validate_exchange(self, exchange):
|
|
1161
|
+
""" 校验exchange """
|
|
1162
|
+
# 是否必填
|
|
1163
|
+
self.general_validate_params_required(exchange, "exchange")
|
|
1164
|
+
|
|
1165
|
+
if not isinstance(exchange, str):
|
|
1166
|
+
raise ValueError("exchange should be str")
|
|
1167
|
+
|
|
1168
|
+
def get_fee_validate_order_book_id_commodity(self, order_book_id, commodity):
|
|
1169
|
+
""" 校验order_book_id和commodity """
|
|
1170
|
+
|
|
1171
|
+
''' 对order_book_ids和commodity_type进行校验 '''
|
|
1172
|
+
self.general_validate_either_or("order_book_id", order_book_id, "commodity", commodity)
|
|
1173
|
+
|
|
1174
|
+
''' 根据order_book_ids和commodity_type进行筛选 '''
|
|
1175
|
+
# 因为前面已经对数据进行校验了,所以直接根据不同的参数进行筛选即可
|
|
1176
|
+
if order_book_id:
|
|
1177
|
+
self.get_fee_data = self._general_filter_data_by_field(self.get_fee_data, "order_book_id",
|
|
1178
|
+
order_book_id)
|
|
1179
|
+
if commodity:
|
|
1180
|
+
self.get_fee_data = self._general_filter_data_by_field(self.get_fee_data, "commodity",
|
|
1181
|
+
commodity)
|
|
1182
|
+
|
|
1183
|
+
def get_fee_validate_date(self, date):
|
|
1184
|
+
""" 校验date """
|
|
1185
|
+
|
|
1186
|
+
if isinstance(date, (str, datetime.date, datetime.datetime)):
|
|
1187
|
+
if isinstance(date, str) and not self.general_validate_date(date):
|
|
1188
|
+
raise ValueError("date 不是有效的日期字符串格式")
|
|
1189
|
+
return True
|
|
1190
|
+
else:
|
|
1191
|
+
raise ValueError("date 类型错误,请传入 str,datetime.date 或 datetime.datetime 类型")
|
|
1192
|
+
|
|
1193
|
+
def get_fee_data_by_date(self, date):
|
|
1194
|
+
"""
|
|
1195
|
+
根据date筛选数据
|
|
1196
|
+
"""
|
|
1197
|
+
|
|
1198
|
+
if isinstance(date, str):
|
|
1199
|
+
date = datetime.datetime.strptime(date, "%Y-%m-%d %H:%M:%S")
|
|
1200
|
+
self.get_fee_data = self.get_fee_data[self.get_fee_data["date"] == date]
|
|
1201
|
+
|
|
1202
|
+
def get_fee_data_by_exchange(self, exchange):
|
|
1203
|
+
"""
|
|
1204
|
+
根据exchange筛选数据
|
|
1205
|
+
"""
|
|
1206
|
+
|
|
1207
|
+
self.get_fee_data = self.get_fee_data[self.get_fee_data["exchange"] == exchange]
|
|
1208
|
+
|
|
1209
|
+
""" get_limit_position 期货限仓数据 """
|
|
1210
|
+
|
|
1211
|
+
def get_limit_position(self, order_book_ids=None, commodity=None, date=datetime.date.today()):
|
|
1212
|
+
"""
|
|
1213
|
+
获取期货限仓数据接口
|
|
1214
|
+
:param order_book_ids: str or list--选填(和commodity二选一),合约代码
|
|
1215
|
+
:param commodity: str or list--选填(和order_book_ids二选一),合约品种
|
|
1216
|
+
:param date: datetime.date--选填(默认今天),日期
|
|
1217
|
+
:return:
|
|
1218
|
+
|
|
1219
|
+
"""
|
|
1220
|
+
""" 校验数据 """
|
|
1221
|
+
# 校验order_book_ids和commodity
|
|
1222
|
+
self.get_limit_position_validate_order_book_ids_commodity(order_book_ids, commodity)
|
|
1223
|
+
|
|
1224
|
+
# 校验date
|
|
1225
|
+
self.get_limit_position_validate_date(date)
|
|
1226
|
+
|
|
1227
|
+
""" 处理数据 """
|
|
1228
|
+
# 根据date筛选数据
|
|
1229
|
+
self.get_limit_position_data_by_date(date)
|
|
1230
|
+
|
|
1231
|
+
return self.get_limit_position_data
|
|
1232
|
+
|
|
1233
|
+
def get_limit_position_validate_order_book_ids_commodity(self, order_book_ids, commodity):
|
|
1234
|
+
""" 对order_book_ids和commodity_type进行校验 """
|
|
1235
|
+
self.general_validate_either_or("order_book_ids", order_book_ids, "commodity", commodity)
|
|
1236
|
+
|
|
1237
|
+
''' 根据order_book_ids和commodity_type进行筛选 '''
|
|
1238
|
+
# 因为前面已经对数据进行校验了,所以直接根据不同的参数进行筛选即可
|
|
1239
|
+
if order_book_ids:
|
|
1240
|
+
self.get_limit_position_data = self._general_filter_data_by_field(self.get_limit_position_data,
|
|
1241
|
+
"order_book_ids",
|
|
1242
|
+
order_book_ids)
|
|
1243
|
+
if commodity:
|
|
1244
|
+
self.get_limit_position_data = self._general_filter_data_by_field(self.get_limit_position_data,
|
|
1245
|
+
"commodity",
|
|
1246
|
+
commodity)
|
|
1247
|
+
|
|
1248
|
+
def get_limit_position_validate_date(self, date):
|
|
1249
|
+
""" 校验date """
|
|
1250
|
+
|
|
1251
|
+
if isinstance(date, (str, datetime.date, datetime.datetime)):
|
|
1252
|
+
if isinstance(date, str) and not self.general_validate_date(date):
|
|
1253
|
+
raise ValueError("date 不是有效的日期字符串格式")
|
|
1254
|
+
return True
|
|
1255
|
+
else:
|
|
1256
|
+
raise ValueError("date 类型错误,请传入 str,datetime.date 或 datetime.datetime 类型")
|
|
1257
|
+
|
|
1258
|
+
def get_limit_position_data_by_date(self, date):
|
|
1259
|
+
"""
|
|
1260
|
+
根据date筛选数据
|
|
1261
|
+
"""
|
|
1262
|
+
|
|
1263
|
+
if isinstance(date, str):
|
|
1264
|
+
date = datetime.datetime.strptime(date, "%Y-%m-%d %H:%M:%S")
|
|
1265
|
+
self.get_limit_position_data = self.get_limit_position_data[self.get_limit_position_data["date"] == date]
|
|
1266
|
+
|
|
1267
|
+
""" get_active_contract 主力/次主力合约 """
|
|
1268
|
+
|
|
1269
|
+
def get_active_contract(self, code=None, begin_date=None, start_date=datetime.date.today(),
|
|
1270
|
+
end_date=datetime.date.today(), asset_type=None,
|
|
1271
|
+
fields=None, source="3"):
|
|
1272
|
+
"""
|
|
1273
|
+
获取主力/次主力合约信息接口
|
|
1274
|
+
:param code: str or str list--必填,品种
|
|
1275
|
+
:param begin_date: datetime--必填,指定日期
|
|
1276
|
+
:param start_date: date--必填,默认当天
|
|
1277
|
+
:param end_date: date--必填,默认当天
|
|
1278
|
+
:param asset_type: str--必填,active指主力;next_active次主力
|
|
1279
|
+
:param fields: str or str list--选填,返回字段,默认全部
|
|
1280
|
+
:param source: str--选填,数据源,默认研究所, 3个来源可选:1-数据中台, 2-米筐, 3-研究所
|
|
1281
|
+
|
|
1282
|
+
:return:
|
|
1283
|
+
"""
|
|
1284
|
+
|
|
1285
|
+
""" 校验参数 """
|
|
1286
|
+
# 校验必填参数
|
|
1287
|
+
self.get_active_contract_validate_required_params(code, begin_date, start_date, end_date, asset_type)
|
|
1288
|
+
|
|
1289
|
+
# 校验日期参数类型
|
|
1290
|
+
self.get_active_contract_validate_date_type(begin_date, start_date, end_date)
|
|
1291
|
+
|
|
1292
|
+
""" 筛选数据 """
|
|
1293
|
+
|
|
1294
|
+
# 根据code筛选数据
|
|
1295
|
+
self.get_active_contract_validate_code(code)
|
|
1296
|
+
|
|
1297
|
+
# 根据日期数据筛选数据
|
|
1298
|
+
self.get_active_contract_filter_by_date(begin_date, start_date, end_date)
|
|
1299
|
+
|
|
1300
|
+
# 根据asset_type筛选数据
|
|
1301
|
+
self.get_active_contract_filter_by_asset_type(asset_type)
|
|
1302
|
+
|
|
1303
|
+
# 根据fields筛选数据
|
|
1304
|
+
self.get_active_contract_filter_data_by_fields(fields)
|
|
1305
|
+
|
|
1306
|
+
# 根据source筛选数据
|
|
1307
|
+
self.get_active_contract_data_by_source(source)
|
|
1308
|
+
|
|
1309
|
+
return self.get_active_contract_data
|
|
1310
|
+
|
|
1311
|
+
def get_active_contract_validate_required_params(self, code, begin_date, start_date, end_date, asset_type):
|
|
1312
|
+
""" 校验参数是否必填 """
|
|
1313
|
+
|
|
1314
|
+
params_dict = {
|
|
1315
|
+
"code": code,
|
|
1316
|
+
"begin_date": begin_date,
|
|
1317
|
+
"start_date": start_date,
|
|
1318
|
+
"end_date": end_date,
|
|
1319
|
+
"asset_type": asset_type
|
|
1320
|
+
}
|
|
1321
|
+
for key, value in params_dict.items():
|
|
1322
|
+
self.general_validate_params_required(value, key) # 校验必填参数
|
|
1323
|
+
|
|
1324
|
+
def get_active_contract_validate_code(self, code):
|
|
1325
|
+
""" 校验code 类型 """
|
|
1326
|
+
self.general_validate_field_str_or_list(code, "code")
|
|
1327
|
+
self.get_active_contract_data = self.get_active_contract_data[
|
|
1328
|
+
self.get_active_contract_data["code"].isin(code)] if isinstance(code, list) else \
|
|
1329
|
+
self.get_active_contract_data[self.get_active_contract_data["code"] == code]
|
|
1330
|
+
|
|
1331
|
+
def get_active_contract_validate_date_type(self, begin_date, start_date, end_date):
|
|
1332
|
+
"""
|
|
1333
|
+
校验日期数据的类型
|
|
1334
|
+
"""
|
|
1335
|
+
# 校验start_date 和 end_date 是否为datetime.date类型或者可以转换成该类型的str
|
|
1336
|
+
if isinstance(start_date, (str, datetime.date)) and isinstance(end_date, (str, datetime.date)):
|
|
1337
|
+
if isinstance(start_date, str) and not self.general_validate_date_str_is_date_type(start_date):
|
|
1338
|
+
raise ValueError("start_date 类型错误,请传入 datetime.date 类型")
|
|
1339
|
+
if isinstance(end_date, str) and not self.general_validate_date_str_is_date_type(end_date):
|
|
1340
|
+
raise ValueError("end_date 类型错误,请传入 datetime.date 类型")
|
|
1341
|
+
else:
|
|
1342
|
+
raise ValueError("start_date 或 end_date 类型错误,请传入datetime.date 类型")
|
|
1343
|
+
|
|
1344
|
+
# 校验begin_date 是否为datetime.datetime类型或者为可以转换为该类型的字符串
|
|
1345
|
+
if isinstance(begin_date, (str, datetime.datetime)):
|
|
1346
|
+
if isinstance(begin_date, str) and not self.general_validate_date_str_is_datetime_type(begin_date):
|
|
1347
|
+
raise ValueError("begin_date 类型错误,请传入 datetime.datetime 类型")
|
|
1348
|
+
else:
|
|
1349
|
+
raise ValueError("begin_date 类型错误,请传入 datetime.datetime 类型")
|
|
1350
|
+
|
|
1351
|
+
def get_active_contract_filter_by_date(self, begin_date, start_date, end_date):
|
|
1352
|
+
"""
|
|
1353
|
+
根据日期筛选数据
|
|
1354
|
+
"""
|
|
1355
|
+
print(begin_date)
|
|
1356
|
+
if start_date > end_date:
|
|
1357
|
+
raise ValueError("start_date should be earlier than end_date")
|
|
1358
|
+
|
|
1359
|
+
# 根据start_date 和 end_date 筛选数据
|
|
1360
|
+
start_date = self.general_date_str_to_date(start_date)
|
|
1361
|
+
end_date = self.general_date_str_to_date(end_date)
|
|
1362
|
+
self.get_active_contract_data = self.get_active_contract_data[
|
|
1363
|
+
(self.get_active_contract_data["date"] >= start_date) & (self.get_active_contract_data["date"] <= end_date)]
|
|
1364
|
+
|
|
1365
|
+
return self.get_active_contract_data
|
|
1366
|
+
|
|
1367
|
+
def get_active_contract_filter_by_asset_type(self, asset_type):
|
|
1368
|
+
"""
|
|
1369
|
+
根据asset_type筛选数据
|
|
1370
|
+
"""
|
|
1371
|
+
|
|
1372
|
+
self.get_active_contract_data = self.general_filter_data_by_field(self.get_active_contract_data,
|
|
1373
|
+
"active_type",
|
|
1374
|
+
asset_type)
|
|
1375
|
+
|
|
1376
|
+
def get_active_contract_filter_data_by_fields(self, fields):
|
|
1377
|
+
"""
|
|
1378
|
+
根据fields筛选数据
|
|
1379
|
+
"""
|
|
1380
|
+
|
|
1381
|
+
if isinstance(fields, (str, list)):
|
|
1382
|
+
self.get_active_contract_data = self.get_active_contract_data[fields] if isinstance(fields, str) else \
|
|
1383
|
+
self.get_active_contract_data[[field for field in fields]]
|
|
1384
|
+
|
|
1385
|
+
@staticmethod
|
|
1386
|
+
def get_active_contract_data_by_source(source):
|
|
1387
|
+
"""
|
|
1388
|
+
根据数据源筛选数据
|
|
1389
|
+
"""
|
|
1390
|
+
|
|
1391
|
+
if not isinstance(source, str):
|
|
1392
|
+
raise ValueError("source 类型错误,请传入 str 类型")
|
|
1393
|
+
|
|
1394
|
+
if source == "1":
|
|
1395
|
+
print("数据中台")
|
|
1396
|
+
elif source == "2":
|
|
1397
|
+
print("米筐")
|
|
1398
|
+
elif source == "3":
|
|
1399
|
+
print("研究所")
|
|
1400
|
+
else:
|
|
1401
|
+
raise ValueError("source 参数错误,取值范围应该在 [1, 2, 3]")
|
|
1402
|
+
|
|
1403
|
+
""" get_basic_data 库存/基差/现货价格-数据(日频) """
|
|
1404
|
+
|
|
1405
|
+
def get_basic_data(self, order_book_id, asset_type, start_date, end_date):
|
|
1406
|
+
"""
|
|
1407
|
+
获取库存/基差/现货价格-数据(日频)接口
|
|
1408
|
+
:param order_book_id: str--必填,合约代码
|
|
1409
|
+
:param asset_type: str--必填,枚举值:库存、基差、现货
|
|
1410
|
+
:param start_date: str, datetime.date, datetime.datetime, pandasTimestamp--必填,开始日期
|
|
1411
|
+
:param end_date: str, datetime.date, datetime.datetime, pandasTimestamp--必填,结束日期
|
|
1412
|
+
"""
|
|
1413
|
+
|
|
1414
|
+
""" 校验参数 """
|
|
1415
|
+
|
|
1416
|
+
# 校验必填参数
|
|
1417
|
+
self.get_basic_data_validate_required_params(order_book_id, asset_type, start_date, end_date)
|
|
1418
|
+
|
|
1419
|
+
# 校验order_book_id 类型
|
|
1420
|
+
self.get_basic_data_validate_order_book_id(order_book_id)
|
|
1421
|
+
|
|
1422
|
+
# 校验asset_type 类型
|
|
1423
|
+
self.get_basic_data_validate_asset_type(asset_type)
|
|
1424
|
+
|
|
1425
|
+
# 校验start_date 和 end_date 类型
|
|
1426
|
+
self.get_basic_data_validate_date(start_date, end_date)
|
|
1427
|
+
|
|
1428
|
+
return None
|
|
1429
|
+
|
|
1430
|
+
def get_basic_data_validate_required_params(self, order_book_id, asset_type, start_date, end_date):
|
|
1431
|
+
params_dict = {
|
|
1432
|
+
"order_book_id": order_book_id,
|
|
1433
|
+
"asset_type": asset_type,
|
|
1434
|
+
"start_date": start_date,
|
|
1435
|
+
"end_date": end_date
|
|
1436
|
+
}
|
|
1437
|
+
for key, value in params_dict.items():
|
|
1438
|
+
self.general_validate_params_required(value, key) # 校验必填参数
|
|
1439
|
+
|
|
1440
|
+
def get_basic_data_validate_order_book_id(self, order_book_id):
|
|
1441
|
+
"""
|
|
1442
|
+
校验order_book_id 类型
|
|
1443
|
+
"""
|
|
1444
|
+
|
|
1445
|
+
self.general_validate_param_is_str("order_book_id", order_book_id)
|
|
1446
|
+
|
|
1447
|
+
def get_basic_data_validate_asset_type(self, asset_type):
|
|
1448
|
+
"""
|
|
1449
|
+
校验asset_type 类型
|
|
1450
|
+
"""
|
|
1451
|
+
|
|
1452
|
+
self.general_validate_param_is_str("asset_type", asset_type)
|
|
1453
|
+
|
|
1454
|
+
def get_basic_data_validate_date(self, start_date, end_date):
|
|
1455
|
+
"""
|
|
1456
|
+
校验start_date 和 end_date 类型
|
|
1457
|
+
"""
|
|
1458
|
+
error_msg = "start_date 或 end_date 类型错误,datetime.date, datetime.datetime, pandasTimestamp类型或者可以转换成该类型的str"
|
|
1459
|
+
|
|
1460
|
+
# 校验start_date 和 end_date 是否为datetime.date, datetime.datetime, pandasTimestamp类型或者可以转换成该类型的str
|
|
1461
|
+
if isinstance(start_date, (str, datetime.date, datetime.datetime, pd.Timestamp)) and isinstance(end_date, (
|
|
1462
|
+
str, datetime.date, datetime.datetime, pd.Timestamp)):
|
|
1463
|
+
if isinstance(start_date, str) and not self.general_validate_date(start_date):
|
|
1464
|
+
raise ValueError(error_msg)
|
|
1465
|
+
if isinstance(end_date, str) and not self.general_validate_date(end_date):
|
|
1466
|
+
raise ValueError(error_msg)
|
|
1467
|
+
else:
|
|
1468
|
+
raise ValueError(error_msg)
|