xtquant-big-convert 0.3.2__tar.gz → 0.3.4__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.
Files changed (82) hide show
  1. {xtquant_big_convert-0.3.2/src/xtquant_big_convert.egg-info → xtquant_big_convert-0.3.4}/PKG-INFO +1 -1
  2. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/pyproject.toml +1 -1
  3. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_backtest/qmt_runtime.py +79 -4
  4. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_backtest/zmq_server.py +28 -7
  5. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/init_config.py +1 -1
  6. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/redis_rpc.py +26 -1
  7. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/version.py +1 -1
  8. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/xtquant_compat.py +13 -3
  9. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4/src/xtquant_big_convert.egg-info}/PKG-INFO +1 -1
  10. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/LICENSE +0 -0
  11. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/README.md +0 -0
  12. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/setup.cfg +0 -0
  13. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/BIGQMT_REDIS_DRYRUN.py +0 -0
  14. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/BIGQMT_ZMQ_BACKTEST.py +0 -0
  15. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/BIGQMT_ZMQ_DRYRUN.py +0 -0
  16. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_backtest/__init__.py +0 -0
  17. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_backtest/__main__.py +0 -0
  18. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_backtest/broker.py +0 -0
  19. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_backtest/client.py +0 -0
  20. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_backtest/data_feed.py +0 -0
  21. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_backtest/engine.py +0 -0
  22. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_backtest/models.py +0 -0
  23. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_backtest/protocol.py +0 -0
  24. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_backtest/server.py +0 -0
  25. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_backtest/strategy.py +0 -0
  26. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/README.md +0 -0
  27. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/__init__.py +0 -0
  28. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/adapter_factory.py +0 -0
  29. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/adapters/__init__.py +0 -0
  30. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/adapters/market_bigqmt.py +0 -0
  31. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/adapters/order_bigqmt.py +0 -0
  32. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/adapters/order_dryrun.py +0 -0
  33. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/adapters/position_bigqmt.py +0 -0
  34. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/adapters/position_sync_redis.py +0 -0
  35. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/adapters/redis_common.py +0 -0
  36. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/adapters/signal_redis.py +0 -0
  37. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/adapters/state_redis.py +0 -0
  38. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/app.py +0 -0
  39. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/code_utils.py +0 -0
  40. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/contracts.py +0 -0
  41. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/download_jobs.py +0 -0
  42. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/exec_events.py +0 -0
  43. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/formula_server.py +0 -0
  44. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/full_tick_cache.py +0 -0
  45. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/local_cache.py +0 -0
  46. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/logging_setup.py +0 -0
  47. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/models.py +0 -0
  48. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/order_id.py +0 -0
  49. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/price_engine.py +0 -0
  50. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/qmt_launcher.py +0 -0
  51. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/quote_push_channel.py +0 -0
  52. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/quote_subscription_manager.py +0 -0
  53. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/risk_guard.py +0 -0
  54. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/runner.py +0 -0
  55. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/runtime_bigqmt.py +0 -0
  56. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/sync.py +0 -0
  57. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/transports/__init__.py +0 -0
  58. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/transports/base.py +0 -0
  59. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/transports/factory.py +0 -0
  60. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/transports/mysql_transport.py +0 -0
  61. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/transports/redis_transport.py +0 -0
  62. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/transports/shm_transport.py +0 -0
  63. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/transports/zmq_transport.py +0 -0
  64. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader/whole_quote_session.py +0 -0
  65. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader_diagnostic.py +0 -0
  66. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader_dryrun.py +0 -0
  67. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader_redis_dryrun.py +0 -0
  68. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader_redis_rpc_runtime.py +0 -0
  69. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/bigqmt_signal_trader_strategy.py +0 -0
  70. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/xtquant/__init__.py +0 -0
  71. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/xtquant/xtconstant.py +0 -0
  72. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/xtquant/xtdata.py +0 -0
  73. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/xtquant/xttrader.py +0 -0
  74. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/xtquant/xttype.py +0 -0
  75. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/xtquant_big_convert.egg-info/SOURCES.txt +0 -0
  76. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/xtquant_big_convert.egg-info/dependency_links.txt +0 -0
  77. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/xtquant_big_convert.egg-info/entry_points.txt +0 -0
  78. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/xtquant_big_convert.egg-info/requires.txt +0 -0
  79. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/src/xtquant_big_convert.egg-info/top_level.txt +0 -0
  80. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/tests/test_single_file_build.py +0 -0
  81. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/tests/test_version_stamp.py +0 -0
  82. {xtquant_big_convert-0.3.2 → xtquant_big_convert-0.3.4}/tests/test_xtquant_shim_import.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xtquant-big-convert
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Big QMT RPC bridge and MiniQMT-compatible adapter layer (redis/zmq/mysql transports)
5
5
  Author: litaolemo
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "xtquant-big-convert"
7
- version = "0.3.2"
7
+ version = "0.3.4"
8
8
  description = "Big QMT RPC bridge and MiniQMT-compatible adapter layer (redis/zmq/mysql transports)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -119,6 +119,12 @@ def _is_qmt_backtest(context):
