cfquant 0.2.39__tar.gz → 0.2.40__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 (158) hide show
  1. {cfquant-0.2.39 → cfquant-0.2.40}/PKG-INFO +1 -1
  2. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/qmt_bridge.py +18 -13
  3. cfquant-0.2.40/cfquant/tests/test_order_time_callback.py +71 -0
  4. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tx_trade_bridge.py +17 -12
  5. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/version.py +2 -2
  6. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/xttype.py +43 -4
  7. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant.egg-info/PKG-INFO +1 -1
  8. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant.egg-info/SOURCES.txt +1 -0
  9. {cfquant-0.2.39 → cfquant-0.2.40}/pyproject.toml +1 -1
  10. {cfquant-0.2.39 → cfquant-0.2.40}/qmt_scripts/CFQUANT_LITE.py +27 -3
  11. {cfquant-0.2.39 → cfquant-0.2.40}/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 +27 -3
  12. {cfquant-0.2.39 → cfquant-0.2.40}/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 +27 -3
  13. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/app.js +4 -1
  14. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/index.html +2 -2
  15. {cfquant-0.2.39 → cfquant-0.2.40}/LICENSE +0 -0
  16. {cfquant-0.2.39 → cfquant-0.2.40}/LTtx/__init__.py +0 -0
  17. {cfquant-0.2.39 → cfquant-0.2.40}/LTtx/tx/Config.txt +0 -0
  18. {cfquant-0.2.39 → cfquant-0.2.40}/LTtx/tx/LTtx_server.py +0 -0
  19. {cfquant-0.2.39 → cfquant-0.2.40}/LTtx/tx/__init__.py +0 -0
  20. {cfquant-0.2.39 → cfquant-0.2.40}/LTtx/tx/tx.py +0 -0
  21. {cfquant-0.2.39 → cfquant-0.2.40}/MANIFEST.in +0 -0
  22. {cfquant-0.2.39 → cfquant-0.2.40}/README.md +0 -0
  23. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/__init__.py +0 -0
  24. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/_editable_install.py +0 -0
  25. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/account_routing.py +0 -0
  26. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/batch_orders.py +0 -0
  27. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/build_info.py +0 -0
  28. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/callback_dispatcher.py +0 -0
  29. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/cftrader.py +0 -0
  30. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/channels.py +0 -0
  31. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/cli.py +0 -0
  32. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/client.py +0 -0
  33. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/config.py +0 -0
  34. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/hub.py +0 -0
  35. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/level2.py +0 -0
  36. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/log_management.py +0 -0
  37. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/logging_i18n.py +0 -0
  38. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/normal_bridge.py +0 -0
  39. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/order_meta.py +0 -0
  40. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/pipe_bridge.py +0 -0
  41. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/pipe_client.py +0 -0
  42. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/pipe_hub.py +0 -0
  43. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/pipe_transport.py +0 -0
  44. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/protocol.py +0 -0
  45. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/qmt_strategy_deploy.py +0 -0
  46. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/qmt_strategy_package.py +0 -0
  47. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/qmt_strategy_runtime.py +0 -0
  48. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/runtime_report.py +0 -0
  49. {cfquant-0.2.39 → cfquant-0.2.40}/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
  50. {cfquant-0.2.39 → cfquant-0.2.40}/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
  51. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/12_/350/256/242/345/215/225/345/244/207/346/263/250/346/265/213/350/257/225.py" +0 -0
  52. {cfquant-0.2.39 → cfquant-0.2.40}/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
  53. {cfquant-0.2.39 → cfquant-0.2.40}/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
  54. {cfquant-0.2.39 → cfquant-0.2.40}/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
  55. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/16_/345/220/257/345/212/250/345/256/211/350/243/205/346/265/213/350/257/225.py" +0 -0
  56. {cfquant-0.2.39 → cfquant-0.2.40}/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
  57. {cfquant-0.2.39 → cfquant-0.2.40}/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
  58. {cfquant-0.2.39 → cfquant-0.2.40}/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
  59. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/1_/350/241/214/346/203/205/346/216/245/346/224/266/346/265/213/350/257/225.py" +0 -0
  60. {cfquant-0.2.39 → cfquant-0.2.40}/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
  61. {cfquant-0.2.39 → cfquant-0.2.40}/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
  62. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/22_/350/277/236/346/216/245/350/257/212/346/226/255/346/265/213/350/257/225.py" +0 -0
  63. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/23_/347/244/272/344/276/213/351/205/215/347/275/256/346/265/213/350/257/225.py" +0 -0
  64. {cfquant-0.2.39 → cfquant-0.2.40}/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
  65. {cfquant-0.2.39 → cfquant-0.2.40}/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
  66. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/26_/345/205/250/346/216/250/350/256/242/351/230/205/346/265/213/350/257/225.py" +0 -0
  67. {cfquant-0.2.39 → cfquant-0.2.40}/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
  68. {cfquant-0.2.39 → cfquant-0.2.40}/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
  69. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/29_Level2/350/241/214/346/203/205/346/265/213/350/257/225.py" +0 -0
  70. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/2_/346/225/260/346/215/256/350/216/267/345/217/226/346/265/213/350/257/225.py" +0 -0
  71. {cfquant-0.2.39 → cfquant-0.2.40}/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
  72. {cfquant-0.2.39 → cfquant-0.2.40}/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
  73. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/32_/345/274/202/346/255/245/344/270/213/345/215/225/346/265/213/350/257/225.py" +0 -0
  74. {cfquant-0.2.39 → cfquant-0.2.40}/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
  75. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/3_/346/225/260/346/215/256/344/270/213/350/275/275/346/265/213/350/257/225.py" +0 -0
  76. {cfquant-0.2.39 → cfquant-0.2.40}/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
  77. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/5_/347/234/237/345/256/236/344/270/213/345/215/225/346/265/213/350/257/225.py" +0 -0
  78. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/6_/345/233/236/350/260/203/346/265/213/350/257/225.py" +0 -0
  79. {cfquant-0.2.39 → cfquant-0.2.40}/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
  80. {cfquant-0.2.39 → cfquant-0.2.40}/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
  81. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/9_/345/217/257/346/222/244/350/256/242/345/215/225/346/265/213/350/257/225.py" +0 -0
  82. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/_helpers.py +0 -0
  83. {cfquant-0.2.39 → cfquant-0.2.40}/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
  84. {cfquant-0.2.39 → cfquant-0.2.40}/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
  85. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/readme.md +0 -0
  86. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_api_tester_browser.py +0 -0
  87. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_api_tester_web.py +0 -0
  88. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_binding_delete_confirmation.py +0 -0
  89. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_callback_requests.py +0 -0
  90. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_cftrader.py +0 -0
  91. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_cftrader_tutorial.py +0 -0
  92. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_cftrader_web.py +0 -0
  93. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_credit_compat.py +0 -0
  94. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_json_serialization.py +0 -0
  95. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_log_management.py +0 -0
  96. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_management_batch.py +0 -0
  97. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_project_updater.py +0 -0
  98. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_python_api_reference.py +0 -0
  99. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_qmt_strategy_browser.py +0 -0
  100. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_qmt_strategy_deploy.py +0 -0
  101. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_qmt_strategy_web.py +0 -0
  102. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_tutorial_reader.py +0 -0
  103. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tests/test_tx_auto_import.py +0 -0
  104. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/tx.py +0 -0
  105. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/xtconstant.py +0 -0
  106. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/xtdata.py +0 -0
  107. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant/xttrader.py +0 -0
  108. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant.egg-info/dependency_links.txt +0 -0
  109. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant.egg-info/entry_points.txt +0 -0
  110. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant.egg-info/requires.txt +0 -0
  111. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant.egg-info/top_level.txt +0 -0
  112. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant_pipe_hub.py +0 -0
  113. {cfquant-0.2.39 → cfquant-0.2.40}/cfquant_web_server.py +0 -0
  114. {cfquant-0.2.39 → cfquant-0.2.40}/qmt_scripts/CFQUANT.py +0 -0
  115. {cfquant-0.2.39 → cfquant-0.2.40}/qmt_scripts/CFQUANT_CTYPE_ALL_LOWLAT.py +0 -0
  116. {cfquant-0.2.39 → cfquant-0.2.40}/qmt_scripts/CFQUANT_TRADE_LOWLAT.py +0 -0
  117. {cfquant-0.2.39 → cfquant-0.2.40}/qmt_scripts/__init__.py +0 -0
  118. {cfquant-0.2.39 → cfquant-0.2.40}/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
  119. {cfquant-0.2.39 → cfquant-0.2.40}/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
  120. {cfquant-0.2.39 → cfquant-0.2.40}/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
  121. {cfquant-0.2.39 → cfquant-0.2.40}/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
  122. {cfquant-0.2.39 → cfquant-0.2.40}/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
  123. {cfquant-0.2.39 → cfquant-0.2.40}/requirements.txt +0 -0
  124. {cfquant-0.2.39 → cfquant-0.2.40}/setup.cfg +0 -0
  125. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/__init__.py +0 -0
  126. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/api-tester.js +0 -0
  127. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/avatars/amber-pulse.svg +0 -0
  128. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/avatars/copper-grid.svg +0 -0
  129. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/avatars/market-blue.svg +0 -0
  130. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/avatars/rose-circuit.svg +0 -0
  131. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/avatars/signal-green.svg +0 -0
  132. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/avatars/slate-wave.svg +0 -0
  133. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/avatars/teal-orbit.svg +0 -0
  134. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/avatars/violet-node.svg +0 -0
  135. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/cftrader-api-data.js +0 -0
  136. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/favicon.svg +0 -0
  137. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-10.png +0 -0
  138. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-11.png +0 -0
  139. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-12.png +0 -0
  140. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-13.png +0 -0
  141. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-14.png +0 -0
  142. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-15.png +0 -0
  143. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-16.png +0 -0
  144. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-17.png +0 -0
  145. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-18.png +0 -0
  146. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-19.png +0 -0
  147. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-20.png +0 -0
  148. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-21.png +0 -0
  149. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-4.png +0 -0
  150. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-5.png +0 -0
  151. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-6.png +0 -0
  152. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-7.png +0 -0
  153. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-8.png +0 -0
  154. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/image/qmt_deploy/image-9.png +0 -0
  155. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/python-api-data.js +0 -0
  156. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/python-api.js +0 -0
  157. {cfquant-0.2.39 → cfquant-0.2.40}/web_dashboard/styles.css +0 -0
  158. {cfquant-0.2.39 → cfquant-0.2.40}/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.39
