axdata 0.1.0__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.
Files changed (427) hide show
  1. axdata/__init__.py +16 -0
  2. axdata/cache.py +19 -0
  3. axdata/client.py +1223 -0
  4. axdata-0.1.0.dist-info/METADATA +238 -0
  5. axdata-0.1.0.dist-info/RECORD +427 -0
  6. axdata-0.1.0.dist-info/WHEEL +5 -0
  7. axdata-0.1.0.dist-info/entry_points.txt +8 -0
  8. axdata-0.1.0.dist-info/licenses/LICENSE +162 -0
  9. axdata-0.1.0.dist-info/top_level.txt +6 -0
  10. axdata_core/__init__.py +221 -0
  11. axdata_core/_tdx_wire/__init__.py +35 -0
  12. axdata_core/_tdx_wire/_shim.py +140 -0
  13. axdata_core/_tdx_wire/api/__init__.py +51 -0
  14. axdata_core/_tdx_wire/api/auction.py +24 -0
  15. axdata_core/_tdx_wire/api/bars.py +24 -0
  16. axdata_core/_tdx_wire/api/base.py +26 -0
  17. axdata_core/_tdx_wire/api/codes.py +25 -0
  18. axdata_core/_tdx_wire/api/corporate.py +24 -0
  19. axdata_core/_tdx_wire/api/finance.py +24 -0
  20. axdata_core/_tdx_wire/api/intraday.py +24 -0
  21. axdata_core/_tdx_wire/api/quotes.py +26 -0
  22. axdata_core/_tdx_wire/api/resources.py +25 -0
  23. axdata_core/_tdx_wire/api/session.py +24 -0
  24. axdata_core/_tdx_wire/api/trades.py +24 -0
  25. axdata_core/_tdx_wire/client.py +33 -0
  26. axdata_core/_tdx_wire/exceptions.py +27 -0
  27. axdata_core/_tdx_wire/hosts.py +106 -0
  28. axdata_core/_tdx_wire/models/__init__.py +93 -0
  29. axdata_core/_tdx_wire/models/auction.py +26 -0
  30. axdata_core/_tdx_wire/models/corporate.py +27 -0
  31. axdata_core/_tdx_wire/models/finance.py +26 -0
  32. axdata_core/_tdx_wire/models/intraday.py +31 -0
  33. axdata_core/_tdx_wire/models/kline.py +27 -0
  34. axdata_core/_tdx_wire/models/quote.py +32 -0
  35. axdata_core/_tdx_wire/models/resource.py +24 -0
  36. axdata_core/_tdx_wire/models/security.py +24 -0
  37. axdata_core/_tdx_wire/models/session.py +27 -0
  38. axdata_core/_tdx_wire/models/subchart.py +25 -0
  39. axdata_core/_tdx_wire/models/trade.py +28 -0
  40. axdata_core/_tdx_wire/protocol/__init__.py +49 -0
  41. axdata_core/_tdx_wire/protocol/commands/__init__.py +43 -0
  42. axdata_core/_tdx_wire/protocol/commands/auction.py +110 -0
  43. axdata_core/_tdx_wire/protocol/commands/codec.py +43 -0
  44. axdata_core/_tdx_wire/protocol/commands/corporate.py +98 -0
  45. axdata_core/_tdx_wire/protocol/commands/finance.py +96 -0
  46. axdata_core/_tdx_wire/protocol/commands/intraday.py +122 -0
  47. axdata_core/_tdx_wire/protocol/commands/klines.py +102 -0
  48. axdata_core/_tdx_wire/protocol/commands/lookup.py +36 -0
  49. axdata_core/_tdx_wire/protocol/commands/price_limits.py +89 -0
  50. axdata_core/_tdx_wire/protocol/commands/quotes.py +102 -0
  51. axdata_core/_tdx_wire/protocol/commands/registry.py +36 -0
  52. axdata_core/_tdx_wire/protocol/commands/resources.py +99 -0
  53. axdata_core/_tdx_wire/protocol/commands/security.py +103 -0
  54. axdata_core/_tdx_wire/protocol/commands/session.py +82 -0
  55. axdata_core/_tdx_wire/protocol/commands/subchart.py +97 -0
  56. axdata_core/_tdx_wire/protocol/commands/trades.py +107 -0
  57. axdata_core/_tdx_wire/protocol/constants.py +124 -0
  58. axdata_core/_tdx_wire/protocol/frame.py +68 -0
  59. axdata_core/_tdx_wire/protocol/unit.py +85 -0
  60. axdata_core/_tdx_wire/py.typed +1 -0
  61. axdata_core/_tdx_wire/transport/__init__.py +34 -0
  62. axdata_core/_tdx_wire/transport/base.py +25 -0
  63. axdata_core/_tdx_wire/transport/memory.py +24 -0
  64. axdata_core/_tdx_wire/transport/pool.py +32 -0
  65. axdata_core/_tdx_wire/transport/socket.py +39 -0
  66. axdata_core/adapters/__init__.py +0 -0
  67. axdata_core/adapters/cls/__init__.py +17 -0
  68. axdata_core/adapters/cls/provider_bridge.py +23 -0
  69. axdata_core/adapters/cls/request.py +632 -0
  70. axdata_core/adapters/cls/source_adapter_registry.py +31 -0
  71. axdata_core/adapters/cninfo/__init__.py +17 -0
  72. axdata_core/adapters/cninfo/provider_bridge.py +25 -0
  73. axdata_core/adapters/cninfo/request.py +2425 -0
  74. axdata_core/adapters/cninfo/source_adapter_registry.py +42 -0
  75. axdata_core/adapters/eastmoney/__init__.py +17 -0
  76. axdata_core/adapters/eastmoney/provider_bridge.py +25 -0
  77. axdata_core/adapters/eastmoney/request.py +1128 -0
  78. axdata_core/adapters/eastmoney/source_adapter_registry.py +42 -0
  79. axdata_core/adapters/exchange/__init__.py +17 -0
  80. axdata_core/adapters/exchange/provider_bridge.py +25 -0
  81. axdata_core/adapters/exchange/request.py +1214 -0
  82. axdata_core/adapters/exchange/source_adapter_registry.py +42 -0
  83. axdata_core/adapters/kph/__init__.py +17 -0
  84. axdata_core/adapters/kph/provider_bridge.py +23 -0
  85. axdata_core/adapters/kph/request.py +509 -0
  86. axdata_core/adapters/kph/source_adapter_registry.py +31 -0
  87. axdata_core/adapters/sina/__init__.py +17 -0
  88. axdata_core/adapters/sina/provider_bridge.py +25 -0
  89. axdata_core/adapters/sina/request.py +5155 -0
  90. axdata_core/adapters/sina/source_adapter_registry.py +42 -0
  91. axdata_core/adapters/tdx/__init__.py +32 -0
  92. axdata_core/adapters/tdx/adjustment.py +50 -0
  93. axdata_core/adapters/tdx/adjustment_fetch.py +51 -0
  94. axdata_core/adapters/tdx/auction_fetch.py +51 -0
  95. axdata_core/adapters/tdx/client_factory.py +110 -0
  96. axdata_core/adapters/tdx/code_fetch.py +62 -0
  97. axdata_core/adapters/tdx/codes.py +54 -0
  98. axdata_core/adapters/tdx/derived_rows.py +69 -0
  99. axdata_core/adapters/tdx/downloader.py +193 -0
  100. axdata_core/adapters/tdx/downloader_interface_sets.py +50 -0
  101. axdata_core/adapters/tdx/downloader_profiles.py +43 -0
  102. axdata_core/adapters/tdx/downloader_registry.py +115 -0
  103. axdata_core/adapters/tdx/execution_utils.py +55 -0
  104. axdata_core/adapters/tdx/f10_executor.py +57 -0
  105. axdata_core/adapters/tdx/f10_normalize.py +61 -0
  106. axdata_core/adapters/tdx/f10_params.py +57 -0
  107. axdata_core/adapters/tdx/f10_postprocess.py +67 -0
  108. axdata_core/adapters/tdx/f10_render.py +48 -0
  109. axdata_core/adapters/tdx/f10_request.py +62 -0
  110. axdata_core/adapters/tdx/finance_fetch.py +61 -0
  111. axdata_core/adapters/tdx/finance_maps.py +54 -0
  112. axdata_core/adapters/tdx/finance_normalize.py +57 -0
  113. axdata_core/adapters/tdx/host_config.py +115 -0
  114. axdata_core/adapters/tdx/interface_sets.py +50 -0
  115. axdata_core/adapters/tdx/intraday_fetch.py +68 -0
  116. axdata_core/adapters/tdx/kline_helpers.py +58 -0
  117. axdata_core/adapters/tdx/limit_ladder_fetch.py +60 -0
  118. axdata_core/adapters/tdx/limit_ladder_topics.py +53 -0
  119. axdata_core/adapters/tdx/normalize_utils.py +75 -0
  120. axdata_core/adapters/tdx/options.py +61 -0
  121. axdata_core/adapters/tdx/price_limit_calendar.py +49 -0
  122. axdata_core/adapters/tdx/price_limit_fetch.py +53 -0
  123. axdata_core/adapters/tdx/price_limit_history.py +50 -0
  124. axdata_core/adapters/tdx/price_limits.py +58 -0
  125. axdata_core/adapters/tdx/provider_bridge.py +68 -0
  126. axdata_core/adapters/tdx/quote_fetch.py +61 -0
  127. axdata_core/adapters/tdx/quote_identity.py +49 -0
  128. axdata_core/adapters/tdx/rank_fetch.py +55 -0
  129. axdata_core/adapters/tdx/rank_params.py +52 -0
  130. axdata_core/adapters/tdx/realtime_refresh.py +45 -0
  131. axdata_core/adapters/tdx/request.py +11 -0
  132. axdata_core/adapters/tdx/request_adapter_runtime.py +41 -0
  133. axdata_core/adapters/tdx/request_client.py +51 -0
  134. axdata_core/adapters/tdx/request_compat.py +89 -0
  135. axdata_core/adapters/tdx/request_dispatch.py +50 -0
  136. axdata_core/adapters/tdx/request_filters.py +60 -0
  137. axdata_core/adapters/tdx/request_host_config.py +110 -0
  138. axdata_core/adapters/tdx/request_limits.py +59 -0
  139. axdata_core/adapters/tdx/request_methods.py +41 -0
  140. axdata_core/adapters/tdx/request_params.py +62 -0
  141. axdata_core/adapters/tdx/request_seams.py +41 -0
  142. axdata_core/adapters/tdx/resources/__init__.py +0 -0
  143. axdata_core/adapters/tdx/resources/finance_maps/__init__.py +0 -0
  144. axdata_core/adapters/tdx/resources/finance_maps/incon.dat +3702 -0
  145. axdata_core/adapters/tdx/resources/finance_maps/tdxhy.cfg +5620 -0
  146. axdata_core/adapters/tdx/resources/finance_maps/tdxzs.cfg +605 -0
  147. axdata_core/adapters/tdx/security_codes.py +54 -0
  148. axdata_core/adapters/tdx/series_history.py +57 -0
  149. axdata_core/adapters/tdx/server_cache.py +58 -0
  150. axdata_core/adapters/tdx/snapshot_normalize.py +56 -0
  151. axdata_core/adapters/tdx/source_adapter_registry.py +69 -0
  152. axdata_core/adapters/tdx/source_execution.py +44 -0
  153. axdata_core/adapters/tdx/source_execution_registry.py +70 -0
  154. axdata_core/adapters/tdx/stats_cache.py +184 -0
  155. axdata_core/adapters/tdx/stats_models.py +159 -0
  156. axdata_core/adapters/tdx/stats_resource.py +304 -0
  157. axdata_core/adapters/tdx/status_fetch.py +55 -0
  158. axdata_core/adapters/tdx/time_series_normalize.py +67 -0
  159. axdata_core/adapters/tdx/tqlex.py +50 -0
  160. axdata_core/adapters/tdx/wire_requests.py +60 -0
  161. axdata_core/adapters/tdx_ext/__init__.py +66 -0
  162. axdata_core/adapters/tdx_ext/client.py +688 -0
  163. axdata_core/adapters/tdx_ext/exceptions.py +51 -0
  164. axdata_core/adapters/tdx_ext/host_config.py +40 -0
  165. axdata_core/adapters/tdx_ext/interface_sets.py +65 -0
  166. axdata_core/adapters/tdx_ext/local_cache.py +649 -0
  167. axdata_core/adapters/tdx_ext/models.py +96 -0
  168. axdata_core/adapters/tdx_ext/options.py +36 -0
  169. axdata_core/adapters/tdx_ext/pool.py +153 -0
  170. axdata_core/adapters/tdx_ext/provider_bridge.py +35 -0
  171. axdata_core/adapters/tdx_ext/request.py +498 -0
  172. axdata_core/adapters/tdx_ext/request_execution.py +118 -0
  173. axdata_core/adapters/tdx_ext/request_instruments.py +221 -0
  174. axdata_core/adapters/tdx_ext/request_normalize.py +356 -0
  175. axdata_core/adapters/tdx_ext/request_params.py +157 -0
  176. axdata_core/adapters/tdx_ext/request_series.py +98 -0
  177. axdata_core/adapters/tdx_ext/server_cache.py +13 -0
  178. axdata_core/adapters/tdx_ext/servers.py +35 -0
  179. axdata_core/adapters/tdx_ext/source_adapter_registry.py +42 -0
  180. axdata_core/adapters/tdx_ext/source_execution.py +19 -0
  181. axdata_core/adapters/tdx_ext/source_execution_registry.py +43 -0
  182. axdata_core/adapters/tencent/__init__.py +17 -0
  183. axdata_core/adapters/tencent/provider_bridge.py +25 -0
  184. axdata_core/adapters/tencent/request.py +729 -0
  185. axdata_core/adapters/tencent/source_adapter_registry.py +42 -0
  186. axdata_core/axp.py +1843 -0
  187. axdata_core/builtin_providers.py +586 -0
  188. axdata_core/builtin_source_declarations.py +156 -0
  189. axdata_core/cli.py +1818 -0
  190. axdata_core/collector_registry.py +227 -0
  191. axdata_core/collector_runner.py +1016 -0
  192. axdata_core/collector_scheduler.py +3155 -0
  193. axdata_core/collector_templates.py +339 -0
  194. axdata_core/data_browser.py +1696 -0
  195. axdata_core/diagnostics.py +734 -0
  196. axdata_core/downloader_engine.py +1480 -0
  197. axdata_core/downloader_registry.py +62 -0
  198. axdata_core/downloaders.py +1619 -0
  199. axdata_core/legacy_provider_adapter.py +68 -0
  200. axdata_core/paths.py +51 -0
  201. axdata_core/plugin_config.py +272 -0
  202. axdata_core/plugin_status.py +419 -0
  203. axdata_core/plugins.py +1363 -0
  204. axdata_core/provider_catalog.py +462 -0
  205. axdata_core/provider_registry.py +833 -0
  206. axdata_core/quality.py +86 -0
  207. axdata_core/query.py +242 -0
  208. axdata_core/resources/__init__.py +2 -0
  209. axdata_core/resources/tdx_extended_servers.json +22 -0
  210. axdata_core/resources/tdx_quote_servers.json +49 -0
  211. axdata_core/sample_collectors.py +42 -0
  212. axdata_core/schema.py +385 -0
  213. axdata_core/source_adapter_factory.py +95 -0
  214. axdata_core/source_adapter_options.py +18 -0
  215. axdata_core/source_errors.py +43 -0
  216. axdata_core/source_execution_options.py +37 -0
  217. axdata_core/source_execution_registry.py +27 -0
  218. axdata_core/source_projection.py +21 -0
  219. axdata_core/source_request.py +441 -0
  220. axdata_core/source_session.py +355 -0
  221. axdata_core/sources/__init__.py +40 -0
  222. axdata_core/sources/base.py +112 -0
  223. axdata_core/sources/catalog.py +60 -0
  224. axdata_core/sources/cls/__init__.py +5 -0
  225. axdata_core/sources/cls/catalog.py +231 -0
  226. axdata_core/sources/cninfo/__init__.py +5 -0
  227. axdata_core/sources/cninfo/catalog.py +1994 -0
  228. axdata_core/sources/display_docs.py +139 -0
  229. axdata_core/sources/eastmoney/__init__.py +5 -0
  230. axdata_core/sources/eastmoney/catalog.py +509 -0
  231. axdata_core/sources/exchange/__init__.py +5 -0
  232. axdata_core/sources/exchange/catalog.py +361 -0
  233. axdata_core/sources/kph/__init__.py +5 -0
  234. axdata_core/sources/kph/catalog.py +255 -0
  235. axdata_core/sources/sina/__init__.py +5 -0
  236. axdata_core/sources/sina/catalog.py +2951 -0
  237. axdata_core/sources/tdx/__init__.py +5 -0
  238. axdata_core/sources/tdx/catalog.py +4546 -0
  239. axdata_core/sources/tdx_ext/__init__.py +5 -0
  240. axdata_core/sources/tdx_ext/catalog.py +1518 -0
  241. axdata_core/sources/tencent/__init__.py +5 -0
  242. axdata_core/sources/tencent/catalog.py +370 -0
  243. axdata_core/storage.py +186 -0
  244. axdata_core/tdx_f10_catalog.py +52 -0
  245. axdata_core/tdx_f10_models.py +50 -0
  246. axdata_core/tdx_f10_names.py +47 -0
  247. axdata_core/tdx_f10_specs.py +56 -0
  248. axdata_core/tdx_plugin_required.py +43 -0
  249. axdata_core/tdx_server_config.py +65 -0
  250. axdata_core/trade_calendar_cache.py +397 -0
  251. axdata_source_cninfo/__init__.py +15 -0
  252. axdata_source_cninfo/adapter.py +31 -0
  253. axdata_source_cninfo/axdata-provider.json +384 -0
  254. axdata_source_cninfo/catalog.py +209 -0
  255. axdata_source_cninfo/metadata.py +8 -0
  256. axdata_source_cninfo/provider.py +41 -0
  257. axdata_source_tdx/__init__.py +15 -0
  258. axdata_source_tdx/_tdx_wire/__init__.py +26 -0
  259. axdata_source_tdx/_tdx_wire/_binary.py +218 -0
  260. axdata_source_tdx/_tdx_wire/_code_utils.py +42 -0
  261. axdata_source_tdx/_tdx_wire/_command_codec.py +186 -0
  262. axdata_source_tdx/_tdx_wire/_command_codes.py +74 -0
  263. axdata_source_tdx/_tdx_wire/_command_defaults.py +15 -0
  264. axdata_source_tdx/_tdx_wire/_command_dispatch.py +96 -0
  265. axdata_source_tdx/_tdx_wire/_command_layouts.py +96 -0
  266. axdata_source_tdx/_tdx_wire/_command_lookup.py +25 -0
  267. axdata_source_tdx/_tdx_wire/_command_metadata.py +32 -0
  268. axdata_source_tdx/_tdx_wire/_command_registry.py +61 -0
  269. axdata_source_tdx/_tdx_wire/_connection_defaults.py +13 -0
  270. axdata_source_tdx/_tdx_wire/_host_defaults.py +51 -0
  271. axdata_source_tdx/_tdx_wire/_host_probe.py +81 -0
  272. axdata_source_tdx/_tdx_wire/_host_resource.py +70 -0
  273. axdata_source_tdx/_tdx_wire/_host_utils.py +31 -0
  274. axdata_source_tdx/_tdx_wire/_market.py +66 -0
  275. axdata_source_tdx/_tdx_wire/_request_defaults.py +11 -0
  276. axdata_source_tdx/_tdx_wire/_security_classification.py +61 -0
  277. axdata_source_tdx/_tdx_wire/_time_utils.py +7 -0
  278. axdata_source_tdx/_tdx_wire/api/__init__.py +45 -0
  279. axdata_source_tdx/_tdx_wire/api/auction.py +25 -0
  280. axdata_source_tdx/_tdx_wire/api/bars.py +31 -0
  281. axdata_source_tdx/_tdx_wire/api/base.py +39 -0
  282. axdata_source_tdx/_tdx_wire/api/codes.py +25 -0
  283. axdata_source_tdx/_tdx_wire/api/corporate.py +11 -0
  284. axdata_source_tdx/_tdx_wire/api/finance.py +10 -0
  285. axdata_source_tdx/_tdx_wire/api/intraday.py +38 -0
  286. axdata_source_tdx/_tdx_wire/api/quotes.py +78 -0
  287. axdata_source_tdx/_tdx_wire/api/resources.py +34 -0
  288. axdata_source_tdx/_tdx_wire/api/session.py +16 -0
  289. axdata_source_tdx/_tdx_wire/api/trades.py +34 -0
  290. axdata_source_tdx/_tdx_wire/client.py +470 -0
  291. axdata_source_tdx/_tdx_wire/exceptions.py +25 -0
  292. axdata_source_tdx/_tdx_wire/hosts.py +27 -0
  293. axdata_source_tdx/_tdx_wire/models/__init__.py +87 -0
  294. axdata_source_tdx/_tdx_wire/models/auction.py +58 -0
  295. axdata_source_tdx/_tdx_wire/models/corporate.py +59 -0
  296. axdata_source_tdx/_tdx_wire/models/finance.py +80 -0
  297. axdata_source_tdx/_tdx_wire/models/intraday.py +112 -0
  298. axdata_source_tdx/_tdx_wire/models/kline.py +58 -0
  299. axdata_source_tdx/_tdx_wire/models/quote.py +262 -0
  300. axdata_source_tdx/_tdx_wire/models/resource.py +18 -0
  301. axdata_source_tdx/_tdx_wire/models/security.py +28 -0
  302. axdata_source_tdx/_tdx_wire/models/session.py +30 -0
  303. axdata_source_tdx/_tdx_wire/models/subchart.py +39 -0
  304. axdata_source_tdx/_tdx_wire/models/trade.py +46 -0
  305. axdata_source_tdx/_tdx_wire/protocol/__init__.py +43 -0
  306. axdata_source_tdx/_tdx_wire/protocol/_frame_constants.py +5 -0
  307. axdata_source_tdx/_tdx_wire/protocol/commands/__init__.py +37 -0
  308. axdata_source_tdx/_tdx_wire/protocol/commands/auction.py +165 -0
  309. axdata_source_tdx/_tdx_wire/protocol/commands/codec.py +37 -0
  310. axdata_source_tdx/_tdx_wire/protocol/commands/corporate.py +163 -0
  311. axdata_source_tdx/_tdx_wire/protocol/commands/finance.py +180 -0
  312. axdata_source_tdx/_tdx_wire/protocol/commands/intraday.py +382 -0
  313. axdata_source_tdx/_tdx_wire/protocol/commands/klines.py +396 -0
  314. axdata_source_tdx/_tdx_wire/protocol/commands/lookup.py +31 -0
  315. axdata_source_tdx/_tdx_wire/protocol/commands/price_limits.py +110 -0
  316. axdata_source_tdx/_tdx_wire/protocol/commands/quotes.py +804 -0
  317. axdata_source_tdx/_tdx_wire/protocol/commands/registry.py +30 -0
  318. axdata_source_tdx/_tdx_wire/protocol/commands/resources.py +107 -0
  319. axdata_source_tdx/_tdx_wire/protocol/commands/security.py +163 -0
  320. axdata_source_tdx/_tdx_wire/protocol/commands/session.py +129 -0
  321. axdata_source_tdx/_tdx_wire/protocol/commands/subchart.py +182 -0
  322. axdata_source_tdx/_tdx_wire/protocol/commands/trades.py +275 -0
  323. axdata_source_tdx/_tdx_wire/protocol/constants.py +70 -0
  324. axdata_source_tdx/_tdx_wire/protocol/frame.py +141 -0
  325. axdata_source_tdx/_tdx_wire/protocol/unit.py +98 -0
  326. axdata_source_tdx/_tdx_wire/py.typed +1 -0
  327. axdata_source_tdx/_tdx_wire/transport/__init__.py +28 -0
  328. axdata_source_tdx/_tdx_wire/transport/base.py +21 -0
  329. axdata_source_tdx/_tdx_wire/transport/memory.py +42 -0
  330. axdata_source_tdx/_tdx_wire/transport/pool.py +148 -0
  331. axdata_source_tdx/_tdx_wire/transport/socket.py +373 -0
  332. axdata_source_tdx/adapter.py +31 -0
  333. axdata_source_tdx/adjustment.py +163 -0
  334. axdata_source_tdx/adjustment_fetch.py +148 -0
  335. axdata_source_tdx/auction_fetch.py +162 -0
  336. axdata_source_tdx/axdata-provider.json +23680 -0
  337. axdata_source_tdx/catalog.py +39 -0
  338. axdata_source_tdx/client_factory.py +61 -0
  339. axdata_source_tdx/code_fetch.py +579 -0
  340. axdata_source_tdx/codes.py +69 -0
  341. axdata_source_tdx/collectors.py +525 -0
  342. axdata_source_tdx/derived_rows.py +500 -0
  343. axdata_source_tdx/downloader.py +139 -0
  344. axdata_source_tdx/downloader_interface_sets.py +29 -0
  345. axdata_source_tdx/downloader_profiles.py +731 -0
  346. axdata_source_tdx/downloader_registry.py +85 -0
  347. axdata_source_tdx/execution_utils.py +141 -0
  348. axdata_source_tdx/f10_executor.py +414 -0
  349. axdata_source_tdx/f10_normalize.py +169 -0
  350. axdata_source_tdx/f10_params.py +221 -0
  351. axdata_source_tdx/f10_postprocess.py +405 -0
  352. axdata_source_tdx/f10_render.py +29 -0
  353. axdata_source_tdx/f10_request.py +365 -0
  354. axdata_source_tdx/finance_fetch.py +514 -0
  355. axdata_source_tdx/finance_maps.py +377 -0
  356. axdata_source_tdx/finance_normalize.py +273 -0
  357. axdata_source_tdx/host_config.py +51 -0
  358. axdata_source_tdx/interface_sets.py +180 -0
  359. axdata_source_tdx/intraday_fetch.py +600 -0
  360. axdata_source_tdx/kline_helpers.py +333 -0
  361. axdata_source_tdx/limit_ladder_fetch.py +614 -0
  362. axdata_source_tdx/limit_ladder_topics.py +280 -0
  363. axdata_source_tdx/metadata.py +8 -0
  364. axdata_source_tdx/normalize_utils.py +264 -0
  365. axdata_source_tdx/options.py +195 -0
  366. axdata_source_tdx/price_limit_calendar.py +106 -0
  367. axdata_source_tdx/price_limit_fetch.py +264 -0
  368. axdata_source_tdx/price_limit_history.py +100 -0
  369. axdata_source_tdx/price_limits.py +142 -0
  370. axdata_source_tdx/provider.py +44 -0
  371. axdata_source_tdx/provider_bridge.py +43 -0
  372. axdata_source_tdx/quote_fetch.py +485 -0
  373. axdata_source_tdx/quote_identity.py +50 -0
  374. axdata_source_tdx/rank_fetch.py +316 -0
  375. axdata_source_tdx/rank_params.py +181 -0
  376. axdata_source_tdx/realtime_refresh.py +51 -0
  377. axdata_source_tdx/request_adapter.py +533 -0
  378. axdata_source_tdx/request_adapter_runtime.py +302 -0
  379. axdata_source_tdx/request_client.py +98 -0
  380. axdata_source_tdx/request_compat.py +432 -0
  381. axdata_source_tdx/request_dispatch.py +138 -0
  382. axdata_source_tdx/request_entrypoints.py +146 -0
  383. axdata_source_tdx/request_filters.py +154 -0
  384. axdata_source_tdx/request_host_config.py +103 -0
  385. axdata_source_tdx/request_limits.py +15 -0
  386. axdata_source_tdx/request_methods.py +1910 -0
  387. axdata_source_tdx/request_params.py +225 -0
  388. axdata_source_tdx/request_seams.py +534 -0
  389. axdata_source_tdx/resources/__init__.py +0 -0
  390. axdata_source_tdx/resources/finance_maps/__init__.py +1 -0
  391. axdata_source_tdx/resources/finance_maps/incon.dat +3702 -0
  392. axdata_source_tdx/resources/finance_maps/tdxhy.cfg +5620 -0
  393. axdata_source_tdx/resources/finance_maps/tdxzs.cfg +605 -0
  394. axdata_source_tdx/resources/tdx_extended_servers.json +22 -0
  395. axdata_source_tdx/resources/tdx_quote_servers.json +49 -0
  396. axdata_source_tdx/security_codes.py +127 -0
  397. axdata_source_tdx/series_history.py +348 -0
  398. axdata_source_tdx/server_cache.py +21 -0
  399. axdata_source_tdx/snapshot_normalize.py +232 -0
  400. axdata_source_tdx/source_adapter_registry.py +42 -0
  401. axdata_source_tdx/source_execution.py +22 -0
  402. axdata_source_tdx/source_execution_registry.py +43 -0
  403. axdata_source_tdx/stats_cache.py +150 -0
  404. axdata_source_tdx/stats_models.py +161 -0
  405. axdata_source_tdx/stats_resource.py +242 -0
  406. axdata_source_tdx/status_fetch.py +209 -0
  407. axdata_source_tdx/tdx_f10_catalog.py +957 -0
  408. axdata_source_tdx/tdx_f10_models.py +47 -0
  409. axdata_source_tdx/tdx_f10_names.py +48 -0
  410. axdata_source_tdx/tdx_f10_specs.py +1142 -0
  411. axdata_source_tdx/tdx_server_config.py +389 -0
  412. axdata_source_tdx/time_series_normalize.py +370 -0
  413. axdata_source_tdx/tqlex.py +138 -0
  414. axdata_source_tdx/wire.py +32 -0
  415. axdata_source_tdx/wire_requests.py +190 -0
  416. axdata_source_tdx_ext/__init__.py +15 -0
  417. axdata_source_tdx_ext/adapter.py +31 -0
  418. axdata_source_tdx_ext/axdata-provider.json +9424 -0
  419. axdata_source_tdx_ext/catalog.py +33 -0
  420. axdata_source_tdx_ext/metadata.py +8 -0
  421. axdata_source_tdx_ext/provider.py +44 -0
  422. axdata_source_tencent/__init__.py +15 -0
  423. axdata_source_tencent/adapter.py +31 -0
  424. axdata_source_tencent/axdata-provider.json +291 -0
  425. axdata_source_tencent/catalog.py +190 -0
  426. axdata_source_tencent/metadata.py +8 -0
  427. axdata_source_tencent/provider.py +41 -0