119
119
  return False
120
120
 
121
121
 
122
+ # What ContextInfo.get_history_data actually serves (API reference 5.2).
123
+ # Anything outside this set produces an ERROR line in QMT's log rather than a
124
+ # quiet miss, so it must never be probed (issue #109).
125
+ HISTORY_DATA_FIELDS = frozenset(("open", "high", "low", "close", "quoter"))
126
+
127
+
122
128
  class QmtBarExtractor(object):
123
129
  def __init__(self):
124
130
  self.previous_close = {}
@@ -160,7 +166,47 @@ class QmtBarExtractor(object):
160
166
  result.append(text)
161
167
  return result
162
168
 
169
+ def _market_data_ex_value(self, context, field):
170
+ """The recommended getter (API reference 5.2, 主推接口).
171
+
172
+ get_history_data is marked 不推荐 there and QMT logs a deprecation
173
+ notice for it, which is what a reporter saw first (issue #109).
174
+ """
175
+ getter = getattr(context, "get_market_data_ex", None)
176
+ if not callable(getter):
177
+ return None
178
+ symbol = self._symbol(context)
179
+ for period in self._periods(context):
180
+ try:
181
+ frame = (getter([field], [symbol], period=period, count=1)
182
+ or {}).get(symbol)
183
+ except Exception:
184
+ continue
185
+ if frame is None:
186
+ continue
187
+ try:
188
+ column = frame[field]
189
+ except Exception:
190
+ continue
191
+ value = _last_value(column)
192
+ if value not in (None, ""):
193
+ return value
194
+ return None
195
+
163
196
  def _history_value(self, context, field):
197
+ # get_history_data serves exactly open/high/low/close/quoter (API
198
+ # reference 5.2). Asking it for anything else is not a miss, it is an
199
+ # ERROR line in QMT's own log -- one per field, per period, per bar:
200
+ #
201
+ # [系统]ERROR获取历史数据,不支持'prev_close'数据字段
202
+ # [系统]ERROR获取历史数据,不支持'preClose'数据字段
203
+ # [系统]ERROR获取历史数据,不支持'lastClose'数据字段
204
+ #
205
+ # which is what issue #109 reported. The probe was guaranteed to fail
206
+ # for those names, and prev_close is derived from the previous bar's
207
+ # close anyway, so there was never anything to gain by asking.
208
+ if field not in HISTORY_DATA_FIELDS:
209
+ return None
164
210
  getter = getattr(context, "get_history_data", None)
165
211
  if not callable(getter):
166
212
  return None
@@ -179,11 +225,16 @@ class QmtBarExtractor(object):
179
225
  return None
180
226
 
181
227
  def _field(self, context, field, aliases=()):
182
- for name in (field,) + tuple(aliases):
228
+ names = (field,) + tuple(aliases)
229
+ for name in names:
183
230
  value = _last_value(getattr(context, name, None))
184
231
  if value not in (None, ""):
185
232
  return value
186
- for name in (field,) + tuple(aliases):
233
+ for name in names:
234
+ value = self._market_data_ex_value(context, name)
235
+ if value not in (None, ""):
236
+ return value
237
+ for name in names:
187
238
  value = self._history_value(context, name)
188
239
  if value not in (None, ""):
189
240
  return value
@@ -650,7 +701,12 @@ class QmtBacktestBridgeRuntime(object):
650
701
  )
651
702
  self.server_thread.start()
652
703
  if not self.server.wait_until_ready(5.0) or not self.server.actual_endpoint:
