rqalpha 5.3.8__tar.gz → 5.3.10__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 (209) hide show
  1. {rqalpha-5.3.8/rqalpha.egg-info → rqalpha-5.3.10}/PKG-INFO +1 -1
  2. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/_version.py +3 -3
  3. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/apis/api_base.py +2 -5
  4. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/data/base_data_source/data_source.py +1 -1
  5. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/data/data_proxy.py +0 -2
  6. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/environment.py +32 -9
  7. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/interface.py +12 -7
  8. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_accounts/api/api_future.py +13 -15
  9. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_accounts/api/api_stock.py +20 -25
  10. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_accounts/component_validator.py +9 -15
  11. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_accounts/position_validator.py +13 -14
  12. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_accounts/validator.py +7 -11
  13. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_analyser/mod.py +53 -20
  14. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_analyser/report/excel_template.py +5 -3
  15. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_analyser/report/report.py +53 -8
  16. rqalpha-5.3.10/rqalpha/mod/rqalpha_mod_sys_analyser/report/templates/summary.xlsx +0 -0
  17. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_risk/validators/cash_validator.py +18 -19
  18. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_risk/validators/is_trading_validator.py +15 -13
  19. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_risk/validators/price_validator.py +12 -13
  20. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_risk/validators/self_trade_validator.py +11 -12
  21. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_simulation/matcher.py +31 -7
  22. rqalpha-5.3.10/rqalpha/mod/rqalpha_mod_sys_simulation/validator.py +20 -0
  23. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/portfolio/account.py +4 -1
  24. rqalpha-5.3.10/rqalpha/utils/translations/zh_Hans_CN/LC_MESSAGES/messages.mo +0 -0
  25. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/translations/zh_Hans_CN/LC_MESSAGES/messages.po +85 -72
  26. {rqalpha-5.3.8 → rqalpha-5.3.10/rqalpha.egg-info}/PKG-INFO +1 -1
  27. {rqalpha-5.3.8 → rqalpha-5.3.10}/setup.cfg +1 -1
  28. rqalpha-5.3.8/rqalpha/mod/rqalpha_mod_sys_analyser/report/templates/summary.xlsx +0 -0
  29. rqalpha-5.3.8/rqalpha/mod/rqalpha_mod_sys_simulation/validator.py +0 -18
  30. rqalpha-5.3.8/rqalpha/utils/translations/zh_Hans_CN/LC_MESSAGES/messages.mo +0 -0
  31. {rqalpha-5.3.8 → rqalpha-5.3.10}/CHANGELOG.rst +0 -0
  32. {rqalpha-5.3.8 → rqalpha-5.3.10}/LICENSE +0 -0
  33. {rqalpha-5.3.8 → rqalpha-5.3.10}/MANIFEST.in +0 -0
  34. {rqalpha-5.3.8 → rqalpha-5.3.10}/README.rst +0 -0
  35. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/__init__.py +0 -0
  36. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/__main__.py +0 -0
  37. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/api.py +0 -0
  38. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/apis/__init__.py +0 -0
  39. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/apis/api_abstract.py +0 -0
  40. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/apis/api_rqdatac.py +0 -0
  41. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/apis/names.py +0 -0
  42. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/cmds/__init__.py +0 -0
  43. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/cmds/bundle.py +0 -0
  44. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/cmds/entry.py +0 -0
  45. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/cmds/misc.py +0 -0
  46. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/cmds/mod.py +0 -0
  47. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/cmds/run.py +0 -0
  48. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/config.yml +0 -0
  49. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/const.py +0 -0
  50. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/core/__init__.py +0 -0
  51. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/core/events.py +0 -0
  52. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/core/execution_context.py +0 -0
  53. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/core/executor.py +0 -0
  54. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/core/global_var.py +0 -0
  55. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/core/strategy.py +0 -0
  56. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/core/strategy_context.py +0 -0
  57. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/core/strategy_loader.py +0 -0
  58. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/core/strategy_universe.py +0 -0
  59. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/data/__init__.py +0 -0
  60. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/data/bar_dict_price_board.py +0 -0
  61. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/data/base_data_source/__init__.py +0 -0
  62. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/data/base_data_source/adjust.py +0 -0
  63. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/data/base_data_source/storage_interface.py +0 -0
  64. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/data/base_data_source/storages.py +0 -0
  65. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/data/bundle.py +0 -0
  66. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/data/trading_dates_mixin.py +0 -0
  67. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/IF1706_20161108.csv +0 -0
  68. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/IF_macd.py +0 -0
  69. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/buy_and_hold.py +0 -0
  70. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/data_source/get_csv_module.py +0 -0
  71. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/data_source/import_get_csv_module.py +0 -0
  72. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/data_source/read_csv_as_df.py +0 -0
  73. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/extend_api/rqalpha_mod_extend_api_demo.py +0 -0
  74. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/extend_api/test_extend_api.py +0 -0
  75. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/golden_cross.py +0 -0
  76. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/macd.py +0 -0
  77. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/pair_trading.py +0 -0
  78. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/rsi.py +0 -0
  79. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/run_code_demo.py +0 -0
  80. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/run_file_demo.py +0 -0
  81. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/run_func_demo.py +0 -0
  82. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/subscribe_event.py +0 -0
  83. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/test_pt.py +0 -0
  84. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/examples/turtle.py +0 -0
  85. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/main.py +0 -0
  86. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/__init__.py +0 -0
  87. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_accounts/__init__.py +0 -0
  88. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_accounts/api/__init__.py +0 -0
  89. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_accounts/mod.py +0 -0
  90. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_accounts/position_model.py +0 -0
  91. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_analyser/__init__.py +0 -0
  92. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_analyser/plot/__init__.py +0 -0
  93. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_analyser/plot/consts.py +0 -0
  94. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_analyser/plot/plot.py +0 -0
  95. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_analyser/plot/utils.py +0 -0
  96. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_analyser/plot_store.py +0 -0
  97. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_analyser/report/__init__.py +0 -0
  98. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_progress/__init__.py +0 -0
  99. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_progress/mod.py +0 -0
  100. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_risk/__init__.py +0 -0
  101. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_risk/mod.py +0 -0
  102. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_risk/validators/__init__.py +0 -0
  103. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_scheduler/__init__.py +0 -0
  104. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_scheduler/mod.py +0 -0
  105. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_scheduler/scheduler.py +0 -0
  106. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_simulation/__init__.py +0 -0
  107. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_simulation/mod.py +0 -0
  108. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_simulation/signal_broker.py +0 -0
  109. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_simulation/simulation_broker.py +0 -0
  110. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_simulation/simulation_event_source.py +0 -0
  111. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_simulation/slippage.py +0 -0
  112. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_simulation/testing.py +0 -0
  113. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_transaction_cost/__init__.py +0 -0
  114. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_transaction_cost/deciders.py +0 -0
  115. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/rqalpha_mod_sys_transaction_cost/mod.py +0 -0
  116. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod/utils.py +0 -0
  117. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/mod_config.yml +0 -0
  118. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/model/__init__.py +0 -0
  119. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/model/bar.py +0 -0
  120. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/model/instrument.py +0 -0
  121. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/model/order.py +0 -0
  122. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/model/tick.py +0 -0
  123. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/model/trade.py +0 -0
  124. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/portfolio/__init__.py +0 -0
  125. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/portfolio/position.py +0 -0
  126. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/resource/ricequant-logo.png +0 -0
  127. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/user_module.py +0 -0
  128. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/__init__.py +0 -0
  129. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/arg_checker.py +0 -0
  130. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/class_helper.py +0 -0
  131. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/click_helper.py +0 -0
  132. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/concurrent.py +0 -0
  133. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/config.py +0 -0
  134. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/datetime_func.py +0 -0
  135. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/dict_func.py +0 -0
  136. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/exception.py +0 -0
  137. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/functools.py +0 -0
  138. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/i18n.py +0 -0
  139. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/log_capture.py +0 -0
  140. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/logger.py +0 -0
  141. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/package_helper.py +0 -0
  142. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/persisit_helper.py +0 -0
  143. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/repr.py +0 -0
  144. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/risk_free_helper.py +0 -0
  145. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/rq_json.py +0 -0
  146. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/strategy_loader_help.py +0 -0
  147. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/testing/__init__.py +0 -0
  148. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/testing/fixtures.py +0 -0
  149. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/testing/mocking.py +0 -0
  150. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/translations/__init__.py +0 -0
  151. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/translations/zh_Hans_CN/LC_MESSAGES/__init__.py +0 -0
  152. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/translations/zh_Hans_CN/__init__.py +0 -0
  153. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha/utils/typing.py +0 -0
  154. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha.egg-info/SOURCES.txt +0 -0
  155. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha.egg-info/dependency_links.txt +0 -0
  156. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha.egg-info/entry_points.txt +0 -0
  157. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha.egg-info/not-zip-safe +0 -0
  158. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha.egg-info/requires.txt +0 -0
  159. {rqalpha-5.3.8 → rqalpha-5.3.10}/rqalpha.egg-info/top_level.txt +0 -0
  160. {rqalpha-5.3.8 → rqalpha-5.3.10}/setup.py +0 -0
  161. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/__init__.py +0 -0
  162. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/__init__.py +0 -0
  163. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/__init__.py +0 -0
  164. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_accounts/__init__.py +0 -0
  165. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_accounts/test_account_model.py +0 -0
  166. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_accounts/test_futures_settlement_price_type.py +0 -0
  167. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_accounts/test_margin_stocks.py +0 -0
  168. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_accounts/test_position_models.py +0 -0
  169. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_scheduler/__init__.py +0 -0
  170. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_scheduler/test_physical_time.py +0 -0
  171. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_scheduler/test_scheduler.py +0 -0
  172. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_simulation/__init__.py +0 -0
  173. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_simulation/test_management_fee.py +0 -0
  174. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_simulation/test_match.py +0 -0
  175. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_simulation/test_signal_broker.py +0 -0
  176. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_simulation/test_simulation_broker.py +0 -0
  177. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_simulation/test_simulation_event_source.py +0 -0
  178. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_transaction_cost/__init__.py +0 -0
  179. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/mod/sys_transaction_cost/test_commission_multiplier.py +0 -0
  180. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/test_api_base.py +0 -0
  181. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/test_api_future.py +0 -0
  182. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/test_api_stock.py +0 -0
  183. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/test_config.py +0 -0
  184. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/api_tests/utils.py +0 -0
  185. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/test_f_buy_and_hold.py +0 -0
  186. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/test_f_delivery.py +0 -0
  187. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/test_f_macd.py +0 -0
  188. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/test_f_macd_signal.py +0 -0
  189. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/test_f_mean_reverting.py +0 -0
  190. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/test_f_tick_size.py +0 -0
  191. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/test_s_buy_and_hold.py +0 -0
  192. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/test_s_dual_thrust.py +0 -0
  193. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/test_s_pit_tax.py +0 -0
  194. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/test_s_scheduler.py +0 -0
  195. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/test_s_tick_size.py +0 -0
  196. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/test_s_turtle.py +0 -0
  197. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/test_s_turtle_signal.py +0 -0
  198. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/test_sf_buy_and_hold.py +0 -0
  199. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/unittest/__init__.py +0 -0
  200. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/unittest/test_data/__init__.py +0 -0
  201. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/unittest/test_data/test_auto_update_bundle/__init__.py +0 -0
  202. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/unittest/test_data/test_auto_update_bundle/test_auto_update_bundle_mixin.py +0 -0
  203. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/unittest/test_data/test_instrument_mixin.py +0 -0
  204. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/unittest/test_data/test_trading_dates_mixin.py +0 -0
  205. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/unittest/test_mod/__init__.py +0 -0
  206. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/unittest/test_mod/test_sys_simulation/__init__.py +0 -0
  207. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/unittest/test_mod/test_sys_simulation/test_simulation_event_source.py +0 -0
  208. {rqalpha-5.3.8 → rqalpha-5.3.10}/tests/utils.py +0 -0
  209. {rqalpha-5.3.8 → rqalpha-5.3.10}/versioneer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: rqalpha