@@ -0,0 +1,275 @@
1
+ """Trade-detail command builders and parsers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import datetime, time
6
+ from importlib import import_module
7
+ from typing import Any
8
+
9
+ from axdata_source_tdx._tdx_wire.protocol.frame import RequestFrame, ResponseFrame
10
+ from axdata_source_tdx._tdx_wire._code_utils import split_code
11
+ from axdata_source_tdx._tdx_wire._command_layouts import SIDE_MAP
12
+
13
+ from axdata_source_tdx._tdx_wire._command_codes import command_code
14
+
15
+ TYPE_HISTORICAL_TRADES = command_code("historical_trades")
16
+ TYPE_TODAY_TRADES = command_code("today_trades")
17
+ _BINARY_MODULE = "axdata_source_tdx._tdx_wire._binary"
18
+ _EXCEPTIONS_MODULE = "axdata_source_tdx._tdx_wire.exceptions"
19
+ _MODEL_MODULE = "axdata_source_tdx._tdx_wire.models.trade"
20
+ _TIME_UTILS_MODULE = "axdata_source_tdx._tdx_wire._time_utils"
21
+ _BINARY_EXPORTS = {
22
+ "consume_tdx_signed_varint",
23
+ "consume_tdx_varint",
24
+ "date_from_yyyymmdd",
25
+ "little_f32",
26
+ "little_u16",
27
+ "yyyymmdd",
28
+ }
29
+ _EXCEPTION_EXPORTS = {"ProtocolError"}
30
+ _MODEL_EXPORTS = {"TradeDetailRecord", "TradeDetailSeries"}
31
+ _TIME_EXPORTS = {"SHANGHAI_TZ"}
32
+
33
+
34
+ def _protocol_error():
35
+ return import_module(_EXCEPTIONS_MODULE).ProtocolError
36
+
37
+
38
+ def _binary():
39
+ return import_module(_BINARY_MODULE)
40
+
41
+
42
+ def _consume_tdx_signed_varint(payload: bytes, offset: int) -> tuple[int, int]:
43
+ return _binary().consume_tdx_signed_varint(payload, offset)
44
+
45
+
46
+ def _consume_tdx_varint(payload: bytes, offset: int) -> tuple[int, int]:
47
+ return _binary().consume_tdx_varint(payload, offset)
48
+
49
+
50
+ def _date_from_yyyymmdd(raw: int):
51
+ return _binary().date_from_yyyymmdd(raw)
52
+
53
+
54
+ def _little_f32(data: bytes) -> float:
55
+ return _binary().little_f32(data)
56
+
57
+
58
+ def _little_u16(data: bytes) -> int:
59
+ return _binary().little_u16(data)
60
+
61
+
62
+ def _yyyymmdd(value) -> int:
63
+ return _binary().yyyymmdd(value)
64
+
65
+
66
+ def _trade_detail_record_cls():
67
+ return import_module(_MODEL_MODULE).TradeDetailRecord
68
+
69
+
70
+ def _trade_detail_series_cls():
71
+ return import_module(_MODEL_MODULE).TradeDetailSeries
72
+
73
+
74
+ def _shanghai_tz():
75
+ return import_module(_TIME_UTILS_MODULE).SHANGHAI_TZ
76
+
77
+
78
+ def build_today_trades_frame(payload: dict[str, Any], msg_id: int) -> RequestFrame:
79
+ market_id, _, number = split_code(payload["code"])
80
+ start = normalize_trade_start(payload.get("start", 0))
81
+ count = normalize_trade_count(payload.get("count", 115))
82
+ data = (
83
+ market_id.to_bytes(1, "little", signed=False)
84
+ + b"\x00"
85
+ + number.encode("ascii")
86
+ + start.to_bytes(2, "little", signed=False)
87
+ + count.to_bytes(2, "little", signed=False)
88
+ )
89
+ return RequestFrame(msg_id=msg_id, msg_type=TYPE_TODAY_TRADES, data=data)
90
+
91
+
92
+ def build_historical_trades_frame(payload: dict[str, Any], msg_id: int) -> RequestFrame:
93
+ market_id, _, number = split_code(payload["code"])
94
+ trade_date_raw = historical_trade_date(payload)
95
+ start = normalize_trade_start(payload.get("start", 0))
96
+ count = normalize_trade_count(payload.get("count", 900))
97
+ data = (
98
+ trade_date_raw.to_bytes(4, "little", signed=False)
99
+ + market_id.to_bytes(2, "little", signed=False)
100
+ + number.encode("ascii")
101
+ + start.to_bytes(2, "little", signed=False)
102
+ + count.to_bytes(2, "little", signed=False)
103
+ )
104
+ return RequestFrame(msg_id=msg_id, msg_type=TYPE_HISTORICAL_TRADES, data=data)
105
+
106
+
107
+ def parse_today_trades_payload(
108
+ response: ResponseFrame,
109
+ request_payload: dict[str, Any] | None = None,
110
+ ) -> TradeDetailSeries:
111
+ request_payload = request_payload or {}
112
+ requested_code = request_payload.get("code", "sz000001")
113
+ market_id, exchange, number = split_code(requested_code)
114
+ start = normalize_trade_start(request_payload.get("start", 0))
115
+ count = normalize_trade_count(request_payload.get("count", 115))
116
+ payload = response.data
117
+ if len(payload) < 2:
118
+ raise _protocol_error()("invalid today trades payload")
119
+
120
+ record_count = _little_u16(payload[:2])
121
+ records = parse_trade_records(payload, offset=2, record_count=record_count, start=start, trade_date_raw=None)
122
+ return _trade_detail_series_cls()(
123
+ exchange=exchange,
124
+ market_id=market_id,
125
+ code=number,
126
+ start=start,
127
+ request_count=count,
128
+ records=tuple(records),
129
+ raw_payload=payload if request_payload.get("include_raw") else b"",
130
+ )
131
+
132
+
133
+ def parse_historical_trades_payload(
134
+ response: ResponseFrame,
135
+ request_payload: dict[str, Any] | None = None,
136
+ ) -> TradeDetailSeries:
137
+ request_payload = request_payload or {}
138
+ requested_code = request_payload.get("code", "sz000001")
139
+ market_id, exchange, number = split_code(requested_code)
140
+ trade_date_raw = historical_trade_date(request_payload)
141
+ trade_date = _date_from_yyyymmdd(trade_date_raw)
142
+ if trade_date is None:
143
+ raise _protocol_error()(f"invalid historical trades trade_date: {trade_date_raw}")
144
+ start = normalize_trade_start(request_payload.get("start", 0))
145
+ count = normalize_trade_count(request_payload.get("count", 900))
146
+ payload = response.data
147
+ if len(payload) < 6:
148
+ raise _protocol_error()("invalid historical trades payload")
149
+
150
+ record_count = _little_u16(payload[:2])
151
+ price_base_raw_f32 = float(_little_f32(payload[2:6]))
152
+ records = parse_trade_records(payload, offset=6, record_count=record_count, start=start, trade_date_raw=trade_date_raw)
153
+ return _trade_detail_series_cls()(
154
+ exchange=exchange,
155
+ market_id=market_id,
156
+ code=number,
157
+ start=start,
158
+ request_count=count,
159
+ records=tuple(records),
160
+ trade_date=trade_date,
161
+ price_base_raw_f32=price_base_raw_f32,
162
+ raw_payload=payload if request_payload.get("include_raw") else b"",
163
+ )
164
+
165
+
166
+ def parse_trade_records(
167
+ payload: bytes,
168
+ *,
169
+ offset: int,
170
+ record_count: int,
171
+ start: int,
172
+ trade_date_raw: int | None,
173
+ ) -> list[TradeDetailRecord]:
174
+ trade_date = _date_from_yyyymmdd(trade_date_raw) if trade_date_raw is not None else None
175
+ trade_detail_record = _trade_detail_record_cls()
176
+ records: list[TradeDetailRecord] = []
177
+ price_acc_raw = 0
178
+ for index in range(record_count):
179
+ record_start = offset
180
+ if offset + 2 > len(payload):
181
+ raise _protocol_error()("truncated trade time field")
182
+ time_minutes = _little_u16(payload[offset : offset + 2])
183
+ offset += 2
184
+ price_delta_raw, offset = _consume_tdx_signed_varint(payload, offset)
185
+ volume, offset = _consume_tdx_varint(payload, offset)
186
+ order_count, offset = _consume_tdx_varint(payload, offset)
187
+ status_raw, offset = _consume_tdx_varint(payload, offset)
188
+ tail_raw, offset = _consume_tdx_varint(payload, offset)
189
+ price_acc_raw += price_delta_raw
190
+ trade_time = trade_time_from_minutes(time_minutes)
191
+ trade_datetime = (
192
+ datetime.combine(trade_date, trade_time, tzinfo=_shanghai_tz())
193
+ if trade_date is not None
194
+ else None
195
+ )
196
+ records.append(
197
+ trade_detail_record(
198
+ trade_time=trade_time,
199
+ trade_datetime=trade_datetime,
200
+ trade_date=trade_date,
201
+ index=index,
202
+ absolute_index=start + index,
203
+ time_minutes=time_minutes,
204
+ price=price_acc_raw / 10000.0,
205
+ price_acc_raw=price_acc_raw,
206
+ price_delta_raw=price_delta_raw,
207
+ volume=volume,
208
+ order_count=order_count,
209
+ status_raw=status_raw,
210
+ side=SIDE_MAP.get(status_raw, f"status_{status_raw}"),
211
+ tail_raw=tail_raw,
212
+ record_hex=payload[record_start:offset].hex(),
213
+ )
214
+ )
215
+
216
+ if offset != len(payload):
217
+ raise _protocol_error()(f"unexpected trailing trade payload bytes: {len(payload) - offset}")
218
+ return records
219
+
220
+
221
+ def trade_time_from_minutes(time_minutes: int) -> time:
222
+ if time_minutes < 0 or time_minutes >= 24 * 60:
223
+ raise _protocol_error()(f"invalid trade time minutes: {time_minutes}")
224
+ return time(time_minutes // 60, time_minutes % 60)
225
+
226
+
227
+ def historical_trade_date(payload: dict[str, Any]) -> int:
228
+ value = payload.get("trade_date", payload.get("date"))
229
+ if value in (None, "", 0, "0"):
230
+ raise _protocol_error()("historical trades trade_date is required")
231
+ return _yyyymmdd(value)
232
+
233
+
234
+ def normalize_trade_start(value: Any) -> int:
235
+ try:
236
+ parsed = int(value)
237
+ except (TypeError, ValueError) as exc:
238
+ raise _protocol_error()("start must be an integer") from exc
239
+ if parsed < 0 or parsed > 0xFFFF:
240
+ raise _protocol_error()("start must be between 0 and 65535")
241
+ return parsed
242
+
243
+
244
+ def normalize_trade_count(value: Any) -> int:
245
+ try:
246
+ parsed = int(value)
247
+ except (TypeError, ValueError) as exc:
248
+ raise _protocol_error()("count must be an integer") from exc
249
+ if parsed <= 0 or parsed > 0xFFFF:
250
+ raise _protocol_error()("count must be between 1 and 65535")
251
+ return parsed
252
+
253
+
254
+ def __getattr__(name: str) -> Any:
255
+ if name in _EXCEPTION_EXPORTS:
256
+ value = getattr(import_module(_EXCEPTIONS_MODULE), name)
257
+ globals()[name] = value
258
+ return value
259
+ if name in _MODEL_EXPORTS:
260
+ value = getattr(import_module(_MODEL_MODULE), name)
261
+ globals()[name] = value
262
+ return value
263
+ if name in _BINARY_EXPORTS:
264
+ value = getattr(import_module(_BINARY_MODULE), name)
265
+ globals()[name] = value
266
+ return value
267
+ if name in _TIME_EXPORTS:
268
+ value = getattr(import_module(_TIME_UTILS_MODULE), name)
269
+ globals()[name] = value
270
+ return value
271
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
272
+
273
+
274
+ def __dir__() -> list[str]:
275
+ return sorted(set(globals()) | _EXCEPTION_EXPORTS | _MODEL_EXPORTS | _BINARY_EXPORTS | _TIME_EXPORTS)
@@ -0,0 +1,70 @@
1
+ """7709 protocol constants."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from importlib import import_module
6
+
7
+
8
+ _COMMAND_CODES_MODULE = "axdata_source_tdx._tdx_wire._command_codes"
9
+ _FRAME_CONSTANTS_MODULE = "axdata_source_tdx._tdx_wire.protocol._frame_constants"
10
+ _REQUEST_DEFAULTS_MODULE = "axdata_source_tdx._tdx_wire._request_defaults"
11
+ _COMMAND_EXPORTS = {
12
+ "TYPE_AUCTION_PROCESS": "auction_process",
13
+ "TYPE_CAPITAL_CHANGES": "capital_changes",
14
+ "TYPE_CATEGORY_QUOTES": "category_quotes",
15
+ "TYPE_EXPLICIT_QUOTES": "explicit_quotes",
16
+ "TYPE_FILE_CONTENT": "file_content",
17
+ "TYPE_FINANCE_INFO": "finance_info",
18
+ "TYPE_HANDSHAKE": "handshake",
19
+ "TYPE_HEARTBEAT": "heartbeat",
20
+ "TYPE_HISTORICAL_INTRADAY": "historical_intraday",
21
+ "TYPE_HISTORICAL_TRADES": "historical_trades",
22
+ "TYPE_INTRADAY_SUBCHART": "intraday_subchart",
23
+ "TYPE_KLINES": "klines",
24
+ "TYPE_LEGACY_QUOTES": "legacy_quotes",
25
+ "TYPE_PRICE_LIMITS": "price_limits",
26
+ "TYPE_RECENT_HISTORICAL_INTRADAY": "recent_historical_intraday",
27
+ "TYPE_REFRESH_QUOTES": "refresh_quotes",
28
+ "TYPE_SECURITY_COUNT": "security_count",
29
+ "TYPE_SECURITY_LIST": "security_list",
30
+ "TYPE_TODAY_INTRADAY": "today_intraday",
31
+ "TYPE_TODAY_TRADES": "today_trades",
32
+ }
33
+ _FRAME_EXPORTS = {"CONTROL_DEFAULT", "PREFIX", "PREFIX_RESP"}
34
+ _REQUEST_DEFAULT_EXPORTS = {"DEFAULT_CODE_PAGE_SIZE", "DEFAULT_QUOTE_BATCH_SIZE"}
35
+
36
+
37
+ def _command_codes_module():
38
+ return import_module(_COMMAND_CODES_MODULE)
39
+
40
+
41
+ def _frame_constants_module():
42
+ return import_module(_FRAME_CONSTANTS_MODULE)
43
+
44
+
45
+ def _request_defaults_module():
46
+ return import_module(_REQUEST_DEFAULTS_MODULE)
47
+
48
+
49
+ def __getattr__(name: str):
50
+ if name in _COMMAND_EXPORTS:
51
+ value = _command_codes_module().command_code(_COMMAND_EXPORTS[name])
52
+ elif name == "command_code":
53
+ value = _command_codes_module().command_code
54
+ elif name == "COMMAND_CODES":
55
+ value = _command_codes_module().COMMAND_CODES
56
+ elif name in _FRAME_EXPORTS:
57
+ value = getattr(_frame_constants_module(), name)
58
+ elif name in _REQUEST_DEFAULT_EXPORTS:
59
+ value = getattr(_request_defaults_module(), name)
60
+ else:
61
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
62
+ globals()[name] = value
63
+ return value
64
+
65
+
66
+ def __dir__() -> list[str]:
67
+ return sorted(set(globals()) | set(__all__))
68
+
69
+
70
+ __all__ = sorted(set(_COMMAND_EXPORTS) | _FRAME_EXPORTS | _REQUEST_DEFAULT_EXPORTS | {"COMMAND_CODES", "command_code"})
@@ -0,0 +1,141 @@
1
+ """7709 TCP frame encoding and decoding."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from importlib import import_module
7
+
8
+
9
+ from ._frame_constants import CONTROL_DEFAULT, PREFIX, PREFIX_RESP
10
+
11
+
12
+ _EXCEPTIONS_MODULE = "axdata_source_tdx._tdx_wire.exceptions"
13
+ _EXCEPTION_EXPORTS = {"ConnectionClosedError", "ProtocolError"}
14
+ _STDLIB_EXPORTS = {"socket", "struct", "zlib"}
15
+
16
+
17
+ def _connection_closed_error():
18
+ return import_module(_EXCEPTIONS_MODULE).ConnectionClosedError
19
+
20
+
21
+ def _protocol_error():
22
+ return import_module(_EXCEPTIONS_MODULE).ProtocolError
23
+
24
+
25
+ def __getattr__(name: str):
26
+ if name in _EXCEPTION_EXPORTS:
27
+ value = getattr(import_module(_EXCEPTIONS_MODULE), name)
28
+ globals()[name] = value
29
+ return value
30
+ if name in _STDLIB_EXPORTS:
31
+ value = import_module(name)
32
+ globals()[name] = value
33
+ return value
34
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
35
+
36
+
37
+ def __dir__() -> list[str]:
38
+ return sorted(set(globals()) | _EXCEPTION_EXPORTS | _STDLIB_EXPORTS)
39
+
40
+
41
+ @dataclass(frozen=True, slots=True)
42
+ class RequestFrame:
43
+ msg_id: int
44
+ msg_type: int
45
+ data: bytes = b""
46
+ control: int = CONTROL_DEFAULT
47
+
48
+ def to_bytes(self) -> bytes:
49
+ import struct
50
+
51
+ length = len(self.data) + 2
52
+ return struct.pack("<BIBHHH", PREFIX, self.msg_id, self.control, length, length, self.msg_type) + self.data
53
+
54
+
55
+ @dataclass(frozen=True, slots=True)
56
+ class ResponseFrame:
57
+ control: int
58
+ msg_id: int
59
+ msg_type: int
60
+ zip_length: int
61
+ length: int
62
+ data: bytes
63
+ raw: bytes
64
+ response_header_reserved: int = 0
65
+
66
+
67
+ def read_exact(sock: socket.socket, size: int) -> bytes:
68
+ chunks = bytearray()
69
+ while len(chunks) < size:
70
+ piece = sock.recv(size - len(chunks))
71
+ if not piece:
72
+ raise _connection_closed_error()("socket closed by remote peer")
73
+ chunks.extend(piece)
74
+ return bytes(chunks)
75
+
76
+
77
+ def read_response_frame(sock: socket.socket) -> bytes:
78
+ window = bytearray(read_exact(sock, 4))
79
+ while bytes(window) != PREFIX_RESP:
80
+ window = window[1:] + read_exact(sock, 1)
81
+
82
+ header = read_exact(sock, 12)
83
+ zip_length = int.from_bytes(header[8:10], "little", signed=False)
84
+ payload = read_exact(sock, zip_length)
85
+ return bytes(window) + header + payload
86
+
87
+
88
+ def decode_response(raw: bytes) -> ResponseFrame:
89
+ if len(raw) < 16:
90
+ raise _protocol_error()(f"invalid response length: {len(raw)}")
91
+ if raw[:4] != PREFIX_RESP:
92
+ raise _protocol_error()(f"invalid response prefix: {raw[:4].hex()}")
93
+
94
+ control = raw[4]
95
+ msg_id = int.from_bytes(raw[5:9], "little", signed=False)
96
+ reserved = raw[9]
97
+ msg_type = int.from_bytes(raw[10:12], "little", signed=False)
98
+ zip_length = int.from_bytes(raw[12:14], "little", signed=False)
99
+ length = int.from_bytes(raw[14:16], "little", signed=False)
100
+ payload = raw[16:]
101
+
102
+ if len(payload) != zip_length:
103
+ raise _protocol_error()(f"zip length mismatch: expected {zip_length}, got {len(payload)}")
104
+
105
+ if zip_length != length:
106
+ import zlib
107
+
108
+ data = zlib.decompress(payload)
109
+ else:
110
+ data = payload
111
+ if len(data) != length:
112
+ raise _protocol_error()(f"decoded length mismatch: expected {length}, got {len(data)}")
113
+
114
+ return ResponseFrame(
115
+ control=control,
116
+ msg_id=msg_id,
117
+ msg_type=msg_type,
118
+ zip_length=zip_length,
119
+ length=length,
120
+ data=data,
121
+ raw=raw,
122
+ response_header_reserved=reserved,
123
+ )
124
+
125
+
126
+ __all__ = [
127
+ "ConnectionClosedError",
128
+ "CONTROL_DEFAULT",
129
+ "PREFIX",
130
+ "PREFIX_RESP",
131
+ "ProtocolError",
132
+ "RequestFrame",
133
+ "ResponseFrame",
134
+ "dataclass",
135
+ "decode_response",
136
+ "read_exact",
137
+ "read_response_frame",
138
+ "socket",
139
+ "struct",
140
+ "zlib",
141
+ ]
@@ -0,0 +1,98 @@
1
+ """Compatibility binary helpers for 7709 command parsers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import date, datetime
6
+ from importlib import import_module
7
+
8
+
9
+ _BINARY_MODULE_NAME = "axdata_source_tdx._tdx_wire._binary"
10
+ _MARKET_MODULE_NAME = "axdata_source_tdx._tdx_wire._market"
11
+ _MARKET_EXPORTS = {"ID_TO_MARKET", "MARKET_TO_ID", "market_to_id", "normalize_market"}
12
+
13
+ _BINARY_MODULE = None
14
+ _MARKET_MODULE = None
15
+
16
+
17
+ def _load_binary_module():
18
+ global _BINARY_MODULE
19
+ if _BINARY_MODULE is None:
20
+ _BINARY_MODULE = import_module(_BINARY_MODULE_NAME)
21
+ return _BINARY_MODULE
22
+
23
+
24
+ def _load_market_module():
25
+ global _MARKET_MODULE
26
+ if _MARKET_MODULE is None:
27
+ _MARKET_MODULE = import_module(_MARKET_MODULE_NAME)
28
+ return _MARKET_MODULE
29
+
30
+
31
+ def little_u16(data: bytes) -> int:
32
+ return _load_binary_module().little_u16(data)
33
+
34
+
35
+ def little_u32(data: bytes) -> int:
36
+ return _load_binary_module().little_u32(data)
37
+
38
+
39
+ def little_f32(data: bytes) -> float:
40
+ return _load_binary_module().little_f32(data)
41
+
42
+
43
+ def tdx_quantity_u32(data: bytes) -> float:
44
+ return _load_binary_module().tdx_quantity_u32(data)
45
+
46
+
47
+ def tdx_quantity_from_u32(raw: int) -> float:
48
+ return _load_binary_module().tdx_quantity_from_u32(raw)
49
+
50
+
51
+ def decode_gbk_text(data: bytes) -> str:
52
+ return _load_binary_module().decode_gbk_text(data)
53
+
54
+
55
+ def yyyymmdd(value: str | int | date | datetime | None = None) -> int:
56
+ return _load_binary_module().yyyymmdd(value)
57
+
58
+
59
+ def date_from_yyyymmdd(raw: int) -> date | None:
60
+ return _load_binary_module().date_from_yyyymmdd(raw)
61
+
62
+
63
+ def consume_tdx_signed_varint(payload: bytes, offset: int) -> tuple[int, int]:
64
+ return _load_binary_module().consume_tdx_signed_varint(payload, offset)
65
+
66
+
67
+ def consume_tdx_varint(payload: bytes, offset: int) -> tuple[int, int]:
68
+ return _load_binary_module().consume_tdx_varint(payload, offset)
69
+
70
+
71
+ def __getattr__(name: str):
72
+ if name in _MARKET_EXPORTS:
73
+ value = getattr(_load_market_module(), name)
74
+ globals()[name] = value
75
+ return value
76
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
77
+
78
+
79
+ def __dir__() -> list[str]:
80
+ return sorted(set(globals()) | set(__all__))
81
+
82
+
83
+ __all__ = [
84
+ "ID_TO_MARKET",
85
+ "MARKET_TO_ID",
86
+ "consume_tdx_signed_varint",
87
+ "consume_tdx_varint",
88
+ "date_from_yyyymmdd",
89
+ "decode_gbk_text",
90
+ "little_f32",
91
+ "little_u16",
92
+ "little_u32",
93
+ "market_to_id",
94
+ "normalize_market",
95
+ "tdx_quantity_from_u32",
96
+ "tdx_quantity_u32",
97
+ "yyyymmdd",
98
+ ]
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,28 @@
1
+ """Transport abstractions for axdata_source_tdx._tdx_wire."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from importlib import import_module
6
+
7
+ __all__ = ["InMemoryTransport", "PooledSocketTransport", "SocketTransport", "Transport"]
8
+
9
+ _EXPORT_MODULES = {
10
+ "InMemoryTransport": ".memory",
11
+ "PooledSocketTransport": ".pool",
12
+ "SocketTransport": ".socket",
13
+ "Transport": ".base",
14
+ }
15
+
16
+
17
+ def __getattr__(name: str):
18
+ module_name = _EXPORT_MODULES.get(name)
19
+ if module_name is None:
20
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
21
+ module = import_module(module_name, __name__)
22
+ value = getattr(module, name)
23
+ globals()[name] = value
24
+ return value
25
+
26
+
27
+ def __dir__() -> list[str]:
28
+ return sorted(set(globals()) | set(__all__))
@@ -0,0 +1,21 @@
1
+ """Transport interface definitions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Protocol
6
+
7
+
8
+ class Transport(Protocol):
9
+ """Request/response transport used by API services."""
10
+
11
+ def connect(self) -> None:
12
+ """Open transport resources."""
13
+
14
+ def close(self) -> None:
15
+ """Close transport resources."""
16
+
17
+ def execute(self, command: int, payload: dict[str, Any] | None = None) -> Any:
18
+ """Execute one logical protocol command."""
19
+
20
+ def request(self, command: str) -> str:
21
+ """Legacy text request used by early health tests."""
@@ -0,0 +1,42 @@
1
+ """测试和示例使用的内存 transport。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+
8
+ class InMemoryTransport:
9
+ """不依赖 socket 的确定性 transport。
10
+
11
+ 用于在接入真实 7709 服务器前验证对外 API 和单元测试。
12
+ """
13
+
14
+ def __init__(self) -> None:
15
+ self.connected = False
16
+ self.calls: list[tuple[int, dict[str, Any]]] = []
17
+ self.responses: dict[int, Any] = {}
18
+
19
+ def connect(self) -> None:
20
+ self.connected = True
21
+
22
+ def close(self) -> None:
23
+ self.connected = False
24
+
25
+ def register_response(self, command: int, response: Any) -> None:
26
+ self.responses[command] = response
27
+
28
+ def execute(self, command: int, payload: dict[str, Any] | None = None) -> Any:
29
+ request_payload = dict(payload or {})
30
+ self.calls.append((command, request_payload))
31
+ if command in self.responses:
32
+ return self.responses[command]
33
+ return {
34
+ "command": f"0x{command:04x}",
35
+ "payload": request_payload,
36
+ "status": "memory_transport",
37
+ }
38
+
39
+ def request(self, command: str) -> str:
40
+ if command == "ping":
41
+ return "pong"
42
+ raise ValueError(f"unsupported command: {command}")