653
- raise RuntimeError("QMT native backtest ZMQ service failed to bind")
704
+ reason = self.server.bind_error
705
+ raise RuntimeError(
706
+ "QMT native backtest ZMQ service failed to bind %s%s"
707
+ % (self.server.endpoint,
708
+ ": %s. A previous run may still hold the port -- stop it, "
709
+ "or wait a moment and start again" % reason if reason else ""))
654
710
  print(
655
711
  "[bigqmt_backtest] QMT native service started run_id=%s endpoint=%s account=%s live_ready=False"
656
712
  % (self.engine.config.run_id, self.server.actual_endpoint, self.engine.config.account_id)
@@ -668,8 +724,19 @@ class QmtBacktestBridgeRuntime(object):
668
724
  def on_qmt_stop(self):
669
725
  self.engine.on_qmt_stop()
670
726
 
671
- def stop_server(self):
727
+ def stop_server(self, timeout_seconds=5.0):
728
+ """Stop serving and wait for the port to be released.
729
+
730
+ Without the wait, a re-run binds while the previous socket is still
731
+ open and fails with EADDRINUSE -- the endpoint is a fixed port, so
732
+ there is no fallback to a free one (issue #109).
733
+ """
672
734
  self.server.stop()
735
+ thread = self.server_thread
736
+ if thread is not None and thread.is_alive():
737
+ self.server.wait_until_stopped(timeout_seconds)
738
+ thread.join(timeout_seconds)
739
+ self.server_thread = None
673
740
 
674
741
 
675
742
  def reset_runtime():
@@ -710,8 +777,16 @@ def deal_callback(ContextInfo, dealInfo):
710
777
 
711
778
 
712
779
  def stop(ContextInfo=None):
780
+ """QMT calls this when the strategy is stopped -- including the stop
781
+ button next to the chart.
782
+
783
+ This used to tell the engine and leave the ZMQ service running, so the
784
+ port stayed bound to a strategy that was no longer there and the next
785
+ run failed to bind (issue #109).
786
+ """
713
787
  if _RUNTIME is not None:
714
788
  _RUNTIME.on_qmt_stop()
789
+ _RUNTIME.stop_server()
715
790
 
716
791
 
717
792
  def after_backtest(ContextInfo=None):
@@ -12,11 +12,22 @@ class ZmqBacktestServer(object):
12
12
  self.poll_ms = int(poll_ms)
13
13
  self._stop_event = threading.Event()
14
14
  self._ready_event = threading.Event()
15
+ self._stopped_event = threading.Event()
15
16
  self.actual_endpoint = None
17
+ self.bind_error = None
16
18
 
17
19
  def wait_until_ready(self, timeout_seconds=None):
18
20
  return self._ready_event.wait(timeout_seconds)
19
21
 
22
+ def wait_until_stopped(self, timeout_seconds=None):
23
+ """True once the socket is closed and the port is free again.
24
+
25
+ stop() only sets a flag; the serving thread notices up to poll_ms
26
+ later and closes the socket after that. A re-run that binds in
27
+ between gets EADDRINUSE (issue #109).
28
+ """
29
+ return self._stopped_event.wait(timeout_seconds)
30
+
20
31
  def stop(self):
21
32
  self._stop_event.set()
22
33
 
@@ -29,13 +40,21 @@ class ZmqBacktestServer(object):
29
40
  socket.setsockopt(zmq.RCVHWM, 1000)
30
41
  socket.setsockopt(zmq.SNDHWM, 1000)
31
42
  try:
32
- if self.endpoint.endswith(":0"):
33
- base = self.endpoint.rsplit(":", 1)[0]
34
- port = socket.bind_to_random_port(base)
35
- self.actual_endpoint = "%s:%d" % (base, port)
36
- else:
37
- socket.bind(self.endpoint)
38
- self.actual_endpoint = self.endpoint
43
+ try:
44
+ if self.endpoint.endswith(":0"):
45
+ base = self.endpoint.rsplit(":", 1)[0]
46
+ port = socket.bind_to_random_port(base)
47
+ self.actual_endpoint = "%s:%d" % (base, port)
48
+ else:
49
+ socket.bind(self.endpoint)
50
+ self.actual_endpoint = self.endpoint
51
+ except Exception as exc:
52
+ # Keep the reason: the caller only sees "failed to bind"
53
+ # otherwise, and the reason is nearly always a previous run
54
+ # still holding the port (issue #109). Raising it on this
55
+ # daemon thread would only print a traceback nobody reads.
56
+ self.bind_error = exc
57
+ return
39
58
  self._ready_event.set()
40
59
  poller = zmq.Poller()
41
60
  poller.register(socket, zmq.POLLIN)
@@ -63,3 +82,5 @@ class ZmqBacktestServer(object):
63
82
  finally:
64
83
  self._ready_event.set()
65
84
  socket.close(linger=0)
85
+ # Only now is the endpoint actually free.
86
+ self._stopped_event.set()
@@ -144,7 +144,7 @@ def render_client_config(answers):
144
144
  '"""',
145
145
  "",
146
146
  "BIGQMT_ACCOUNT_ID = %r" % str(answers["account_id"]),
147
- "BIGQMT_RPC_TIMEOUT_SECONDS = 6.0",
147
+ "BIGQMT_RPC_TIMEOUT_SECONDS = 30.0",
148
148
  "",
149
149
  "BIGQMT_REDIS_CONFIG = {",
150
150
  ' "transport": %r,' % transport,
@@ -1097,7 +1097,32 @@ class BigQmtRpcHandlers:
1097
1097
  raise ValueError(
1098
1098
  "order_type %s has no implicit buy/sell side; pass action "
1099
1099
  "explicitly" % raw)
1100
- raise ValueError("action or order_type is required")
1100
+ if raw in (None, ""):
1101
+ raise ValueError("action or order_type is required")
1102
+ # An order_type WAS supplied and was not recognised. Saying "required"
1103
+ # here sent a reporter looking at their own call for twenty minutes
1104
+ # (issue #92): the real answer is almost always that the package
1105
+ # deployed inside QMT predates the type they are using, and a
1106
+ # client-side pip upgrade cannot fix that -- this code runs in QMT.
1107
+ raise ValueError(
1108
+ # ASCII only: this text is written to QMT's own log, which drops
1109
+ # non-ASCII characters (a Chinese install path came back mangled).
1110
+ "order_type %r is not recognised by the package deployed in QMT "
1111
+ "(%s). Credit order types (27-32, and 40-45 special) need 0.3.1 "
1112
+ "or newer HERE, in the QMT python directory -- upgrading the "
1113
+ "client with pip does not change this file. Run "
1114
+ "xt_trader.sync_deployment(), restart the strategy, then check "
1115
+ "xtdata.get_deployment_info()." % (raw, self._deployed_version()))
1116
+
1117
+ @staticmethod
1118
+ def _deployed_version():
1119
+ """Never raises: this only ever runs while building an error message."""
1120
+ try:
1121
+ from bigqmt_signal_trader.version import __version__
1122
+
1123
+ return __version__
1124
+ except Exception:
1125
+ return "unknown version"
1101
1126
 
1102
1127
  def _credit_order_type_from_params(self, params):
1103
1128
  """The MiniQMT order_type to forward, when it is a credit operation."""
@@ -21,7 +21,7 @@ copy never happened" and "the copy landed but was not picked up" look identical
21
21
  from the outside.
22
22
  """
23
23
 
24
- __version__ = "0.3.2"
24
+ __version__ = "0.3.4"
25
25
 
26
26
 
27
27
  def deployment_report(package_dir=None):
@@ -533,7 +533,7 @@ class BigQmtRpcClient:
533
533
  if timeout_seconds is not None
534
534
  else config_timeout
535
535
  if config_timeout is not None
536
- else _env_float("BIGQMT_RPC_TIMEOUT_SECONDS", 6.0)
536
+ else _env_float("BIGQMT_RPC_TIMEOUT_SECONDS", DEFAULT_RPC_TIMEOUT_SECONDS)
537
537
  )
538
538
  config_download_wait = client_config.get("download_wait_seconds")
539
539
  self.download_wait_seconds = float(
@@ -882,6 +882,15 @@ def ipo_market_of(code):
882
882
  MARKET_TOKENS = frozenset({"SH", "SZ", "BJ", "HK"})
883
883
  # Above this many explicit codes, one RPC's single timeout starts to matter more
884
884
  # than the extra payload of reading the exchange and filtering (issue #104).
885
+ # Measured against a live bridge: query_orders 1.5s, get_asset 1.4s,
886
+ # get_financial_data 0.8s warm, a whole-market get_full_tick 7.7s. The old
887
+ # 6s default sat under the cost of ordinary QMT data calls, and timing out
888
+ # here is worse than waiting: the bridge keeps working on the abandoned
889
+ # request, so the next call queues behind it and one timeout breeds more.
890
+ # 30s is also what the whole-market snapshot path already used, so there is
891
+ # one number rather than two.
892
+ DEFAULT_RPC_TIMEOUT_SECONDS = 30.0
893
+
885
894
  LARGE_CODE_LIST = 1000
886
895
  # What the fallback reads first. Stocks are 8.7% of an exchange listing, so
887
896
  # starting narrow is 1.08s against 7.4s; it widens to "all" only if that misses.
@@ -1096,8 +1105,9 @@ class BigQmtXtData:
1096
1105
  Args:
1097
1106
  code_list: stock codes to query.
1098
1107
  timeout_seconds: per-request RPC timeout. None = auto (30s for whole-market
1099
- snapshots, else client default 120s). Callers can pass a larger value
1100
- when querying many codes (e.g. 1256 ETF options may need 150-180s).
1108
+ snapshots, else the client default, DEFAULT_RPC_TIMEOUT_SECONDS).
1109
+ Callers can pass a larger value when querying many codes (e.g. 1256
1110
+ ETF options may need 150-180s).
1101
1111
  """
1102
1112
  codes = list(code_list or [])
1103
1113
  if not codes:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xtquant-big-convert
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Big QMT RPC bridge and MiniQMT-compatible adapter layer (redis/zmq/mysql transports)
5
5
  Author: litaolemo
6
6
  License: MIT