3
+ Version: 0.2.40
4
4
  Summary: QMT local bridge and xtquant-compatible Python client.
5
5
  License: MIT
6
6
  Requires-Python: >=3.8
@@ -18,7 +18,7 @@ from .level2 import (
18
18
  require_l2_callable,
19
19
  thousand_price,
20
20
  )
21
- from .xttype import filter_cancelable_orders
21
+ from .xttype import _is_zero_time_value, filter_cancelable_orders
22
22
 
23
23
 
24
24
  class CfquantQmtBridge(object):
@@ -1111,23 +1111,26 @@ class CfquantQmtBridge(object):
1111
1111
  "order_time": self._first_value(obj, (
1112
1112
  "time",
1113
1113
  "order_time",
1114
- "entrust_time",
1114
+ "entrust_time",
1115
1115
  "insert_time",
1116
1116
  "m_strOrderTime",
1117
1117
  "m_strEntrustTime",
1118
1118
  "m_strInsertTime",
1119
- "m_nOrderTime",
1120
- "m_nEntrustTime",
1121
- "m_nInsertTime",
1122
- )),
1119
+ "m_nOrderTime",
1120
+ "m_nEntrustTime",
1121
+ "m_nInsertTime",
1122
+ ), skip_zero=True),
1123
1123
  "order_date": self._first_value(obj, (
1124
1124
  "order_date",
1125
1125
  "entrust_date",
1126
+ "insert_date",
1126
1127
  "m_strOrderDate",
1127
1128
  "m_strEntrustDate",
1129
+ "m_strInsertDate",
1128
1130
  "m_strTradingDay",
1129
1131
  "m_nOrderDate",
1130
1132
  "m_nEntrustDate",
1133
+ "m_nInsertDate",
1131
1134
  )),
