kaq-quant-common 0.2.9__py3-none-any.whl → 0.2.10__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.
- kaq_quant_common/api/common/__init__.py +1 -1
- kaq_quant_common/api/common/api_interface.py +38 -38
- kaq_quant_common/api/rest/api_client_base.py +42 -42
- kaq_quant_common/api/rest/instruction/helper/order_helper.py +342 -342
- kaq_quant_common/api/rest/instruction/models/__init__.py +17 -17
- kaq_quant_common/api/rest/instruction/models/transfer.py +32 -32
- kaq_quant_common/api/ws/exchange/models.py +23 -23
- kaq_quant_common/api/ws/exchange/ws_exchange_server.py +440 -440
- kaq_quant_common/common/ddb_table_monitor.py +106 -106
- kaq_quant_common/common/http_monitor.py +69 -69
- kaq_quant_common/common/modules/funding_rate_helper.py +30 -15
- kaq_quant_common/common/modules/limit_order_helper.py +28 -13
- kaq_quant_common/common/monitor_base.py +84 -84
- kaq_quant_common/common/monitor_group.py +97 -97
- kaq_quant_common/common/ws_wrapper.py +21 -21
- kaq_quant_common/utils/logger_utils.py +5 -5
- kaq_quant_common/utils/signal_utils.py +23 -23
- kaq_quant_common/utils/uuid_utils.py +5 -5
- {kaq_quant_common-0.2.9.dist-info → kaq_quant_common-0.2.10.dist-info}/METADATA +1 -1
- {kaq_quant_common-0.2.9.dist-info → kaq_quant_common-0.2.10.dist-info}/RECORD +21 -21
- {kaq_quant_common-0.2.9.dist-info → kaq_quant_common-0.2.10.dist-info}/WHEEL +1 -1
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
import threading
|
|
2
|
-
import traceback
|
|
3
|
-
from abc import abstractmethod
|
|
4
|
-
|
|
5
|
-
import dolphindb as ddb
|
|
6
|
-
import numpy as np
|
|
7
|
-
from kaq_quant_common.common.monitor_base import MonitorBase
|
|
8
|
-
from kaq_quant_common.utils import logger_utils
|
|
9
|
-
|
|
10
|
-
mutex = threading.Lock()
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# ddb表订阅监听器
|
|
14
|
-
class DdbTableMonitor(MonitorBase):
|
|
15
|
-
|
|
16
|
-
def __init__(self, table_name: str, action_name: str, batch_size=1000, filter=[]):
|
|
17
|
-
# 表名
|
|
18
|
-
self._table_name = table_name
|
|
19
|
-
#
|
|
20
|
-
self._action_name = action_name
|
|
21
|
-
#
|
|
22
|
-
self._batch_size = batch_size
|
|
23
|
-
#
|
|
24
|
-
self._filter = filter
|
|
25
|
-
|
|
26
|
-
# logger
|
|
27
|
-
self._logger = logger_utils.get_logger(self)
|
|
28
|
-
#
|
|
29
|
-
super().__init__()
|
|
30
|
-
|
|
31
|
-
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ abstract methods
|
|
32
|
-
def _do_init(self):
|
|
33
|
-
# 初始化ddb
|
|
34
|
-
self._init_ddb()
|
|
35
|
-
|
|
36
|
-
def _do_start(self):
|
|
37
|
-
# 开启ddb订阅
|
|
38
|
-
self._start_subscribe()
|
|
39
|
-
|
|
40
|
-
def _do_stop(self):
|
|
41
|
-
# 关闭订阅
|
|
42
|
-
self._stop_subscribe()
|
|
43
|
-
|
|
44
|
-
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
|
|
45
|
-
# 初始化ddb
|
|
46
|
-
def _init_ddb(self):
|
|
47
|
-
'''
|
|
48
|
-
创建ddb连接 && 添加ddb流数据表支持
|
|
49
|
-
'''
|
|
50
|
-
try:
|
|
51
|
-
ddb_config = self._on_get_ddb_config()
|
|
52
|
-
host, port, user, passwd = ddb_config['host'], ddb_config['port'], ddb_config['user'], ddb_config['passwd']
|
|
53
|
-
mutex.acquire()
|
|
54
|
-
self._session = ddb.session(enableASYNC=True)
|
|
55
|
-
self._host = host
|
|
56
|
-
self._port = port
|
|
57
|
-
self._user = user
|
|
58
|
-
self._passwd = passwd
|
|
59
|
-
self._session.connect(host, port, user, passwd)
|
|
60
|
-
self._session.enableStreaming()
|
|
61
|
-
except Exception as e:
|
|
62
|
-
self._logger.error(f'DdbTableMonitor._init_ddb error: {str(e)} - {str(traceback.format_exc())}')
|
|
63
|
-
finally:
|
|
64
|
-
mutex.release()
|
|
65
|
-
|
|
66
|
-
# 开启订阅
|
|
67
|
-
def _start_subscribe(self):
|
|
68
|
-
'''
|
|
69
|
-
订阅ddb表
|
|
70
|
-
'''
|
|
71
|
-
self._session.subscribe(
|
|
72
|
-
self._host,
|
|
73
|
-
self._port,
|
|
74
|
-
self._handle,
|
|
75
|
-
tableName=self._table_name,
|
|
76
|
-
actionName=self._action_name,
|
|
77
|
-
filter=np.array(self._filter),
|
|
78
|
-
offset=-1,
|
|
79
|
-
batchSize=self._batch_size,
|
|
80
|
-
throttle=5,
|
|
81
|
-
msgAsTable=True,
|
|
82
|
-
)
|
|
83
|
-
self._logger.info(f'开始订阅 {self._host}:{self._port} {self._table_name} - {self._action_name}')
|
|
84
|
-
|
|
85
|
-
def _stop_subscribe(self):
|
|
86
|
-
# TODO
|
|
87
|
-
# script = f"""
|
|
88
|
-
# existsSubscriptionTopic(,`{self._table_name},`{self._action_name})
|
|
89
|
-
# """
|
|
90
|
-
# exitsTopic = self._session.run(script)
|
|
91
|
-
exitsTopic = True
|
|
92
|
-
if exitsTopic is True:
|
|
93
|
-
self._session.unsubscribe(self._host, self._port, self._table_name, self._action_name)
|
|
94
|
-
self._logger.info(f'取消订阅 {self._table_name} - {self._action_name}')
|
|
95
|
-
if not self._session.isClosed():
|
|
96
|
-
self._session.close()
|
|
97
|
-
|
|
98
|
-
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ abstract methods
|
|
99
|
-
# 需要返回ddb配置,包含host, port, user, passwd 添加类型提示
|
|
100
|
-
@abstractmethod
|
|
101
|
-
def _on_get_ddb_config(self, data) -> dict:
|
|
102
|
-
pass
|
|
103
|
-
|
|
104
|
-
@abstractmethod
|
|
105
|
-
def _handle(self, data):
|
|
106
|
-
pass
|
|
1
|
+
import threading
|
|
2
|
+
import traceback
|
|
3
|
+
from abc import abstractmethod
|
|
4
|
+
|
|
5
|
+
import dolphindb as ddb
|
|
6
|
+
import numpy as np
|
|
7
|
+
from kaq_quant_common.common.monitor_base import MonitorBase
|
|
8
|
+
from kaq_quant_common.utils import logger_utils
|
|
9
|
+
|
|
10
|
+
mutex = threading.Lock()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# ddb表订阅监听器
|
|
14
|
+
class DdbTableMonitor(MonitorBase):
|
|
15
|
+
|
|
16
|
+
def __init__(self, table_name: str, action_name: str, batch_size=1000, filter=[]):
|
|
17
|
+
# 表名
|
|
18
|
+
self._table_name = table_name
|
|
19
|
+
#
|
|
20
|
+
self._action_name = action_name
|
|
21
|
+
#
|
|
22
|
+
self._batch_size = batch_size
|
|
23
|
+
#
|
|
24
|
+
self._filter = filter
|
|
25
|
+
|
|
26
|
+
# logger
|
|
27
|
+
self._logger = logger_utils.get_logger(self)
|
|
28
|
+
#
|
|
29
|
+
super().__init__()
|
|
30
|
+
|
|
31
|
+
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ abstract methods
|
|
32
|
+
def _do_init(self):
|
|
33
|
+
# 初始化ddb
|
|
34
|
+
self._init_ddb()
|
|
35
|
+
|
|
36
|
+
def _do_start(self):
|
|
37
|
+
# 开启ddb订阅
|
|
38
|
+
self._start_subscribe()
|
|
39
|
+
|
|
40
|
+
def _do_stop(self):
|
|
41
|
+
# 关闭订阅
|
|
42
|
+
self._stop_subscribe()
|
|
43
|
+
|
|
44
|
+
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
|
|
45
|
+
# 初始化ddb
|
|
46
|
+
def _init_ddb(self):
|
|
47
|
+
'''
|
|
48
|
+
创建ddb连接 && 添加ddb流数据表支持
|
|
49
|
+
'''
|
|
50
|
+
try:
|
|
51
|
+
ddb_config = self._on_get_ddb_config()
|
|
52
|
+
host, port, user, passwd = ddb_config['host'], ddb_config['port'], ddb_config['user'], ddb_config['passwd']
|
|
53
|
+
mutex.acquire()
|
|
54
|
+
self._session = ddb.session(enableASYNC=True)
|
|
55
|
+
self._host = host
|
|
56
|
+
self._port = port
|
|
57
|
+
self._user = user
|
|
58
|
+
self._passwd = passwd
|
|
59
|
+
self._session.connect(host, port, user, passwd)
|
|
60
|
+
self._session.enableStreaming()
|
|
61
|
+
except Exception as e:
|
|
62
|
+
self._logger.error(f'DdbTableMonitor._init_ddb error: {str(e)} - {str(traceback.format_exc())}')
|
|
63
|
+
finally:
|
|
64
|
+
mutex.release()
|
|
65
|
+
|
|
66
|
+
# 开启订阅
|
|
67
|
+
def _start_subscribe(self):
|
|
68
|
+
'''
|
|
69
|
+
订阅ddb表
|
|
70
|
+
'''
|
|
71
|
+
self._session.subscribe(
|
|
72
|
+
self._host,
|
|
73
|
+
self._port,
|
|
74
|
+
self._handle,
|
|
75
|
+
tableName=self._table_name,
|
|
76
|
+
actionName=self._action_name,
|
|
77
|
+
filter=np.array(self._filter),
|
|
78
|
+
offset=-1,
|
|
79
|
+
batchSize=self._batch_size,
|
|
80
|
+
throttle=5,
|
|
81
|
+
msgAsTable=True,
|
|
82
|
+
)
|
|
83
|
+
self._logger.info(f'开始订阅 {self._host}:{self._port} {self._table_name} - {self._action_name}')
|
|
84
|
+
|
|
85
|
+
def _stop_subscribe(self):
|
|
86
|
+
# TODO
|
|
87
|
+
# script = f"""
|
|
88
|
+
# existsSubscriptionTopic(,`{self._table_name},`{self._action_name})
|
|
89
|
+
# """
|
|
90
|
+
# exitsTopic = self._session.run(script)
|
|
91
|
+
exitsTopic = True
|
|
92
|
+
if exitsTopic is True:
|
|
93
|
+
self._session.unsubscribe(self._host, self._port, self._table_name, self._action_name)
|
|
94
|
+
self._logger.info(f'取消订阅 {self._table_name} - {self._action_name}')
|
|
95
|
+
if not self._session.isClosed():
|
|
96
|
+
self._session.close()
|
|
97
|
+
|
|
98
|
+
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ abstract methods
|
|
99
|
+
# 需要返回ddb配置,包含host, port, user, passwd 添加类型提示
|
|
100
|
+
@abstractmethod
|
|
101
|
+
def _on_get_ddb_config(self, data) -> dict:
|
|
102
|
+
pass
|
|
103
|
+
|
|
104
|
+
@abstractmethod
|
|
105
|
+
def _handle(self, data):
|
|
106
|
+
pass
|
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
import threading
|
|
2
|
-
import time
|
|
3
|
-
from abc import abstractmethod
|
|
4
|
-
|
|
5
|
-
from kaq_quant_common.common.monitor_base import MonitorBase
|
|
6
|
-
from kaq_quant_common.common.ws_wrapper import WsWrapper
|
|
7
|
-
from kaq_quant_common.utils import logger_utils
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# 封装http定时请求
|
|
11
|
-
class HttpMonitor(MonitorBase):
|
|
12
|
-
def __init__(self, interval=5):
|
|
13
|
-
super().__init__()
|
|
14
|
-
# 执行间隔
|
|
15
|
-
self._interval = interval
|
|
16
|
-
self._logger = logger_utils.get_logger()
|
|
17
|
-
|
|
18
|
-
def _do_start(self):
|
|
19
|
-
# 开启一条线程,定时执行http请求
|
|
20
|
-
self._ticker_thread_event = threading.Event()
|
|
21
|
-
|
|
22
|
-
def http_request():
|
|
23
|
-
# 上次请求时间
|
|
24
|
-
last_request_time = 0
|
|
25
|
-
while True:
|
|
26
|
-
# 检查是否需要退出
|
|
27
|
-
if self._ticker_thread_event.is_set():
|
|
28
|
-
self._logger.info("ticker thread exit")
|
|
29
|
-
break
|
|
30
|
-
|
|
31
|
-
# 当前时间
|
|
32
|
-
current_time = time.time()
|
|
33
|
-
# 如果上次请求时间距离当前时间不足,等待
|
|
34
|
-
if current_time - last_request_time < self._interval:
|
|
35
|
-
time.sleep(0.1)
|
|
36
|
-
continue
|
|
37
|
-
|
|
38
|
-
#
|
|
39
|
-
last_request_time = time.time()
|
|
40
|
-
|
|
41
|
-
# self._logger.debug('tick start')
|
|
42
|
-
try:
|
|
43
|
-
self._do_request()
|
|
44
|
-
except Exception as e:
|
|
45
|
-
self._logger.error(f"http request error: {e}")
|
|
46
|
-
# self._logger.debug('tick finish')
|
|
47
|
-
#
|
|
48
|
-
time.sleep(0.1)
|
|
49
|
-
|
|
50
|
-
# 开启线程
|
|
51
|
-
self._ticker_thread = threading.Thread(target=http_request)
|
|
52
|
-
# 设置为守护线程
|
|
53
|
-
self._ticker_thread.daemon = True
|
|
54
|
-
self._ticker_thread.start()
|
|
55
|
-
|
|
56
|
-
def _do_stop(self):
|
|
57
|
-
if self._ticker_thread_event is not None:
|
|
58
|
-
self._ticker_thread_event.set()
|
|
59
|
-
|
|
60
|
-
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
|
|
61
|
-
|
|
62
|
-
@abstractmethod
|
|
63
|
-
def _do_request(self):
|
|
64
|
-
"""
|
|
65
|
-
子类实现
|
|
66
|
-
"""
|
|
67
|
-
pass
|
|
68
|
-
|
|
69
|
-
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
|
|
1
|
+
import threading
|
|
2
|
+
import time
|
|
3
|
+
from abc import abstractmethod
|
|
4
|
+
|
|
5
|
+
from kaq_quant_common.common.monitor_base import MonitorBase
|
|
6
|
+
from kaq_quant_common.common.ws_wrapper import WsWrapper
|
|
7
|
+
from kaq_quant_common.utils import logger_utils
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# 封装http定时请求
|
|
11
|
+
class HttpMonitor(MonitorBase):
|
|
12
|
+
def __init__(self, interval=5):
|
|
13
|
+
super().__init__()
|
|
14
|
+
# 执行间隔
|
|
15
|
+
self._interval = interval
|
|
16
|
+
self._logger = logger_utils.get_logger()
|
|
17
|
+
|
|
18
|
+
def _do_start(self):
|
|
19
|
+
# 开启一条线程,定时执行http请求
|
|
20
|
+
self._ticker_thread_event = threading.Event()
|
|
21
|
+
|
|
22
|
+
def http_request():
|
|
23
|
+
# 上次请求时间
|
|
24
|
+
last_request_time = 0
|
|
25
|
+
while True:
|
|
26
|
+
# 检查是否需要退出
|
|
27
|
+
if self._ticker_thread_event.is_set():
|
|
28
|
+
self._logger.info("ticker thread exit")
|
|
29
|
+
break
|
|
30
|
+
|
|
31
|
+
# 当前时间
|
|
32
|
+
current_time = time.time()
|
|
33
|
+
# 如果上次请求时间距离当前时间不足,等待
|
|
34
|
+
if current_time - last_request_time < self._interval:
|
|
35
|
+
time.sleep(0.1)
|
|
36
|
+
continue
|
|
37
|
+
|
|
38
|
+
#
|
|
39
|
+
last_request_time = time.time()
|
|
40
|
+
|
|
41
|
+
# self._logger.debug('tick start')
|
|
42
|
+
try:
|
|
43
|
+
self._do_request()
|
|
44
|
+
except Exception as e:
|
|
45
|
+
self._logger.error(f"http request error: {e}")
|
|
46
|
+
# self._logger.debug('tick finish')
|
|
47
|
+
#
|
|
48
|
+
time.sleep(0.1)
|
|
49
|
+
|
|
50
|
+
# 开启线程
|
|
51
|
+
self._ticker_thread = threading.Thread(target=http_request)
|
|
52
|
+
# 设置为守护线程
|
|
53
|
+
self._ticker_thread.daemon = True
|
|
54
|
+
self._ticker_thread.start()
|
|
55
|
+
|
|
56
|
+
def _do_stop(self):
|
|
57
|
+
if self._ticker_thread_event is not None:
|
|
58
|
+
self._ticker_thread_event.set()
|
|
59
|
+
|
|
60
|
+
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
|
|
61
|
+
|
|
62
|
+
@abstractmethod
|
|
63
|
+
def _do_request(self):
|
|
64
|
+
"""
|
|
65
|
+
子类实现
|
|
66
|
+
"""
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
|
|
@@ -68,10 +68,16 @@ class FundingRateHelper:
|
|
|
68
68
|
for symbol, (data, arg) in to_process:
|
|
69
69
|
sub_data = self._build_data(symbol, data, arg)
|
|
70
70
|
|
|
71
|
+
if sub_data is None:
|
|
72
|
+
continue
|
|
73
|
+
|
|
74
|
+
if len(sub_data) == 0:
|
|
75
|
+
continue
|
|
76
|
+
|
|
71
77
|
if not self._isMtwDdb:
|
|
72
78
|
# 可以是数组,可以是dataFrame
|
|
73
79
|
is_df = type(sub_data) is pd.DataFrame
|
|
74
|
-
|
|
80
|
+
|
|
75
81
|
if is_df:
|
|
76
82
|
# df就用df的方式写入
|
|
77
83
|
# data_first_now = int(sub_data["create_time"].iloc[0])
|
|
@@ -85,21 +91,30 @@ class FundingRateHelper:
|
|
|
85
91
|
df = pd.concat([df, sub_data], ignore_index=True)
|
|
86
92
|
else:
|
|
87
93
|
# 数组就用数组的方式写入
|
|
88
|
-
#
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
+
# 子元素是否数组
|
|
95
|
+
is_sub_list = type(sub_data) is list
|
|
96
|
+
if is_sub_list:
|
|
97
|
+
# 多条数据
|
|
98
|
+
# data_first_now = int(sub_data[0][0])
|
|
99
|
+
# if now - data_first_now > 2000:
|
|
100
|
+
# self._logger.debug(f"数据时间{data_first_now} 与当前时间{now} 差值{now - data_first_now} 超过2000ms")
|
|
101
|
+
# pass
|
|
102
|
+
list_data.extend(sub_data)
|
|
103
|
+
else:
|
|
104
|
+
# 单条数据
|
|
105
|
+
# data_first_now = int(sub_data[0])
|
|
106
|
+
# if now - data_first_now > 2000:
|
|
107
|
+
# self._logger.debug(f"数据时间{data_first_now} 与当前时间{now} 差值{now - data_first_now} 超过2000ms")
|
|
108
|
+
# pass
|
|
109
|
+
list_data.append(sub_data)
|
|
94
110
|
else:
|
|
95
|
-
#
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
self._logger.error(f"批量写入数组失败: {e}")
|
|
111
|
+
# 直接调用 save2stream_list 写入
|
|
112
|
+
try:
|
|
113
|
+
self._ddb.save2stream_list(sub_data)
|
|
114
|
+
except Exception as e:
|
|
115
|
+
# 避免刷库异常导致线程退出
|
|
116
|
+
self._logger.error(f"批量写入数组失败: {e}")
|
|
117
|
+
|
|
103
118
|
|
|
104
119
|
# 入库
|
|
105
120
|
if not self._isMtwDdb:
|
|
@@ -70,6 +70,12 @@ class LimitOrderHelper:
|
|
|
70
70
|
for symbol, (data, arg) in to_process:
|
|
71
71
|
sub_data = self._build_data(symbol, data, arg)
|
|
72
72
|
|
|
73
|
+
if sub_data is None:
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
if len(sub_data) == 0:
|
|
77
|
+
continue
|
|
78
|
+
|
|
73
79
|
if not self._isMtwDdb:
|
|
74
80
|
# 可以是数组,可以是dataFrame
|
|
75
81
|
is_df = type(sub_data) is pd.DataFrame
|
|
@@ -87,21 +93,30 @@ class LimitOrderHelper:
|
|
|
87
93
|
df = pd.concat([df, sub_data], ignore_index=True)
|
|
88
94
|
else:
|
|
89
95
|
# 数组就用数组的方式写入
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
96
|
+
# 子元素是否数组
|
|
97
|
+
is_sub_list = type(sub_data[0]) is list
|
|
98
|
+
if is_sub_list:
|
|
99
|
+
# 多条数据
|
|
100
|
+
data_first_now = int(sub_data[0][0])
|
|
101
|
+
if now - data_first_now > 2000:
|
|
102
|
+
self._logger.debug(f"数据时间{data_first_now} 与当前时间{now} 差值{now - data_first_now} 超过2000ms")
|
|
103
|
+
pass
|
|
104
|
+
list_data.extend(sub_data)
|
|
105
|
+
else:
|
|
106
|
+
# 单条数据
|
|
107
|
+
data_first_now = int(sub_data[0])
|
|
108
|
+
if now - data_first_now > 2000:
|
|
109
|
+
self._logger.debug(f"数据时间{data_first_now} 与当前时间{now} 差值{now - data_first_now} 超过2000ms")
|
|
110
|
+
pass
|
|
111
|
+
list_data.append(sub_data)
|
|
94
112
|
|
|
95
|
-
list_data.append(sub_data)
|
|
96
113
|
else:
|
|
97
|
-
#
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
# 避免刷库异常导致线程退出
|
|
104
|
-
self._logger.error(f"批量写入数组失败: {e}")
|
|
114
|
+
# 直接调用 save2stream_list 写入
|
|
115
|
+
try:
|
|
116
|
+
self._ddb.save2stream_list(sub_data)
|
|
117
|
+
except Exception as e:
|
|
118
|
+
# 避免刷库异常导致线程退出
|
|
119
|
+
self._logger.error(f"批量写入数组失败: {e}")
|
|
105
120
|
|
|
106
121
|
convert_time = int(datetime.datetime.now().timestamp() * 1000)
|
|
107
122
|
|
|
@@ -1,84 +1,84 @@
|
|
|
1
|
-
import threading
|
|
2
|
-
import time
|
|
3
|
-
from abc import ABC, abstractmethod
|
|
4
|
-
|
|
5
|
-
from kaq_quant_common.utils import logger_utils, signal_utils
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
# 通用的抽象类
|
|
9
|
-
class MonitorBase(ABC):
|
|
10
|
-
def __init__(self):
|
|
11
|
-
# 初始化
|
|
12
|
-
self.init()
|
|
13
|
-
# 用来标记最后一次收到数据的时间,超过指定时间没有收到数据,认为连接断开
|
|
14
|
-
self._keep_alive_deadline = 0
|
|
15
|
-
|
|
16
|
-
# 初始化
|
|
17
|
-
def init(self):
|
|
18
|
-
# 执行初始化
|
|
19
|
-
self._do_init()
|
|
20
|
-
|
|
21
|
-
@abstractmethod
|
|
22
|
-
def _do_init(self):
|
|
23
|
-
pass
|
|
24
|
-
|
|
25
|
-
# 开始,需要确保这个方法在op线程执行,执行这个方法会阻塞当前线程!
|
|
26
|
-
def start(self, block=True):
|
|
27
|
-
# 全局退出事件,用于传递终止信号
|
|
28
|
-
exit_event = threading.Event()
|
|
29
|
-
self._exit_event = exit_event
|
|
30
|
-
|
|
31
|
-
logger = logger_utils.get_logger(self)
|
|
32
|
-
|
|
33
|
-
#
|
|
34
|
-
def handle_terminate_signal(signum, frame=None):
|
|
35
|
-
"""信号处理函数:捕获终止信号并触发退出事件"""
|
|
36
|
-
logger.info(f"收到终止信号 {signum}")
|
|
37
|
-
exit_event.set()
|
|
38
|
-
# 优雅地停止
|
|
39
|
-
try:
|
|
40
|
-
self.stop()
|
|
41
|
-
except Exception as e:
|
|
42
|
-
pass
|
|
43
|
-
|
|
44
|
-
signal_utils.register_signal_handler(handle_terminate_signal)
|
|
45
|
-
|
|
46
|
-
self._do_start()
|
|
47
|
-
|
|
48
|
-
# 需要阻塞
|
|
49
|
-
if block:
|
|
50
|
-
# 监听退出事件
|
|
51
|
-
while not exit_event.is_set():
|
|
52
|
-
time.sleep(1)
|
|
53
|
-
if self._check_exit():
|
|
54
|
-
# 假装发送信号
|
|
55
|
-
handle_terminate_signal("exit")
|
|
56
|
-
if self._keep_alive_deadline > 0 and time.time() > self._keep_alive_deadline:
|
|
57
|
-
logger.warning("MonitorBase 收据接收超时,需要停止 MonitorBase")
|
|
58
|
-
# 假装发送信号
|
|
59
|
-
handle_terminate_signal("recv time out")
|
|
60
|
-
|
|
61
|
-
logger.warning("MonitorBase 线程退出")
|
|
62
|
-
|
|
63
|
-
# 子类实现,判断连接是否断开,断开返回True
|
|
64
|
-
def _check_exit(self):
|
|
65
|
-
return False
|
|
66
|
-
|
|
67
|
-
@abstractmethod
|
|
68
|
-
def _do_start(self):
|
|
69
|
-
pass
|
|
70
|
-
|
|
71
|
-
# 停止
|
|
72
|
-
def stop(self):
|
|
73
|
-
self._do_stop()
|
|
74
|
-
|
|
75
|
-
@abstractmethod
|
|
76
|
-
def _do_stop(self):
|
|
77
|
-
pass
|
|
78
|
-
|
|
79
|
-
def keep_alive(self, deadline: int = 60):
|
|
80
|
-
"""
|
|
81
|
-
保持连接alive,超过指定时间不活跃,认为需要停止
|
|
82
|
-
"""
|
|
83
|
-
cur_time = time.time()
|
|
84
|
-
self._keep_alive_deadline = cur_time + deadline
|
|
1
|
+
import threading
|
|
2
|
+
import time
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
|
|
5
|
+
from kaq_quant_common.utils import logger_utils, signal_utils
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# 通用的抽象类
|
|
9
|
+
class MonitorBase(ABC):
|
|
10
|
+
def __init__(self):
|
|
11
|
+
# 初始化
|
|
12
|
+
self.init()
|
|
13
|
+
# 用来标记最后一次收到数据的时间,超过指定时间没有收到数据,认为连接断开
|
|
14
|
+
self._keep_alive_deadline = 0
|
|
15
|
+
|
|
16
|
+
# 初始化
|
|
17
|
+
def init(self):
|
|
18
|
+
# 执行初始化
|
|
19
|
+
self._do_init()
|
|
20
|
+
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def _do_init(self):
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
# 开始,需要确保这个方法在op线程执行,执行这个方法会阻塞当前线程!
|
|
26
|
+
def start(self, block=True):
|
|
27
|
+
# 全局退出事件,用于传递终止信号
|
|
28
|
+
exit_event = threading.Event()
|
|
29
|
+
self._exit_event = exit_event
|
|
30
|
+
|
|
31
|
+
logger = logger_utils.get_logger(self)
|
|
32
|
+
|
|
33
|
+
#
|
|
34
|
+
def handle_terminate_signal(signum, frame=None):
|
|
35
|
+
"""信号处理函数:捕获终止信号并触发退出事件"""
|
|
36
|
+
logger.info(f"收到终止信号 {signum}")
|
|
37
|
+
exit_event.set()
|
|
38
|
+
# 优雅地停止
|
|
39
|
+
try:
|
|
40
|
+
self.stop()
|
|
41
|
+
except Exception as e:
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
signal_utils.register_signal_handler(handle_terminate_signal)
|
|
45
|
+
|
|
46
|
+
self._do_start()
|
|
47
|
+
|
|
48
|
+
# 需要阻塞
|
|
49
|
+
if block:
|
|
50
|
+
# 监听退出事件
|
|
51
|
+
while not exit_event.is_set():
|
|
52
|
+
time.sleep(1)
|
|
53
|
+
if self._check_exit():
|
|
54
|
+
# 假装发送信号
|
|
55
|
+
handle_terminate_signal("exit")
|
|
56
|
+
if self._keep_alive_deadline > 0 and time.time() > self._keep_alive_deadline:
|
|
57
|
+
logger.warning("MonitorBase 收据接收超时,需要停止 MonitorBase")
|
|
58
|
+
# 假装发送信号
|
|
59
|
+
handle_terminate_signal("recv time out")
|
|
60
|
+
|
|
61
|
+
logger.warning("MonitorBase 线程退出")
|
|
62
|
+
|
|
63
|
+
# 子类实现,判断连接是否断开,断开返回True
|
|
64
|
+
def _check_exit(self):
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
@abstractmethod
|
|
68
|
+
def _do_start(self):
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
# 停止
|
|
72
|
+
def stop(self):
|
|
73
|
+
self._do_stop()
|
|
74
|
+
|
|
75
|
+
@abstractmethod
|
|
76
|
+
def _do_stop(self):
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
def keep_alive(self, deadline: int = 60):
|
|
80
|
+
"""
|
|
81
|
+
保持连接alive,超过指定时间不活跃,认为需要停止
|
|
82
|
+
"""
|
|
83
|
+
cur_time = time.time()
|
|
84
|
+
self._keep_alive_deadline = cur_time + deadline
|