2019-01-20 17:31:01 +08:00
|
|
|
|
#!/usr/bin/python
|
|
|
|
|
# -*- coding: utf8 -*-
|
|
|
|
|
# cp936
|
|
|
|
|
#
|
|
|
|
|
# The MIT License (MIT)
|
|
|
|
|
#
|
|
|
|
|
# Copyright (c) 2010-2019 weituo2002
|
|
|
|
|
#
|
|
|
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
# in the Software without restriction, including without limitation the rights
|
|
|
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
# furnished to do so, subject to the following conditions:
|
|
|
|
|
#
|
|
|
|
|
# The above copyright notice and this permission notice shall be included in all
|
|
|
|
|
# copies or substantial portions of the Software.
|
|
|
|
|
#
|
|
|
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
|
# SOFTWARE.
|
|
|
|
|
|
|
|
|
|
####################################################################
|
|
|
|
|
#
|
|
|
|
|
# 使用 jqdata 作为K线数据驱动,可自行实现自己的K线数据驱动
|
2020-06-25 15:59:37 +08:00
|
|
|
|
#
|
2019-01-20 17:31:01 +08:00
|
|
|
|
# 感谢网友哥本哈斯根贡献
|
|
|
|
|
#
|
|
|
|
|
#####################################################################
|
|
|
|
|
|
2020-06-25 15:59:37 +08:00
|
|
|
|
from ..cpp.core import KDataDriver, DataDriverFactory
|
2020-10-02 17:31:33 +08:00
|
|
|
|
from hikyuu import KRecord, Query, Datetime, Parameter, KRecordList
|
2019-01-20 17:31:01 +08:00
|
|
|
|
|
|
|
|
|
from jqdatasdk import *
|
|
|
|
|
from datetime import *
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class jqdataKDataDriver(KDataDriver):
|
|
|
|
|
def __init__(self):
|
|
|
|
|
super(jqdataKDataDriver, self).__init__('jqdata')
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2021-01-20 23:23:01 +08:00
|
|
|
|
def clone(self):
|
|
|
|
|
return jqdataKDataDriver()
|
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
def _init(self):
|
|
|
|
|
"""【重载接口】(可选)初始化子类私有变量"""
|
2020-06-25 15:59:37 +08:00
|
|
|
|
self._max = {
|
|
|
|
|
Query.DAY: 10,
|
|
|
|
|
Query.WEEK: 2,
|
|
|
|
|
Query.MONTH: 1,
|
|
|
|
|
Query.QUARTER: 1,
|
|
|
|
|
#Query.HALFYEAR:1,
|
|
|
|
|
Query.YEAR: 1,
|
|
|
|
|
Query.MIN: 25,
|
|
|
|
|
Query.MIN5: 25,
|
|
|
|
|
Query.MIN15: 25,
|
|
|
|
|
Query.MIN30: 25,
|
|
|
|
|
Query.MIN60: 25
|
|
|
|
|
}
|
2021-02-06 14:45:52 +08:00
|
|
|
|
return True
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2020-10-02 17:31:33 +08:00
|
|
|
|
def isIndexFirst(self):
|
|
|
|
|
return False
|
|
|
|
|
|
2021-02-06 14:45:52 +08:00
|
|
|
|
def canParallelLoad(self):
|
|
|
|
|
return False
|
|
|
|
|
|
2020-10-12 01:14:16 +08:00
|
|
|
|
def getKRecordList(self, market, code, query): # ktype, start_ix, end_ix, out_buffer):
|
2019-01-20 17:31:01 +08:00
|
|
|
|
"""
|
|
|
|
|
【重载接口】(必须)按指定的位置[start_ix, end_ix)读取K线数据至out_buffer
|
|
|
|
|
|
|
|
|
|
:param str market: 市场标识
|
|
|
|
|
:param str code: 证券代码
|
2020-06-30 23:27:23 +08:00
|
|
|
|
:param Query.KType ktype: K线类型
|
2019-01-20 17:31:01 +08:00
|
|
|
|
:param int start_ix: 起始位置
|
|
|
|
|
:param int end_ix: 结束位置
|
|
|
|
|
:param KRecordListPtr out_buffer: 传入的数据缓存,读取数据后使用
|
|
|
|
|
out_buffer.append(krecord) 加入数据
|
|
|
|
|
"""
|
2021-02-06 14:45:52 +08:00
|
|
|
|
if query.query_type == Query.DATE:
|
2020-10-12 01:14:16 +08:00
|
|
|
|
print("未实现按日期查询")
|
|
|
|
|
return KRecordList()
|
2020-10-02 17:31:33 +08:00
|
|
|
|
start_ix = query.start
|
|
|
|
|
end_ix = query.end
|
2020-06-25 15:59:37 +08:00
|
|
|
|
if start_ix >= end_ix or start_ix < 0 or end_ix < 0:
|
2020-10-02 17:31:33 +08:00
|
|
|
|
return KRecordList()
|
2019-01-20 17:31:01 +08:00
|
|
|
|
|
2020-10-02 17:31:33 +08:00
|
|
|
|
data = self._get_bars(market, code, query.ktype)
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
if len(data) < start_ix:
|
2020-10-02 17:31:33 +08:00
|
|
|
|
return KRecordList()
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2020-10-02 17:31:33 +08:00
|
|
|
|
result = KRecordList()
|
2019-01-20 17:31:01 +08:00
|
|
|
|
total = end_ix if end_ix < len(data) else len(data)
|
|
|
|
|
for i in range(start_ix, total):
|
|
|
|
|
record = KRecord()
|
|
|
|
|
record.datetime = Datetime(data.index[i])
|
2020-07-04 23:54:02 +08:00
|
|
|
|
record.open = data['open'][i]
|
|
|
|
|
record.high = data['high'][i]
|
|
|
|
|
record.low = data['low'][i]
|
|
|
|
|
record.close = data['close'][i]
|
|
|
|
|
record.amount = data['money'][i]
|
|
|
|
|
record.volume = data['volume'][i]
|
2020-10-02 17:31:33 +08:00
|
|
|
|
result.append(record)
|
|
|
|
|
return result
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
def getCount(self, market, code, ktype):
|
|
|
|
|
"""
|
|
|
|
|
【重载接口】(必须)获取K线数量
|
|
|
|
|
|
|
|
|
|
:param str market: 市场标识
|
|
|
|
|
:param str code: 证券代码
|
2020-06-30 23:27:23 +08:00
|
|
|
|
:param Query.KType ktype: K线类型
|
2019-01-20 17:31:01 +08:00
|
|
|
|
"""
|
|
|
|
|
data = self._get_bars(market, code, ktype)
|
|
|
|
|
return len(data)
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
def _getIndexRangeByDate(self, market, code, query):
|
|
|
|
|
"""
|
|
|
|
|
【重载接口】(必须)按日期获取指定的K线数据
|
|
|
|
|
|
|
|
|
|
:param str market: 市场标识
|
|
|
|
|
:param str code: 证券代码
|
2020-06-30 23:27:23 +08:00
|
|
|
|
:param Query query: 日期查询条件(QueryByDate)
|
2019-01-20 17:31:01 +08:00
|
|
|
|
"""
|
|
|
|
|
print("getIndexRangeByDate")
|
|
|
|
|
|
2021-02-06 14:45:52 +08:00
|
|
|
|
if query.query_type != Query.DATE:
|
2019-01-20 17:31:01 +08:00
|
|
|
|
return (0, 0)
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
start_datetime = query.startDatetime
|
|
|
|
|
end_datetime = query.endDatetime
|
|
|
|
|
if start_datetime >= end_datetime or start_datetime > Datetime.max():
|
|
|
|
|
return (0, 0)
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
data = self._get_bars(market, code, query.kType)
|
|
|
|
|
total = len(data)
|
|
|
|
|
if total == 0:
|
|
|
|
|
return (0, 0)
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
mid, low = 0, 0
|
2020-06-25 15:59:37 +08:00
|
|
|
|
high = total - 1
|
2019-01-20 17:31:01 +08:00
|
|
|
|
while low <= high:
|
|
|
|
|
tmp_datetime = Datetime(data.index[high])
|
|
|
|
|
if start_datetime > tmp_datetime:
|
|
|
|
|
mid = high + 1
|
|
|
|
|
break
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
tmp_datetime = Datetime(data.index[low])
|
|
|
|
|
if tmp_datetime >= start_datetime:
|
|
|
|
|
mid = low
|
|
|
|
|
break
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
mid = (low + high) // 2
|
|
|
|
|
tmp_datetime = Datetime(data.index[mid])
|
|
|
|
|
if start_datetime > tmp_datetime:
|
|
|
|
|
low = mid + 1
|
|
|
|
|
else:
|
|
|
|
|
high = mid - 1
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
if mid >= total:
|
|
|
|
|
return (0, 0)
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
start_pos = mid
|
|
|
|
|
low = mid
|
|
|
|
|
high = total - 1
|
|
|
|
|
while low <= high:
|
|
|
|
|
tmp_datetime = Datetime(data.index[high])
|
|
|
|
|
if end_datetime > tmp_datetime:
|
|
|
|
|
mid = high + 1
|
|
|
|
|
break
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
tmp_datetime = Datetime(data.index[low])
|
|
|
|
|
if tmp_datetime >= end_datetime:
|
|
|
|
|
mid = low
|
|
|
|
|
break
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
mid = (low + high) // 2
|
|
|
|
|
tmp_datetime = Datetime(data.index[mid])
|
|
|
|
|
if end_datetime > tmp_datetime:
|
|
|
|
|
low = mid + 1
|
|
|
|
|
else:
|
|
|
|
|
high = mid - 1
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
end_pos = total if mid >= total else mid
|
|
|
|
|
if start_pos >= end_pos:
|
2020-06-25 15:59:37 +08:00
|
|
|
|
return (0, 0)
|
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
return (start_pos, end_pos)
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
def getKRecord(self, market, code, pos, ktype):
|
|
|
|
|
"""
|
|
|
|
|
【重载接口】(必须)获取指定位置的K线记录
|
|
|
|
|
|
|
|
|
|
:param str market: 市场标识
|
|
|
|
|
:param str code: 证券代码
|
|
|
|
|
:param int pos: 指定位置(大于等于0)
|
2020-06-30 23:27:23 +08:00
|
|
|
|
:param Query.KType ktype: K线类型
|
2019-01-20 17:31:01 +08:00
|
|
|
|
"""
|
|
|
|
|
record = KRecord()
|
|
|
|
|
if pos < 0:
|
|
|
|
|
return record
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
data = self._get_bars(market, code, ktype)
|
|
|
|
|
if data is None:
|
|
|
|
|
return record
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
if pos < len(data):
|
2020-06-25 15:59:37 +08:00
|
|
|
|
record.datetime = Datetime(data.index[pos])
|
2020-07-04 23:54:02 +08:00
|
|
|
|
record.open = data['open'][pos]
|
|
|
|
|
record.high = data['high'][pos]
|
|
|
|
|
record.low = data['low'][pos]
|
|
|
|
|
record.close = data['close'][pos]
|
|
|
|
|
record.amount = data['money'][pos]
|
|
|
|
|
record.volume = data['volume'][pos]
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
return record
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
|
|
|
|
def _trans_ktype(self, ktype): #此处的周月季年数据只是近似的,目前jqdata未提供聚宽网络平台上的get_bar函数,不能直接取,需要自行用日线数据拼装
|
|
|
|
|
ktype_map = {
|
|
|
|
|
Query.MIN: '1m',
|
|
|
|
|
Query.MIN5: '5m',
|
|
|
|
|
Query.MIN15: '15m',
|
|
|
|
|
Query.MIN30: '30m',
|
|
|
|
|
Query.MIN60: '60m',
|
|
|
|
|
Query.DAY: '1d',
|
|
|
|
|
Query.WEEK: '7d',
|
|
|
|
|
Query.MONTH: '30d',
|
|
|
|
|
Query.QUARTER: '90d',
|
|
|
|
|
Query.YEAR: '365d'
|
|
|
|
|
}
|
2019-01-20 17:31:01 +08:00
|
|
|
|
return ktype_map.get(ktype)
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
def _get_bars(self, market, code, ktype):
|
|
|
|
|
data = []
|
|
|
|
|
username = self.getParam('username')
|
|
|
|
|
password = self.getParam('password')
|
|
|
|
|
auth(username, password)
|
|
|
|
|
|
|
|
|
|
jqdataCode = normalize_code(code)
|
|
|
|
|
jqdata_ktype = self._trans_ktype(ktype)
|
|
|
|
|
|
|
|
|
|
if jqdata_ktype is None:
|
|
|
|
|
print("jqdata_ktype == None")
|
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
print(jqdataCode)
|
|
|
|
|
security_info = get_security_info(jqdataCode)
|
|
|
|
|
|
2020-06-25 15:59:37 +08:00
|
|
|
|
if security_info is None: #有可能取不到任何信息
|
2019-01-20 17:31:01 +08:00
|
|
|
|
return data
|
|
|
|
|
#print(security_info)
|
|
|
|
|
|
|
|
|
|
data = get_price(jqdataCode, security_info.start_date, datetime.now(), jqdata_ktype)
|
|
|
|
|
|
|
|
|
|
return data
|
2020-06-25 15:59:37 +08:00
|
|
|
|
|
|
|
|
|
|
2019-01-20 17:31:01 +08:00
|
|
|
|
#DataDriverFactory.regKDataDriver(jqdataKDataDriver())
|
|
|
|
|
|
|
|
|
|
#jqdata_param = Parameter()
|
|
|
|
|
#jqdata_param.set('type', 'jqdata')
|
|
|
|
|
#jqdata_param.set('username', '用户名')
|
|
|
|
|
#jqdata_param.set('password', '密码')
|
|
|
|
|
|
|
|
|
|
#base_param = sm.getBaseInfoDriverParameter()
|
|
|
|
|
#block_param = sm.getBlockDriverParameter()
|
|
|
|
|
#kdata_param = sm.getKDataDriverParameter()
|
|
|
|
|
#preload_param = sm.getPreloadParameter()
|
|
|
|
|
#hku_param = sm.getHikyuuParameter()
|
|
|
|
|
|
|
|
|
|
#切换K线数据驱动,重新初始化
|
2021-02-17 19:43:59 +08:00
|
|
|
|
#sm.init(base_param, block_param, jqdata_param, preload_param, hku_param)
|