1132
1135
  "direction": self._get_value(obj, "m_nDirection"),
1133
1136
  "offset_flag": self._get_value(obj, "m_nOffsetFlag"),
@@ -1205,7 +1208,7 @@ class CfquantQmtBridge(object):
1205
1208
  "m_strDealTime",
1206
1209
  "m_nTradeTime",
1207
1210
  "m_nDealTime",
1208
- )),
1211
+ ), skip_zero=True),
1209
1212
  "trade_date": self._first_value(obj, (
1210
1213
  "trade_date",
1211
1214
  "deal_date",
@@ -1377,12 +1380,14 @@ class CfquantQmtBridge(object):
1377
1380
  text = " ".join(str(value or "") for value in values).strip().lower()
1378
1381
  return "cfquant" if "cfquant" in text else "other"
1379
1382
 
1380
- def _first_value(self, obj, names):
1381
- for name in names:
1382
- value = self._get_value(obj, name)
1383
- if value is not None and value != "":
1384
- return value
1385
- return None
1383
+ def _first_value(self, obj, names, skip_zero=False):
1384
+ for name in names:
1385
+ value = self._get_value(obj, name)
1386
+ if value is not None and value != "":
1387
+ if skip_zero and _is_zero_time_value(value):
1388
+ continue
1389
+ return value
1390
+ return None
1386
1391
 
1387
1392
  def _object_to_dict(self, obj):
1388
1393
  if hasattr(obj, "items"):
@@ -0,0 +1,71 @@
1
+ import datetime
2
+ import json
3
+
4
+ from cfquant.normal_bridge import NormalQmtBridge
5
+ from cfquant.xttype import XtOrder
6
+
7
+
8
+ class RecordingTx(object):
9
+ def __init__(self):
10
+ self.pushes = []
11
+
12
+ def push(self, kind, payload, key):
13
+ self.pushes.append((kind, payload, key))
14
+
15
+
16
+ def _expected_timestamp(hour=21, minute=24, second=23):
17
+ timezone = datetime.timezone(datetime.timedelta(hours=8))
18
+ value = datetime.datetime(2026, 9, 24, hour, minute, second, tzinfo=timezone)
19
+ return int(value.timestamp())
20
+
21
+
22
+ def test_order_callback_skips_zero_placeholder_time():
23
+ raw = {
24
+ "time": 0,
25
+ "order_time": 0,
26
+ "m_strOrderTime": "212423",
27
+ "m_strOrderDate": "20260924",
28
+ "m_strAccountID": "A123",
29
+ "m_strInstrumentID": "000001",
30
+ "m_strExchangeID": "SZ",
31
+ }
32
+ bridge = NormalQmtBridge(None, show=False, schedule_timer=False, order_meta_enabled=False)
33
+ tx = RecordingTx()
34
+ bridge.tx = tx
35
+ try:
36
+ bridge.publish_callback_event("trader:on_stock_order", raw)
37
+ payload = json.loads(tx.pushes[-1][1])
38
+ assert payload["data"]["order_time"] == "212423"
39
+ assert XtOrder.from_any(payload["data"]).order_time == _expected_timestamp()
40
+ finally:
41
+ bridge.close()
42
+
43
+
44
+ def test_order_time_conversion_skips_zero_before_valid_qmt_time():
45
+ raw = {
46
+ "time": 0,
47
+ "m_strOrderTime": "212423",
48
+ "order_date": 0,
49
+ "m_strOrderDate": "20260924",
50
+ }
51
+ assert XtOrder.from_any(raw).order_time == _expected_timestamp()
52
+
53
+
54
+ def test_order_callback_uses_insert_time_and_insert_date():
55
+ raw = {
56
+ "time": 0,
57
+ "m_strOrderTime": None,
58
+ "m_strInsertTime": "112021",
59
+ "m_strInsertDate": "20260924",
60
+ "m_strAccountID": "A123",
61
+ "m_strInstrumentID": "688051",
62
+ "m_strExchangeID": "SH",
63
+ }
64
+ bridge = NormalQmtBridge(None, show=False, schedule_timer=False, order_meta_enabled=False)
65
+ try:
66
+ row = bridge._format_trade_detail(raw, "order")
67
+ assert row["order_time"] == "112021"
68
+ assert row["order_date"] == "20260924"
69
+ assert XtOrder.from_any(row).order_time == _expected_timestamp(11, 20, 21)
70
+ finally:
71
+ bridge.close()
@@ -30,7 +30,7 @@ from .runtime_report import build_qmt_runtime_report, module_source_state, sourc
30
30
  from .xttype import (
31
31
  CreditAssure, CreditSloCode, CreditSubjects, StkCompacts, XtCreditDetail, XtPositionStatistics,
32
32
  XtAccountInfo, XtAccountStatus, XtSmtAppointmentResponse,
33
- filter_cancelable_orders, normalize_order_price_type, _with_qmt_compact_aliases,
33
+ filter_cancelable_orders, normalize_order_price_type, _is_zero_time_value, _with_qmt_compact_aliases,
34
34
  )
35
35
 
36
36
 
@@ -3069,23 +3069,26 @@ class TxTradeBridge(object):
3069
3069
  "order_time": self._first_value(obj, (
3070
3070
  "time",
3071
3071
  "order_time",
3072
- "entrust_time",
3072
+ "entrust_time",
3073
3073
  "insert_time",
3074
3074
  "m_strOrderTime",
3075
3075
  "m_strEntrustTime",
3076
3076
  "m_strInsertTime",
3077
- "m_nOrderTime",
3078
- "m_nEntrustTime",
3079
- "m_nInsertTime",
3080
- )),
3077
+ "m_nOrderTime",
3078
+ "m_nEntrustTime",
3079
+ "m_nInsertTime",
3080
+ ), skip_zero=True),
3081
3081
  "order_date": self._first_value(obj, (
3082
3082
  "order_date",
3083
3083
  "entrust_date",
3084
+ "insert_date",
3084
3085
  "m_strOrderDate",
3085
3086
  "m_strEntrustDate",
3087
+ "m_strInsertDate",
3086
3088
  "m_strTradingDay",
3087
3089
  "m_nOrderDate",
3088
3090
  "m_nEntrustDate",
3091
+ "m_nInsertDate",
3089
3092
  )),
