cfquant 0.2.37__tar.gz → 0.2.38__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 (154) hide show
  1. {cfquant-0.2.37 → cfquant-0.2.38}/PKG-INFO +1 -1
  2. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/qmt_bridge.py +3 -1
  3. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tx_trade_bridge.py +4 -2
  4. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/version.py +2 -2
  5. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/xttype.py +60 -18
  6. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant.egg-info/PKG-INFO +1 -1
  7. {cfquant-0.2.37 → cfquant-0.2.38}/pyproject.toml +1 -1
  8. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/app.js +45 -7
  9. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/index.html +2 -3
  10. {cfquant-0.2.37 → cfquant-0.2.38}/LICENSE +0 -0
  11. {cfquant-0.2.37 → cfquant-0.2.38}/LTtx/__init__.py +0 -0
  12. {cfquant-0.2.37 → cfquant-0.2.38}/LTtx/tx/Config.txt +0 -0
  13. {cfquant-0.2.37 → cfquant-0.2.38}/LTtx/tx/LTtx_server.py +0 -0
  14. {cfquant-0.2.37 → cfquant-0.2.38}/LTtx/tx/__init__.py +0 -0
  15. {cfquant-0.2.37 → cfquant-0.2.38}/LTtx/tx/tx.py +0 -0
  16. {cfquant-0.2.37 → cfquant-0.2.38}/MANIFEST.in +0 -0
  17. {cfquant-0.2.37 → cfquant-0.2.38}/README.md +0 -0
  18. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/__init__.py +0 -0
  19. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/_editable_install.py +0 -0
  20. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/account_routing.py +0 -0
  21. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/batch_orders.py +0 -0
  22. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/cftrader.py +0 -0
  23. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/channels.py +0 -0
  24. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/cli.py +0 -0
  25. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/client.py +0 -0
  26. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/config.py +0 -0
  27. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/hub.py +0 -0
  28. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/level2.py +0 -0
  29. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/log_management.py +0 -0
  30. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/logging_i18n.py +0 -0
  31. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/normal_bridge.py +0 -0
  32. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/order_meta.py +0 -0
  33. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/pipe_bridge.py +0 -0
  34. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/pipe_client.py +0 -0
  35. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/pipe_hub.py +0 -0
  36. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/pipe_transport.py +0 -0
  37. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/protocol.py +0 -0
  38. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/qmt_strategy_deploy.py +0 -0
  39. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/qmt_strategy_package.py +0 -0
  40. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/qmt_strategy_runtime.py +0 -0
  41. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/runtime_report.py +0 -0
  42. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/10_/345/221/275/344/273/244/350/241/214/346/216/245/345/217/243/346/265/213/350/257/225.py" +0 -0
  43. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/11_/346/231/256/351/200/232/346/241/245/346/216/245/346/264/276/345/217/221/346/265/213/350/257/225.py" +0 -0
  44. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/12_/350/256/242/345/215/225/345/244/207/346/263/250/346/265/213/350/257/225.py" +0 -0
  45. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/13_/347/256/241/351/201/223/344/270/255/345/277/203/350/277/236/346/216/245/346/265/213/350/257/225.py" +0 -0
  46. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/14_/350/277/220/350/241/214/346/227/266/346/212/245/345/221/212/346/265/213/350/257/225.py" +0 -0
  47. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/15_/347/275/221/351/241/265/347/212/266/346/200/201/347/274/223/345/255/230/346/265/213/350/257/225.py" +0 -0
  48. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/16_/345/220/257/345/212/250/345/256/211/350/243/205/346/265/213/350/257/225.py" +0 -0
  49. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/17_/345/244/247QMT/346/216/245/345/217/243/351/200/202/351/205/215/346/265/213/350/257/225.py" +0 -0
  50. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/18_/351/253/230/347/272/247/346/250/241/345/274/217/345/256/236/346/234/272/350/201/224/350/260/203.py" +0 -0
  51. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/19_/345/256/236/346/234/272/350/201/224/350/260/203/345/210/244/345/256/232/346/265/213/350/257/225.py" +0 -0
  52. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/1_/350/241/214/346/203/205/346/216/245/346/224/266/346/265/213/350/257/225.py" +0 -0
  53. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/20_/350/201/224/350/260/203/351/227/256/351/242/230/344/277/256/345/244/215/346/265/213/350/257/225.py" +0 -0
  54. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/21_/345/215/225/350/202/241/350/241/214/346/203/205/350/256/242/351/230/205/346/265/213/350/257/225.py" +0 -0
  55. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/22_/350/277/236/346/216/245/350/257/212/346/226/255/346/265/213/350/257/225.py" +0 -0
  56. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/23_/347/244/272/344/276/213/351/205/215/347/275/256/346/265/213/350/257/225.py" +0 -0
  57. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/24_/350/264/246/346/210/267/347/274/223/345/255/230/346/214/211/351/234/200/345/210/267/346/226/260/346/265/213/350/257/225.py" +0 -0
  58. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/25_/350/264/246/346/210/267/347/274/223/345/255/230/351/241/265/351/235/242/346/265/213/350/257/225.py" +0 -0
  59. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/26_/345/205/250/346/216/250/350/256/242/351/230/205/346/265/213/350/257/225.py" +0 -0
  60. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/27_/345/205/250/346/216/250/350/256/242/351/230/205/351/241/265/351/235/242/346/265/213/350/257/225.py" +0 -0
  61. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/28_Level2/346/216/245/345/217/243/351/200/202/351/205/215/346/265/213/350/257/225.py" +0 -0
  62. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/29_Level2/350/241/214/346/203/205/346/265/213/350/257/225.py" +0 -0
  63. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/2_/346/225/260/346/215/256/350/216/267/345/217/226/346/265/213/350/257/225.py" +0 -0
  64. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/30_cftrader/346/211/271/351/207/217/344/270/213/345/215/225/346/200/247/350/203/275/345/237/272/345/207/206.py" +0 -0
  65. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/31_cftrader/346/250/241/346/213/237/350/264/246/345/217/267/346/211/271/351/207/217/344/270/213/345/215/225/346/265/213/350/257/225.py" +0 -0
  66. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/32_/345/274/202/346/255/245/344/270/213/345/215/225/346/265/213/350/257/225.py" +0 -0
  67. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/33_/345/220/214/346/255/245/344/270/213/345/215/225/345/233/236/350/260/203/346/265/213/350/257/225.py" +0 -0
  68. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/3_/346/225/260/346/215/256/344/270/213/350/275/275/346/265/213/350/257/225.py" +0 -0
  69. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/4_/344/272/244/346/230/223/345/247/224/346/211/230/346/237/245/350/257/242/346/265/213/350/257/225.py" +0 -0
  70. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/5_/347/234/237/345/256/236/344/270/213/345/215/225/346/265/213/350/257/225.py" +0 -0
  71. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/6_/345/233/236/350/260/203/346/265/213/350/257/225.py" +0 -0
  72. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/7_/345/220/214/346/255/245/345/274/202/346/255/245/344/270/213/345/215/225/346/265/213/350/257/225.py" +0 -0
  73. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/8_/346/210/220/344/272/244/350/256/242/345/215/225/345/222/214/345/247/224/346/211/230/350/256/242/345/215/225/346/237/245/350/257/242/346/265/213/350/257/225.py" +0 -0
  74. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/9_/345/217/257/346/222/244/350/256/242/345/215/225/346/265/213/350/257/225.py" +0 -0
  75. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/_helpers.py +0 -0
  76. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/log/cftrader/346/250/241/346/213/237/350/264/246/345/217/267/346/211/271/351/207/217/344/270/213/345/215/225/346/265/213/350/257/225_20260911_024617.md" +0 -0
  77. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/log/cftrader/346/250/241/346/213/237/350/264/246/345/217/267/346/211/271/351/207/217/344/270/213/345/215/225/346/265/213/350/257/225_20260921_175732.md" +0 -0
  78. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/readme.md +0 -0
  79. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_api_tester_browser.py +0 -0
  80. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_api_tester_web.py +0 -0
  81. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_binding_delete_confirmation.py +0 -0
  82. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_cftrader.py +0 -0
  83. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_cftrader_tutorial.py +0 -0
  84. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_cftrader_web.py +0 -0
  85. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_credit_compat.py +0 -0
  86. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_json_serialization.py +0 -0
  87. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_log_management.py +0 -0
  88. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_management_batch.py +0 -0
  89. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_project_updater.py +0 -0
  90. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_python_api_reference.py +0 -0
  91. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_qmt_strategy_browser.py +0 -0
  92. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_qmt_strategy_deploy.py +0 -0
  93. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_qmt_strategy_web.py +0 -0
  94. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_tutorial_reader.py +0 -0
  95. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tests/test_tx_auto_import.py +0 -0
  96. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/tx.py +0 -0
  97. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/xtconstant.py +0 -0
  98. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/xtdata.py +0 -0
  99. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant/xttrader.py +0 -0
  100. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant.egg-info/SOURCES.txt +0 -0
  101. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant.egg-info/dependency_links.txt +0 -0
  102. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant.egg-info/entry_points.txt +0 -0
  103. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant.egg-info/requires.txt +0 -0
  104. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant.egg-info/top_level.txt +0 -0
  105. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant_pipe_hub.py +0 -0
  106. {cfquant-0.2.37 → cfquant-0.2.38}/cfquant_web_server.py +0 -0
  107. {cfquant-0.2.37 → cfquant-0.2.38}/qmt_scripts/CFQUANT.py +0 -0
  108. {cfquant-0.2.37 → cfquant-0.2.38}/qmt_scripts/CFQUANT_CTYPE_ALL_LOWLAT.py +0 -0
  109. {cfquant-0.2.37 → cfquant-0.2.38}/qmt_scripts/CFQUANT_LITE.py +0 -0
  110. {cfquant-0.2.37 → cfquant-0.2.38}/qmt_scripts/CFQUANT_TRADE_LOWLAT.py +0 -0
  111. {cfquant-0.2.37 → cfquant-0.2.38}/qmt_scripts/__init__.py +0 -0
  112. {cfquant-0.2.37 → cfquant-0.2.38}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_CTYPE_ALL_LOWLAT_SH.py" +0 -0
  113. {cfquant-0.2.37 → cfquant-0.2.38}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_CTYPE_ALL_LOWLAT_SZ.py" +0 -0
  114. {cfquant-0.2.37 → cfquant-0.2.38}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_LITE_SH.py" +0 -0
  115. {cfquant-0.2.37 → cfquant-0.2.38}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_LITE_SZ.py" +0 -0
  116. {cfquant-0.2.37 → cfquant-0.2.38}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_TRADE_LOWLAT_SH.py" +0 -0
  117. {cfquant-0.2.37 → cfquant-0.2.38}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_TRADE_LOWLAT_SZ.py" +0 -0
  118. {cfquant-0.2.37 → cfquant-0.2.38}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/readme.md" +0 -0
  119. {cfquant-0.2.37 → cfquant-0.2.38}/requirements.txt +0 -0
  120. {cfquant-0.2.37 → cfquant-0.2.38}/setup.cfg +0 -0
  121. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/__init__.py +0 -0
  122. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/api-tester.js +0 -0
  123. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/avatars/amber-pulse.svg +0 -0
  124. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/avatars/copper-grid.svg +0 -0
  125. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/avatars/market-blue.svg +0 -0
  126. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/avatars/rose-circuit.svg +0 -0
  127. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/avatars/signal-green.svg +0 -0
  128. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/avatars/slate-wave.svg +0 -0
  129. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/avatars/teal-orbit.svg +0 -0
  130. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/avatars/violet-node.svg +0 -0
  131. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/cftrader-api-data.js +0 -0
  132. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/favicon.svg +0 -0
  133. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-10.png +0 -0
  134. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-11.png +0 -0
  135. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-12.png +0 -0
  136. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-13.png +0 -0
  137. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-14.png +0 -0
  138. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-15.png +0 -0
  139. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-16.png +0 -0
  140. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-17.png +0 -0
  141. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-18.png +0 -0
  142. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-19.png +0 -0
  143. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-20.png +0 -0
  144. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-21.png +0 -0
  145. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-4.png +0 -0
  146. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-5.png +0 -0
  147. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-6.png +0 -0
  148. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-7.png +0 -0
  149. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-8.png +0 -0
  150. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-9.png +0 -0
  151. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/python-api-data.js +0 -0
  152. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/python-api.js +0 -0
  153. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/styles.css +0 -0
  154. {cfquant-0.2.37 → cfquant-0.2.38}/web_dashboard/vendor/mermaid.min.js +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cfquant
