xtquant-share 1.1.6__tar.gz → 1.2.2__tar.gz
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.
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/PKG-INFO +1 -1
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/pyproject.toml +4 -2
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/xqshare/server.py +42 -3
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/xtquant_share.egg-info/PKG-INFO +1 -1
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/xtquant_share.egg-info/entry_points.txt +3 -1
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/LICENSE +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/README.md +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/setup.cfg +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/tests/test_auth.py +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/tests/test_client.py +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/tests/test_client_permission.py +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/tests/test_integration.py +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/tests/test_server.py +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/tests/test_server_permission.py +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/tests/test_tools_common.py +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/xqshare/__init__.py +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/xqshare/auth.py +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/xqshare/client.py +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/xqshare/tools/__init__.py +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/xqshare/tools/common.py +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/xqshare/tools/xtdata.py +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/xqshare/tools/xttrader.py +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/xtquant_share.egg-info/SOURCES.txt +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/xtquant_share.egg-info/dependency_links.txt +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/xtquant_share.egg-info/requires.txt +0 -0
- {xtquant_share-1.1.6 → xtquant_share-1.2.2}/xtquant_share.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "xtquant-share"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.2.2"
|
|
8
8
|
description = "Xtreme Quant Share - eXtreme transparent sharing proxy for XtQuant on macOS/Linux"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "GPL-3.0-only"
|
|
@@ -52,10 +52,12 @@ dev = [
|
|
|
52
52
|
]
|
|
53
53
|
|
|
54
54
|
[project.scripts]
|
|
55
|
-
xqshare-server = "xqshare.server:main"
|
|
56
55
|
xtdata = "xqshare.tools.xtdata:main"
|
|
57
56
|
xttrader = "xqshare.tools.xttrader:main"
|
|
58
57
|
|
|
58
|
+
[project.gui-scripts]
|
|
59
|
+
xqshare-server = "xqshare.server:main"
|
|
60
|
+
|
|
59
61
|
[project.urls]
|
|
60
62
|
Homepage = "https://gitee.com/jdragonhu/xqshare"
|
|
61
63
|
Documentation = "https://gitee.com/jdragonhu/xqshare#readme"
|
|
@@ -81,7 +81,14 @@ def setup_logging(log_dir: str = None, log_level: str = "INFO"):
|
|
|
81
81
|
root_logger = logging.getLogger()
|
|
82
82
|
root_logger.setLevel(getattr(logging, log_level.upper()))
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
import sys
|
|
85
|
+
import io
|
|
86
|
+
# 强制 stdout 使用 UTF-8(解决 Windows 后台启动时日志乱码)
|
|
87
|
+
if sys.stdout and hasattr(sys.stdout, 'buffer'):
|
|
88
|
+
utf8_stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
|
89
|
+
else:
|
|
90
|
+
utf8_stdout = sys.stdout
|
|
91
|
+
console_handler = logging.StreamHandler(utf8_stdout)
|
|
85
92
|
console_handler.setFormatter(formatter)
|
|
86
93
|
console_handler.setLevel(logging.INFO)
|
|
87
94
|
root_logger.addHandler(console_handler)
|
|
@@ -118,8 +125,34 @@ def _init_logging(log_level="INFO"):
|
|
|
118
125
|
|
|
119
126
|
# ==================== 日志装饰器 ====================
|
|
120
127
|
|
|
128
|
+
def _deliver(obj):
|
|
129
|
+
"""将 rpyc netref 对象本地化为真正的 Python 对象。
|
|
130
|
+
xtquant 底层 C++ 扩展做严格类型检查,netref 不被识别为 list/dict 等原生类型,
|
|
131
|
+
必须在调用前将参数本地化。
|
|
132
|
+
"""
|
|
133
|
+
try:
|
|
134
|
+
import rpyc
|
|
135
|
+
if isinstance(obj, rpyc.BaseNetref):
|
|
136
|
+
return rpyc.classic.obtain(obj)
|
|
137
|
+
except Exception:
|
|
138
|
+
pass
|
|
139
|
+
# 对类 list 的可迭代容器做兜底转换(排除 str/bytes,避免被拆成字符数组)
|
|
140
|
+
if (type(obj) not in (list, str, bytes)
|
|
141
|
+
and hasattr(obj, '__iter__')
|
|
142
|
+
and hasattr(obj, '__len__')):
|
|
143
|
+
try:
|
|
144
|
+
return list(obj)
|
|
145
|
+
except Exception:
|
|
146
|
+
pass
|
|
147
|
+
return obj
|
|
148
|
+
|
|
149
|
+
|
|
121
150
|
def _log_call(name: str, client_info: str, func, *args, **kwargs):
|
|
122
151
|
"""通用的 API 调用日志记录函数"""
|
|
152
|
+
# 将 rpyc netref 参数本地化,避免 C++ 扩展类型检查失败
|
|
153
|
+
args = tuple(_deliver(a) for a in args)
|
|
154
|
+
kwargs = {k: _deliver(v) for k, v in kwargs.items()}
|
|
155
|
+
|
|
123
156
|
try:
|
|
124
157
|
args_str = str(args)[:200] if args else ""
|
|
125
158
|
kwargs_str = str(kwargs)[:200] if kwargs else ""
|
|
@@ -386,8 +419,14 @@ class XtQuantService(rpyc.Service):
|
|
|
386
419
|
client_info = getattr(self, '_client_info', 'unknown')
|
|
387
420
|
logger.info(f"[断开] 客户端离开: {client_info}")
|
|
388
421
|
# 自动清理本次连接创建的所有 trader 实例,防止 session 资源泄漏
|
|
422
|
+
# 必须先 disconnect() 再 stop(),否则 miniQMT 内部 session 不会真正释放
|
|
389
423
|
traders = getattr(self, '_traders', [])
|
|
390
424
|
for trader in traders:
|
|
425
|
+
try:
|
|
426
|
+
trader.disconnect()
|
|
427
|
+
logger.info(f"[清理Trader] 已自动 disconnect trader | client={client_info}")
|
|
428
|
+
except Exception as e:
|
|
429
|
+
logger.warning(f"[清理Trader] disconnect trader 失败: {e} | client={client_info}")
|
|
391
430
|
try:
|
|
392
431
|
trader.stop()
|
|
393
432
|
logger.info(f"[清理Trader] 已自动 stop trader | client={client_info}")
|
|
@@ -885,13 +924,13 @@ def _cmd_background(args):
|
|
|
885
924
|
if args.env_file != ".env":
|
|
886
925
|
cmd += ["--env-file", args.env_file]
|
|
887
926
|
|
|
888
|
-
with open(log_file, "a") as log_f:
|
|
927
|
+
with open(log_file, "a", encoding="utf-8") as log_f:
|
|
889
928
|
if sys.platform == "win32":
|
|
890
929
|
proc = subprocess.Popen(
|
|
891
930
|
cmd,
|
|
892
931
|
stdout=log_f,
|
|
893
932
|
stderr=log_f,
|
|
894
|
-
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.DETACHED_PROCESS,
|
|
933
|
+
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.DETACHED_PROCESS | subprocess.CREATE_NO_WINDOW,
|
|
895
934
|
close_fds=True,
|
|
896
935
|
)
|
|
897
936
|
else:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|