3090
3093
  "direction": self._get_value(obj, "m_nDirection"),
3091
3094
  "offset_flag": self._get_value(obj, "m_nOffsetFlag"),
@@ -3166,12 +3169,12 @@ class TxTradeBridge(object):
3166
3169
  "trade_time": self._first_value(obj, (
3167
3170
  "time",
3168
3171
  "trade_time",
3169
- "deal_time",
3172
+ "deal_time",
3170
3173
  "m_strTradeTime",
3171
3174
  "m_strDealTime",
3172
- "m_nTradeTime",
3173
- "m_nDealTime",
3174
- )),
3175
+ "m_nTradeTime",
3176
+ "m_nDealTime",
3177
+ ), skip_zero=True),
3175
3178
  "trade_date": self._first_value(obj, (
3176
3179
  "trade_date",
3177
3180
  "deal_date",
@@ -3286,11 +3289,13 @@ class TxTradeBridge(object):
3286
3289
  return value
3287
3290
  return None
3288
3291
 
3289
- def _first_value(self, obj, names):
3292
+ def _first_value(self, obj, names, skip_zero=False):
3290
3293
  for name in names:
3291
3294
  value = self._get_value(obj, name)
3292
3295
  if value is not None and value != "":
3293
- return value
3296
+ if skip_zero and _is_zero_time_value(value):
3297
+ continue
3298
+ return value
3294
3299
  return None
3295
3300
 
3296
3301
  def _stock_order_type(self, obj):
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """cfquant core version metadata."""
3
3
 
4
- __version__ = "0.2.39"
5
- WEB_VERSION = "web_20260923_03"
4
+ __version__ = "0.2.40"
5
+ WEB_VERSION = "web_20260924_01"
@@ -249,10 +249,49 @@ def _coerce_timestamp(value, date_value=None, default=0):
249
249
  return default
250
250
 
251
251
 
252
+ def _is_zero_time_value(value):
253
+ """Return whether a time field contains the provider's empty value."""
254
+ if value is None or isinstance(value, bool):
255
+ return True
256
+ if isinstance(value, (int, float)):
257
+ return value == 0
258
+ text = str(value).strip()
259
+ if not text:
260
+ return True
261
+ # QMT uses both numeric zero and display forms such as 00:00:00 for an
262
+ # unavailable order/trade time. Do not discard values such as 000001.
263
+ if re.fullmatch(r"[+-]?\d+(?:\.\d+)?", text):
264
+ try:
265
+ return float(text) == 0
266
+ except (TypeError, ValueError):
267
+ return False
268
+ digits = re.sub(r"\D", "", text)
269
+ return bool(digits) and not set(digits) - {"0"}
270
+
271
+
252
272
  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)
273
+ date_value = None
274
+ for name in _with_qmt_compact_aliases(*date_names):
275
+ if name not in data:
276
+ continue
277
+ candidate = data.get(name)
278
+ if _is_empty(candidate) or _is_zero_time_value(candidate):
279
+ continue
280
+ date_value = candidate
281
+ break
282
+ # A callback can expose a generic ``time``/canonical field as 0 while a
283
+ # later QMT field (for example m_strOrderTime) contains the real value.
284
+ # Try every candidate instead of letting the zero placeholder win.
285
+ for name in _with_qmt_compact_aliases(*time_names):
286
+ if name not in data:
287
+ continue
288
+ value = data.get(name)
289
+ if _is_empty(value) or _is_zero_time_value(value):
290
+ continue
291
+ timestamp = _coerce_timestamp(value, date_value)
292
+ if timestamp:
293
+ return timestamp
294
+ return 0
256
295
 
257
296
 
258
297
  def normalize_order_price_type(value, market=""):
@@ -636,7 +675,7 @@ class XtOrder(DictObject):
636
675
  data["order_time"] = _time_field_timestamp(
637
676
  data,
638
677
  ("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"),
678
+ ("order_date", "entrust_date", "insert_date", "m_strOrderDate", "m_strEntrustDate", "m_strInsertDate", "m_strTradingDay", "m_nOrderDate", "m_nEntrustDate", "m_nInsertDate"),
640
679
  )
641
680
  for name in ("order_type", "order_volume", "price_type", "traded_volume", "order_status", "direction", "offset_flag"):
642
681
  data[name] = _coerce_int(data.get(name))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cfquant
3
- Version: 0.2.39
3
+ Version: 0.2.40
4
4
  Summary: QMT local bridge and xtquant-compatible Python client.
5
5
  License: MIT
6
6
  Requires-Python: >=3.8
@@ -96,6 +96,7 @@ cfquant/tests/test_credit_compat.py
96
96
  cfquant/tests/test_json_serialization.py
97
97
  cfquant/tests/test_log_management.py
98
98
  cfquant/tests/test_management_batch.py
99
+ cfquant/tests/test_order_time_callback.py
99
100
  cfquant/tests/test_project_updater.py
100
101
  cfquant/tests/test_python_api_reference.py
101
102
  cfquant/tests/test_qmt_strategy_browser.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cfquant"
7
- version = "0.2.39"
7
+ version = "0.2.40"
8
8
  description = "QMT local bridge and xtquant-compatible Python client."
9
9
  license = {text = "MIT"}
10
10
  readme = "README.md"
@@ -1529,6 +1529,23 @@ def l2_query(func, period, params):
1529
1529
  return {"columns": columns, "records": rows}
1530
1530
 
1531
1531
 
1532
+ def _is_zero_time_value(value):
1533
+ if value is None or isinstance(value, bool):
1534
+ return True
1535
+ if isinstance(value, (int, float)):
1536
+ return value == 0
1537
+ text = str(value).strip()
1538
+ if not text:
1539
+ return True
1540
+ if re.fullmatch(r"[+-]?\d+(?:\.\d+)?", text):
1541
+ try:
1542
+ return float(text) == 0
1543
+ except (TypeError, ValueError):
1544
+ return False
1545
+ digits = re.sub(r"\D", "", text)
1546
+ return bool(digits) and not set(digits) - {"0"}
1547
+
1548
+
1532
1549
  class TxTradeBridge(object):
1533
1550
  def __init__(
1534
1551
  self,
@@ -3617,6 +3634,7 @@ class TxTradeBridge(object):
3617
3634
  "order_sysid": self._get_value(obj, "m_strOrderSysID"),
3618
3635
  "order_type": self._stock_order_type(obj),
3619
3636
  "order_time": self._first_value(obj, (
3637
+ "time",
3620
3638
  "order_time",
3621
3639
  "entrust_time",
3622
3640
  "insert_time",
@@ -3626,15 +3644,18 @@ class TxTradeBridge(object):
3626
3644
  "m_nOrderTime",
3627
3645
  "m_nEntrustTime",
3628
3646
  "m_nInsertTime",
3629
- )),
3647
+ ), skip_zero=True),
3630
3648
  "order_date": self._first_value(obj, (
3631
3649
  "order_date",
3632
3650
  "entrust_date",
3651
+ "insert_date",
3633
3652
  "m_strOrderDate",
3634
3653
  "m_strEntrustDate",
3654
+ "m_strInsertDate",
3635
3655
  "m_strTradingDay",
3636
3656
  "m_nOrderDate",
3637
3657
  "m_nEntrustDate",
3658
+ "m_nInsertDate",
3638
3659
  )),