3
- Version: 0.2.37
3
+ Version: 0.2.38
4
4
  Summary: QMT local bridge and xtquant-compatible Python client.
5
5
  License: MIT
6
6
  Requires-Python: >=3.8
@@ -1109,7 +1109,8 @@ class CfquantQmtBridge(object):
1109
1109
  "order_sysid": self._get_value(obj, "m_strOrderSysID"),
1110
1110
  "order_type": self._stock_order_type(obj),
1111
1111
  "order_time": self._first_value(obj, (
1112
- "order_time",
1112
+ "time",
1113
+ "order_time",
1113
1114
  "entrust_time",
1114
1115
  "insert_time",
1115
1116
  "m_strOrderTime",
@@ -1197,6 +1198,7 @@ class CfquantQmtBridge(object):
1197
1198
  "order_sysid": self._get_value(obj, "m_strOrderSysID"),
1198
1199
  "traded_id": self._first_value(obj, ("m_strTradeID", "m_strDealID", "m_nTradeID", "m_nDealID")),
1199
1200
  "trade_time": self._first_value(obj, (
1201
+ "time",
1200
1202
  "trade_time",
1201
1203
  "deal_time",
1202
1204
  "m_strTradeTime",
@@ -3067,7 +3067,8 @@ class TxTradeBridge(object):
3067
3067
  "order_sysid": self._get_value(obj, "m_strOrderSysID"),
3068
3068
  "order_type": self._stock_order_type(obj),
3069
3069
  "order_time": self._first_value(obj, (
3070
- "order_time",
3070
+ "time",
3071
+ "order_time",
3071
3072
  "entrust_time",
3072
3073
  "insert_time",
3073
3074
  "m_strOrderTime",
@@ -3163,7 +3164,8 @@ class TxTradeBridge(object):
3163
3164
  "contract_no": self._first_value(obj, ("contract_no", "m_strCompactNo", "m_strContractNo", "m_strCompactID")),
3164
3165
  "stock_code1": self._first_value(obj, ("stock_code1", "m_stockCode", "m_strStockCode1", "m_strUnderCode")),
3165
3166
  "trade_time": self._first_value(obj, (
3166
- "trade_time",
3167
+ "time",
3168
+ "trade_time",
3167
3169
  "deal_time",
3168
3170
  "m_strTradeTime",
3169
3171
  "m_strDealTime",
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """cfquant core version metadata."""
3
3
 
4
- __version__ = "0.2.36"
5
- WEB_VERSION = "web_20260922_04"
4
+ __version__ = "0.2.38"
5
+ WEB_VERSION = "web_20260923_02"
@@ -1,4 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
+ import datetime
2
3
  import re
3
4
 
4
5
  from . import xtconstant
@@ -198,31 +199,62 @@ def _coerce_bool(value, default=False):
198
199
  return default
199
200
 
200
201
 
201
- def _coerce_time_int(value, default=0):
202
- """Convert QMT's string trade/order time to xtquant's integer form."""
202
+ def _coerce_timestamp(value, date_value=None, default=0):
203
+ """Convert QMT's display time to MiniQMT's Unix timestamp in seconds."""
203
204
  if value is None or isinstance(value, bool):
204
205
  return default
205
206
  if isinstance(value, int):
206
- return value
207
- if isinstance(value, float):
208
- return int(value) if value.is_integer() else default
209
- text = str(value).strip()
207
+ if value >= 100000000000:
208
+ return value // 1000
209
+ if value >= 100000000:
210
+ return value
211
+ text = str(value)
212
+ elif isinstance(value, float):
213
+ if value >= 100000000000:
214
+ return int(value / 1000)
215
+ if value >= 100000000:
216
+ return int(value)
217
+ text = str(int(value)) if value.is_integer() else str(value)
218
+ else:
219
+ text = str(value).strip()
210
220
  if not text:
211
221
  return default
212
- if re.fullmatch(r"[+-]?\d+", text):
222
+ if re.fullmatch(r"[+-]?\d{9,}", text):
213
223
  try:
214
- return int(text)
224
+ number = int(text)
225
+ return number // 1000 if number >= 100000000000 else number
215
226
  except ValueError:
216
227
  return default
217
228
  digits = re.sub(r"\D", "", text)
218
229
  if not digits:
219
230
  return default
231
+ # HHMMSS / HHMMSSmmm values need the trading date before they can
232
+ # represent the same Unix timestamp exposed by native xtquant.
233
+ if len(digits) not in (5, 6, 8, 9):
234
+ return default
235
+ if len(digits) == 5:
236
+ digits = "0" + digits
237
+ hour, minute, second = int(digits[:2]), int(digits[2:4]), int(digits[4:6])
238
+ microsecond = int((digits[6:] + "000000")[:6]) if len(digits) > 6 else 0
239
+ date_text = re.sub(r"\D", "", str(date_value or ""))
240
+ if len(date_text) != 8:
241
+ return default
220
242
  try:
221
- return int(digits)
222
- except ValueError:
243
+ dt = datetime.datetime.strptime(date_text, "%Y%m%d").replace(
244
+ hour=hour, minute=minute, second=second, microsecond=microsecond,
245
+ tzinfo=datetime.timezone(datetime.timedelta(hours=8)),
246
+ )
247
+ return int(dt.timestamp())
248
+ except (TypeError, ValueError, OverflowError):
223
249
  return default
224
250
 
225
251
 
252
+ def _time_field_timestamp(data, time_names, date_names):
253
+ value = _first_value(data, time_names, default=None)
254
+ date_value = _first_value(data, date_names, default=None)
255
+ return _coerce_timestamp(value, date_value)
256
+
257
+
226
258
  def normalize_order_price_type(value, market=""):
227
259
  """Translate documented QMT broker price enums, preserving unknown values."""
228
260
  try:
@@ -525,8 +557,9 @@ class XtOrder(DictObject):
525
557
  "sysid",
526
558
  "m_strOrderID",
527
559
  ), default="")
528
- _set_first(data, "order_time", (
529
- "entrust_time",
560
+ _set_first(data, "order_time", (
561
+ "time",
562
+ "entrust_time",
530
563
  "insert_time",
531
564
  "m_strOrderTime",
532
565
  "m_strEntrustTime",
@@ -600,7 +633,11 @@ class XtOrder(DictObject):
600
633
  data["stock_code"] = _coerce_text(data.get("stock_code"))
601
634
  data["order_id"] = _coerce_int(data.get("order_id"), -1)
602
635
  data["order_sysid"] = _coerce_text(data.get("order_sysid"))
603
- data["order_time"] = _coerce_time_int(data.get("order_time"))
636
+ data["order_time"] = _time_field_timestamp(
637
+ data,
638
+ ("order_time", "time", "entrust_time", "insert_time", "m_strOrderTime", "m_strEntrustTime", "m_strInsertTime", "m_nOrderTime", "m_nEntrustTime", "m_nInsertTime"),
639
+ ("order_date", "entrust_date", "m_strOrderDate", "m_strEntrustDate", "m_strTradingDay", "m_nOrderDate", "m_nEntrustDate"),
640
+ )
604
641
  for name in ("order_type", "order_volume", "price_type", "traded_volume", "order_status", "direction", "offset_flag"):
605
642
  data[name] = _coerce_int(data.get(name))
606
643
  for name in ("price", "traded_price"):
@@ -636,7 +673,7 @@ class XtCreditOrder(XtOrder):
636
673
  account_id=_coerce_text(data.get("account_id")),
637
674
  stock_code=_coerce_text(data.get("stock_code")),
638
675
  order_id=_coerce_int(data.get("order_id"), -1),
639
- order_time=_coerce_time_int(data.get("order_time")),
676
+ order_time=data.get("order_time", 0),
640
677
  order_type=_coerce_int(data.get("order_type")),
641
678
  order_volume=_coerce_int(data.get("order_volume")),
642
679
  price_type=_coerce_int(data.get("price_type")),
@@ -698,8 +735,9 @@ class XtTrade(DictObject):
698
735
  "m_nTradeID",
699
736
  "m_nDealID",
700
737
  ), default="")
701
- _set_first(data, "traded_time", (
702
- "trade_time",
738
+ _set_first(data, "traded_time", (
739
+ "time",
740
+ "trade_time",
703
741
  "deal_time",
704
742
  "m_strTradeTime",
705
743
  "m_strDealTime",
@@ -763,7 +801,11 @@ class XtTrade(DictObject):
763
801
  data["stock_code"] = _coerce_text(data.get("stock_code"))
764
802
  data["order_type"] = _coerce_int(data.get("order_type"))
765
803
  data["traded_id"] = _coerce_text(data.get("traded_id"))
766
- data["traded_time"] = _coerce_time_int(data.get("traded_time"))
804
+ data["traded_time"] = _time_field_timestamp(
805
+ data,
806
+ ("traded_time", "time", "trade_time", "deal_time", "m_strTradeTime", "m_strDealTime", "m_nTradeTime", "m_nDealTime"),
807
+ ("trade_date", "deal_date", "m_strTradeDate", "m_strDealDate", "m_strTradingDay", "m_nTradeDate", "m_nDealDate"),
808
+ )
767
809
  for name in ("traded_volume",):
768
810
  data[name] = _coerce_int(data.get(name))
769
811
  for name in ("traded_price", "traded_amount", "commission"):
@@ -803,7 +845,7 @@ class XtCreditDeal(DictObject):
803
845
  account_id=_coerce_text(data.get("account_id")),
804
846
  stock_code=_coerce_text(data.get("stock_code")),
805
847
  traded_id=_coerce_text(data.get("traded_id")),
806
- traded_time=_coerce_time_int(data.get("traded_time")),
848
+ traded_time=data.get("traded_time", 0),
807
849
  traded_price=_coerce_float(data.get("traded_price")),
808
850
  traded_volume=_coerce_int(data.get("traded_volume")),
809
851
  order_id=_coerce_int(data.get("order_id"), -1),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cfquant
3
- Version: 0.2.37
3
+ Version: 0.2.38
4
4
  Summary: QMT local bridge and xtquant-compatible Python client.
5
5
  License: MIT
6
6
  Requires-Python: >=3.8
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cfquant"
7
- version = "0.2.37"
7
+ version = "0.2.38"
8
8
  description = "QMT local bridge and xtquant-compatible Python client."
9
9
  license = {text = "MIT"}
10
10
  readme = "README.md"
@@ -1,4 +1,4 @@
1
- const FRONTEND_VERSION = 'web_20260922_04';
1
+ const FRONTEND_VERSION = 'web_20260923_02';
2
2
 
3
3
  const state = {
4
4
  accountId: '',
@@ -2500,9 +2500,42 @@ function normalizeApiBaseUrl(value) {
2500
2500
  }
2501
2501
  }
2502
2502
 
2503
+ function isPrivateApiHost(host) {
2504
+ host = String(host || '').trim().toLowerCase();
2505
+ if (!host || host === 'localhost' || host === '::1' || host === '[::1]') return true;
2506
+ if (/^127\./.test(host)) return true;
2507
+ const parts = host.split('.').map((item) => Number(item));
2508
+ if (parts.length !== 4 || parts.some((item) => !Number.isInteger(item) || item < 0 || item > 255)) return false;
2509
+ return parts[0] === 10
2510
+ || parts[0] === 192 && parts[1] === 168
2511
+ || parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31
2512
+ || parts[0] === 169 && parts[1] === 254;
2513
+ }
2514
+
2515
+ function apiBaseUrlForPage(value) {
2516
+ const configured = normalizeApiBaseUrl(value);
2517
+ const page = normalizeApiBaseUrl(window.location.origin);
2518
+ try {
2519
+ const configuredUrl = new URL(configured);
2520
+ const pageUrl = new URL(page);
2521
+ // A saved LAN address belongs to the machine that last ran Web. When the
2522
+ // page is opened from another private/loopback address, follow the current
2523
+ // page so changing the host IP does not leave the tester pointing at the
2524
+ // old machine. Public/explicit remote URLs remain user-configurable.
2525
+ if (isPrivateApiHost(configuredUrl.hostname)
2526
+ && isPrivateApiHost(pageUrl.hostname)
2527
+ && configuredUrl.hostname !== pageUrl.hostname) {
2528
+ return page;
2529
+ }
2530
+ } catch (error) {
2531
+ return page;
2532
+ }
2533
+ return configured;
2534
+ }
2535
+
2503
2536
  function currentApiBaseUrl() {
2504
2537
  const input = $('apiBaseUrlInput');
2505
- if (input && input.value.trim()) return normalizeApiBaseUrl(input.value);
2538
+ if (input && input.value.trim()) return apiBaseUrlForPage(input.value);
2506
2539
  return normalizeApiBaseUrl(window.location.origin);
2507
2540
  }
2508
2541
 
@@ -4616,7 +4649,10 @@ function renderServerAccessLegacy(info) {
4616
4649
 
4617
4650
  const baseInput = $('apiBaseUrlInput');
4618
4651
  if (baseInput && !baseInput.value.trim()) {
4619
- baseInput.value = normalizeApiBaseUrl(state.serverAccess.api_base_url || window.location.origin);
4652
+ baseInput.value = apiBaseUrlForPage(state.serverAccess.api_base_url || window.location.origin);
4653
+ } else if (baseInput && baseInput.value.trim()) {
4654
+ const effectiveBaseUrl = apiBaseUrlForPage(baseInput.value);
4655
+ if (effectiveBaseUrl !== normalizeApiBaseUrl(baseInput.value)) baseInput.value = effectiveBaseUrl;
4620
4656
  }
4621
4657
  updateApiRequestPreview();
4622
4658
  }
@@ -4732,7 +4768,10 @@ function renderServerAccess(info) {
4732
4768
  const baseInput = $('apiBaseUrlInput');
4733
4769
  if (baseInput && !baseInput.value.trim()) {
4734
4770
  const currentUrl = state.serverAccess.api_base_url || state.serverAccess.local_url || window.location.origin;
4735
- baseInput.value = normalizeApiBaseUrl(currentUrl);
4771
+ baseInput.value = apiBaseUrlForPage(currentUrl);
4772
+ } else if (baseInput && baseInput.value.trim()) {
4773
+ const effectiveBaseUrl = apiBaseUrlForPage(baseInput.value);
4774
+ if (effectiveBaseUrl !== normalizeApiBaseUrl(baseInput.value)) baseInput.value = effectiveBaseUrl;
4736
4775
  }
4737
4776
  if (!authEnabled) {
4738
4777
  clearWebAuthToken();
@@ -10369,7 +10408,7 @@ async function loadConfigLegacy() {
10369
10408
  const savedBaseUrl = data.server_access && data.server_access.api_base_url
10370
10409
  ? data.server_access.api_base_url
10371
10410
  : window.location.origin;
10372
- apiBaseInput.value = normalizeApiBaseUrl(savedBaseUrl);
10411
+ apiBaseInput.value = apiBaseUrlForPage(savedBaseUrl);
10373
10412
  }
10374
10413
  renderServerAccess(data.server_access);
10375
10414
  renderUserProfile(data.user_profile);
@@ -10430,7 +10469,7 @@ async function loadConfig() {
10430
10469
  const savedBaseUrl = data.server_access && data.server_access.api_base_url
10431
10470
  ? data.server_access.api_base_url
10432
10471
  : window.location.origin;
10433
- apiBaseInput.value = normalizeApiBaseUrl(savedBaseUrl);
10472
+ apiBaseInput.value = apiBaseUrlForPage(savedBaseUrl);
10434
10473
  }
10435
10474
  renderServerAccess(data.server_access);
10436
10475
  renderUserProfile(data.user_profile);
@@ -14027,4 +14066,3 @@ async function boot() {
14027
14066
  }
14028
14067
 
14029
14068
  boot().catch((error) => log('启动失败', { error: error.message }));
14030
-
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <title>cfquant 控制台</title>
7
7
  <link rel="icon" type="image/svg+xml" href="/favicon.svg">
8
- <link rel="stylesheet" href="/styles.css?v=web_20260922_04">
8
+ <link rel="stylesheet" href="/styles.css?v=web_20260923_02">
9
9
  </head>
10
10
  <body>
11
11
  <div id="webAuthOverlay" class="auth-overlay hidden" aria-live="polite">
@@ -3202,7 +3202,6 @@ else:
3202
3202
  <script src="/cftrader-api-data.js?v=20260911_02"></script>
3203
3203
  <script src="/api-tester.js?v=20260916_apikey_01"></script>
3204
3204
  <script src="/python-api.js?v=20260911_api_test_01"></script>
3205
- <script src="/app.js?v=web_20260922_04"></script>
3205
+ <script src="/app.js?v=web_20260923_02"></script>
3206
3206
  </body>
3207
3207
  </html>
3208
-
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
File without changes
File without changes
File without changes
File without changes
File without changes