3
- Version: 5.3.8
3
+ Version: 5.3.10
4
4
  Summary: Ricequant Algorithm Trading System
5
5
  Home-page: https://github.com/ricequant/rqalpha
6
6
  Author: ricequant
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2024-03-27T18:19:51+0800",
11
+ "date": "2024-04-25T10:32:21+0800",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "7322d2b4d1da97bcde04288d0bd114624dc4c6d2",
15
- "version": "5.3.8"
14
+ "full-revisionid": "215d9b2f7ef5175ff99ced5555a81ff7295416c2",
15
+ "version": "5.3.10"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -170,11 +170,8 @@ def submit_order(id_or_ins, amount, side, price=None, position_effect=None):
170
170
  style = cal_style(price, None)
171
171
  market_price = env.get_last_price(order_book_id)
172
172
  if not is_valid_price(market_price):
173
- user_system_log.warn(
174
- _(u"Order Creation Failed: [{order_book_id}] No market data").format(
175
- order_book_id=order_book_id
176
- )
177
- )
173
+ reason = _(u"Order Creation Failed: [{order_book_id}] No market data").format(order_book_id=order_book_id)
174
+ env.order_creation_failed(order_book_id, reason)
178
175
  return
179
176
 
180
177
  amount = int(amount)
@@ -42,7 +42,7 @@ from rqalpha.data.base_data_source.storages import (DateSet, DayBarStore, Divide
42
42
  ExchangeTradingCalendarStore, FutureDayBarStore,
43
43
  FutureInfoStore, FuturesTradingParametersStore,InstrumentStore,
44
44
  ShareTransformationStore, SimpleFactorStore,
45
- YieldCurveStore)
45
+ YieldCurveStore, FuturesTradingParameters)
46
46
 