3639
3660
  "direction": self._get_value(obj, "m_nDirection"),
3640
3661
  "offset_flag": self._get_value(obj, "m_nOffsetFlag"),
@@ -3707,13 +3728,14 @@ class TxTradeBridge(object):
3707
3728
  "strategy_name": self._get_value(obj, "m_strStrategyName"),
3708
3729
  "order_remark": self._first_value(obj, ("m_strRemark", "m_strOrderRemark")),
3709
3730
  "trade_time": self._first_value(obj, (
3731
+ "time",
3710
3732
  "trade_time",
3711
3733
  "deal_time",
3712
3734
  "m_strTradeTime",
3713
3735
  "m_strDealTime",
3714
3736
  "m_nTradeTime",
3715
3737
  "m_nDealTime",
3716
- )),
3738
+ ), skip_zero=True),
3717
3739
  "trade_date": self._first_value(obj, (
3718
3740
  "trade_date",
3719
3741
  "deal_date",
@@ -3850,10 +3872,12 @@ class TxTradeBridge(object):
3850
3872
  continue
3851
3873
  return value
3852
3874
  return None
3853
- def _first_value(self, obj, names):
3875
+ def _first_value(self, obj, names, skip_zero=False):
3854
3876
  for name in names:
3855
3877
  value = self._get_value(obj, name)
3856
3878
  if value is not None and value != "":
3879
+ if skip_zero and _is_zero_time_value(value):
3880
+ continue
3857
3881
  return value
3858
3882
  return None
3859
3883
 
@@ -1583,6 +1583,23 @@ def l2_query(func, period, params):
1583
1583
  return {"columns": columns, "records": rows}
1584
1584
 
1585
1585
 
1586
+ def _is_zero_time_value(value):
1587
+ if value is None or isinstance(value, bool):
1588
+ return True
1589
+ if isinstance(value, (int, float)):
1590
+ return value == 0
1591
+ text = str(value).strip()
1592
+ if not text:
1593
+ return True
1594
+ if re.fullmatch(r"[+-]?\d+(?:\.\d+)?", text):
1595
+ try:
1596
+ return float(text) == 0
1597
+ except (TypeError, ValueError):
1598
+ return False
1599
+ digits = re.sub(r"\D", "", text)
1600
+ return bool(digits) and not set(digits) - {"0"}
1601
+
1602
+
1586
1603
  class TxTradeBridge(object):
1587
1604
  def __init__(
1588
1605
  self,
@@ -3709,6 +3726,7 @@ class TxTradeBridge(object):
3709
3726
  "order_sysid": self._get_value(obj, "m_strOrderSysID"),
3710
3727
  "order_type": self._stock_order_type(obj),
3711
3728
  "order_time": self._first_value(obj, (
3729
+ "time",
3712
3730
  "order_time",
3713
3731
  "entrust_time",
3714
3732
  "insert_time",
@@ -3718,15 +3736,18 @@ class TxTradeBridge(object):
3718
3736
  "m_nOrderTime",
3719
3737
  "m_nEntrustTime",
3720
3738
  "m_nInsertTime",
3721
- )),
3739
+ ), skip_zero=True),
3722
3740
  "order_date": self._first_value(obj, (
3723
3741
  "order_date",
3724
3742
  "entrust_date",
3743
+ "insert_date",
3725
3744
  "m_strOrderDate",
3726
3745
  "m_strEntrustDate",
3746
+ "m_strInsertDate",
3727
3747
  "m_strTradingDay",
3728
3748
  "m_nOrderDate",
3729
3749
  "m_nEntrustDate",
3750
+ "m_nInsertDate",
3730
3751
  )),
3731
3752
  "direction": self._get_value(obj, "m_nDirection"),
3732
3753
  "offset_flag": self._get_value(obj, "m_nOffsetFlag"),
@@ -3799,13 +3820,14 @@ class TxTradeBridge(object):
3799
3820
  "strategy_name": self._get_value(obj, "m_strStrategyName"),
3800
3821
  "order_remark": self._first_value(obj, ("m_strRemark", "m_strOrderRemark")),
3801
3822
  "trade_time": self._first_value(obj, (
3823
+ "time",
3802
3824
  "trade_time",
3803
3825
  "deal_time",
3804
3826
  "m_strTradeTime",
3805
3827
  "m_strDealTime",
3806
3828
  "m_nTradeTime",
3807
3829
  "m_nDealTime",
3808
- )),
3830
+ ), skip_zero=True),
3809
3831
  "trade_date": self._first_value(obj, (
3810
3832
  "trade_date",
3811
3833
  "deal_date",
@@ -3942,10 +3964,12 @@ class TxTradeBridge(object):
3942
3964
  continue
3943
3965
  return value
3944
3966
  return None
3945
- def _first_value(self, obj, names):
3967
+ def _first_value(self, obj, names, skip_zero=False):
3946
3968
  for name in names:
3947
3969
  value = self._get_value(obj, name)
3948
3970
  if value is not None and value != "":
3971
+ if skip_zero and _is_zero_time_value(value):
3972
+ continue
3949
3973
  return value
3950
3974
  return None
3951
3975
 
@@ -1583,6 +1583,23 @@ def l2_query(func, period, params):
1583
1583
  return {"columns": columns, "records": rows}
1584
1584
 
1585
1585
 
1586
+ def _is_zero_time_value(value):
1587
+ if value is None or isinstance(value, bool):
1588
+ return True
1589
+ if isinstance(value, (int, float)):
1590
+ return value == 0
1591
+ text = str(value).strip()
1592
+ if not text:
1593
+ return True
1594
+ if re.fullmatch(r"[+-]?\d+(?:\.\d+)?", text):
1595
+ try:
1596
+ return float(text) == 0
1597
+ except (TypeError, ValueError):
1598
+ return False
1599
+ digits = re.sub(r"\D", "", text)
1600
+ return bool(digits) and not set(digits) - {"0"}
1601
+
1602
+
1586
1603
  class TxTradeBridge(object):
1587
1604
  def __init__(
1588
1605
  self,
@@ -3709,6 +3726,7 @@ class TxTradeBridge(object):
3709
3726
  "order_sysid": self._get_value(obj, "m_strOrderSysID"),
3710
3727
  "order_type": self._stock_order_type(obj),
3711
3728
  "order_time": self._first_value(obj, (
3729
+ "time",
3712
3730
  "order_time",
3713
3731
  "entrust_time",
3714
3732
  "insert_time",
@@ -3718,15 +3736,18 @@ class TxTradeBridge(object):
3718
3736
  "m_nOrderTime",
3719
3737
  "m_nEntrustTime",
3720
3738
  "m_nInsertTime",
3721
- )),
3739
+ ), skip_zero=True),
3722
3740
  "order_date": self._first_value(obj, (
3723
3741
  "order_date",
3724
3742
  "entrust_date",
3743
+ "insert_date",
3725
3744
  "m_strOrderDate",
3726
3745
  "m_strEntrustDate",
3746
+ "m_strInsertDate",
3727
3747
  "m_strTradingDay",
3728
3748
  "m_nOrderDate",
3729
3749
  "m_nEntrustDate",
3750
+ "m_nInsertDate",
3730
3751
  )),
3731
3752
  "direction": self._get_value(obj, "m_nDirection"),
3732
3753
  "offset_flag": self._get_value(obj, "m_nOffsetFlag"),
@@ -3799,13 +3820,14 @@ class TxTradeBridge(object):
3799
3820
  "strategy_name": self._get_value(obj, "m_strStrategyName"),
3800
3821
  "order_remark": self._first_value(obj, ("m_strRemark", "m_strOrderRemark")),
3801
3822
  "trade_time": self._first_value(obj, (
3823
+ "time",
3802
3824
  "trade_time",
3803
3825
  "deal_time",
3804
3826
  "m_strTradeTime",
3805
3827
  "m_strDealTime",
3806
3828
  "m_nTradeTime",
3807
3829
  "m_nDealTime",
3808
- )),
3830
+ ), skip_zero=True),
3809
3831
  "trade_date": self._first_value(obj, (
3810
3832
  "trade_date",
3811
3833
  "deal_date",
@@ -3942,10 +3964,12 @@ class TxTradeBridge(object):
3942
3964
  continue
3943
3965
  return value
3944
3966
  return None
3945
- def _first_value(self, obj, names):
3967
+ def _first_value(self, obj, names, skip_zero=False):
3946
3968
  for name in names:
3947
3969
  value = self._get_value(obj, name)
3948
3970
  if value is not None and value != "":
3971
+ if skip_zero and _is_zero_time_value(value):
3972
+ continue
3949
3973
  return value
3950
3974
  return None
3951
3975
 
@@ -1,4 +1,4 @@
1
- const FRONTEND_VERSION = 'web_20260923_03';
1
+ const FRONTEND_VERSION = 'web_20260924_01';
2
2
 
3
3
  const state = {
4
4
  accountId: '',
@@ -11029,11 +11029,14 @@ const ORDER_TIME_FIELDS = [
11029
11029
  const ORDER_DATE_FIELDS = [
11030
11030
  'order_date',
11031
11031
  'entrust_date',
11032
+ 'insert_date',
11032
11033
  'm_strOrderDate',
11033
11034
  'm_strEntrustDate',
11035
+ 'm_strInsertDate',
11034
11036
  'm_strTradingDay',
11035
11037
  'm_nOrderDate',
11036
11038
  'm_nEntrustDate',
11039
+ 'm_nInsertDate',
11037
11040
  ];
11038
11041
 
11039
11042
  const TRADE_TIME_FIELDS = [
@@ -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_20260923_03">
8
+ <link rel="stylesheet" href="/styles.css?v=web_20260924_01">
9
9
  </head>
10
10
  <body>
11
11
  <div id="webAuthOverlay" class="auth-overlay hidden" aria-live="polite">
@@ -3211,6 +3211,6 @@ else:
3211
3211
  <script src="/cftrader-api-data.js?v=20260911_02"></script>
3212
3212
  <script src="/api-tester.js?v=20260916_apikey_01"></script>
3213
3213
  <script src="/python-api.js?v=20260911_api_test_01"></script>
3214
- <script src="/app.js?v=web_20260923_03"></script>
3214
+ <script src="/app.js?v=web_20260924_01"></script>
3215
3215
  </body>
3216
3216
  </html>
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
File without changes