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.
@@ -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
+