47
47
 
48
48
  BAR_RESAMPLE_FIELD_METHODS = {
@@ -326,5 +326,3 @@ class DataProxy(TradingDatesMixin):
326
326
  return np.nan, 0
327
327
  bar = self._data_source.get_algo_bar(id_or_ins, order_style.start_min, order_style.end_min, dt)
328
328
  return (bar[order_style.TYPE], bar["volume"]) if bar else (np.nan, 0)
329
-
330
-
@@ -18,13 +18,16 @@
18
18
  from datetime import datetime
19
19
  from typing import Optional, Dict, List
20
20
  from itertools import chain
21
+ from typing import TYPE_CHECKING
21
22
 
22
23
  import rqalpha
23
- from rqalpha.core.events import EventBus
24
+ from rqalpha.core.events import EventBus, Event, EVENT
24
25
  from rqalpha.const import INSTRUMENT_TYPE
25
26
  from rqalpha.utils.logger import system_log, user_log, user_system_log
26
27
  from rqalpha.core.global_var import GlobalVars
27
28
  from rqalpha.utils.i18n import gettext as _
29
+ if TYPE_CHECKING:
30
+ from rqalpha.model.order import Order
28
31
 
29
32
 
30
33
  class Environment(object):
@@ -114,9 +117,7 @@ class Environment(object):
114
117
  return chain(self._frontend_validators.get(instrument_type, []), self._default_frontend_validators)
115
118
 
116
119
  def submit_order(self, order):
117
- instrument_type = self.data_proxy.instrument(order.order_book_id).type
118
- account = self.portfolio.get_account(order.order_book_id)
119
- if all(v.can_submit_order(order, account) for v in self._get_frontend_validators(instrument_type)):
120
+ if self.can_submit_order(order):
120
121
  self.broker.submit_order(order)
121
122
  return order
122
123
 
@@ -124,9 +125,24 @@ class Environment(object):
124
125
  instrument_type = self.data_proxy.instrument(order.order_book_id).type
125
126
  account = self.portfolio.get_account(order.order_book_id)
126
127
  for v in chain(self._frontend_validators.get(instrument_type, []), self._default_frontend_validators):
127
- if not v.can_cancel_order(order, account):
128
- return False
128
+ try:
129
+ reason = v.validate_cancellation(order, account)
130
+ if reason:
131
+ self.order_cancellation_failed(order_book_id=order.order_book_id, reason=reason)
132
+ return False
133
+ except NotImplementedError:
134
+ # 避免由于某些 mod 版本未更新,Validator method 未修改
135
+ if not v.can_cancel_order(order, account):
136
+ return False
129
137
  return True
138
+
139
+ def order_creation_failed(self, order_book_id, reason):
140
+ user_system_log.warn(reason)
141
+ self.event_bus.publish_event(Event(EVENT.ORDER_CREATION_REJECT, order_book_id=order_book_id, reason=reason))
142
+
143
+ def order_cancellation_failed(self, order_book_id, reason):
144
+ user_system_log.warn(reason)
145
+ self.event_bus.publish_event(Event(EVENT.ORDER_CANCELLATION_REJECT, order_book_id=order_book_id, reason=reason))
130
146
 
131
147
  def get_universe(self):
132
148
  return self._universe.get()
@@ -179,11 +195,18 @@ class Environment(object):
179
195
  self.calendar_dt = calendar_dt
180
196
  self.trading_dt = trading_dt
181
197
 
182
- def can_submit_order(self, order):
198
+ def can_submit_order(self, order: 'Order') -> bool:
183
199
  # forward compatible
184
200
  instrument_type = self.data_proxy.instrument(order.order_book_id).type
185
201
  account = self.portfolio.get_account(order.order_book_id)
186
202
  for v in self._get_frontend_validators(instrument_type):
187
- if not v.can_submit_order(order, account):
188
- return False
203
+ try:
204
+ reason = v.validate_submission(order, account)
205
+ if reason:
206
+ self.order_creation_failed(order_book_id=order.order_book_id, reason=reason)
207
+ return False
208
+ except NotImplementedError:
209
+ # 避免由于某些 mod 版本未更新,Validator method 未修改
210
+ if not v.can_submit_order(order, account):
211
+ return False
189
212
  return True
@@ -17,7 +17,9 @@
17
17
 
18
18
  import abc
19
19
  from datetime import datetime, date
20
- from typing import Any, Union, Optional, Iterable, Dict, List, Sequence
20
+ from typing import Any, Union, Optional, Iterable, Dict, List, Sequence, TYPE_CHECKING
21
+ if TYPE_CHECKING:
22
+ from rqalpha.portfolio.account import Account
21
23
 
22
24
  import numpy
23
25
  from six import with_metaclass
@@ -649,18 +651,21 @@ class AbstractFrontendValidator(with_metaclass(abc.ABCMeta)):
649
651
 
650
652
  扩展模块可以通过 env.add_frontend_validator 添加自定义的前端风控逻辑
651
653
  """
652
-
653
654
  @abc.abstractmethod
654
- def can_submit_order(self, order, account=None):
655
+ def validate_submission(self, order: Order, account: Optional['Account'] = None) -> Optional[str]:
655
656
  """
656
- 判断是否可以下单
657
+ 进行下单前的验证,若通过则返回 None
658
+
659
+ :return: `Optional[str]`
657
660
  """
658
661
  raise NotImplementedError
659
-
662
+
660
663
  @abc.abstractmethod
661
- def can_cancel_order(self, order, account=None):
664
+ def validate_cancellation(self, order: Order, account: Optional['Account'] = None) -> Optional[str]:
662
665
  """
663
- 判读是否可以撤单
666
+ 进行撤销订单前的验证,若通过则返回 None
667
+
668
+ :return: `Optional[str]`
664
669
  """
665
670
  raise NotImplementedError
666
671
 
@@ -47,9 +47,10 @@ def _submit_order(id_or_ins, amount, side, position_effect, style):
47
47
 
48
48
  amount = int(amount)
49
49
  if amount == 0:
50
- user_system_log.warn(_(
51
- u"Order Creation Failed: 0 order quantity, order_book_id={order_book_id}"
52
- ).format(order_book_id=order_book_id))
50
+ reason = _(u"Order Creation Failed: 0 order quantity, order_book_id={order_book_id}").format(
51
+ order_book_id=order_book_id
52
+ )
53
+ env.order_creation_failed(order_book_id=order_book_id, reason=reason)
53
54
  return None
54
55
  if isinstance(style, LimitOrder) and np.isnan(style.get_limit_price()):
55
56
  raise RQInvalidArgument(_(u"Limit order price should not be nan."))
@@ -62,23 +63,21 @@ def _submit_order(id_or_ins, amount, side, position_effect, style):
62
63
 
63
64
  price = env.get_last_price(order_book_id)
64
65
  if not is_valid_price(price):
65
- user_system_log.warn(
66
- _(u"Order Creation Failed: [{order_book_id}] No market data").format(order_book_id=order_book_id)
67
- )
66
+ reason = _(u"Order Creation Failed: [{order_book_id}] No market data").format(order_book_id=order_book_id)
67
+ env.order_creation_failed(order_book_id=order_book_id, reason=reason)
68
68
  return
69
69
 
70
- env = Environment.get_instance()
71
-
72
70
  orders = []
73
71
  if position_effect in (POSITION_EFFECT.CLOSE_TODAY, POSITION_EFFECT.CLOSE):
74
72
  direction = POSITION_DIRECTION.LONG if side == SIDE.SELL else POSITION_DIRECTION.SHORT
75
73
  position = env.portfolio.get_position(order_book_id, direction) # type: Position
76
74
  if position_effect == POSITION_EFFECT.CLOSE_TODAY:
77
75
  if amount > position.today_closable:
78
- user_system_log.warning(_(
76
+ reason = _(
79
77
  "Order Creation Failed: "
80
- "close today amount {amount} is larger than today closable quantity {quantity}"
81
- ).format(amount=amount, quantity=position.today_closable))
78
+ "close today amount {amount} is larger than today closable quantity {quantity}").format(
79
+ amount=amount, quantity=position.today_closable)
80
+ env.order_creation_failed(order_book_id=order_book_id, reason=reason)
82
81
  return []
83
82
  orders.append(Order.__from_create__(
84
83
  order_book_id, amount, side, style, POSITION_EFFECT.CLOSE_TODAY
@@ -86,10 +85,9 @@ def _submit_order(id_or_ins, amount, side, position_effect, style):
86
85
  else:
87
86
  quantity, old_quantity = position.quantity, position.old_quantity
88
87
  if amount > quantity:
89
- user_system_log.warn(_(
90
- u"Order Creation Failed: close amount {amount} is larger than position quantity {quantity}").format(
91
- amount=amount, quantity=quantity
92
- ))
88
+ reason = _(u"Order Creation Failed: close amount {amount} is larger than position quantity {quantity}").format(
89
+ amount=amount, quantity=quantity)
90
+ env.order_creation_failed(order_book_id=order_book_id, reason=reason)
93
91
  return []
94
92
  if amount > old_quantity:
95
93
  if old_quantity != 0:
@@ -34,9 +34,9 @@ from rqalpha.const import (DEFAULT_ACCOUNT_TYPE, EXECUTION_PHASE,
34
34
  INSTRUMENT_TYPE, ORDER_TYPE, POSITION_DIRECTION,
35
35
  POSITION_EFFECT, SIDE)
36
36
  from rqalpha.core.execution_context import ExecutionContext
37
+ from rqalpha.core.events import Event, EVENT
37
38
  from rqalpha.environment import Environment
38
- from rqalpha.mod.rqalpha_mod_sys_risk.validators.cash_validator import \
39
- is_cash_enough
39
+ from rqalpha.mod.rqalpha_mod_sys_risk.validators.cash_validator import validate_cash
40
40
  from rqalpha.model.instrument import IndustryCode as industry_code
41
41
  from rqalpha.model.instrument import IndustryCodeItem, Instrument
42
42
  from rqalpha.model.instrument import SectorCode as sector_code
@@ -100,8 +100,8 @@ def _submit_order(ins, amount, side, position_effect, style, current_quantity, a
100
100
  raise RQInvalidArgument(_(u"Limit order price should not be nan."))
101
101
  price = env.data_proxy.get_last_price(ins.order_book_id)
102
102
  if not is_valid_price(price):
103
- user_system_log.warn(
104
- _(u"Order Creation Failed: [{order_book_id}] No market data").format(order_book_id=ins.order_book_id))
103
+ reason = _(u"Order Creation Failed: [{order_book_id}] No market data").format(order_book_id=ins.order_book_id)
104
+ env.order_creation_failed(order_book_id=ins.order_book_id, reason=reason)
105
105
  return
106
106
 
107
107
  if (side == SIDE.BUY and current_quantity != -amount) or (side == SIDE.SELL and current_quantity != abs(amount)):
@@ -109,14 +109,13 @@ def _submit_order(ins, amount, side, position_effect, style, current_quantity, a
109
109
  amount = _round_order_quantity(ins, amount)
110
110
 
111
111
  if amount == 0:
112
- user_system_log.warn(_(
113
- u"Order Creation Failed: 0 order quantity, order_book_id={order_book_id}"
114
- ).format(order_book_id=ins.order_book_id))
112
+ reason = _(u"Order Creation Failed: 0 order quantity, order_book_id={order_book_id}").format(order_book_id=ins.order_book_id)
113
+ env.order_creation_failed(order_book_id=ins.order_book_id, reason=reason)
115
114
  return
116
115
  order = Order.__from_create__(ins.order_book_id, abs(amount), side, style, position_effect)
117
116
  if side == SIDE.BUY and auto_switch_order_value:
118
117
  account, position, ins = _get_account_position_ins(ins)
119
- if not is_cash_enough(env, order, account.cash):
118
+ if validate_cash(env, order, account.cash):
120
119
  user_system_log.warn(_(
121
120
  "insufficient cash, use all remaining cash({}) to create order"
122
121
  ).format(account.cash))
@@ -129,7 +128,7 @@ def _order_shares(ins, amount, style, quantity, auto_switch_order_value):
129
128
  return _submit_order(ins, amount, side, position_effect, style, quantity, auto_switch_order_value)
130
129
 
131
130
 
132
- def _order_value(account, position, ins, cash_amount, style):
131
+ def _order_value(account, position, ins, cash_amount, style, zero_amount_as_exception=True):
133
132
  env = Environment.get_instance()
134
133
  if cash_amount > 0:
135
134
  cash_amount = min(cash_amount, account.cash)
@@ -138,9 +137,8 @@ def _order_value(account, position, ins, cash_amount, style):
138
137
  else:
139
138
  price = env.data_proxy.get_last_price(ins.order_book_id)
140
139
  if not is_valid_price(price):
141
- user_system_log.warn(
142
- _(u"Order Creation Failed: [{order_book_id}] No market data").format(order_book_id=ins.order_book_id)
143
- )
140
+ reason = _(u"Order Creation Failed: [{order_book_id}] No market data").format(order_book_id=ins.order_book_id)
141
+ env.order_creation_failed(order_book_id=ins.order_book_id, reason=reason)
144
142
  return
145
143
 
146
144
  amount = int(Decimal(cash_amount) / Decimal(price))
@@ -155,9 +153,9 @@ def _order_value(account, position, ins, cash_amount, style):
155
153
  break
156
154
  amount -= round_lot
157
155
  else:
158
- user_system_log.warn(_(
159
- u"Order Creation Failed: 0 order quantity, order_book_id={order_book_id}"
160
- ).format(order_book_id=ins.order_book_id))
156
+ if zero_amount_as_exception:
157
+ reason = _(u"Order Creation Failed: 0 order quantity, order_book_id={order_book_id}").format(order_book_id=ins.order_book_id)
158
+ env.order_creation_failed(order_book_id=ins.order_book_id, reason=reason)
161
159
  return
162
160
 
163
161
  if amount < 0:
@@ -198,7 +196,7 @@ def stock_order_target_value(id_or_ins, cash_amount, price_or_style=None, price=
198
196
  )
199
197
  _delta = cash_amount - position.market_value
200
198
  _style = open_style if _delta > 0 else close_style
201
- return _order_value(account, position, ins, _delta, _style)
199
+ return _order_value(account, position, ins, _delta, _style, zero_amount_as_exception=False)
202
200
 
203
201
 
204
202
  @order_target_percent.register(INST_TYPE_IN_STOCK_ACCOUNT)
@@ -211,7 +209,7 @@ def stock_order_target_percent(id_or_ins, percent, price_or_style=None, price=No
211
209
  )
212
210
  _delta = account.total_value * percent - position.market_value
213
211
  _style = open_style if _delta > 0 else close_style
214
- return _order_value(account, position, ins, _delta, _style)
212
+ return _order_value(account, position, ins, _delta, _style, zero_amount_as_exception=False)
215
213
 
216
214
 
217
215
  @order.register(INST_TYPE_IN_STOCK_ACCOUNT)
@@ -342,9 +340,8 @@ def order_target_portfolio(
342
340
  order_book_id = ins.order_book_id
343
341
  last_price = env.data_proxy.get_last_price(order_book_id)
344
342
  if not is_valid_price(last_price):
345
- user_system_log.warn(
346
- _(u"Order Creation Failed: [{order_book_id}] No market data").format(order_book_id=order_book_id)
347
- )
343
+ reason = _(u"Order Creation Failed: [{order_book_id}] No market data").format(order_book_id=order_book_id)
344
+ env.order_creation_failed(order_book_id=order_book_id, reason=reason)
348
345
  continue
349
346
 
350
347
  price_or_style = price_or_styles.get(ins.order_book_id)
@@ -380,12 +377,10 @@ def order_target_portfolio(
380
377
  open_price = _get_order_style_price(order_book_id, open_style)
381
378
  close_price = _get_order_style_price(order_book_id, close_style)
382
379
  if not (is_valid_price(close_price) and is_valid_price(open_price)):
383
- user_system_log.warn(_(
384
- "Adjust position of {id_or_ins} Failed: "
385
- "Invalid close/open price {close_price}/{open_price}").format(
386
- id_or_ins=order_book_id, close_price=close_price, open_price=open_price
387
- )
380
+ reason = _("Adjust position of {id_or_ins} Failed: Invalid close/open price {close_price}/{open_price}").format(
381
+ id_or_ins=order_book_id, close_price=close_price, open_price=open_price
388
382
  )
383
+ env.order_creation_failed(order_book_id=order_book_id, reason=reason)
389
384
  continue
390
385
 
391
386
  delta_quantity = (account_value * target_percent / close_price) - current_quantities.get(order_book_id, 0)
@@ -13,24 +13,18 @@ class MarginComponentValidator(AbstractFrontendValidator):
13
13
  self._margin_type = margin_type
14
14
  from rqalpha.apis.api_rqdatac import get_margin_stocks
15
15
  self._get_margin_stocks = get_margin_stocks
16
-
17
- def can_cancel_order(self, order, account=None):
18
- return True
19
-
20
- def can_submit_order(self, order, account=None):
21
- # type: (Order, Optional[Account]) -> bool
22
-
16
+
17
+ def validate_submission(self, order: Order, account: Optional[Account] = None) -> Optional[str]:
23
18
  # 没负债等于没融资,则不需要限制股票池
24
19
  if account.cash_liabilities == 0:
25
- return True
26
-
20
+ return None
27
21
  symbols = self._get_margin_stocks(margin_type=self._margin_type)
28
-
29
22
  # 是否在股票池中
30
23
  if order.order_book_id in set(symbols):
31
- return True
24
+ return None
32
25
  else:
33
- user_system_log.warn("Order Creation Failed: margin stock pool not contains {}.".format(
34
- order.order_book_id)
35
- )
36
- return False
26
+ reason = "Order Creation Failed: margin stock pool not contains {}.".format(order.order_book_id)
27
+ return reason
28
+
29
+ def validate_cancellation(self, order: Order, account: Optional[Account] = None) -> Optional[str]:
30
+ return None
@@ -27,32 +27,31 @@ from rqalpha.utils.i18n import gettext as _
27
27
 
28
28
 
29
29
  class PositionValidator(AbstractFrontendValidator):
30
- def can_cancel_order(self, order, account=None):
31
- return True
32
-
33
- def can_submit_order(self, order, account=None):
34
- # type: (Order, Optional[Account]) -> bool
30
+ def validate_cancellation(self, order: Order, account: Optional[Account] = None) -> Optional[str]:
31
+ return None
32
+
33
+ def validate_submission(self, order: Order, account: Optional[Account] = None) -> Optional[str]:
35
34
  if account is None:
36
- return True
35
+ return None
37
36
  if order.position_effect in (POSITION_EFFECT.OPEN, POSITION_EFFECT.EXERCISE):
38
- return True
37
+ return None
39
38
  position = account.get_position(order.order_book_id, order.position_direction) # type: AbstractPosition
40
39
  if order.position_effect == POSITION_EFFECT.CLOSE_TODAY and order.quantity > position.today_closable:
41
- user_system_log.warn(_(
40
+ reason = _(
42
41
  "Order Creation Failed: not enough today position {order_book_id} to close, target"
43
42
  " quantity is {quantity}, closable today quantity is {closable}").format(
44
43
  order_book_id=order.order_book_id,
45
44
  quantity=order.quantity,
46
45
  closable=position.today_closable,
47
- ))
48
- return False
46
+ )
47
+ return reason
49
48
  if order.position_effect == POSITION_EFFECT.CLOSE and order.quantity > position.closable:
50
- user_system_log.warn(_(
49
+ reason = _(
51
50
  "Order Creation Failed: not enough position {order_book_id} to close or exercise, target"
52
51
  " sell quantity is {quantity}, closable quantity is {closable}").format(
53
52
  order_book_id=order.order_book_id,
54
53
  quantity=order.quantity,
55
54
  closable=position.closable,
56
- ))
57
- return False
58
- return True
55
+ )
56
+ return reason
57
+ return None
@@ -9,16 +9,12 @@ from rqalpha.portfolio.account import Account
9
9
  class MarginInstrumentValidator(AbstractFrontendValidator):
10
10
  """ 融资下单品种限制: 当开启股票池限制且有融资余额时只能交易股票和ETF """
11
11
 
12
- def can_cancel_order(self, order, account=None):
13
- return True
14
-
15
- def can_submit_order(self, order, account=None):
16
- # type: (Order, Optional[Account]) -> bool
17
-
12
+ def validate_submission(self, order: Order, account: Optional[Account] = None) -> Optional[str]:
18
13
  if account.cash_liabilities > 0:
19
- user_system_log.warn("Order Creation Failed: cash liabilities > 0, {} not support submit order".format(
20
- order.order_book_id)
21
- )
22
- return False
14
+ reason = "Order Creation Failed: cash liabilities > 0, {} not support submit order".format(order.order_book_id)
15
+ return reason
23
16
  else:
24
- return True
17
+ return None
18
+
19
+ def validate_cancellation(self, order: Order, account: Optional[Account] = None) -> Optional[str]:
20
+ return None
@@ -33,6 +33,7 @@ from rqalpha.core.events import EVENT
33
33
  from rqalpha.interface import AbstractMod, AbstractPosition
34
34
  from rqalpha.utils.i18n import gettext as _
35
35
  from rqalpha.utils import INST_TYPE_IN_STOCK_ACCOUNT
36
+ from rqalpha.utils.datetime_func import convert_int_to_date
36
37
  from rqalpha.utils.logger import user_system_log
37
38
  from rqalpha.const import DAYS_CNT
38
39
  from rqalpha.api import export_as_api
@@ -131,23 +132,60 @@ class AnalyserMod(AbstractMod):
131
132
  daily_return_list.append((bar.close / bar.prev_close - 1.0, benchmark[1]))
132
133
  weights += benchmark[1]
133
134
  return sum([daily[0] * daily[1] / weights for daily in daily_return_list])
134
-
135
- def _subscribe_events(self, event):
136
- if self._benchmark:
137
- _s = self._env.config.base.start_date
138
- _e = self._env.config.base.end_date
139
- for order_book_id, weight in self._benchmark:
140
- ins = self._env.data_proxy.instrument(order_book_id)
141
- if ins is None:
142
- raise RuntimeError(
143
- _("benchmark {} not exists, please entry correct order_book_id").format(order_book_id)
144
- )
145
- if ins.listed_date.date() > _s or ins.de_listed_date.date() <= _e:
146
- raise RuntimeError(
147
- _("benchmark {} listed date {} > backtest start date {} or de_listed date {} <= backtest end "
148
- "date {}").format(order_book_id, ins.listed_date.date(), _s, ins.de_listed_date.date(), _e)
135
+
136
+ def generate_benchmark_daily_returns_and_portfolio(self, event):
137
+ _s = self._env.config.base.start_date
138
+ _e = self._env.config.base.end_date
139
+ trading_dates = self._env.data_proxy.get_trading_dates(_s, _e)
140
+ if self._benchmark is None:
141
+ self._benchmark_daily_returns = list(np.full(len(trading_dates), np.nan))
142
+ return
143
+
144
+ # generate benchmerk daily returns
145
+ self._benchmark_daily_returns = np.zeros(len(trading_dates))
146
+ weights = 0
147
+ for order_book_id, weight in self._benchmark:
148
+ ins = self._env.data_proxy.instrument(order_book_id)
149
+ if ins is None:
150
+ raise RuntimeError(
151
+ _("benchmark {} not exists, please entry correct order_book_id").format(order_book_id)
152
+ )
153
+ bars = self._env.data_proxy.history_bars(
154
+ order_book_id = order_book_id,
155
+ bar_count = len(trading_dates) + 1, # Get an extra day for calculation
156
+ frequency = "1d",
157
+ field = ["datetime", "close"],
158
+ dt = _e,
159
+ skip_suspended=False,
160
+ )
161
+ if len(bars) == len(trading_dates) + 1:
162
+ if convert_int_to_date(bars[1]['datetime']).date() != _s:
163
+ raise RuntimeError(_(
164
+ "benchmark {} missing data between backtest start date {} and end date {}").format(order_book_id, _s, _e)
149
165
  )
166
+ daily_returns = (bars['close'] / np.roll(bars['close'], 1) - 1.0)[1: ]
167
+ self._benchmark_daily_returns = self._benchmark_daily_returns + daily_returns * weight
168
+ weights += weight
169
+ else:
170
+ if len(bars) == 0:
171
+ (available_s, available_e) = (ins.listed_date, ins.de_listed_date)
172
+ else:
173
+ (available_s, available_e) = (convert_int_to_date(bars[0]['datetime']).date(), convert_int_to_date(bars[-1]['datetime']).date())
174
+ raise RuntimeError(
175
+ _("benchmark {} available data start date {} >= backtest start date {} or end date {} <= backtest end "
176
+ "date {}").format(order_book_id, available_s, _s, available_e, _e)
177
+ )
178
+ self._benchmark_daily_returns = self._benchmark_daily_returns / weight
179
+
180
+ # generate benchmark portfolio
181
+ unit_net_value = (self._benchmark_daily_returns + 1).cumprod()
182
+ self._total_benchmark_portfolios = {
183
+ "date": trading_dates,
184
+ "unit_net_value": unit_net_value
185
+ }
150
186
 
187
+ def _subscribe_events(self, event):
188
+ self._env.event_bus.add_listener(EVENT.BEFORE_STRATEGY_RUN, self.generate_benchmark_daily_returns_and_portfolio)
151
189
  self._env.event_bus.add_listener(EVENT.TRADE, self._collect_trade)
152
190
  self._env.event_bus.add_listener(EVENT.ORDER_CREATION_PASS, self._collect_order)
153
191
  self._env.event_bus.prepend_listener(EVENT.POST_SETTLEMENT, self._collect_daily)
@@ -164,11 +202,6 @@ class AnalyserMod(AbstractMod):
164
202
 
165
203
  self._portfolio_daily_returns.append(portfolio.daily_returns)
166
204
  self._total_portfolios.append(self._to_portfolio_record(date, portfolio))
167
- self._benchmark_daily_returns.append(self.get_benchmark_daily_returns())
168
- self._total_benchmark_portfolios.append({
169
- "date": date,
170
- "unit_net_value": (np.array(self._benchmark_daily_returns) + 1).prod()
171
- })
172
205
  self._daily_pnl.append(portfolio.daily_pnl)
173
206
 
174
207
  for account_type, account in self._env.portfolio.accounts.items():
@@ -70,9 +70,10 @@ class VerticalSeriesSchema(SheetSchema):
70
70
  if not data:
71
71
  for key, (row, column, style) in self._cell_map.items():
72
72
  self._write_cell(ws, row, column, None, style)
73
- for key, (row, column, style) in self._cell_map.items():
74
- for i, item in enumerate(data.get(key, [])):
75
- self._write_cell(ws, row + i, column, item, style)
73
+ else:
74
+ for key, (row, column, style) in self._cell_map.items():
75
+ for i, item in enumerate(data.get(key, [])):
76
+ self._write_cell(ws, row + i, column, item, style)
76
77
 
77
78
 
78
79
  class SummaryTemplate(ExcelTemplate):
@@ -83,6 +84,7 @@ class SummaryTemplate(ExcelTemplate):
83
84
  "月度收益": VerticalSeriesSchema,
84
85
  "月度超额收益(几何)": VerticalSeriesSchema,
85
86
  "个股权重": VerticalSeriesSchema,
87
+ "压力测试": VerticalSeriesSchema,
86
88
  }
87
89
 
88
90