cmesdata 1.2.2__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.
- cmesdata/__init__.py +1 -0
- cmesdata/stock.py +266 -0
- cmesdata/third/__init__.py +3 -0
- cmesdata/third/maths.py +1780 -0
- cmesdata-1.2.2.dist-info/METADATA +21 -0
- cmesdata-1.2.2.dist-info/RECORD +8 -0
- cmesdata-1.2.2.dist-info/WHEEL +5 -0
- cmesdata-1.2.2.dist-info/top_level.txt +1 -0
cmesdata/third/maths.py
ADDED
|
@@ -0,0 +1,1780 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Just for practising
|
|
5
|
+
#
|
|
6
|
+
import random
|
|
7
|
+
import sys
|
|
8
|
+
import threading
|
|
9
|
+
from threading import Thread
|
|
10
|
+
import datetime
|
|
11
|
+
import time
|
|
12
|
+
import socket
|
|
13
|
+
import functools
|
|
14
|
+
import logging
|
|
15
|
+
import zlib
|
|
16
|
+
import pandas as pd
|
|
17
|
+
import os
|
|
18
|
+
#from __future__ import unicode_literals, division
|
|
19
|
+
from collections import OrderedDict
|
|
20
|
+
import struct
|
|
21
|
+
import six
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
DEBUG = os.getenv("JSP_DEBUG", "")
|
|
25
|
+
|
|
26
|
+
if DEBUG:
|
|
27
|
+
LOGLEVEL = logging.DEBUG
|
|
28
|
+
else:
|
|
29
|
+
LOGLEVEL = logging.INFO
|
|
30
|
+
|
|
31
|
+
log = logging.getLogger("PYJSP")
|
|
32
|
+
|
|
33
|
+
log.setLevel(LOGLEVEL)
|
|
34
|
+
ch = logging.StreamHandler()
|
|
35
|
+
ch.setLevel(LOGLEVEL)
|
|
36
|
+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
37
|
+
ch.setFormatter(formatter)
|
|
38
|
+
log.addHandler(ch)
|
|
39
|
+
|
|
40
|
+
class JspConnectionError(Exception):
|
|
41
|
+
pass
|
|
42
|
+
class JspFunctionCallError(Exception):
|
|
43
|
+
def __init__(self, *args, **kwargs):
|
|
44
|
+
super(JspFunctionCallError, self).__init__(*args, **kwargs)
|
|
45
|
+
self.original_exception = None
|
|
46
|
+
|
|
47
|
+
DEFAULT_HEARTBEAT_INTERVAL = 10.0 # 10秒一个heartbeat
|
|
48
|
+
class HqHeartBeatThread(Thread):
|
|
49
|
+
|
|
50
|
+
def __init__(self, api, stop_event, heartbeat_interval=DEFAULT_HEARTBEAT_INTERVAL):
|
|
51
|
+
self.api = api
|
|
52
|
+
self.client = api.client
|
|
53
|
+
self.stop_event = stop_event
|
|
54
|
+
self.heartbeat_interval = heartbeat_interval
|
|
55
|
+
super(HqHeartBeatThread, self).__init__()
|
|
56
|
+
|
|
57
|
+
def run(self):
|
|
58
|
+
while not self.stop_event.is_set():
|
|
59
|
+
self.stop_event.wait(self.heartbeat_interval)
|
|
60
|
+
if self.client and (time.time() - self.api.last_ack_time > self.heartbeat_interval):
|
|
61
|
+
try:
|
|
62
|
+
self.api.do_heartbeat()
|
|
63
|
+
except Exception as e:
|
|
64
|
+
log.debug(str(e))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
import cython
|
|
69
|
+
if cython.compiled:
|
|
70
|
+
def buffer(x):
|
|
71
|
+
return x
|
|
72
|
+
except ImportError:
|
|
73
|
+
pass
|
|
74
|
+
class SocketClientNotReady(Exception):
|
|
75
|
+
pass
|
|
76
|
+
class SendPkgNotReady(Exception):
|
|
77
|
+
pass
|
|
78
|
+
class SendRequestPkgFails(Exception):
|
|
79
|
+
pass
|
|
80
|
+
class ResponseHeaderRecvFails(Exception):
|
|
81
|
+
pass
|
|
82
|
+
class ResponseRecvFails(Exception):
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
RSP_HEADER_LEN = 0x10
|
|
86
|
+
|
|
87
|
+
class BaseParser(object):
|
|
88
|
+
|
|
89
|
+
def __init__(self, client, lock=None):
|
|
90
|
+
self.client = client
|
|
91
|
+
self.data = None
|
|
92
|
+
self.send_pkg = None
|
|
93
|
+
|
|
94
|
+
self.rsp_header = None
|
|
95
|
+
self.rsp_body = None
|
|
96
|
+
self.rsp_header_len = RSP_HEADER_LEN
|
|
97
|
+
|
|
98
|
+
if lock:
|
|
99
|
+
self.lock = lock
|
|
100
|
+
else:
|
|
101
|
+
self.lock = None
|
|
102
|
+
|
|
103
|
+
def setParams(self, *args, **xargs):
|
|
104
|
+
"""
|
|
105
|
+
构建请求
|
|
106
|
+
:return:
|
|
107
|
+
"""
|
|
108
|
+
pass
|
|
109
|
+
|
|
110
|
+
def parseResponse(self, body_buf):
|
|
111
|
+
pass
|
|
112
|
+
|
|
113
|
+
def setup(self):
|
|
114
|
+
pass
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def call_api(self):
|
|
118
|
+
if self.lock:
|
|
119
|
+
with self.lock:
|
|
120
|
+
log.debug("sending thread lock api call")
|
|
121
|
+
result = self._call_api()
|
|
122
|
+
else:
|
|
123
|
+
result = self._call_api()
|
|
124
|
+
return result
|
|
125
|
+
|
|
126
|
+
def _call_api(self):
|
|
127
|
+
|
|
128
|
+
self.setup()
|
|
129
|
+
|
|
130
|
+
if not(self.client):
|
|
131
|
+
raise SocketClientNotReady("socket client not ready")
|
|
132
|
+
|
|
133
|
+
if not(self.send_pkg):
|
|
134
|
+
raise SendPkgNotReady("send pkg not ready")
|
|
135
|
+
|
|
136
|
+
nsended = self.client.send(self.send_pkg)
|
|
137
|
+
|
|
138
|
+
self.client.send_pkg_num += 1
|
|
139
|
+
self.client.send_pkg_bytes += nsended
|
|
140
|
+
self.client.last_api_send_bytes = nsended
|
|
141
|
+
|
|
142
|
+
if self.client.first_pkg_send_time is None:
|
|
143
|
+
self.client.first_pkg_send_time = datetime.datetime.now()
|
|
144
|
+
|
|
145
|
+
if DEBUG:
|
|
146
|
+
log.debug("send package:" + str(self.send_pkg))
|
|
147
|
+
if nsended != len(self.send_pkg):
|
|
148
|
+
log.debug("send bytes error")
|
|
149
|
+
raise SendRequestPkgFails("send fails")
|
|
150
|
+
else:
|
|
151
|
+
head_buf = self.client.recv(self.rsp_header_len)
|
|
152
|
+
if DEBUG:
|
|
153
|
+
log.debug("recv head_buf:" + str(head_buf) + " |len is :" + str(len(head_buf)))
|
|
154
|
+
if len(head_buf) == self.rsp_header_len:
|
|
155
|
+
self.client.recv_pkg_num += 1
|
|
156
|
+
self.client.recv_pkg_bytes += self.rsp_header_len
|
|
157
|
+
_, _, _, zipsize, unzipsize = struct.unpack("<IIIHH", head_buf)
|
|
158
|
+
if DEBUG:
|
|
159
|
+
log.debug("zip size is: " + str(zipsize))
|
|
160
|
+
body_buf = bytearray()
|
|
161
|
+
|
|
162
|
+
last_api_recv_bytes = self.rsp_header_len
|
|
163
|
+
while True:
|
|
164
|
+
buf = self.client.recv(zipsize)
|
|
165
|
+
len_buf = len(buf)
|
|
166
|
+
self.client.recv_pkg_num += 1
|
|
167
|
+
self.client.recv_pkg_bytes += len_buf
|
|
168
|
+
last_api_recv_bytes += len_buf
|
|
169
|
+
body_buf.extend(buf)
|
|
170
|
+
if not(buf) or len_buf == 0 or len(body_buf) == zipsize:
|
|
171
|
+
break
|
|
172
|
+
|
|
173
|
+
self.client.last_api_recv_bytes = last_api_recv_bytes
|
|
174
|
+
|
|
175
|
+
if len(buf) == 0:
|
|
176
|
+
log.debug("接收数据体失败服务器断开连接")
|
|
177
|
+
raise ResponseRecvFails("接收数据体失败服务器断开连接")
|
|
178
|
+
if zipsize == unzipsize:
|
|
179
|
+
log.debug("不需要解压")
|
|
180
|
+
else:
|
|
181
|
+
log.debug("需要解压")
|
|
182
|
+
if sys.version_info[0] == 2:
|
|
183
|
+
unziped_data = zlib.decompress(buffer(body_buf))
|
|
184
|
+
else:
|
|
185
|
+
unziped_data = zlib.decompress(body_buf)
|
|
186
|
+
body_buf = unziped_data
|
|
187
|
+
## 解压
|
|
188
|
+
if DEBUG:
|
|
189
|
+
log.debug("recv body: ")
|
|
190
|
+
log.debug(body_buf)
|
|
191
|
+
|
|
192
|
+
return self.parseResponse(body_buf)
|
|
193
|
+
|
|
194
|
+
else:
|
|
195
|
+
log.debug("head_buf is not 0x10")
|
|
196
|
+
raise ResponseHeaderRecvFails("head_buf is not 0x10 : " + str(head_buf))
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class RawParser(BaseParser):
|
|
200
|
+
def setParams(self, pkg):
|
|
201
|
+
self.send_pkg = pkg
|
|
202
|
+
def parseResponse(self, body_buf):
|
|
203
|
+
return body_buf
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
CONNECT_TIMEOUT = 5.000
|
|
207
|
+
RECV_HEADER_LEN = 0x10
|
|
208
|
+
DEFAULT_HEARTBEAT_INTERVAL = 10.0
|
|
209
|
+
def update_last_ack_time(func):
|
|
210
|
+
@functools.wraps(func)
|
|
211
|
+
def wrapper(self, *args, **kw):
|
|
212
|
+
self.last_ack_time = time.time()
|
|
213
|
+
log.debug("last ack time update to " + str(self.last_ack_time))
|
|
214
|
+
current_exception = None
|
|
215
|
+
try:
|
|
216
|
+
ret = func(self, *args, **kw)
|
|
217
|
+
except Exception as e:
|
|
218
|
+
current_exception = e
|
|
219
|
+
log.debug("hit exception on req exception is " + str(e))
|
|
220
|
+
if self.auto_retry:
|
|
221
|
+
for time_interval in self.retry_strategy.gen():
|
|
222
|
+
try:
|
|
223
|
+
time.sleep(time_interval)
|
|
224
|
+
self.disconnect()
|
|
225
|
+
self.connect(self.ip, self.port)
|
|
226
|
+
ret = func(self, *args, **kw)
|
|
227
|
+
if ret:
|
|
228
|
+
return ret
|
|
229
|
+
except Exception as retry_e:
|
|
230
|
+
current_exception = retry_e
|
|
231
|
+
log.debug(
|
|
232
|
+
"hit exception on *retry* req exception is " + str(retry_e))
|
|
233
|
+
|
|
234
|
+
log.debug("perform auto retry on req ")
|
|
235
|
+
|
|
236
|
+
self.last_transaction_failed = True
|
|
237
|
+
ret = None
|
|
238
|
+
if self.raise_exception:
|
|
239
|
+
to_raise = JspFunctionCallError("calling function error")
|
|
240
|
+
to_raise.original_exception = current_exception if current_exception else None
|
|
241
|
+
raise to_raise
|
|
242
|
+
return ret
|
|
243
|
+
return wrapper
|
|
244
|
+
class RetryStrategy(object):
|
|
245
|
+
@classmethod
|
|
246
|
+
def gen(cls):
|
|
247
|
+
raise NotImplementedError("need to override")
|
|
248
|
+
class DefaultRetryStrategy(RetryStrategy):
|
|
249
|
+
@classmethod
|
|
250
|
+
def gen(cls):
|
|
251
|
+
# 默认重试4次 ... 时间间隔如下
|
|
252
|
+
for time_interval in [0.1, 0.5, 1, 2]:
|
|
253
|
+
yield time_interval
|
|
254
|
+
class TrafficStatSocket(socket.socket):
|
|
255
|
+
|
|
256
|
+
def __init__(self, sock, mode):
|
|
257
|
+
super(TrafficStatSocket, self).__init__(sock, mode)
|
|
258
|
+
# 流量统计相关
|
|
259
|
+
self.send_pkg_num = 0 # 发送次数
|
|
260
|
+
self.recv_pkg_num = 0 # 接收次数
|
|
261
|
+
self.send_pkg_bytes = 0 # 发送字节
|
|
262
|
+
self.recv_pkg_bytes = 0 # 接收字节数
|
|
263
|
+
self.first_pkg_send_time = None # 第一个数据包发送时间
|
|
264
|
+
|
|
265
|
+
self.last_api_send_bytes = 0 # 最近的一次api调用的发送字节数
|
|
266
|
+
self.last_api_recv_bytes = 0 # 最近一次api调用的接收字节数
|
|
267
|
+
class BaseSocketClient(object):
|
|
268
|
+
|
|
269
|
+
def __init__(self, multithread=False, heartbeat=True, auto_retry=False, raise_exception=False):
|
|
270
|
+
self.need_setup = True
|
|
271
|
+
if multithread or heartbeat:
|
|
272
|
+
self.lock = threading.Lock()
|
|
273
|
+
else:
|
|
274
|
+
self.lock = None
|
|
275
|
+
|
|
276
|
+
self.client = None
|
|
277
|
+
self.heartbeat = heartbeat
|
|
278
|
+
self.heartbeat_thread = None
|
|
279
|
+
self.stop_event = None
|
|
280
|
+
self.heartbeat_interval = DEFAULT_HEARTBEAT_INTERVAL # 默认10秒一个心跳包
|
|
281
|
+
self.last_ack_time = time.time()
|
|
282
|
+
self.last_transaction_failed = False
|
|
283
|
+
self.ip = None
|
|
284
|
+
self.port = None
|
|
285
|
+
|
|
286
|
+
# 是否重试
|
|
287
|
+
self.auto_retry = auto_retry
|
|
288
|
+
# 可以覆盖这个属性,使用新的重试策略
|
|
289
|
+
self.retry_strategy = DefaultRetryStrategy()
|
|
290
|
+
# 是否在函数调用出错的时候抛出异常
|
|
291
|
+
self.raise_exception = raise_exception
|
|
292
|
+
|
|
293
|
+
def connect(self, ip='101.227.73.20', port=7709, time_out=CONNECT_TIMEOUT, bindport=None, bindip='0.0.0.0'):
|
|
294
|
+
|
|
295
|
+
self.client = TrafficStatSocket(socket.AF_INET, socket.SOCK_STREAM)
|
|
296
|
+
self.client.settimeout(time_out)
|
|
297
|
+
log.debug("connecting to server : %s on port :%d" % (ip, port))
|
|
298
|
+
try:
|
|
299
|
+
self.ip = ip
|
|
300
|
+
self.port = port
|
|
301
|
+
if bindport is not None:
|
|
302
|
+
self.client.bind((bindip, bindport))
|
|
303
|
+
self.client.connect((ip, port))
|
|
304
|
+
except socket.timeout as e:
|
|
305
|
+
# print(str(e))
|
|
306
|
+
log.debug("connection expired")
|
|
307
|
+
if self.raise_exception:
|
|
308
|
+
raise JspConnectionError("connection timeout error")
|
|
309
|
+
return False
|
|
310
|
+
except Exception as e:
|
|
311
|
+
if self.raise_exception:
|
|
312
|
+
raise JspConnectionError("other errors")
|
|
313
|
+
return False
|
|
314
|
+
|
|
315
|
+
log.debug("connected!")
|
|
316
|
+
|
|
317
|
+
if self.need_setup:
|
|
318
|
+
self.setup()
|
|
319
|
+
|
|
320
|
+
if self.heartbeat:
|
|
321
|
+
self.stop_event = threading.Event()
|
|
322
|
+
self.heartbeat_thread = HqHeartBeatThread(
|
|
323
|
+
self, self.stop_event, self.heartbeat_interval)
|
|
324
|
+
self.heartbeat_thread.start()
|
|
325
|
+
return self
|
|
326
|
+
|
|
327
|
+
def disconnect(self):
|
|
328
|
+
|
|
329
|
+
if self.heartbeat_thread and \
|
|
330
|
+
self.heartbeat_thread.is_alive():
|
|
331
|
+
self.stop_event.set()
|
|
332
|
+
|
|
333
|
+
if self.client:
|
|
334
|
+
log.debug("disconnecting")
|
|
335
|
+
try:
|
|
336
|
+
self.client.shutdown(socket.SHUT_RDWR)
|
|
337
|
+
self.client.close()
|
|
338
|
+
self.client = None
|
|
339
|
+
except Exception as e:
|
|
340
|
+
log.debug(str(e))
|
|
341
|
+
if self.raise_exception:
|
|
342
|
+
raise JspConnectionError("disconnect err")
|
|
343
|
+
log.debug("disconnected")
|
|
344
|
+
|
|
345
|
+
def close(self):
|
|
346
|
+
self.disconnect()
|
|
347
|
+
|
|
348
|
+
def get_traffic_stats(self):
|
|
349
|
+
if self.client.first_pkg_send_time is not None:
|
|
350
|
+
total_seconds = (datetime.datetime.now() -
|
|
351
|
+
self.client.first_pkg_send_time).total_seconds()
|
|
352
|
+
if total_seconds != 0:
|
|
353
|
+
send_bytes_per_second = self.client.send_pkg_bytes // total_seconds
|
|
354
|
+
recv_bytes_per_second = self.client.recv_pkg_bytes // total_seconds
|
|
355
|
+
else:
|
|
356
|
+
send_bytes_per_second = None
|
|
357
|
+
recv_bytes_per_second = None
|
|
358
|
+
else:
|
|
359
|
+
total_seconds = None
|
|
360
|
+
send_bytes_per_second = None
|
|
361
|
+
recv_bytes_per_second = None
|
|
362
|
+
|
|
363
|
+
return {
|
|
364
|
+
"send_pkg_num": self.client.send_pkg_num,
|
|
365
|
+
"recv_pkg_num": self.client.recv_pkg_num,
|
|
366
|
+
"send_pkg_bytes": self.client.send_pkg_bytes,
|
|
367
|
+
"recv_pkg_bytes": self.client.recv_pkg_bytes,
|
|
368
|
+
"first_pkg_send_time": self.client.first_pkg_send_time,
|
|
369
|
+
"total_seconds": total_seconds,
|
|
370
|
+
"send_bytes_per_second": send_bytes_per_second,
|
|
371
|
+
"recv_bytes_per_second": recv_bytes_per_second,
|
|
372
|
+
"last_api_send_bytes": self.client.last_api_send_bytes,
|
|
373
|
+
"last_api_recv_bytes": self.client.last_api_recv_bytes,
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
# for debuging and testing protocol
|
|
377
|
+
def send_raw_pkg(self, pkg):
|
|
378
|
+
cmd = RawParser(self.client, lock=self.lock)
|
|
379
|
+
cmd.setParams(pkg)
|
|
380
|
+
return cmd.call_api()
|
|
381
|
+
|
|
382
|
+
def __enter__(self):
|
|
383
|
+
return self
|
|
384
|
+
|
|
385
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
386
|
+
self.close()
|
|
387
|
+
|
|
388
|
+
def to_df(self, v):
|
|
389
|
+
if isinstance(v, list):
|
|
390
|
+
return pd.DataFrame(data=v)
|
|
391
|
+
elif isinstance(v, dict):
|
|
392
|
+
return pd.DataFrame(data=[v, ])
|
|
393
|
+
else:
|
|
394
|
+
return pd.DataFrame(data=[{'value': v}])
|
|
395
|
+
|
|
396
|
+
class JspFileNotFoundException(Exception):
|
|
397
|
+
pass
|
|
398
|
+
class JspNotAssignVipdocPathException(Exception):
|
|
399
|
+
pass
|
|
400
|
+
class BaseReader(object):
|
|
401
|
+
|
|
402
|
+
def unpack_records(self, format, data):
|
|
403
|
+
record_struct = struct.Struct(format)
|
|
404
|
+
return (record_struct.unpack_from(data, offset)
|
|
405
|
+
for offset in range(0, len(data), record_struct.size))
|
|
406
|
+
|
|
407
|
+
def get_df(self, code_or_file, exchange=None):
|
|
408
|
+
raise NotImplementedError('not yet')
|
|
409
|
+
BlockReader_TYPE_FLAT = 0
|
|
410
|
+
BlockReader_TYPE_GROUP = 1
|
|
411
|
+
|
|
412
|
+
class BlockReader(BaseReader):
|
|
413
|
+
|
|
414
|
+
def get_df(self, fname, result_type=BlockReader_TYPE_FLAT):
|
|
415
|
+
result = self.get_data(fname, result_type)
|
|
416
|
+
return pd.DataFrame(result)
|
|
417
|
+
|
|
418
|
+
def get_data(self, fname, result_type=BlockReader_TYPE_FLAT):
|
|
419
|
+
|
|
420
|
+
result = []
|
|
421
|
+
|
|
422
|
+
if type(fname) is not bytearray:
|
|
423
|
+
with open(fname, "rb") as f:
|
|
424
|
+
data = f.read()
|
|
425
|
+
else:
|
|
426
|
+
data = fname
|
|
427
|
+
|
|
428
|
+
pos = 384
|
|
429
|
+
(num,) = struct.unpack("<H", data[pos: pos + 2])
|
|
430
|
+
pos += 2
|
|
431
|
+
for i in range(num):
|
|
432
|
+
blockname_raw = data[pos: pos + 9]
|
|
433
|
+
pos += 9
|
|
434
|
+
blockname = blockname_raw.decode("gbk", 'ignore').rstrip("\x00")
|
|
435
|
+
stock_count, block_type = struct.unpack("<HH", data[pos: pos + 4])
|
|
436
|
+
pos += 4
|
|
437
|
+
block_stock_begin = pos
|
|
438
|
+
codes = []
|
|
439
|
+
for code_index in range(stock_count):
|
|
440
|
+
one_code = data[pos: pos + 7].decode("utf-8", 'ignore').rstrip("\x00")
|
|
441
|
+
pos += 7
|
|
442
|
+
|
|
443
|
+
if result_type == BlockReader_TYPE_FLAT:
|
|
444
|
+
result.append(
|
|
445
|
+
OrderedDict([
|
|
446
|
+
("blockname", blockname),
|
|
447
|
+
("block_type", block_type),
|
|
448
|
+
("code_index", code_index),
|
|
449
|
+
("code", one_code),
|
|
450
|
+
])
|
|
451
|
+
)
|
|
452
|
+
elif result_type == BlockReader_TYPE_GROUP:
|
|
453
|
+
codes.append(one_code)
|
|
454
|
+
|
|
455
|
+
if result_type == BlockReader_TYPE_GROUP:
|
|
456
|
+
result.append(
|
|
457
|
+
OrderedDict([
|
|
458
|
+
("blockname", blockname),
|
|
459
|
+
("block_type", block_type),
|
|
460
|
+
("stock_count", stock_count),
|
|
461
|
+
("code_list", ",".join(codes))
|
|
462
|
+
])
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
pos = block_stock_begin + 2800
|
|
466
|
+
|
|
467
|
+
return result
|
|
468
|
+
class CustomerBlockReader(BaseReader):
|
|
469
|
+
|
|
470
|
+
def get_df(self, fname, result_type=BlockReader_TYPE_FLAT):
|
|
471
|
+
result = self.get_data(fname, result_type)
|
|
472
|
+
return pd.DataFrame(result)
|
|
473
|
+
|
|
474
|
+
def get_data(self, fname, result_type=BlockReader_TYPE_FLAT):
|
|
475
|
+
|
|
476
|
+
result = []
|
|
477
|
+
|
|
478
|
+
if not os.path.isdir(fname):
|
|
479
|
+
raise Exception('not a directory')
|
|
480
|
+
|
|
481
|
+
block_file = '/'.join([fname, 'blocknew.cfg'])
|
|
482
|
+
|
|
483
|
+
if not os.path.exists(block_file):
|
|
484
|
+
raise Exception('file not exists')
|
|
485
|
+
|
|
486
|
+
block_data = open(block_file, 'rb').read()
|
|
487
|
+
|
|
488
|
+
pos = 0
|
|
489
|
+
result = []
|
|
490
|
+
# print(block_data.decode('gbk','ignore'))
|
|
491
|
+
while pos < len(block_data):
|
|
492
|
+
n1 = block_data[pos:pos + 50].decode('gbk', 'ignore').rstrip("\x00")
|
|
493
|
+
n2 = block_data[pos + 50:pos + 120].decode('gbk', 'ignore').rstrip("\x00")
|
|
494
|
+
pos = pos + 120
|
|
495
|
+
|
|
496
|
+
n1 = n1.split('\x00')[0]
|
|
497
|
+
n2 = n2.split('\x00')[0]
|
|
498
|
+
bf = '/'.join([fname, n2 + '.blk'])
|
|
499
|
+
if not os.path.exists(bf):
|
|
500
|
+
raise Exception('file not exists')
|
|
501
|
+
|
|
502
|
+
codes = open(bf).read().splitlines()
|
|
503
|
+
if result_type == BlockReader_TYPE_FLAT:
|
|
504
|
+
for index, code in enumerate(codes):
|
|
505
|
+
if code != '':
|
|
506
|
+
result.append(
|
|
507
|
+
OrderedDict([
|
|
508
|
+
("blockname", n1),
|
|
509
|
+
("block_type", n2),
|
|
510
|
+
('code_index', index),
|
|
511
|
+
('code', code[1:])
|
|
512
|
+
])
|
|
513
|
+
)
|
|
514
|
+
|
|
515
|
+
if result_type == BlockReader_TYPE_GROUP:
|
|
516
|
+
cc = [c[1:] for c in codes if c != '']
|
|
517
|
+
result.append(
|
|
518
|
+
OrderedDict([
|
|
519
|
+
("blockname", n1),
|
|
520
|
+
("block_type", n2),
|
|
521
|
+
("stock_count", len(cc)),
|
|
522
|
+
("code_list", ",".join(cc))
|
|
523
|
+
])
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
return result
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
class GetBlockInfoMeta(BaseParser):
|
|
530
|
+
def setParams(self, block_file):
|
|
531
|
+
if type(block_file) is six.text_type:
|
|
532
|
+
block_file = block_file.encode("utf-8")
|
|
533
|
+
pkg = bytearray.fromhex(u'0C 39 18 69 00 01 2A 00 2A 00 C5 02')
|
|
534
|
+
pkg.extend(struct.pack(u"<{}s".format(0x2a - 2), block_file))
|
|
535
|
+
self.send_pkg = pkg
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def parseResponse(self, body_buf):
|
|
539
|
+
(size, _, hash_value, _ ) = struct.unpack(u"<I1s32s1s", body_buf)
|
|
540
|
+
return {
|
|
541
|
+
"size": size,
|
|
542
|
+
"hash_value" : hash_value
|
|
543
|
+
}
|
|
544
|
+
class GetBlockInfo(BaseParser):
|
|
545
|
+
|
|
546
|
+
def setParams(self, block_file, start, size):
|
|
547
|
+
if type(block_file) is six.text_type:
|
|
548
|
+
block_file = block_file.encode("utf-8")
|
|
549
|
+
pkg = bytearray.fromhex(u'0c 37 18 6a 00 01 6e 00 6e 00 b9 06')
|
|
550
|
+
#pkg = bytearray.fromhex(u'0c 33 18 6a 00 01 6e 00 6e 00 b9 06 60 ea 00 00 30 75 00 00')
|
|
551
|
+
pkg.extend(struct.pack(u"<II{}s".format(0x6e-10), start, size, block_file))
|
|
552
|
+
self.send_pkg = pkg
|
|
553
|
+
|
|
554
|
+
def parseResponse(self, body_buf):
|
|
555
|
+
return body_buf[4:]
|
|
556
|
+
def get_and_parse_block_info(client, blockfile):
|
|
557
|
+
try:
|
|
558
|
+
meta = client.get_block_info_meta(blockfile)
|
|
559
|
+
except Exception as e:
|
|
560
|
+
return None
|
|
561
|
+
|
|
562
|
+
if not meta:
|
|
563
|
+
return None
|
|
564
|
+
|
|
565
|
+
size = meta['size']
|
|
566
|
+
one_chunk = 0x7530
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
chuncks = size // one_chunk
|
|
570
|
+
if size % one_chunk != 0:
|
|
571
|
+
chuncks += 1
|
|
572
|
+
|
|
573
|
+
file_content = bytearray()
|
|
574
|
+
for seg in range(chuncks):
|
|
575
|
+
start = seg * one_chunk
|
|
576
|
+
piece_data = client.get_block_info(blockfile, start, size)
|
|
577
|
+
file_content.extend(piece_data)
|
|
578
|
+
|
|
579
|
+
return BlockReader().get_data(file_content, BlockReader_TYPE_FLAT)
|
|
580
|
+
|
|
581
|
+
class GetCompanyInfoCategory(BaseParser):
|
|
582
|
+
|
|
583
|
+
def setParams(self, market, code):
|
|
584
|
+
if type(code) is six.text_type:
|
|
585
|
+
code = code.encode("utf-8")
|
|
586
|
+
|
|
587
|
+
pkg = bytearray.fromhex(u'0c 0f 10 9b 00 01 0e 00 0e 00 cf 02')
|
|
588
|
+
pkg.extend(struct.pack(u"<H6sI", market, code, 0))
|
|
589
|
+
self.send_pkg = pkg
|
|
590
|
+
|
|
591
|
+
def parseResponse(self, body_buf):
|
|
592
|
+
pos = 0
|
|
593
|
+
(num, ) = struct.unpack("<H", body_buf[:2])
|
|
594
|
+
pos += 2
|
|
595
|
+
|
|
596
|
+
category = []
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
def get_str(b):
|
|
601
|
+
p = b.find(b'\x00')
|
|
602
|
+
if p != -1:
|
|
603
|
+
b = b[0: p]
|
|
604
|
+
try:
|
|
605
|
+
n = b.decode("gbk")
|
|
606
|
+
except Exception as e:
|
|
607
|
+
n = "unkown_str"
|
|
608
|
+
return n
|
|
609
|
+
|
|
610
|
+
for i in range(num):
|
|
611
|
+
(name, filename, start, length) = struct.unpack(u"<64s80sII", body_buf[pos: pos+ 152])
|
|
612
|
+
pos += 152
|
|
613
|
+
entry = OrderedDict(
|
|
614
|
+
[
|
|
615
|
+
('name', get_str(name)),
|
|
616
|
+
('filename', get_str(filename)),
|
|
617
|
+
('start', start),
|
|
618
|
+
('length', length),
|
|
619
|
+
]
|
|
620
|
+
)
|
|
621
|
+
category.append(entry)
|
|
622
|
+
return category
|
|
623
|
+
|
|
624
|
+
class GetCompanyInfoContent(BaseParser):
|
|
625
|
+
|
|
626
|
+
def setParams(self, market, code, filename, start, length):
|
|
627
|
+
if type(code) is six.text_type:
|
|
628
|
+
code = code.encode("utf-8")
|
|
629
|
+
|
|
630
|
+
if type(filename) is six.text_type:
|
|
631
|
+
filename = filename.encode("utf-8")
|
|
632
|
+
|
|
633
|
+
if len(filename) != 80:
|
|
634
|
+
filename = filename.ljust(80, b'\x00')
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
pkg = bytearray.fromhex(u'0c 07 10 9c 00 01 68 00 68 00 d0 02')
|
|
638
|
+
pkg.extend(struct.pack(u"<H6sH80sIII", market, code, 0, filename, start, length, 0))
|
|
639
|
+
self.send_pkg = pkg
|
|
640
|
+
|
|
641
|
+
def parseResponse(self, body_buf):
|
|
642
|
+
pos = 0
|
|
643
|
+
_, length = struct.unpack(u'<10sH', body_buf[:12])
|
|
644
|
+
pos += 12
|
|
645
|
+
content = body_buf[pos: pos+length]
|
|
646
|
+
return content.decode("gbk")
|
|
647
|
+
|
|
648
|
+
class GetFinanceInfo(BaseParser):
|
|
649
|
+
|
|
650
|
+
def setParams(self, market, code):
|
|
651
|
+
if type(code) is six.text_type:
|
|
652
|
+
code = code.encode("utf-8")
|
|
653
|
+
pkg = bytearray.fromhex(u'0c 1f 18 76 00 01 0b 00 0b 00 10 00 01 00')
|
|
654
|
+
pkg.extend(struct.pack(u"<B6s", market, code))
|
|
655
|
+
self.send_pkg = pkg
|
|
656
|
+
|
|
657
|
+
def parseResponse(self, body_buf):
|
|
658
|
+
pos = 0
|
|
659
|
+
pos += 2 #skip num ,we only query 1 in this case
|
|
660
|
+
market, code = struct.unpack(u"<B6s",body_buf[pos: pos+7])
|
|
661
|
+
pos += 7
|
|
662
|
+
|
|
663
|
+
(
|
|
664
|
+
liutongguben,
|
|
665
|
+
province,
|
|
666
|
+
industry,
|
|
667
|
+
updated_date,
|
|
668
|
+
ipo_date,
|
|
669
|
+
zongguben,
|
|
670
|
+
guojiagu,
|
|
671
|
+
faqirenfarengu,
|
|
672
|
+
farengu,
|
|
673
|
+
bgu,
|
|
674
|
+
hgu,
|
|
675
|
+
zhigonggu,
|
|
676
|
+
zongzichan,
|
|
677
|
+
liudongzichan,
|
|
678
|
+
gudingzichan,
|
|
679
|
+
wuxingzichan,
|
|
680
|
+
gudongrenshu,
|
|
681
|
+
liudongfuzhai,
|
|
682
|
+
changqifuzhai,
|
|
683
|
+
zibengongjijin,
|
|
684
|
+
jingzichan,
|
|
685
|
+
zhuyingshouru,
|
|
686
|
+
zhuyinglirun,
|
|
687
|
+
yingshouzhangkuan,
|
|
688
|
+
yingyelirun,
|
|
689
|
+
touzishouyu,
|
|
690
|
+
jingyingxianjinliu,
|
|
691
|
+
zongxianjinliu,
|
|
692
|
+
cunhuo,
|
|
693
|
+
lirunzonghe,
|
|
694
|
+
shuihoulirun,
|
|
695
|
+
jinglirun,
|
|
696
|
+
weifenlirun,
|
|
697
|
+
baoliu1,
|
|
698
|
+
baoliu2
|
|
699
|
+
) = struct.unpack("<fHHIIffffffffffffffffffffffffffffff", body_buf[pos:])
|
|
700
|
+
|
|
701
|
+
def _get_v(v):
|
|
702
|
+
return v
|
|
703
|
+
|
|
704
|
+
return OrderedDict(
|
|
705
|
+
[
|
|
706
|
+
("market", market),
|
|
707
|
+
("code", code.decode("utf-8")),
|
|
708
|
+
("liutongguben", _get_v(liutongguben)*10000),
|
|
709
|
+
('province', province),
|
|
710
|
+
('industry', industry),
|
|
711
|
+
('updated_date', updated_date),
|
|
712
|
+
('ipo_date', ipo_date),
|
|
713
|
+
("zongguben", _get_v(zongguben)*10000),
|
|
714
|
+
("guojiagu", _get_v(guojiagu)*10000),
|
|
715
|
+
("faqirenfarengu", _get_v(faqirenfarengu)*10000),
|
|
716
|
+
("farengu", _get_v(farengu)*10000),
|
|
717
|
+
("bgu", _get_v(bgu)*10000),
|
|
718
|
+
("hgu", _get_v(hgu)*10000),
|
|
719
|
+
("zhigonggu", _get_v(zhigonggu)*10000),
|
|
720
|
+
("zongzichan", _get_v(zongzichan)*10000),
|
|
721
|
+
("liudongzichan", _get_v(liudongzichan)*10000),
|
|
722
|
+
("gudingzichan", _get_v(gudingzichan)*10000),
|
|
723
|
+
("wuxingzichan", _get_v(wuxingzichan)*10000),
|
|
724
|
+
("gudongrenshu", _get_v(gudongrenshu)),
|
|
725
|
+
("liudongfuzhai", _get_v(liudongfuzhai)*10000),
|
|
726
|
+
("changqifuzhai", _get_v(changqifuzhai)*10000),
|
|
727
|
+
("zibengongjijin", _get_v(zibengongjijin)*10000),
|
|
728
|
+
("jingzichan", _get_v(jingzichan)*10000),
|
|
729
|
+
("zhuyingshouru", _get_v(zhuyingshouru)*10000),
|
|
730
|
+
("zhuyinglirun", _get_v(zhuyinglirun)*10000),
|
|
731
|
+
("yingshouzhangkuan", _get_v(yingshouzhangkuan)*10000),
|
|
732
|
+
("yingyelirun", _get_v(yingyelirun)*10000),
|
|
733
|
+
("touzishouyu", _get_v(touzishouyu)*10000),
|
|
734
|
+
("jingyingxianjinliu", _get_v(jingyingxianjinliu)*10000),
|
|
735
|
+
("zongxianjinliu", _get_v(zongxianjinliu)*10000),
|
|
736
|
+
("cunhuo", _get_v(cunhuo)*10000),
|
|
737
|
+
("lirunzonghe", _get_v(lirunzonghe)*10000),
|
|
738
|
+
("shuihoulirun", _get_v(shuihoulirun)*10000),
|
|
739
|
+
("jinglirun", _get_v(jinglirun)*10000),
|
|
740
|
+
("weifenpeilirun", _get_v(weifenlirun)*10000),
|
|
741
|
+
("meigujingzichan", _get_v(baoliu1)),
|
|
742
|
+
("baoliu2", _get_v(baoliu2))
|
|
743
|
+
]
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
def get_price(data, pos):
|
|
747
|
+
pos_byte = 6
|
|
748
|
+
bdata = indexbytes(data, pos)
|
|
749
|
+
intdata = bdata & 0x3f
|
|
750
|
+
if bdata & 0x40:
|
|
751
|
+
sign = True
|
|
752
|
+
else:
|
|
753
|
+
sign = False
|
|
754
|
+
|
|
755
|
+
if bdata & 0x80:
|
|
756
|
+
while True:
|
|
757
|
+
pos += 1
|
|
758
|
+
bdata = indexbytes(data, pos)
|
|
759
|
+
intdata += (bdata & 0x7f) << pos_byte
|
|
760
|
+
pos_byte += 7
|
|
761
|
+
|
|
762
|
+
if bdata & 0x80:
|
|
763
|
+
pass
|
|
764
|
+
else:
|
|
765
|
+
break
|
|
766
|
+
|
|
767
|
+
pos += 1
|
|
768
|
+
|
|
769
|
+
if sign:
|
|
770
|
+
intdata = -intdata
|
|
771
|
+
|
|
772
|
+
return intdata, pos
|
|
773
|
+
def get_volume(ivol):
|
|
774
|
+
logpoint = ivol >> (8 * 3)
|
|
775
|
+
hheax = ivol >> (8 * 3); # [3]
|
|
776
|
+
hleax = (ivol >> (8 * 2)) & 0xff; # [2]
|
|
777
|
+
lheax = (ivol >> 8) & 0xff; # [1]
|
|
778
|
+
lleax = ivol & 0xff; # [0]
|
|
779
|
+
|
|
780
|
+
dbl_1 = 1.0
|
|
781
|
+
dbl_2 = 2.0
|
|
782
|
+
dbl_128 = 128.0
|
|
783
|
+
|
|
784
|
+
dwEcx = logpoint * 2 - 0x7f;
|
|
785
|
+
dwEdx = logpoint * 2 - 0x86;
|
|
786
|
+
dwEsi = logpoint * 2 - 0x8e;
|
|
787
|
+
dwEax = logpoint * 2 - 0x96;
|
|
788
|
+
if dwEcx < 0:
|
|
789
|
+
tmpEax = - dwEcx
|
|
790
|
+
else:
|
|
791
|
+
tmpEax = dwEcx
|
|
792
|
+
|
|
793
|
+
dbl_xmm6 = 0.0
|
|
794
|
+
dbl_xmm6 = pow(2.0, tmpEax)
|
|
795
|
+
if dwEcx < 0:
|
|
796
|
+
dbl_xmm6 = 1.0 / dbl_xmm6
|
|
797
|
+
|
|
798
|
+
dbl_xmm4 = 0
|
|
799
|
+
if hleax > 0x80:
|
|
800
|
+
tmpdbl_xmm3 = 0.0
|
|
801
|
+
tmpdbl_xmm1 = 0.0
|
|
802
|
+
dwtmpeax = dwEdx + 1
|
|
803
|
+
tmpdbl_xmm3 = pow(2.0, dwtmpeax)
|
|
804
|
+
dbl_xmm0 = pow(2.0, dwEdx) * 128.0
|
|
805
|
+
dbl_xmm0 += (hleax & 0x7f) * tmpdbl_xmm3
|
|
806
|
+
dbl_xmm4 = dbl_xmm0
|
|
807
|
+
|
|
808
|
+
else:
|
|
809
|
+
dbl_xmm0 = 0.0
|
|
810
|
+
if dwEdx >= 0:
|
|
811
|
+
dbl_xmm0 = pow(2.0, dwEdx) * hleax
|
|
812
|
+
else:
|
|
813
|
+
dbl_xmm0 = (1 / pow(2.0, dwEdx)) * hleax
|
|
814
|
+
dbl_xmm4 = dbl_xmm0
|
|
815
|
+
|
|
816
|
+
dbl_xmm3 = pow(2.0, dwEsi) * lheax
|
|
817
|
+
dbl_xmm1 = pow(2.0, dwEax) * lleax
|
|
818
|
+
if hleax & 0x80:
|
|
819
|
+
dbl_xmm3 *= 2.0
|
|
820
|
+
dbl_xmm1 *= 2.0
|
|
821
|
+
|
|
822
|
+
dbl_ret = dbl_xmm6 + dbl_xmm4 + dbl_xmm3 + dbl_xmm1
|
|
823
|
+
return dbl_ret
|
|
824
|
+
def get_datetime(category, buffer, pos):
|
|
825
|
+
year = 0
|
|
826
|
+
month = 0
|
|
827
|
+
day = 0
|
|
828
|
+
hour = 15
|
|
829
|
+
minute = 0
|
|
830
|
+
if category < 4 or category == 7 or category == 8:
|
|
831
|
+
(zipday, tminutes) = struct.unpack("<HH", buffer[pos: pos + 4])
|
|
832
|
+
year = (zipday >> 11) + 2004
|
|
833
|
+
month = int((zipday % 2048) / 100)
|
|
834
|
+
day = (zipday % 2048) % 100
|
|
835
|
+
|
|
836
|
+
hour = int(tminutes / 60)
|
|
837
|
+
minute = tminutes % 60
|
|
838
|
+
else:
|
|
839
|
+
(zipday,) = struct.unpack("<I", buffer[pos: pos + 4])
|
|
840
|
+
|
|
841
|
+
year = int(zipday / 10000);
|
|
842
|
+
month = int((zipday % 10000) / 100)
|
|
843
|
+
day = zipday % 100
|
|
844
|
+
|
|
845
|
+
pos += 4
|
|
846
|
+
|
|
847
|
+
return year, month, day, hour, minute, pos
|
|
848
|
+
def get_time(buffer, pos):
|
|
849
|
+
(tminutes, ) = struct.unpack("<H", buffer[pos: pos + 2])
|
|
850
|
+
hour = int(tminutes / 60)
|
|
851
|
+
minute = tminutes % 60
|
|
852
|
+
pos += 2
|
|
853
|
+
|
|
854
|
+
return hour, minute, pos
|
|
855
|
+
def indexbytes(data, pos):
|
|
856
|
+
|
|
857
|
+
if six.PY2:
|
|
858
|
+
if type(data) is bytearray:
|
|
859
|
+
return data[pos]
|
|
860
|
+
else:
|
|
861
|
+
return six.indexbytes(data, pos)
|
|
862
|
+
else:
|
|
863
|
+
return data[pos]
|
|
864
|
+
class GetHistoryMinuteTimeData(BaseParser):
|
|
865
|
+
|
|
866
|
+
def setParams(self, market, code, date):
|
|
867
|
+
if (type(date) is six.text_type) or (type(date) is six.binary_type):
|
|
868
|
+
date = int(date)
|
|
869
|
+
|
|
870
|
+
if type(code) is six.text_type:
|
|
871
|
+
code = code.encode("utf-8")
|
|
872
|
+
|
|
873
|
+
pkg = bytearray.fromhex(u'0c 01 30 00 01 01 0d 00 0d 00 b4 0f')
|
|
874
|
+
pkg.extend(struct.pack("<IB6s", date, market, code))
|
|
875
|
+
self.send_pkg = pkg
|
|
876
|
+
|
|
877
|
+
def parseResponse(self, body_buf):
|
|
878
|
+
pos = 0
|
|
879
|
+
(num, ) = struct.unpack("<H", body_buf[:2])
|
|
880
|
+
last_price = 0
|
|
881
|
+
# 跳过了4个字节,实在不知道是什么意思
|
|
882
|
+
pos += 6
|
|
883
|
+
prices = []
|
|
884
|
+
for i in range(num):
|
|
885
|
+
price_raw, pos = get_price(body_buf, pos)
|
|
886
|
+
reversed1, pos = get_price(body_buf, pos)
|
|
887
|
+
vol, pos = get_price(body_buf, pos)
|
|
888
|
+
last_price = last_price + price_raw
|
|
889
|
+
price = OrderedDict(
|
|
890
|
+
[
|
|
891
|
+
("price", float(last_price)/100),
|
|
892
|
+
("vol", vol)
|
|
893
|
+
]
|
|
894
|
+
)
|
|
895
|
+
prices.append(price)
|
|
896
|
+
return prices
|
|
897
|
+
|
|
898
|
+
class GetHistoryTransactionData(BaseParser):
|
|
899
|
+
def setParams(self, market, code, start, count, date):
|
|
900
|
+
if type(code) is six.text_type:
|
|
901
|
+
code = code.encode("utf-8")
|
|
902
|
+
|
|
903
|
+
if type(date) is (type(date) is six.text_type) or (type(date) is six.binary_type):
|
|
904
|
+
date = int(date)
|
|
905
|
+
|
|
906
|
+
pkg = bytearray.fromhex(u'0c 01 30 01 00 01 12 00 12 00 b5 0f')
|
|
907
|
+
pkg.extend(struct.pack("<IH6sHH", date, market, code, start, count))
|
|
908
|
+
self.send_pkg = pkg
|
|
909
|
+
def parseResponse(self, body_buf):
|
|
910
|
+
pos = 0
|
|
911
|
+
(num, ) = struct.unpack("<H", body_buf[:2])
|
|
912
|
+
pos += 2
|
|
913
|
+
ticks = []
|
|
914
|
+
|
|
915
|
+
# skip 4 bytes
|
|
916
|
+
pos += 4
|
|
917
|
+
|
|
918
|
+
last_price = 0
|
|
919
|
+
for i in range(num):
|
|
920
|
+
### ?? get_time
|
|
921
|
+
# \x80\x03 = 14:56
|
|
922
|
+
|
|
923
|
+
hour, minute, pos = get_time(body_buf, pos)
|
|
924
|
+
|
|
925
|
+
price_raw, pos = get_price(body_buf, pos)
|
|
926
|
+
vol, pos = get_price(body_buf, pos)
|
|
927
|
+
buyorsell, pos = get_price(body_buf, pos)
|
|
928
|
+
_, pos = get_price(body_buf, pos)
|
|
929
|
+
|
|
930
|
+
last_price = last_price + price_raw
|
|
931
|
+
|
|
932
|
+
tick = OrderedDict(
|
|
933
|
+
[
|
|
934
|
+
("time", "%02d:%02d" % (hour, minute)),
|
|
935
|
+
("price", float(last_price)/100),
|
|
936
|
+
("vol", vol),
|
|
937
|
+
("buyorsell", buyorsell),
|
|
938
|
+
]
|
|
939
|
+
)
|
|
940
|
+
|
|
941
|
+
ticks.append(tick)
|
|
942
|
+
|
|
943
|
+
return ticks
|
|
944
|
+
|
|
945
|
+
class GetIndexBarsCmd(BaseParser):
|
|
946
|
+
|
|
947
|
+
def setParams(self, category, market, code, start, count):
|
|
948
|
+
if type(code) is six.text_type:
|
|
949
|
+
code = code.encode("utf-8")
|
|
950
|
+
|
|
951
|
+
self.category = category
|
|
952
|
+
|
|
953
|
+
values = (
|
|
954
|
+
0x10c,
|
|
955
|
+
0x01016408,
|
|
956
|
+
0x1c,
|
|
957
|
+
0x1c,
|
|
958
|
+
0x052d,
|
|
959
|
+
market,
|
|
960
|
+
code,
|
|
961
|
+
category,
|
|
962
|
+
1,
|
|
963
|
+
start,
|
|
964
|
+
count,
|
|
965
|
+
0, 0, 0 # I + I + H total 10 zero
|
|
966
|
+
)
|
|
967
|
+
|
|
968
|
+
pkg = struct.pack("<HIHHHH6sHHHHIIH", *values)
|
|
969
|
+
self.send_pkg = pkg
|
|
970
|
+
|
|
971
|
+
def parseResponse(self, body_buf):
|
|
972
|
+
pos = 0
|
|
973
|
+
|
|
974
|
+
(ret_count,) = struct.unpack("<H", body_buf[0: 2])
|
|
975
|
+
pos += 2
|
|
976
|
+
|
|
977
|
+
klines = []
|
|
978
|
+
|
|
979
|
+
pre_diff_base = 0
|
|
980
|
+
for i in range(ret_count):
|
|
981
|
+
year, month, day, hour, minute, pos = get_datetime(self.category, body_buf, pos)
|
|
982
|
+
|
|
983
|
+
price_open_diff, pos = get_price(body_buf, pos)
|
|
984
|
+
price_close_diff, pos = get_price(body_buf, pos)
|
|
985
|
+
|
|
986
|
+
price_high_diff, pos = get_price(body_buf, pos)
|
|
987
|
+
price_low_diff, pos = get_price(body_buf, pos)
|
|
988
|
+
|
|
989
|
+
(vol_raw,) = struct.unpack("<I", body_buf[pos: pos + 4])
|
|
990
|
+
vol = get_volume(vol_raw)
|
|
991
|
+
|
|
992
|
+
pos += 4
|
|
993
|
+
(dbvol_raw,) = struct.unpack("<I", body_buf[pos: pos + 4])
|
|
994
|
+
dbvol = get_volume(dbvol_raw)
|
|
995
|
+
pos += 4
|
|
996
|
+
|
|
997
|
+
(up_count, down_count) = struct.unpack("<HH", body_buf[pos: pos + 4])
|
|
998
|
+
pos += 4
|
|
999
|
+
|
|
1000
|
+
open = self._cal_price1000(price_open_diff, pre_diff_base)
|
|
1001
|
+
|
|
1002
|
+
price_open_diff = price_open_diff + pre_diff_base
|
|
1003
|
+
|
|
1004
|
+
close = self._cal_price1000(price_open_diff, price_close_diff)
|
|
1005
|
+
high = self._cal_price1000(price_open_diff, price_high_diff)
|
|
1006
|
+
low = self._cal_price1000(price_open_diff, price_low_diff)
|
|
1007
|
+
|
|
1008
|
+
pre_diff_base = price_open_diff + price_close_diff
|
|
1009
|
+
|
|
1010
|
+
#### 为了避免python处理浮点数的时候,浮点数运算不精确问题,这里引入了多余的代码
|
|
1011
|
+
|
|
1012
|
+
kline = OrderedDict([
|
|
1013
|
+
("open", open),
|
|
1014
|
+
("close", close),
|
|
1015
|
+
("high", high),
|
|
1016
|
+
("low", low),
|
|
1017
|
+
("vol", vol),
|
|
1018
|
+
("amount", dbvol),
|
|
1019
|
+
("year", year),
|
|
1020
|
+
("month", month),
|
|
1021
|
+
("day", day),
|
|
1022
|
+
("hour", hour),
|
|
1023
|
+
("minute", minute),
|
|
1024
|
+
("datetime", "%d-%02d-%02d %02d:%02d" % (year, month, day, hour, minute)),
|
|
1025
|
+
("up_count", up_count),
|
|
1026
|
+
("down_count", down_count)
|
|
1027
|
+
])
|
|
1028
|
+
klines.append(kline)
|
|
1029
|
+
return klines
|
|
1030
|
+
|
|
1031
|
+
def _cal_price1000(self, base_p, diff):
|
|
1032
|
+
return float(base_p + diff)/1000
|
|
1033
|
+
|
|
1034
|
+
class GetMinuteTimeData(BaseParser):
|
|
1035
|
+
|
|
1036
|
+
def setParams(self, market, code):
|
|
1037
|
+
if type(code) is six.text_type:
|
|
1038
|
+
code = code.encode("utf-8")
|
|
1039
|
+
pkg = bytearray.fromhex(u'0c 1b 08 00 01 01 0e 00 0e 00 1d 05')
|
|
1040
|
+
pkg.extend(struct.pack("<H6sI", market, code, 0))
|
|
1041
|
+
self.send_pkg = pkg
|
|
1042
|
+
|
|
1043
|
+
def parseResponse(self, body_buf):
|
|
1044
|
+
pos = 0
|
|
1045
|
+
(num, ) = struct.unpack("<H", body_buf[:2])
|
|
1046
|
+
last_price = 0
|
|
1047
|
+
pos += 4
|
|
1048
|
+
prices = []
|
|
1049
|
+
for i in range(num):
|
|
1050
|
+
price_raw, pos = get_price(body_buf, pos)
|
|
1051
|
+
reversed1, pos = get_price(body_buf, pos)
|
|
1052
|
+
vol, pos = get_price(body_buf, pos)
|
|
1053
|
+
last_price = last_price + price_raw
|
|
1054
|
+
price = OrderedDict(
|
|
1055
|
+
[
|
|
1056
|
+
("price", float(last_price)/100),
|
|
1057
|
+
("vol", vol)
|
|
1058
|
+
]
|
|
1059
|
+
)
|
|
1060
|
+
prices.append(price)
|
|
1061
|
+
return prices
|
|
1062
|
+
|
|
1063
|
+
class GetSecurityBarsCmd(BaseParser):
|
|
1064
|
+
|
|
1065
|
+
def setParams(self, category, market, code, start, count):
|
|
1066
|
+
if type(code) is six.text_type:
|
|
1067
|
+
code = code.encode("utf-8")
|
|
1068
|
+
|
|
1069
|
+
self.category = category
|
|
1070
|
+
|
|
1071
|
+
values = (
|
|
1072
|
+
0x10c,
|
|
1073
|
+
0x01016408,
|
|
1074
|
+
0x1c,
|
|
1075
|
+
0x1c,
|
|
1076
|
+
0x052d,
|
|
1077
|
+
market,
|
|
1078
|
+
code,
|
|
1079
|
+
category,
|
|
1080
|
+
1,
|
|
1081
|
+
start,
|
|
1082
|
+
count,
|
|
1083
|
+
0, 0, 0 # I + I + H total 10 zero
|
|
1084
|
+
)
|
|
1085
|
+
|
|
1086
|
+
pkg = struct.pack("<HIHHHH6sHHHHIIH", *values)
|
|
1087
|
+
self.send_pkg = pkg
|
|
1088
|
+
|
|
1089
|
+
def parseResponse(self, body_buf):
|
|
1090
|
+
pos = 0
|
|
1091
|
+
|
|
1092
|
+
(ret_count,) = struct.unpack("<H", body_buf[0: 2])
|
|
1093
|
+
pos += 2
|
|
1094
|
+
|
|
1095
|
+
klines = []
|
|
1096
|
+
|
|
1097
|
+
pre_diff_base = 0
|
|
1098
|
+
for i in range(ret_count):
|
|
1099
|
+
year, month, day, hour, minute, pos = get_datetime(self.category, body_buf, pos)
|
|
1100
|
+
|
|
1101
|
+
price_open_diff, pos = get_price(body_buf, pos)
|
|
1102
|
+
price_close_diff, pos = get_price(body_buf, pos)
|
|
1103
|
+
|
|
1104
|
+
price_high_diff, pos = get_price(body_buf, pos)
|
|
1105
|
+
price_low_diff, pos = get_price(body_buf, pos)
|
|
1106
|
+
|
|
1107
|
+
(vol_raw,) = struct.unpack("<I", body_buf[pos: pos + 4])
|
|
1108
|
+
vol = get_volume(vol_raw)
|
|
1109
|
+
|
|
1110
|
+
pos += 4
|
|
1111
|
+
(dbvol_raw,) = struct.unpack("<I", body_buf[pos: pos + 4])
|
|
1112
|
+
dbvol = get_volume(dbvol_raw)
|
|
1113
|
+
pos += 4
|
|
1114
|
+
|
|
1115
|
+
open = self._cal_price1000(price_open_diff, pre_diff_base)
|
|
1116
|
+
|
|
1117
|
+
price_open_diff = price_open_diff + pre_diff_base
|
|
1118
|
+
|
|
1119
|
+
close = self._cal_price1000(price_open_diff, price_close_diff)
|
|
1120
|
+
high = self._cal_price1000(price_open_diff, price_high_diff)
|
|
1121
|
+
low = self._cal_price1000(price_open_diff, price_low_diff)
|
|
1122
|
+
|
|
1123
|
+
pre_diff_base = price_open_diff + price_close_diff
|
|
1124
|
+
|
|
1125
|
+
#### 为了避免python处理浮点数的时候,浮点数运算不精确问题,这里引入了多余的代码
|
|
1126
|
+
|
|
1127
|
+
kline = OrderedDict([
|
|
1128
|
+
("open", open),
|
|
1129
|
+
("close", close),
|
|
1130
|
+
("high", high),
|
|
1131
|
+
("low", low),
|
|
1132
|
+
("vol", vol),
|
|
1133
|
+
("amount", dbvol),
|
|
1134
|
+
("year", year),
|
|
1135
|
+
("month", month),
|
|
1136
|
+
("day", day),
|
|
1137
|
+
("hour", hour),
|
|
1138
|
+
("minute", minute),
|
|
1139
|
+
("datetime", "%d-%02d-%02d %02d:%02d" % (year, month, day, hour, minute))
|
|
1140
|
+
])
|
|
1141
|
+
klines.append(kline)
|
|
1142
|
+
return klines
|
|
1143
|
+
|
|
1144
|
+
def _cal_price1000(self, base_p, diff):
|
|
1145
|
+
return float(base_p + diff)/1000
|
|
1146
|
+
|
|
1147
|
+
class GetSecurityCountCmd(BaseParser):
|
|
1148
|
+
|
|
1149
|
+
def setParams(self, market):
|
|
1150
|
+
|
|
1151
|
+
pkg = bytearray.fromhex(u"0c 0c 18 6c 00 01 08 00 08 00 4e 04")
|
|
1152
|
+
market_pkg = struct.pack("<H", market)
|
|
1153
|
+
pkg.extend(market_pkg)
|
|
1154
|
+
pkg.extend(b'\x75\xc7\x33\x01')
|
|
1155
|
+
self.send_pkg = pkg
|
|
1156
|
+
|
|
1157
|
+
def parseResponse(self, body_buf):
|
|
1158
|
+
(num, ) = struct.unpack("<H", body_buf[:2])
|
|
1159
|
+
return num
|
|
1160
|
+
|
|
1161
|
+
class GetSecurityList(BaseParser):
|
|
1162
|
+
|
|
1163
|
+
def setParams(self, market, start):
|
|
1164
|
+
pkg = bytearray.fromhex(u'0c 01 18 64 01 01 06 00 06 00 50 04')
|
|
1165
|
+
pkg_param = struct.pack("<HH", market, start)
|
|
1166
|
+
pkg.extend(pkg_param)
|
|
1167
|
+
self.send_pkg = pkg
|
|
1168
|
+
|
|
1169
|
+
def parseResponse(self, body_buf):
|
|
1170
|
+
|
|
1171
|
+
pos = 0
|
|
1172
|
+
(num, ) = struct.unpack("<H", body_buf[:2])
|
|
1173
|
+
pos += 2
|
|
1174
|
+
stocks = []
|
|
1175
|
+
for i in range(num):
|
|
1176
|
+
|
|
1177
|
+
# b'880023d\x00\xd6\xd0\xd0\xa1\xc6\xbd\xbe\xf9.9\x04\x00\x02\x9a\x99\x8cA\x00\x00\x00\x00'
|
|
1178
|
+
# 880023 100 中小平均 276782 2 17.575001 0 80846648
|
|
1179
|
+
|
|
1180
|
+
one_bytes = body_buf[pos: pos + 29]
|
|
1181
|
+
|
|
1182
|
+
(code, volunit,
|
|
1183
|
+
name_bytes, reversed_bytes1, decimal_point,
|
|
1184
|
+
pre_close_raw, reversed_bytes2) = struct.unpack("<6sH8s4sBI4s", one_bytes)
|
|
1185
|
+
|
|
1186
|
+
code = code.decode("utf-8")
|
|
1187
|
+
name = name_bytes.decode("gbk").rstrip("\x00")
|
|
1188
|
+
pre_close = get_volume(pre_close_raw)
|
|
1189
|
+
pos += 29
|
|
1190
|
+
|
|
1191
|
+
one = OrderedDict(
|
|
1192
|
+
[
|
|
1193
|
+
('code', code),
|
|
1194
|
+
('volunit', volunit),
|
|
1195
|
+
('decimal_point', decimal_point),
|
|
1196
|
+
('name', name),
|
|
1197
|
+
('pre_close', pre_close),
|
|
1198
|
+
]
|
|
1199
|
+
)
|
|
1200
|
+
|
|
1201
|
+
stocks.append(one)
|
|
1202
|
+
|
|
1203
|
+
|
|
1204
|
+
return stocks
|
|
1205
|
+
|
|
1206
|
+
class GetSecurityQuotesCmd(BaseParser):
|
|
1207
|
+
|
|
1208
|
+
def setParams(self, all_stock):
|
|
1209
|
+
stock_len = len(all_stock)
|
|
1210
|
+
if stock_len <= 0:
|
|
1211
|
+
return False
|
|
1212
|
+
|
|
1213
|
+
pkgdatalen = stock_len * 7 + 12
|
|
1214
|
+
|
|
1215
|
+
values = (
|
|
1216
|
+
0x10c,
|
|
1217
|
+
0x02006320,
|
|
1218
|
+
pkgdatalen,
|
|
1219
|
+
pkgdatalen,
|
|
1220
|
+
0x5053e,
|
|
1221
|
+
0,
|
|
1222
|
+
0,
|
|
1223
|
+
stock_len,
|
|
1224
|
+
)
|
|
1225
|
+
|
|
1226
|
+
pkg_header = struct.pack("<HIHHIIHH", *values)
|
|
1227
|
+
pkg = bytearray(pkg_header)
|
|
1228
|
+
for stock in all_stock:
|
|
1229
|
+
market, code = stock
|
|
1230
|
+
if type(code) is six.text_type:
|
|
1231
|
+
code = code.encode("utf-8")
|
|
1232
|
+
one_stock_pkg = struct.pack("<B6s", market, code)
|
|
1233
|
+
pkg.extend(one_stock_pkg)
|
|
1234
|
+
|
|
1235
|
+
self.send_pkg = pkg
|
|
1236
|
+
|
|
1237
|
+
def parseResponse(self, body_buf):
|
|
1238
|
+
pos = 0
|
|
1239
|
+
pos += 2 # skip b1 cb
|
|
1240
|
+
(num_stock,) = struct.unpack("<H", body_buf[pos: pos + 2])
|
|
1241
|
+
pos += 2
|
|
1242
|
+
stocks = []
|
|
1243
|
+
|
|
1244
|
+
for _ in range(num_stock):
|
|
1245
|
+
# print(body_buf[pos:])
|
|
1246
|
+
# b'\x00000001\x95\n\x87\x0e\x01\x01\x05\x00\xb1\xb9\xd6\r\xc7\x0e\x8d\xd7\x1a\x84\x04S\x9c<M\xb6\xc8\x0e\x97\x8e\x0c\x00\xae\n\x00\x01\xa0\x1e\x9e\xb3\x03A\x02\x84\xf9\x01\xa8|B\x03\x8c\xd6\x01\xb0lC\x04\xb7\xdb\x02\xac\x7fD\x05\xbb\xb0\x01\xbe\xa0\x01y\x08\x01GC\x04\x00\x00\x95\n'
|
|
1247
|
+
(market, code, active1) = struct.unpack(
|
|
1248
|
+
"<B6sH", body_buf[pos: pos + 9])
|
|
1249
|
+
pos += 9
|
|
1250
|
+
price, pos = get_price(body_buf, pos)
|
|
1251
|
+
last_close_diff, pos = get_price(body_buf, pos)
|
|
1252
|
+
open_diff, pos = get_price(body_buf, pos)
|
|
1253
|
+
high_diff, pos = get_price(body_buf, pos)
|
|
1254
|
+
low_diff, pos = get_price(body_buf, pos)
|
|
1255
|
+
# 不确定这里应该是用 get_price 跳过还是直接跳过4个bytes
|
|
1256
|
+
# if price == 0 and last_close_diff == 0 and open_diff == 0 and high_diff == 0 and low_diff == 0:
|
|
1257
|
+
# # 这个股票当前应该无法获取信息, 这个时候,这个值一般是0 或者 100
|
|
1258
|
+
# #reversed_bytes0 = body_buf[pos: pos + 1]
|
|
1259
|
+
# #pos += 1
|
|
1260
|
+
# # 感觉这里应该都可以用 get_price ,但是由于一次性改动影响比较大,所以暂时只针对没有行情的股票做改动
|
|
1261
|
+
# reversed_bytes0, pos = get_price(body_buf, pos)
|
|
1262
|
+
# else:
|
|
1263
|
+
# reversed_bytes0 = body_buf[pos: pos + 4]
|
|
1264
|
+
# pos += 4
|
|
1265
|
+
reversed_bytes0, pos = get_price(body_buf, pos)
|
|
1266
|
+
# reversed_bytes0, pos = get_price(body_buf, pos)
|
|
1267
|
+
# 应该是 -price
|
|
1268
|
+
reversed_bytes1, pos = get_price(body_buf, pos)
|
|
1269
|
+
# print('reversed_bytes1:' + str(reversed_bytes1) + ",price" + str(price))
|
|
1270
|
+
# assert (reversed_bytes1 == -price)
|
|
1271
|
+
vol, pos = get_price(body_buf, pos)
|
|
1272
|
+
cur_vol, pos = get_price(body_buf, pos)
|
|
1273
|
+
(amount_raw,) = struct.unpack("<I", body_buf[pos: pos + 4])
|
|
1274
|
+
amount = get_volume(amount_raw)
|
|
1275
|
+
pos += 4
|
|
1276
|
+
s_vol, pos = get_price(body_buf, pos)
|
|
1277
|
+
b_vol, pos = get_price(body_buf, pos)
|
|
1278
|
+
reversed_bytes2, pos = get_price(body_buf, pos)
|
|
1279
|
+
reversed_bytes3, pos = get_price(body_buf, pos)
|
|
1280
|
+
|
|
1281
|
+
bid1, pos = get_price(body_buf, pos)
|
|
1282
|
+
ask1, pos = get_price(body_buf, pos)
|
|
1283
|
+
bid_vol1, pos = get_price(body_buf, pos)
|
|
1284
|
+
ask_vol1, pos = get_price(body_buf, pos)
|
|
1285
|
+
|
|
1286
|
+
bid2, pos = get_price(body_buf, pos)
|
|
1287
|
+
ask2, pos = get_price(body_buf, pos)
|
|
1288
|
+
bid_vol2, pos = get_price(body_buf, pos)
|
|
1289
|
+
ask_vol2, pos = get_price(body_buf, pos)
|
|
1290
|
+
|
|
1291
|
+
bid3, pos = get_price(body_buf, pos)
|
|
1292
|
+
ask3, pos = get_price(body_buf, pos)
|
|
1293
|
+
bid_vol3, pos = get_price(body_buf, pos)
|
|
1294
|
+
ask_vol3, pos = get_price(body_buf, pos)
|
|
1295
|
+
|
|
1296
|
+
bid4, pos = get_price(body_buf, pos)
|
|
1297
|
+
ask4, pos = get_price(body_buf, pos)
|
|
1298
|
+
bid_vol4, pos = get_price(body_buf, pos)
|
|
1299
|
+
ask_vol4, pos = get_price(body_buf, pos)
|
|
1300
|
+
|
|
1301
|
+
bid5, pos = get_price(body_buf, pos)
|
|
1302
|
+
ask5, pos = get_price(body_buf, pos)
|
|
1303
|
+
bid_vol5, pos = get_price(body_buf, pos)
|
|
1304
|
+
ask_vol5, pos = get_price(body_buf, pos)
|
|
1305
|
+
|
|
1306
|
+
# (reversed_bytes4, reversed_bytes5, reversed_bytes6,
|
|
1307
|
+
# reversed_bytes7, reversed_bytes8, reversed_bytes9,
|
|
1308
|
+
# active2) = struct.unpack("<HbbbbHH", body_buf[pos: pos + 10])
|
|
1309
|
+
# pos += 10
|
|
1310
|
+
|
|
1311
|
+
reversed_bytes4 = struct.unpack("<H", body_buf[pos:pos+2])
|
|
1312
|
+
pos += 2
|
|
1313
|
+
reversed_bytes5, pos = get_price(body_buf, pos)
|
|
1314
|
+
reversed_bytes6, pos = get_price(body_buf, pos)
|
|
1315
|
+
reversed_bytes7, pos = get_price(body_buf, pos)
|
|
1316
|
+
reversed_bytes8, pos = get_price(body_buf, pos)
|
|
1317
|
+
(reversed_bytes9, active2) = struct.unpack(
|
|
1318
|
+
"<hH", body_buf[pos: pos + 4])
|
|
1319
|
+
pos += 4
|
|
1320
|
+
|
|
1321
|
+
one_stock = OrderedDict([
|
|
1322
|
+
("market", market),
|
|
1323
|
+
("code", code.decode("utf-8")),
|
|
1324
|
+
("active1", active1),
|
|
1325
|
+
("price", self._cal_price(price, 0)),
|
|
1326
|
+
("last_close", self._cal_price(price, last_close_diff)),
|
|
1327
|
+
("open", self._cal_price(price, open_diff)),
|
|
1328
|
+
("high", self._cal_price(price, high_diff)),
|
|
1329
|
+
("low", self._cal_price(price, low_diff)),
|
|
1330
|
+
("servertime", self._format_time('%s' % reversed_bytes0)),
|
|
1331
|
+
("reversed_bytes0", reversed_bytes0),
|
|
1332
|
+
("reversed_bytes1", reversed_bytes1),
|
|
1333
|
+
("vol", vol),
|
|
1334
|
+
("cur_vol", cur_vol),
|
|
1335
|
+
("amount", amount),
|
|
1336
|
+
("s_vol", s_vol),
|
|
1337
|
+
("b_vol", b_vol),
|
|
1338
|
+
("reversed_bytes2", reversed_bytes2),
|
|
1339
|
+
("reversed_bytes3", reversed_bytes3),
|
|
1340
|
+
("bid1", self._cal_price(price, bid1)),
|
|
1341
|
+
("ask1", self._cal_price(price, ask1)),
|
|
1342
|
+
("bid_vol1", bid_vol1),
|
|
1343
|
+
("ask_vol1", ask_vol1),
|
|
1344
|
+
("bid2", self._cal_price(price, bid2)),
|
|
1345
|
+
("ask2", self._cal_price(price, ask2)),
|
|
1346
|
+
("bid_vol2", bid_vol2),
|
|
1347
|
+
("ask_vol2", ask_vol2),
|
|
1348
|
+
("bid3", self._cal_price(price, bid3)),
|
|
1349
|
+
("ask3", self._cal_price(price, ask3)),
|
|
1350
|
+
("bid_vol3", bid_vol3),
|
|
1351
|
+
("ask_vol3", ask_vol3),
|
|
1352
|
+
("bid4", self._cal_price(price, bid4)),
|
|
1353
|
+
("ask4", self._cal_price(price, ask4)),
|
|
1354
|
+
("bid_vol4", bid_vol4),
|
|
1355
|
+
("ask_vol4", ask_vol4),
|
|
1356
|
+
("bid5", self._cal_price(price, bid5)),
|
|
1357
|
+
("ask5", self._cal_price(price, ask5)),
|
|
1358
|
+
("bid_vol5", bid_vol5),
|
|
1359
|
+
("ask_vol5", ask_vol5),
|
|
1360
|
+
("reversed_bytes4", reversed_bytes4),
|
|
1361
|
+
("reversed_bytes5", reversed_bytes5),
|
|
1362
|
+
("reversed_bytes6", reversed_bytes6),
|
|
1363
|
+
("reversed_bytes7", reversed_bytes7),
|
|
1364
|
+
("reversed_bytes8", reversed_bytes8),
|
|
1365
|
+
("reversed_bytes9", reversed_bytes9/100.0), # 涨速
|
|
1366
|
+
("active2", active2)
|
|
1367
|
+
])
|
|
1368
|
+
stocks.append(one_stock)
|
|
1369
|
+
return stocks
|
|
1370
|
+
|
|
1371
|
+
def _cal_price(self, base_p, diff):
|
|
1372
|
+
return float(base_p + diff)/100
|
|
1373
|
+
|
|
1374
|
+
def _format_time(self, time_stamp):
|
|
1375
|
+
|
|
1376
|
+
time = time_stamp[:-6] + ':'
|
|
1377
|
+
if int(time_stamp[-6:-4]) < 60:
|
|
1378
|
+
time += '%s:' % time_stamp[-6:-4]
|
|
1379
|
+
time += '%06.3f' % (
|
|
1380
|
+
int(time_stamp[-4:]) * 60 / 10000.0
|
|
1381
|
+
)
|
|
1382
|
+
else:
|
|
1383
|
+
time += '%02d:' % (
|
|
1384
|
+
int(time_stamp[-6:]) * 60 / 1000000
|
|
1385
|
+
)
|
|
1386
|
+
time += '%06.3f' % (
|
|
1387
|
+
(int(time_stamp[-6:]) * 60 % 1000000) * 60 / 1000000.0
|
|
1388
|
+
)
|
|
1389
|
+
return time
|
|
1390
|
+
|
|
1391
|
+
class GetTransactionData(BaseParser):
|
|
1392
|
+
|
|
1393
|
+
def setParams(self, market, code, start, count):
|
|
1394
|
+
if type(code) is six.text_type:
|
|
1395
|
+
code = code.encode("utf-8")
|
|
1396
|
+
pkg = bytearray.fromhex(u'0c 17 08 01 01 01 0e 00 0e 00 c5 0f')
|
|
1397
|
+
pkg.extend(struct.pack("<H6sHH", market, code, start, count))
|
|
1398
|
+
self.send_pkg = pkg
|
|
1399
|
+
|
|
1400
|
+
def parseResponse(self, body_buf):
|
|
1401
|
+
pos = 0
|
|
1402
|
+
(num, ) = struct.unpack("<H", body_buf[:2])
|
|
1403
|
+
pos += 2
|
|
1404
|
+
ticks = []
|
|
1405
|
+
last_price = 0
|
|
1406
|
+
for i in range(num):
|
|
1407
|
+
### ?? get_time
|
|
1408
|
+
# \x80\x03 = 14:56
|
|
1409
|
+
|
|
1410
|
+
hour, minute, pos = get_time(body_buf, pos)
|
|
1411
|
+
|
|
1412
|
+
price_raw, pos = get_price(body_buf, pos)
|
|
1413
|
+
vol, pos = get_price(body_buf, pos)
|
|
1414
|
+
num, pos = get_price(body_buf, pos)
|
|
1415
|
+
buyorsell, pos = get_price(body_buf, pos)
|
|
1416
|
+
_, pos = get_price(body_buf, pos)
|
|
1417
|
+
|
|
1418
|
+
last_price = last_price + price_raw
|
|
1419
|
+
|
|
1420
|
+
tick = OrderedDict(
|
|
1421
|
+
[
|
|
1422
|
+
("time", "%02d:%02d" % (hour, minute)),
|
|
1423
|
+
("price", float(last_price)/100),
|
|
1424
|
+
("vol", vol),
|
|
1425
|
+
("num", num),
|
|
1426
|
+
("buyorsell", buyorsell),
|
|
1427
|
+
]
|
|
1428
|
+
)
|
|
1429
|
+
|
|
1430
|
+
ticks.append(tick)
|
|
1431
|
+
|
|
1432
|
+
return ticks
|
|
1433
|
+
|
|
1434
|
+
XDXR_CATEGORY_MAPPING = {
|
|
1435
|
+
1 : "除权除息",
|
|
1436
|
+
2 : "送配股上市",
|
|
1437
|
+
3 : "非流通股上市",
|
|
1438
|
+
4 : "未知股本变动",
|
|
1439
|
+
5 : "股本变化",
|
|
1440
|
+
6 : "增发新股",
|
|
1441
|
+
7 : "股份回购",
|
|
1442
|
+
8 : "增发新股上市",
|
|
1443
|
+
9 : "转配股上市",
|
|
1444
|
+
10 : "可转债上市",
|
|
1445
|
+
11 : "扩缩股",
|
|
1446
|
+
12 : "非流通股缩股",
|
|
1447
|
+
13 : "送认购权证",
|
|
1448
|
+
14 : "送认沽权证"
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
class GetXdXrInfo(BaseParser):
|
|
1452
|
+
|
|
1453
|
+
def setParams(self, market, code):
|
|
1454
|
+
if type(code) is six.text_type:
|
|
1455
|
+
code = code.encode("utf-8")
|
|
1456
|
+
pkg = bytearray.fromhex(u'0c 1f 18 76 00 01 0b 00 0b 00 0f 00 01 00')
|
|
1457
|
+
pkg.extend(struct.pack("<B6s", market, code))
|
|
1458
|
+
self.send_pkg = pkg
|
|
1459
|
+
|
|
1460
|
+
def parseResponse(self, body_buf):
|
|
1461
|
+
pos = 0
|
|
1462
|
+
|
|
1463
|
+
if len(body_buf) < 11:
|
|
1464
|
+
return []
|
|
1465
|
+
|
|
1466
|
+
pos += 9 # skip 9
|
|
1467
|
+
(num, ) = struct.unpack("<H", body_buf[pos:pos+2])
|
|
1468
|
+
pos += 2
|
|
1469
|
+
|
|
1470
|
+
rows = []
|
|
1471
|
+
|
|
1472
|
+
def _get_v(v):
|
|
1473
|
+
if v == 0:
|
|
1474
|
+
return 0
|
|
1475
|
+
else:
|
|
1476
|
+
return get_volume(v)
|
|
1477
|
+
|
|
1478
|
+
for i in range(num):
|
|
1479
|
+
market, code = struct.unpack(u"<B6s", body_buf[:7])
|
|
1480
|
+
pos += 7
|
|
1481
|
+
# noused = struct.unpack(u"<B", body_buf[pos: pos+1])
|
|
1482
|
+
pos += 1 #skip a byte
|
|
1483
|
+
year, month, day, hour, minite, pos = get_datetime(9, body_buf, pos)
|
|
1484
|
+
(category, ) = struct.unpack(u"<B", body_buf[pos: pos+1])
|
|
1485
|
+
pos += 1
|
|
1486
|
+
|
|
1487
|
+
|
|
1488
|
+
|
|
1489
|
+
# b'\x00\xe8\x00G' => 33000.00000
|
|
1490
|
+
# b'\x00\xc0\x0fF' => 9200.00000
|
|
1491
|
+
# b'\x00@\x83E' => 4200.0000
|
|
1492
|
+
|
|
1493
|
+
suogu = None
|
|
1494
|
+
panqianliutong, panhouliutong, qianzongguben, houzongguben = None, None, None, None
|
|
1495
|
+
songzhuangu, fenhong, peigu, peigujia = None, None, None, None
|
|
1496
|
+
fenshu, xingquanjia = None, None
|
|
1497
|
+
if category == 1:
|
|
1498
|
+
fenhong, peigujia, songzhuangu, peigu = struct.unpack("<ffff", body_buf[pos: pos + 16])
|
|
1499
|
+
elif category in [11, 12]:
|
|
1500
|
+
(_, _, suogu, _) = struct.unpack("<IIfI", body_buf[pos: pos + 16])
|
|
1501
|
+
elif category in [13, 14]:
|
|
1502
|
+
xingquanjia, _, fenshu, _ = struct.unpack("<fIfI", body_buf[pos: pos + 16])
|
|
1503
|
+
else:
|
|
1504
|
+
panqianliutong_raw, qianzongguben_raw, panhouliutong_raw, houzongguben_raw = struct.unpack("<IIII", body_buf[pos: pos + 16])
|
|
1505
|
+
panqianliutong = _get_v(panqianliutong_raw)
|
|
1506
|
+
panhouliutong = _get_v(panhouliutong_raw)
|
|
1507
|
+
qianzongguben = _get_v(qianzongguben_raw)
|
|
1508
|
+
houzongguben = _get_v(houzongguben_raw)
|
|
1509
|
+
|
|
1510
|
+
|
|
1511
|
+
|
|
1512
|
+
pos += 16
|
|
1513
|
+
|
|
1514
|
+
row = OrderedDict(
|
|
1515
|
+
[
|
|
1516
|
+
('year', year),
|
|
1517
|
+
('month', month),
|
|
1518
|
+
('day', day),
|
|
1519
|
+
('category', category),
|
|
1520
|
+
('name', self.get_category_name(category)),
|
|
1521
|
+
('fenhong', fenhong),
|
|
1522
|
+
('peigujia', peigujia),
|
|
1523
|
+
('songzhuangu', songzhuangu),
|
|
1524
|
+
('peigu', peigu),
|
|
1525
|
+
('suogu', suogu),
|
|
1526
|
+
('panqianliutong', panqianliutong),
|
|
1527
|
+
('panhouliutong', panhouliutong),
|
|
1528
|
+
('qianzongguben', qianzongguben),
|
|
1529
|
+
('houzongguben', houzongguben),
|
|
1530
|
+
('fenshu', fenshu),
|
|
1531
|
+
('xingquanjia', xingquanjia)
|
|
1532
|
+
]
|
|
1533
|
+
)
|
|
1534
|
+
rows.append(row)
|
|
1535
|
+
|
|
1536
|
+
return rows
|
|
1537
|
+
|
|
1538
|
+
def get_category_name(self, category_id):
|
|
1539
|
+
|
|
1540
|
+
if category_id in XDXR_CATEGORY_MAPPING:
|
|
1541
|
+
return XDXR_CATEGORY_MAPPING[category_id]
|
|
1542
|
+
else:
|
|
1543
|
+
return str(category_id)
|
|
1544
|
+
|
|
1545
|
+
class GetReportFile(BaseParser):
|
|
1546
|
+
def setParams(self, filename, offset=0):
|
|
1547
|
+
pkg = bytearray.fromhex(u'0C 12 34 00 00 00')
|
|
1548
|
+
# Fom DTGear request.py file
|
|
1549
|
+
node_size = 0x7530
|
|
1550
|
+
raw_data = struct.pack(r"<H2I100s", 0x06B9,
|
|
1551
|
+
offset, node_size, filename.encode("utf-8"))
|
|
1552
|
+
raw_data_len = struct.calcsize(r"<H2I100s")
|
|
1553
|
+
pkg.extend(struct.pack(u"<HH{}s".format(raw_data_len),
|
|
1554
|
+
raw_data_len, raw_data_len, raw_data))
|
|
1555
|
+
self.send_pkg = pkg
|
|
1556
|
+
|
|
1557
|
+
def parseResponse(self, body_buf):
|
|
1558
|
+
(chunksize, ) = struct.unpack("<I", body_buf[:4])
|
|
1559
|
+
|
|
1560
|
+
if chunksize > 0:
|
|
1561
|
+
return {
|
|
1562
|
+
"chunksize": chunksize,
|
|
1563
|
+
"chunkdata": body_buf[4:]
|
|
1564
|
+
}
|
|
1565
|
+
else:
|
|
1566
|
+
return {
|
|
1567
|
+
"chunksize": 0
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
class SetupCmd1(BaseParser):
|
|
1571
|
+
def setup(self):
|
|
1572
|
+
self.send_pkg = bytearray.fromhex(u'0c 02 18 93 00 01 03 00 03 00 0d 00 01')
|
|
1573
|
+
|
|
1574
|
+
def parseResponse(self, body_buf):
|
|
1575
|
+
return body_buf
|
|
1576
|
+
class SetupCmd2(BaseParser):
|
|
1577
|
+
def setup(self):
|
|
1578
|
+
self.send_pkg = bytearray.fromhex(u'0c 02 18 94 00 01 03 00 03 00 0d 00 02')
|
|
1579
|
+
|
|
1580
|
+
def parseResponse(self, body_buf):
|
|
1581
|
+
return body_buf
|
|
1582
|
+
class SetupCmd3(BaseParser):
|
|
1583
|
+
|
|
1584
|
+
def setup(self):
|
|
1585
|
+
self.send_pkg = bytearray.fromhex(u'0c 03 18 99 00 01 20 00 20 00 db 0f d5'
|
|
1586
|
+
u'd0 c9 cc d6 a4 a8 af 00 00 00 8f c2 25'
|
|
1587
|
+
u'40 13 00 00 d5 00 c9 cc bd f0 d7 ea 00'
|
|
1588
|
+
u'00 00 02')
|
|
1589
|
+
|
|
1590
|
+
def parseResponse(self, body_buf):
|
|
1591
|
+
return body_buf
|
|
1592
|
+
|
|
1593
|
+
try:
|
|
1594
|
+
# Python 3
|
|
1595
|
+
from collections.abc import Iterable
|
|
1596
|
+
except ImportError:
|
|
1597
|
+
# Python 2.7
|
|
1598
|
+
from collections import Iterable
|
|
1599
|
+
|
|
1600
|
+
if __name__ == '__main__':
|
|
1601
|
+
sys.path.append(os.path.dirname(
|
|
1602
|
+
os.path.dirname(os.path.realpath(__file__))))
|
|
1603
|
+
|
|
1604
|
+
|
|
1605
|
+
class Jsp_API(BaseSocketClient):
|
|
1606
|
+
|
|
1607
|
+
def setup(self):
|
|
1608
|
+
SetupCmd1(self.client).call_api()
|
|
1609
|
+
SetupCmd2(self.client).call_api()
|
|
1610
|
+
SetupCmd3(self.client).call_api()
|
|
1611
|
+
|
|
1612
|
+
# API List
|
|
1613
|
+
|
|
1614
|
+
# Notice:,如果一个股票当天停牌,那天的K线还是能取到,成交量为0
|
|
1615
|
+
@update_last_ack_time
|
|
1616
|
+
def get_security_bars(self, category, market, code, start, count):
|
|
1617
|
+
cmd = GetSecurityBarsCmd(self.client, lock=self.lock)
|
|
1618
|
+
cmd.setParams(category, market, code, start, count)
|
|
1619
|
+
return cmd.call_api()
|
|
1620
|
+
|
|
1621
|
+
@update_last_ack_time
|
|
1622
|
+
def get_index_bars(self, category, market, code, start, count):
|
|
1623
|
+
cmd = GetIndexBarsCmd(self.client, lock=self.lock)
|
|
1624
|
+
cmd.setParams(category, market, code, start, count)
|
|
1625
|
+
return cmd.call_api()
|
|
1626
|
+
|
|
1627
|
+
@update_last_ack_time
|
|
1628
|
+
def get_security_quotes(self, all_stock, code=None):
|
|
1629
|
+
"""
|
|
1630
|
+
支持三种形式的参数
|
|
1631
|
+
get_security_quotes(market, code )
|
|
1632
|
+
get_security_quotes((market, code))
|
|
1633
|
+
get_security_quotes([(market1, code1), (market2, code2)] )
|
|
1634
|
+
:param all_stock (market, code) 的数组
|
|
1635
|
+
:param code{optional} code to query
|
|
1636
|
+
:return:
|
|
1637
|
+
"""
|
|
1638
|
+
|
|
1639
|
+
if code is not None:
|
|
1640
|
+
all_stock = [(all_stock, code)]
|
|
1641
|
+
elif (isinstance(all_stock, list) or isinstance(all_stock, tuple))\
|
|
1642
|
+
and len(all_stock) == 2 and type(all_stock[0]) is int:
|
|
1643
|
+
all_stock = [all_stock]
|
|
1644
|
+
|
|
1645
|
+
cmd = GetSecurityQuotesCmd(self.client, lock=self.lock)
|
|
1646
|
+
cmd.setParams(all_stock)
|
|
1647
|
+
return cmd.call_api()
|
|
1648
|
+
|
|
1649
|
+
@update_last_ack_time
|
|
1650
|
+
def get_security_count(self, market):
|
|
1651
|
+
cmd = GetSecurityCountCmd(self.client, lock=self.lock)
|
|
1652
|
+
cmd.setParams(market)
|
|
1653
|
+
return cmd.call_api()
|
|
1654
|
+
|
|
1655
|
+
@update_last_ack_time
|
|
1656
|
+
def get_security_list(self, market, start):
|
|
1657
|
+
cmd = GetSecurityList(self.client, lock=self.lock)
|
|
1658
|
+
cmd.setParams(market, start)
|
|
1659
|
+
return cmd.call_api()
|
|
1660
|
+
|
|
1661
|
+
@update_last_ack_time
|
|
1662
|
+
def get_minute_time_data(self, market, code):
|
|
1663
|
+
cmd = GetMinuteTimeData(self.client, lock=self.lock)
|
|
1664
|
+
cmd.setParams(market, code)
|
|
1665
|
+
return cmd.call_api()
|
|
1666
|
+
|
|
1667
|
+
@update_last_ack_time
|
|
1668
|
+
def get_history_minute_time_data(self, market, code, date):
|
|
1669
|
+
cmd = GetHistoryMinuteTimeData(self.client, lock=self.lock)
|
|
1670
|
+
cmd.setParams(market, code, date)
|
|
1671
|
+
return cmd.call_api()
|
|
1672
|
+
|
|
1673
|
+
@update_last_ack_time
|
|
1674
|
+
def get_transaction_data(self, market, code, start, count):
|
|
1675
|
+
cmd = GetTransactionData(self.client, lock=self.lock)
|
|
1676
|
+
cmd.setParams(market, code, start, count)
|
|
1677
|
+
return cmd.call_api()
|
|
1678
|
+
|
|
1679
|
+
@update_last_ack_time
|
|
1680
|
+
def get_history_transaction_data(self, market, code, start, count, date):
|
|
1681
|
+
cmd = GetHistoryTransactionData(self.client, lock=self.lock)
|
|
1682
|
+
cmd.setParams(market, code, start, count, date)
|
|
1683
|
+
return cmd.call_api()
|
|
1684
|
+
|
|
1685
|
+
@update_last_ack_time
|
|
1686
|
+
def get_company_info_category(self, market, code):
|
|
1687
|
+
cmd = GetCompanyInfoCategory(self.client, lock=self.lock)
|
|
1688
|
+
cmd.setParams(market, code)
|
|
1689
|
+
return cmd.call_api()
|
|
1690
|
+
|
|
1691
|
+
@update_last_ack_time
|
|
1692
|
+
def get_company_info_content(self, market, code, filename, start, length):
|
|
1693
|
+
cmd = GetCompanyInfoContent(self.client, lock=self.lock)
|
|
1694
|
+
cmd.setParams(market, code, filename, start, length)
|
|
1695
|
+
return cmd.call_api()
|
|
1696
|
+
|
|
1697
|
+
@update_last_ack_time
|
|
1698
|
+
def get_xdxr_info(self, market, code):
|
|
1699
|
+
cmd = GetXdXrInfo(self.client, lock=self.lock)
|
|
1700
|
+
cmd.setParams(market, code)
|
|
1701
|
+
return cmd.call_api()
|
|
1702
|
+
|
|
1703
|
+
@update_last_ack_time
|
|
1704
|
+
def get_finance_info(self, market, code):
|
|
1705
|
+
cmd = GetFinanceInfo(self.client, lock=self.lock)
|
|
1706
|
+
cmd.setParams(market, code)
|
|
1707
|
+
return cmd.call_api()
|
|
1708
|
+
|
|
1709
|
+
@update_last_ack_time
|
|
1710
|
+
def get_block_info_meta(self, blockfile):
|
|
1711
|
+
cmd = GetBlockInfoMeta(self.client, lock=self.lock)
|
|
1712
|
+
cmd.setParams(blockfile)
|
|
1713
|
+
return cmd.call_api()
|
|
1714
|
+
|
|
1715
|
+
@update_last_ack_time
|
|
1716
|
+
def get_block_info(self, blockfile, start, size):
|
|
1717
|
+
cmd = GetBlockInfo(self.client, lock=self.lock)
|
|
1718
|
+
cmd.setParams(blockfile, start, size)
|
|
1719
|
+
return cmd.call_api()
|
|
1720
|
+
|
|
1721
|
+
def get_and_parse_block_info(self, blockfile):
|
|
1722
|
+
return get_and_parse_block_info(self, blockfile)
|
|
1723
|
+
|
|
1724
|
+
@update_last_ack_time
|
|
1725
|
+
def get_report_file(self, filename, offset):
|
|
1726
|
+
cmd = GetReportFile(self.client, lock=self.lock)
|
|
1727
|
+
cmd.setParams(filename, offset)
|
|
1728
|
+
return cmd.call_api()
|
|
1729
|
+
|
|
1730
|
+
def get_report_file_by_size(self, filename, filesize=0, reporthook=None):
|
|
1731
|
+
"""
|
|
1732
|
+
Download file from proxy server
|
|
1733
|
+
|
|
1734
|
+
:param filename the filename to download
|
|
1735
|
+
:param filesize the filesize to download , if you do not known the actually filesize, leave this value 0
|
|
1736
|
+
"""
|
|
1737
|
+
filecontent = bytearray(filesize)
|
|
1738
|
+
current_downloaded_size = 0
|
|
1739
|
+
get_zero_length_package_times = 0
|
|
1740
|
+
while current_downloaded_size < filesize or filesize == 0:
|
|
1741
|
+
response = self.get_report_file(filename, current_downloaded_size)
|
|
1742
|
+
if response["chunksize"] > 0:
|
|
1743
|
+
current_downloaded_size = current_downloaded_size + \
|
|
1744
|
+
response["chunksize"]
|
|
1745
|
+
filecontent.extend(response["chunkdata"])
|
|
1746
|
+
if reporthook is not None:
|
|
1747
|
+
reporthook(current_downloaded_size,filesize)
|
|
1748
|
+
else:
|
|
1749
|
+
get_zero_length_package_times = get_zero_length_package_times + 1
|
|
1750
|
+
if filesize == 0:
|
|
1751
|
+
break
|
|
1752
|
+
elif get_zero_length_package_times > 2:
|
|
1753
|
+
break
|
|
1754
|
+
|
|
1755
|
+
return filecontent
|
|
1756
|
+
|
|
1757
|
+
def do_heartbeat(self):
|
|
1758
|
+
self.get_security_count(random.randint(0, 1))
|
|
1759
|
+
|
|
1760
|
+
def get_k_data(self, code, start_date, end_date):
|
|
1761
|
+
def __select_market_code(code):
|
|
1762
|
+
code = str(code)
|
|
1763
|
+
if code[0] in ['5', '6', '9'] or code[:3] in ["009", "126", "110", "201", "202", "203", "204"]:
|
|
1764
|
+
return 1
|
|
1765
|
+
return 0
|
|
1766
|
+
|
|
1767
|
+
market_code = 1 if str(code)[0] == '6' else 0
|
|
1768
|
+
# 0 - 深圳, 1 - 上海
|
|
1769
|
+
|
|
1770
|
+
data = pd.concat([self.to_df(self.get_security_bars(9, __select_market_code(
|
|
1771
|
+
code), code, (9 - i) * 800, 800)) for i in range(10)], axis=0)
|
|
1772
|
+
|
|
1773
|
+
data = data.assign(date=data['datetime'].apply(lambda x: str(x)[0:10])).assign(code=str(code))\
|
|
1774
|
+
.set_index('date', drop=False, inplace=False)\
|
|
1775
|
+
.drop(['year', 'month', 'day', 'hour', 'minute', 'datetime'], axis=1)[start_date:end_date]
|
|
1776
|
+
return data.assign(date=data['date'].apply(lambda x: str(x)[0:10]))
|
|
1777
|
+
|
|
1778
|
+
|
|
1779
|
+
|
|
1780
|
+
|