st-comp 0.0.277 → 0.0.279

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 (319) hide show
  1. package/README.md +19 -19
  2. package/es/ChartLayout.cjs +1 -1
  3. package/es/ChartLayout.js +1 -1
  4. package/es/ConfigProvider.cjs +1 -1
  5. package/es/ConfigProvider.js +3 -3
  6. package/es/Contextmenu.cjs +1 -1
  7. package/es/Contextmenu.js +7 -7
  8. package/es/CustomFunction.cjs +2 -2
  9. package/es/CustomFunction.js +514 -308
  10. package/es/FactorWarning.cjs +1 -1
  11. package/es/FactorWarning.js +37 -37
  12. package/es/HeatMap.cjs +1 -1
  13. package/es/HeatMap.js +7 -7
  14. package/es/Kline.cjs +1 -1
  15. package/es/Kline.js +18 -18
  16. package/es/KlineBasic.cjs +1 -1
  17. package/es/KlineBasic.js +93 -93
  18. package/es/KlineConfig.cjs +1 -1
  19. package/es/KlineConfig.js +17 -17
  20. package/es/KlineNew.cjs +1 -1
  21. package/es/KlineNew.js +14 -14
  22. package/es/KlinePlus.cjs +4 -4
  23. package/es/KlinePlus.js +760 -656
  24. package/es/LinearLegend.cjs +1 -1
  25. package/es/LinearLegend.js +1 -1
  26. package/es/Map.cjs +1 -1
  27. package/es/Map.js +1 -1
  28. package/es/MonacoEditor.cjs +1 -1
  29. package/es/MonacoEditor.js +18 -18
  30. package/es/Pagination.cjs +1 -1
  31. package/es/Pagination.js +76 -76
  32. package/es/PasswordPrompt.cjs +1 -1
  33. package/es/PasswordPrompt.js +2 -2
  34. package/es/Pie.cjs +2 -2
  35. package/es/Pie.js +14 -14
  36. package/es/Table.cjs +1 -1
  37. package/es/Table.js +22 -22
  38. package/es/TreeMap.cjs +1 -1
  39. package/es/TreeMap.js +4 -4
  40. package/es/User.cjs +1 -1
  41. package/es/User.js +73 -73
  42. package/es/VarSelectDialog.cjs +2 -2
  43. package/es/VarSelectDialog.js +21 -21
  44. package/es/VarietyAiHelper.cjs +4 -4
  45. package/es/VarietyAiHelper.js +139 -138
  46. package/es/VarietyAutoComplete.cjs +1 -1
  47. package/es/VarietyAutoComplete.js +16 -16
  48. package/es/VarietySearch.cjs +4 -4
  49. package/es/VarietySearch.js +861 -857
  50. package/es/{VarietySelect-6a166293.js → VarietySelect-41daac7b.js} +10 -10
  51. package/es/{VarietySelect-610903f0.cjs → VarietySelect-d58eee29.cjs} +1 -1
  52. package/es/VarietyTextCopy.cjs +2 -2
  53. package/es/VarietyTextCopy.js +25 -25
  54. package/es/VirtualTable.cjs +1 -1
  55. package/es/VirtualTable.js +6 -6
  56. package/es/{_initCloneObject-152b4f4e.js → _initCloneObject-5e73c9c8.js} +2 -2
  57. package/es/{_initCloneObject-76e116d0.cjs → _initCloneObject-a5832933.cjs} +1 -1
  58. package/es/aiTools-229609fb.cjs +2 -0
  59. package/es/aiTools-ce2f9281.js +115 -0
  60. package/es/aiTools.js +179 -176
  61. package/es/{config-provider-4c784baf.cjs → config-provider-06ea6b42.cjs} +1 -1
  62. package/es/{config-provider-7a3aca55.js → config-provider-88b637a8.js} +3 -3
  63. package/es/{dropdown-987c47fb.cjs → dropdown-4ce4c3e2.cjs} +1 -1
  64. package/es/{dropdown-01e09205.js → dropdown-72fbc15d.js} +2 -2
  65. package/es/{el-autocomplete-342ae823.js → el-autocomplete-6cafcdf1.js} +5 -5
  66. package/es/{el-autocomplete-16f66b34.cjs → el-autocomplete-e0857c5b.cjs} +1 -1
  67. package/es/{el-button-13dc915f.cjs → el-button-613e0bb2.cjs} +1 -1
  68. package/es/{el-button-314171a0.js → el-button-94d3de38.js} +3 -3
  69. package/es/{el-checkbox-5899681f.js → el-checkbox-6d4cb393.js} +3 -3
  70. package/es/{el-checkbox-bdf64663.cjs → el-checkbox-e90762df.cjs} +1 -1
  71. package/es/{el-dialog-0ef95df6.cjs → el-dialog-02942e22.cjs} +1 -1
  72. package/es/{el-dialog-86a3eec2.js → el-dialog-5e30161f.js} +4 -4
  73. package/es/{el-form-item-77ef6784.cjs → el-form-item-44f060d8.cjs} +1 -1
  74. package/es/{el-form-item-cda4d93c.js → el-form-item-9e8969ea.js} +5 -5
  75. package/es/{el-input-fa1445ad.js → el-input-342b2def.js} +13 -13
  76. package/es/{el-input-89222943.cjs → el-input-9a9a7f7f.cjs} +1 -1
  77. package/es/{el-input-number-d3338e5e.cjs → el-input-number-65c847d6.cjs} +1 -1
  78. package/es/{el-input-number-8f6dbf74.js → el-input-number-c22b803a.js} +35 -35
  79. package/es/{el-loading-84dde1a8.cjs → el-loading-8179b497.cjs} +1 -1
  80. package/es/{el-loading-9b671203.js → el-loading-bcc51e3d.js} +1 -1
  81. package/es/{el-menu-item-535fef90.js → el-menu-item-339baf6d.js} +21 -21
  82. package/es/{el-menu-item-4531fd0e.cjs → el-menu-item-83186444.cjs} +1 -1
  83. package/es/{el-message-box-621ed2f1.js → el-message-box-035b699c.js} +9 -9
  84. package/es/{el-message-box-f5717070.cjs → el-message-box-c62d3217.cjs} +1 -1
  85. package/es/{el-overlay-23de4324.js → el-overlay-3e17604b.js} +3 -3
  86. package/es/{el-overlay-151708cb.cjs → el-overlay-8f1da9e8.cjs} +1 -1
  87. package/es/{el-popconfirm-b8aa490e.cjs → el-popconfirm-4e32ec1b.cjs} +1 -1
  88. package/es/{el-popconfirm-bcff0aa5.js → el-popconfirm-f8a86e2c.js} +4 -4
  89. package/es/{el-popper-43ec37f4.cjs → el-popper-a4f3ae4d.cjs} +1 -1
  90. package/es/{el-popper-03988662.js → el-popper-fbd0dcea.js} +1 -1
  91. package/es/{el-segmented-db3a86be.js → el-segmented-56bd58a8.js} +2 -2
  92. package/es/{el-segmented-79a1367c.cjs → el-segmented-833ac177.cjs} +1 -1
  93. package/es/{el-select-4bd0010d.js → el-select-44fa547d.js} +8 -8
  94. package/es/{el-select-ec04e7ce.cjs → el-select-70806166.cjs} +1 -1
  95. package/es/{el-table-column-35e47229.cjs → el-table-column-3e2cdfca.cjs} +1 -1
  96. package/es/{el-table-column-7af2bec7.js → el-table-column-b74a857d.js} +9 -9
  97. package/es/{el-tag-bef9e83d.js → el-tag-66c83156.js} +2 -2
  98. package/es/{el-tag-5d5608e0.cjs → el-tag-9c2f329f.cjs} +1 -1
  99. package/es/{el-text-f998902c.js → el-text-034bd3f4.js} +1 -1
  100. package/es/{el-text-abf10fdf.cjs → el-text-6b2374bb.cjs} +1 -1
  101. package/es/index-00f6ca75.cjs +1 -0
  102. package/es/{index-a00e0534.cjs → index-185792a7.cjs} +1 -1
  103. package/es/{index-d1b554ac.js → index-1e2a38ab.js} +2 -2
  104. package/es/{index-0986e373.cjs → index-3153c1db.cjs} +1 -1
  105. package/es/{index-936e7dec.js → index-44a382a5.js} +2 -2
  106. package/es/{index-ce21e2ce.js → index-5216d5f5.js} +5 -5
  107. package/es/{index-7ed0999e.js → index-53cc4e43.js} +720 -716
  108. package/es/{index-cfcd60ca.cjs → index-5c0dd943.cjs} +1 -1
  109. package/es/{index-cfd00899.cjs → index-870b6c9d.cjs} +1 -1
  110. package/es/{index-a83ec4b7.js → index-8c2d7e05.js} +1 -1
  111. package/es/{index-8901a38c.cjs → index-94131fd7.cjs} +30 -30
  112. package/es/{index-db846633.cjs → index-9d16cea8.cjs} +1 -1
  113. package/es/{index-f3f6ee27.js → index-a33b2fb8.js} +178 -178
  114. package/es/{index-2d7ac156.cjs → index-a9246d17.cjs} +17 -17
  115. package/es/{index-60c69dd1.cjs → index-ac8dc53d.cjs} +1 -1
  116. package/es/{index-102edf6c.js → index-c5f2d372.js} +2 -2
  117. package/es/{index-6290ae0f.js → index-c6584658.js} +2 -2
  118. package/es/{index-5c44d71a.js → index-eb96e074.js} +149 -119
  119. package/es/{index-5ed42e9c.js → index-f034b910.js} +2 -2
  120. package/es/{index-c58e90e9.cjs → index-f58b2920.cjs} +1 -1
  121. package/es/{python-6cc6ec1b.js → python-8a1664e6.js} +18 -18
  122. package/es/{python-71f59893.cjs → python-a3db9620.cjs} +1 -1
  123. package/es/style.css +1 -1
  124. package/es/{use-form-common-props-02be4928.cjs → use-form-common-props-ac666630.cjs} +1 -1
  125. package/es/{use-form-common-props-76a09d89.js → use-form-common-props-ed72e914.js} +11 -11
  126. package/es/{use-global-config-31b3ec57.cjs → use-global-config-23472471.cjs} +1 -1
  127. package/es/{use-global-config-0f43458b.js → use-global-config-ee406d58.js} +2 -2
  128. package/es/{validator-ea292506.cjs → validator-366dbf39.cjs} +1 -1
  129. package/es/{validator-0e037618.js → validator-c60a8956.js} +1 -1
  130. package/es/{zh-cn-1227eb8a.js → zh-cn-b59a0910.js} +1 -1
  131. package/es/{zh-cn-0edc7234.cjs → zh-cn-c21d12d8.cjs} +1 -1
  132. package/lib/aiTools.js +179 -176
  133. package/lib/bundle.js +1 -1
  134. package/lib/bundle.umd.cjs +230 -230
  135. package/lib/{index-2a269748.js → index-62fa175a.js} +30149 -29800
  136. package/lib/{python-41da18e5.js → python-4a48fa39.js} +1 -1
  137. package/lib/style.css +1 -1
  138. package/package.json +53 -44
  139. package/auto-imports.d.ts +0 -13
  140. package/components.d.ts +0 -59
  141. package/es/aiTools-a3b095f6.js +0 -113
  142. package/es/aiTools-f36136a4.cjs +0 -2
  143. package/es/index-476c4459.cjs +0 -1
  144. package/index.html +0 -13
  145. package/packages/ChartLayout/index.ts +0 -8
  146. package/packages/ChartLayout/index.vue +0 -63
  147. package/packages/ConfigProvider/index.ts +0 -8
  148. package/packages/ConfigProvider/index.vue +0 -66
  149. package/packages/Contextmenu/index.ts +0 -8
  150. package/packages/Contextmenu/index.vue +0 -134
  151. package/packages/CustomFunction/components/ManageDialog.vue +0 -706
  152. package/packages/CustomFunction/index.ts +0 -8
  153. package/packages/CustomFunction/index.vue +0 -200
  154. package/packages/FactorWarning/index.ts +0 -8
  155. package/packages/FactorWarning/index.vue +0 -754
  156. package/packages/FactorWarning/tools.js +0 -10
  157. package/packages/HeatMap/index.ts +0 -8
  158. package/packages/HeatMap/index.vue +0 -141
  159. package/packages/Kline/components/Contextmenu/index.vue +0 -110
  160. package/packages/Kline/components/Tips/index.vue +0 -40
  161. package/packages/Kline/componentsNew/KlineSlide/index.vue +0 -155
  162. package/packages/Kline/componentsNew/KlineSub/index.vue +0 -297
  163. package/packages/Kline/componentsNew/KlineTips/index.vue +0 -66
  164. package/packages/Kline/componentsNew/KlineUtils/index.vue +0 -84
  165. package/packages/Kline/componentsNew/Tips/index.vue +0 -33
  166. package/packages/Kline/formatKlineData.ts +0 -109
  167. package/packages/Kline/images/buy.svg +0 -1
  168. package/packages/Kline/images/pen.png +0 -0
  169. package/packages/Kline/images/sell.svg +0 -1
  170. package/packages/Kline/images/t.svg +0 -1
  171. package/packages/Kline/index.ts +0 -16
  172. package/packages/Kline/index.vue +0 -891
  173. package/packages/Kline/option.ts +0 -539
  174. package/packages/Kline/type.d.ts +0 -219
  175. package/packages/Kline/utils.ts +0 -682
  176. package/packages/KlineBasic/api.js +0 -58
  177. package/packages/KlineBasic/components/AverageTips/index.vue +0 -33
  178. package/packages/KlineBasic/components/Contextmenu/index.vue +0 -105
  179. package/packages/KlineBasic/components/KlineSub/index.vue +0 -332
  180. package/packages/KlineBasic/components/KlineTips/index.vue +0 -99
  181. package/packages/KlineBasic/components/Tips/index.vue +0 -56
  182. package/packages/KlineBasic/index.ts +0 -8
  183. package/packages/KlineBasic/index.vue +0 -839
  184. package/packages/KlineBasic/utils.js +0 -258
  185. package/packages/KlineConfig/config.js +0 -46
  186. package/packages/KlineConfig/index.ts +0 -8
  187. package/packages/KlineConfig/index.vue +0 -356
  188. package/packages/KlineNew/components/KlineSlide/index.vue +0 -156
  189. package/packages/KlineNew/components/KlineSub/index.vue +0 -335
  190. package/packages/KlineNew/components/KlineTips/index.vue +0 -96
  191. package/packages/KlineNew/components/KlineUtils/index.vue +0 -341
  192. package/packages/KlineNew/components/Tips/index.vue +0 -33
  193. package/packages/KlineNew/index.ts +0 -14
  194. package/packages/KlinePlus/components/SliderChart.vue +0 -208
  195. package/packages/KlinePlus/components/Tips.vue +0 -36
  196. package/packages/KlinePlus/images/buy.svg +0 -1
  197. package/packages/KlinePlus/images/sell.svg +0 -1
  198. package/packages/KlinePlus/images/t.svg +0 -1
  199. package/packages/KlinePlus/index.ts +0 -8
  200. package/packages/KlinePlus/index.vue +0 -1067
  201. package/packages/KlinePlus/utils.js +0 -771
  202. package/packages/LinearLegend/index.ts +0 -8
  203. package/packages/LinearLegend/index.vue +0 -112
  204. package/packages/Map/China.json +0 -1
  205. package/packages/Map/index.ts +0 -8
  206. package/packages/Map/index.vue +0 -147
  207. package/packages/MonacoEditor/index.ts +0 -8
  208. package/packages/MonacoEditor/index.vue +0 -1141
  209. package/packages/MonacoEditor/tools.js +0 -18
  210. package/packages/Pagination/index.ts +0 -8
  211. package/packages/Pagination/index.vue +0 -87
  212. package/packages/PasswordPrompt/index.ts +0 -8
  213. package/packages/PasswordPrompt/index.vue +0 -267
  214. package/packages/Pie/index.ts +0 -8
  215. package/packages/Pie/index.vue +0 -148
  216. package/packages/Table/components/Button/index.vue +0 -61
  217. package/packages/Table/components/Formatter/index.vue +0 -26
  218. package/packages/Table/index.d.ts +0 -0
  219. package/packages/Table/index.ts +0 -8
  220. package/packages/Table/index.vue +0 -133
  221. package/packages/TreeMap/index.ts +0 -8
  222. package/packages/TreeMap/index.vue +0 -186
  223. package/packages/User/components/EditInfoDialog/Mobile.vue +0 -214
  224. package/packages/User/components/EditInfoDialog/index.vue +0 -161
  225. package/packages/User/components/EditPasswordDialog.vue +0 -168
  226. package/packages/User/components/SetPasswordDialog.vue +0 -160
  227. package/packages/User/index.ts +0 -8
  228. package/packages/User/index.vue +0 -117
  229. package/packages/VarSelectDialog/Mock.js +0 -495
  230. package/packages/VarSelectDialog/VarietySelect.vue +0 -78
  231. package/packages/VarSelectDialog/index.ts +0 -8
  232. package/packages/VarSelectDialog/index.vue +0 -323
  233. package/packages/VarietyAiHelper/images/like.png +0 -0
  234. package/packages/VarietyAiHelper/images/like_no.png +0 -0
  235. package/packages/VarietyAiHelper/index.ts +0 -8
  236. package/packages/VarietyAiHelper/index.vue +0 -910
  237. package/packages/VarietyAutoComplete/index.ts +0 -8
  238. package/packages/VarietyAutoComplete/index.vue +0 -89
  239. package/packages/VarietySearch/components/AddTag/index.vue +0 -268
  240. package/packages/VarietySearch/components/CommonIndicator/IndicatorTags.vue +0 -52
  241. package/packages/VarietySearch/components/CommonIndicator/index.vue +0 -697
  242. package/packages/VarietySearch/components/CommonIndicator/tools.js +0 -260
  243. package/packages/VarietySearch/components/CompositeOrder/index.vue +0 -260
  244. package/packages/VarietySearch/components/FactorScreen/FactorDescription.vue +0 -70
  245. package/packages/VarietySearch/components/FactorScreen/index.vue +0 -1158
  246. package/packages/VarietySearch/components/FactorScreen/tools.js +0 -34
  247. package/packages/VarietySearch/config.js +0 -539
  248. package/packages/VarietySearch/index.ts +0 -8
  249. package/packages/VarietySearch/index.vue +0 -688
  250. package/packages/VarietyTextCopy/index.ts +0 -8
  251. package/packages/VarietyTextCopy/index.vue +0 -136
  252. package/packages/VirtualTable/index.ts +0 -8
  253. package/packages/VirtualTable/index.vue +0 -241
  254. package/packages/index.ts +0 -59
  255. package/public/aiTools.js +0 -176
  256. package/public/talib.wasm +0 -0
  257. package/public/vite.svg +0 -1
  258. package/src/App.vue +0 -140
  259. package/src/assets/vue.svg +0 -1
  260. package/src/components/Dialog/index.vue +0 -16
  261. package/src/components/Kline/index.vue +0 -21
  262. package/src/components/Table/index.vue +0 -27
  263. package/src/main.ts +0 -17
  264. package/src/pages/ChartLayout/index.vue +0 -22
  265. package/src/pages/ConfigProvider/index.vue +0 -9
  266. package/src/pages/Contextmenu/index.vue +0 -46
  267. package/src/pages/CustomFunction/index.vue +0 -13
  268. package/src/pages/FactorWarning/index.vue +0 -203
  269. package/src/pages/HeatMap/index.vue +0 -128
  270. package/src/pages/Kline/index.vue +0 -12
  271. package/src/pages/KlineBasic/api.js +0 -48
  272. package/src/pages/KlineBasic/index.vue +0 -366
  273. package/src/pages/KlineBasic/indicator.js +0 -114
  274. package/src/pages/KlineConfig/index.vue +0 -20
  275. package/src/pages/KlineNew/components/KlineAction/components/ContextMenu/index.vue +0 -91
  276. package/src/pages/KlineNew/components/KlineAction/components/YearChart/index.vue +0 -532
  277. package/src/pages/KlineNew/components/KlineAction/images/pen.png +0 -0
  278. package/src/pages/KlineNew/components/KlineAction/index.vue +0 -716
  279. package/src/pages/KlineNew/components/KlineAction/mockApi/index.js +0 -13
  280. package/src/pages/KlineNew/components/KlineAction/utils.js +0 -571
  281. package/src/pages/KlineNew/components/KlineBasic/index.vue +0 -336
  282. package/src/pages/KlineNew/components/KlineBasic/utils.js +0 -46
  283. package/src/pages/KlineNew/components/KlineNew/index.vue +0 -316
  284. package/src/pages/KlineNew/components/KlineNew/utils.js +0 -31
  285. package/src/pages/KlineNew/components/KlineSlide/index.vue +0 -448
  286. package/src/pages/KlineNew/components/KlineSlide/utils.js +0 -78
  287. package/src/pages/KlineNew/components/KlineSlideNew/index.vue +0 -430
  288. package/src/pages/KlineNew/components/KlineSlideNew/utils.js +0 -78
  289. package/src/pages/KlineNew/index.vue +0 -92
  290. package/src/pages/KlinePlus/KlineDialog/MultiCycle.vue +0 -312
  291. package/src/pages/KlinePlus/KlineDialog/api.js +0 -108
  292. package/src/pages/KlinePlus/KlineDialog/index.vue +0 -582
  293. package/src/pages/KlinePlus/KlineDialog/indicator.js +0 -109
  294. package/src/pages/KlinePlus/KlineDialog/tools.js +0 -86
  295. package/src/pages/KlinePlus/index.vue +0 -30
  296. package/src/pages/KlinePlus/tradeLogMock.js +0 -1927
  297. package/src/pages/LinearLegend/index.vue +0 -92
  298. package/src/pages/Map/index.vue +0 -62
  299. package/src/pages/MonacoEditor/index.vue +0 -63
  300. package/src/pages/Pagination/index.vue +0 -24
  301. package/src/pages/PasswordPrompt/index.vue +0 -12
  302. package/src/pages/Pie/index.vue +0 -36
  303. package/src/pages/Table/index.vue +0 -117
  304. package/src/pages/TreeMap/index.vue +0 -542
  305. package/src/pages/User/index.vue +0 -24
  306. package/src/pages/VarSelectDialog/index.vue +0 -16
  307. package/src/pages/VarietyAiHelper/index.vue +0 -20
  308. package/src/pages/VarietyAutoComplete/index.vue +0 -19
  309. package/src/pages/VarietySearch/api.js +0 -70
  310. package/src/pages/VarietySearch/index.vue +0 -467
  311. package/src/pages/VarietyTextCopy/index.vue +0 -24
  312. package/src/pages/VirtualTable/demo.json +0 -6377
  313. package/src/pages/VirtualTable/index.vue +0 -79
  314. package/src/router/index.ts +0 -9
  315. package/src/router/routes.ts +0 -132
  316. package/src/style.css +0 -79
  317. package/src/vite-env.d.ts +0 -9
  318. package/tsconfig.json +0 -30
  319. package/tsconfig.node.json +0 -10
@@ -1,771 +0,0 @@
1
- import dayjs from "dayjs";
2
- import { stMath } from "st-func";
3
-
4
- const { round } = stMath;
5
-
6
- // 获取K线展示根数上限配置
7
- export const loadKlineConfig = {
8
- // 单屏展示条目上限
9
- minValueSpan: 5,
10
- maxValueSpan: 2000,
11
- // 加载更多: 触发阈值
12
- loadCheckCount: 500,
13
- // 加载更多: 载入条目
14
- loadAddCount: 2000,
15
- };
16
-
17
- // 前端估算K线根数的周期分布
18
- export const dayBarsNumByCycle = {
19
- 1: 240, // 每天240根(4小时×60分钟)
20
- 2: 48, // 每天48根(4小时×12根)
21
- 3: 16, // 每天16根(4小时×4根)
22
- 4: 8, // 每天8根(4小时×2根)
23
- 5: 4, // 每天4根(4小时×1根)
24
- 6: 1, // 每天1根
25
- 7: 0.2, // 每周1根(按5个交易日算)
26
- 8: 0.033, // 每月1根(按21个交易日算)
27
- };
28
-
29
- /**
30
- * @description: 校验时间间隔, 避免开始和结束时间过大, 超过一屏根数上限
31
- */
32
- export const checkTimeInterval = ({ startTime, endTime, cycle, type = "end" }) => {
33
- // 大切小时可能会出现请求超过一屏上限的数据量, 进行时间间隔校验, 由于是估算, 所以计算时可以比一屏上限根数多一些
34
- const { maxValueSpan } = loadKlineConfig;
35
- const N = Math.ceil((maxValueSpan + 1000) / dayBarsNumByCycle[cycle]);
36
- const d1 = dayjs(startTime);
37
- const d2 = dayjs(endTime);
38
- const diff = d2.diff(d1, "day");
39
- // 未超出间隔, 返回原本的开始, 结束时间
40
- if (diff <= N) return [startTime, endTime];
41
- // 超出间隔, 按照期望以结束时间, 还是中间时间去计算
42
- if (type === "end") return [dayjs(endTime).subtract(N, "day").format("YYYY-MM-DD HH:mm:ss"), endTime];
43
- if (type === "middle") {
44
- const middleTime = dayjs((dayjs(startTime).valueOf() + dayjs(endTime).valueOf()) / 2).format("YYYY-MM-DD HH:mm:ss");
45
- console.log("超过一屏数量上限, 进行中间时间计算", middleTime, N / 2);
46
- return [
47
- dayjs(middleTime)
48
- .subtract(N / 2, "day")
49
- .format("YYYY-MM-DD HH:mm:ss"),
50
- dayjs(middleTime)
51
- .add(N / 2, "day")
52
- .format("YYYY-MM-DD HH:mm:ss"),
53
- ];
54
- }
55
- };
56
-
57
- // 获取副图配置
58
- const getSubBarStyle = (data, index) => {
59
- const itemData = data[index];
60
- const preItemData = index === 0 ? data[index] : data[index - 1];
61
- if (itemData[0] === itemData[1]) {
62
- return itemData[0] >= preItemData[1]
63
- ? {
64
- color: "transparent",
65
- borderColor: "#FF0000",
66
- }
67
- : {
68
- color: "#00FFFF",
69
- };
70
- } else {
71
- return itemData[1] > itemData[0]
72
- ? {
73
- color: "transparent",
74
- borderColor: "#FF0000",
75
- }
76
- : {
77
- color: "#00FFFF",
78
- };
79
- }
80
- };
81
- export const getSubOptions = (klineData, startValue, endValue) => {
82
- const series = klineData.subIndicator.map((item) => {
83
- if (item.series === "bar") {
84
- return {
85
- name: "subMain",
86
- xAxisIndex: 0,
87
- yAxisIndex: 1,
88
- type: "bar",
89
- silent: true,
90
- symbol: "none",
91
- data: item.data.map((val, index) => {
92
- if (item.seriesColor === "kline") {
93
- return {
94
- value: val,
95
- itemStyle: getSubBarStyle(klineData.data, index),
96
- };
97
- } else if (item.seriesColor === "value") {
98
- return {
99
- value: val,
100
- itemStyle: {
101
- color: val >= 0 ? "#FF0000" : "#00FFFF",
102
- },
103
- };
104
- } else {
105
- return {
106
- value: val,
107
- itemStyle: {
108
- color: item.seriesColor,
109
- },
110
- };
111
- }
112
- }),
113
- };
114
- } else if (item.series === "line") {
115
- return {
116
- xAxisIndex: 0,
117
- yAxisIndex: item.yAxis === "right" ? 2 : 1,
118
- name: item.key,
119
- type: "line",
120
- silent: true,
121
- symbol: "none",
122
- data: item.data,
123
- lineStyle: {
124
- width: 1,
125
- },
126
- itemStyle: {
127
- color: item.color,
128
- },
129
- };
130
- }
131
- });
132
- return {
133
- animation: false,
134
- grid: {
135
- top: "10px",
136
- left: "60px",
137
- right: "20px",
138
- bottom: "10px",
139
- },
140
- dataZoom: [
141
- {
142
- type: "inside",
143
- startValue,
144
- endValue,
145
- maxValueSpan: loadKlineConfig.maxValueSpan,
146
- },
147
- ],
148
- tooltip: {
149
- show: false,
150
- },
151
- axisPointer: {
152
- show: true,
153
- triggerTooltip: false,
154
- label: {
155
- rich: {},
156
- formatter: (data) => {
157
- const { axisDimension, value } = data;
158
- if (axisDimension === "x") {
159
- return null;
160
- } else if (data.axisIndex === 1) {
161
- return String(round(value));
162
- }
163
- },
164
- },
165
- },
166
- xAxis: {
167
- type: "category",
168
- data: klineData.time,
169
- axisLine: {
170
- show: true,
171
- },
172
- splitLine: {
173
- show: false,
174
- },
175
- axisLabel: {
176
- show: false,
177
- },
178
- },
179
- yAxis: [
180
- {
181
- position: "right",
182
- },
183
- {
184
- position: "left",
185
- min: klineData.subIndicator[0]?.leftYAxisRange === "cover" ? (value) => value.min : null,
186
- max: klineData.subIndicator[0]?.leftYAxisRange === "cover" ? (value) => value.max : null,
187
- splitNumber: 1,
188
- axisLine: {
189
- show: true,
190
- },
191
- splitLine: {
192
- show: true,
193
- lineStyle: {
194
- type: "dotted",
195
- color: "#333",
196
- },
197
- },
198
- },
199
- {
200
- position: "right",
201
- min: klineData.subIndicator[0]?.rightYAxisRange === "cover" ? (value) => value.min : null,
202
- max: klineData.subIndicator[0]?.rightYAxisRange === "cover" ? (value) => value.max : null,
203
- splitNumber: 1,
204
- axisLine: {
205
- show: false,
206
- },
207
- splitLine: {
208
- show: false,
209
- },
210
- axisLabel: {
211
- show: false,
212
- },
213
- },
214
- ],
215
- series,
216
- };
217
- };
218
-
219
- /**
220
- * @description: 二分查找法
221
- * @param {Array}: 值数组
222
- * @param {any}: 值
223
- * @param {string}: 查找模式
224
- * - "strict": 精确查找(默认)
225
- * - "gte": 查找第一个大于等于目标值的元素
226
- * @returns {Number}: 索引 (-1表示未找到)
227
- */
228
- export const binarySearch = (arr, target, type = "strict") => {
229
- let left = 0;
230
- let right = arr.length - 1;
231
- let result = -1; // 仅用于 gte 模式
232
-
233
- while (left <= right) {
234
- let mid = Math.floor((left + right) / 2);
235
- if (type === "strict") {
236
- // 精确查找模式
237
- if (arr[mid] === target) {
238
- return mid;
239
- } else if (arr[mid] < target) {
240
- // 左半区
241
- left = mid + 1;
242
- } else {
243
- // 右半区
244
- right = mid - 1;
245
- }
246
- }
247
- // 大于等于模式
248
- else if (type === "gte") {
249
- if (arr[mid] >= target) {
250
- result = mid; // 记录可能的结果
251
- right = mid - 1; // 继续向左尝试找到更小的匹配
252
- } else {
253
- left = mid + 1;
254
- }
255
- }
256
- }
257
-
258
- return type === "strict" ? -1 : result;
259
- };
260
-
261
- /**
262
- * @description: 统一兼容处理标记点Y轴偏移量问题
263
- */
264
- export const handleMarkPointOffset = (markPointData) => {
265
- const data = [];
266
- markPointData.reduce((result, item) => {
267
- // 1. 找到当前标记的位置
268
- const key = `${item.coord[0]}+${item.label.position}`;
269
- const baseOffset = item.label.position === "top" ? -16 : 16;
270
- // 2. 找到先前处于相同位置 [key] 标记的数量
271
- const sameNum = result.get(key);
272
- if (sameNum) {
273
- result.set(key, sameNum + 1);
274
- item.symbolOffset[1] = baseOffset * (sameNum + 1);
275
- } else {
276
- result.set(key, 1);
277
- item.symbolOffset[1] = item.label.position === "top" ? -7 : 7;
278
- }
279
- data.push(item);
280
- return result;
281
- }, new Map());
282
- return data;
283
- };
284
-
285
- // K线数据合并
286
- export const mergeklineData = (leftData, rightData) => {
287
- return {
288
- data: [...leftData.data, ...rightData.data.slice(1)],
289
- mainIndicator: leftData.mainIndicator.map((item, index) => ({
290
- ...item,
291
- data: [...item.data, ...rightData.mainIndicator[index].data.slice(1)],
292
- })),
293
- subIndicator: leftData.subIndicator.map((item, index) => ({
294
- ...item,
295
- data: [...item.data, ...rightData.subIndicator[index].data.slice(1)],
296
- })),
297
- time: [...leftData.time, ...rightData.time.slice(1)],
298
- };
299
- };
300
-
301
- // 将时间标准化为K线时间(精准计算)
302
- export const normalizeToKlineTime = (klineTimeArray, time, cycle) => {
303
- // 5, 6, 7, 8特殊处理
304
- switch (cycle) {
305
- /**
306
- * @description: 60min
307
- * 按照最新的20根K线时分秒做匹配
308
- * 不进行步阶计算的原因是无法确认首根K线的时间, 例如真实时间 09:35:00, 该品种首根可能是 10:00:00 也可能是 10:30:00
309
- */
310
- case "5": {
311
- let HmsArray = [
312
- ...new Set(
313
- klineTimeArray.slice(-20).map((item) => {
314
- const date = new Date(item);
315
- const hour = String(date.getHours()).padStart(2, "0");
316
- const minute = String(date.getMinutes()).padStart(2, "0");
317
- const second = String(date.getSeconds()).padStart(2, "0");
318
- return `${hour}:${minute}:${second}`;
319
- })
320
- ),
321
- ];
322
- if (HmsArray.includes("00:00:00")) {
323
- HmsArray.splice(HmsArray.indexOf("00:00:00"), 1);
324
- HmsArray.push("24:00:00");
325
- }
326
- HmsArray = HmsArray.sort((a, b) => new Date(`2000-01-30 ${a}`).getTime() - new Date(`2000-01-30 ${b}`).getTime());
327
-
328
- const date = new Date(time);
329
- const year = date.getFullYear();
330
- const month = String(date.getMonth() + 1).padStart(2, "0");
331
- const day = String(date.getDate()).padStart(2, "0");
332
- const hour = String(date.getHours()).padStart(2, "0");
333
- const minute = String(date.getMinutes()).padStart(2, "0");
334
- const second = String(date.getSeconds()).padStart(2, "0");
335
-
336
- // 该类为数据中台补全的数据, 不管它
337
- if (`${hour}:${minute}:${second}` === "00:00:00") {
338
- return `${year}-${month}-${day} 01:00:00`;
339
- }
340
- // 进行处理
341
- else {
342
- let Hms = null;
343
- for (let index = 0; index < HmsArray.length; index++) {
344
- const item = HmsArray[index].split(":");
345
- if (Number(`${item[0]}${item[1]}${item[2]}`) >= Number(`${hour}${minute}${second}`)) {
346
- Hms = HmsArray[index];
347
- break;
348
- }
349
- }
350
- if (Hms === "24:00:00") {
351
- const date = new Date(time);
352
- date.setDate(date.getDate() + 1);
353
- const year = date.getFullYear();
354
- const month = String(date.getMonth() + 1).padStart(2, "0");
355
- const day = String(date.getDate()).padStart(2, "0");
356
- return `${year}-${month}-${day} 00:00:00`;
357
- }
358
- return `${year}-${month}-${day} ${Hms}`;
359
- }
360
- }
361
- /**
362
- * @description: 1d
363
- * 因为考虑到期货的操作, 并且日线不像周月线那样直接统一成周五,或月末, 如果直接+1天会面临可能存在的非交易日的情况
364
- * 所以针对 [21:00:00 ~ 04:00:00)的数据, 都要进行匹配的算法, 即去klineTimeArray找到当前time的下一个日期
365
- */
366
- case "6": {
367
- const date = new Date(time);
368
- const hours = date.getHours();
369
- // 常规处理的 [04:00:00 ~ 21:00:00) => 直接格式化
370
- if (hours >= 4 && hours < 21) {
371
- const year = date.getFullYear();
372
- const month = String(date.getMonth() + 1).padStart(2, "0");
373
- const day = String(date.getDate()).padStart(2, "0");
374
- return `${year}-${month}-${day} 09:00:00`;
375
- }
376
- // 特殊处理的 [21:00:00 ~ 04:00:00) => 匹配算法
377
- else {
378
- const currentDate = new Date(time);
379
- // 如果是21:00:00之后, 需要将日期+1天
380
- if (currentDate.getHours() >= 21) {
381
- currentDate.setDate(currentDate.getDate() + 1);
382
- }
383
- const year = currentDate.getFullYear();
384
- const month = String(currentDate.getMonth() + 1).padStart(2, "0");
385
- const day = String(currentDate.getDate()).padStart(2, "0");
386
- const currentDateStr = `${year}-${month}-${day} 09:00:00`;
387
-
388
- // 在klineTimeArray中找到当前日期或之后的第一个交易日 (二分优化)
389
- const idx = binarySearch(klineTimeArray, currentDateStr, "gte");
390
- return idx === -1 ? currentDateStr : klineTimeArray[idx];
391
- }
392
- }
393
- /**
394
- * @description: 1w
395
- * 周五 || 下周五
396
- */
397
- case "7": {
398
- const date = new Date(time);
399
- const startOfWeek = new Date(date);
400
- startOfWeek.setDate(date.getDate() - date.getDay());
401
- startOfWeek.setHours(0, 0, 0, 0);
402
- const nowWeek5 = new Date(startOfWeek);
403
- nowWeek5.setDate(startOfWeek.getDate() + 5);
404
- nowWeek5.setHours(23, 59, 59, 0);
405
- const nextWeek5 = new Date(startOfWeek);
406
- nextWeek5.setDate(startOfWeek.getDate() + 12);
407
- nextWeek5.setHours(9, 0, 0, 0);
408
- const result = date <= nowWeek5 ? nowWeek5 : nextWeek5;
409
- const year = result.getFullYear();
410
- const month = String(result.getMonth() + 1).padStart(2, "0");
411
- const day = String(result.getDate()).padStart(2, "0");
412
- return `${year}-${month}-${day} 09:00:00`;
413
- }
414
- /**
415
- * @description: 1mon
416
- * 本月最后一天
417
- */
418
- case "8": {
419
- const date = new Date(time);
420
- const nextMonth = new Date(date.getFullYear(), date.getMonth() + 1, 1);
421
- const endOfMonth = new Date(nextMonth);
422
- endOfMonth.setDate(nextMonth.getDate() - 1);
423
- endOfMonth.setHours(9, 0, 0, 0);
424
- const year = endOfMonth.getFullYear();
425
- const month = String(endOfMonth.getMonth() + 1).padStart(2, "0");
426
- const day = String(endOfMonth.getDate()).padStart(2, "0");
427
- return `${year}-${month}-${day} 09:00:00`;
428
- }
429
- }
430
- // 1, 2, 3, 4步阶计算
431
- const date = new Date(time);
432
- const year = date.getFullYear();
433
- const month = date.getMonth(); // 0-based
434
- const day = date.getDate();
435
- const hour = date.getHours();
436
- const minute = date.getMinutes();
437
- const second = date.getSeconds();
438
- const computeSmallCycle = (periodMinutes) => {
439
- let targetMinute = null;
440
- // 计算是否需要进位
441
- const currentPeriod = Math.floor(minute / periodMinutes);
442
- if (minute % periodMinutes === 0 && second === 0) {
443
- // 正好在周期边界上且秒为0,不调整
444
- targetMinute = minute;
445
- } else {
446
- // 计算下一个周期点
447
- targetMinute = (currentPeriod + 1) * periodMinutes;
448
- }
449
-
450
- // 处理小时, 分钟的进位
451
- const minuteCarry = Math.floor(targetMinute / 60);
452
- const adjustedHour = hour + minuteCarry;
453
- const adjustedMinute = targetMinute % 60;
454
-
455
- // 创建新日期(自动处理日/月/年进位)
456
- const resultDate = new Date(year, month, day, adjustedHour, adjustedMinute, 0);
457
-
458
- // 格式化输出
459
- const formatPart = (num) => String(num).padStart(2, "0");
460
- const formattedYear = resultDate.getFullYear();
461
- const formattedMonth = formatPart(resultDate.getMonth() + 1);
462
- const formattedDay = formatPart(resultDate.getDate());
463
- const formattedHour = formatPart(resultDate.getHours());
464
- const formattedMinute = formatPart(resultDate.getMinutes());
465
-
466
- return `${formattedYear}-${formattedMonth}-${formattedDay} ${formattedHour}:${formattedMinute}:00`;
467
- };
468
- switch (cycle) {
469
- case "1":
470
- return computeSmallCycle(1); // 1m周期
471
- case "2":
472
- return computeSmallCycle(5); // 5m周期
473
- case "3":
474
- return computeSmallCycle(15); // 15m周期
475
- case "4":
476
- return computeSmallCycle(30); // 30m周期
477
- default:
478
- throw new Error(`Unsupported cycle: ${time} ${cycle}`);
479
- }
480
- };
481
-
482
- // 将时间标准化为K线时间范围(匹配算法)
483
- export const normalizeToKlineTimeByMatch = (klineTimeArray, timeRange, cycle) => {
484
- let klineStart = null;
485
- let klineEnd = null;
486
- const [start, end] = timeRange;
487
- switch (cycle) {
488
- // 日线
489
- case "6": {
490
- klineStart = klineTimeArray.find((t) => new Date(dayjs(t).format("YYYY-MM-DD 23:59:59")).getTime() >= new Date(start).getTime());
491
- klineEnd = klineTimeArray.findLast((t) => new Date(dayjs(t).format("YYYY-MM-DD 00:00:00")).getTime() <= new Date(end).getTime());
492
- break;
493
- }
494
- // 周线
495
- case "7": {
496
- const format5 = dayjs(end).endOf("week").add(1, "day").format("YYYY-MM-DD 23:59:59");
497
- klineStart = klineTimeArray.find((t) => dayjs(t).endOf("week").add(1, "day").format("YYYY-MM-DD") === dayjs(start).endOf("week").add(1, "day").format("YYYY-MM-DD"));
498
- klineEnd = klineTimeArray.findLast((t) => new Date(t).getTime() <= new Date(format5).getTime());
499
- break;
500
- }
501
- // 月线 (仅判断是否同属本月即可)
502
- case "8": {
503
- klineStart = klineTimeArray.find((t) => dayjs(t).format("YYYY-MM") === dayjs(start).format("YYYY-MM"));
504
- klineEnd = klineTimeArray.findLast((t) => dayjs(t).format("YYYY-MM") === dayjs(end).format("YYYY-MM"));
505
- break;
506
- }
507
- // 常规匹配
508
- default: {
509
- klineStart = klineTimeArray.find((t) => new Date(t).getTime() >= new Date(start).getTime());
510
- klineEnd = klineTimeArray.findLast((t) => new Date(t).getTime() <= new Date(end).getTime());
511
- }
512
- }
513
- return [klineStart, klineEnd];
514
- };
515
-
516
- // 生成图表配置所需数据: 成交点位, 成交点位连线
517
- export const handleMarkPointTradeLog = (tradeLog, cycle, sellBuy, klineTimeArray, klineDataArray, userKlineConfig) => {
518
- // 获取交易类型
519
- const handleTradeType = (data, type) => {
520
- const { direction = "", tradeAction = "", tradeType = "" } = data;
521
- const key = tradeType ?? direction + tradeAction;
522
- switch (type) {
523
- // 买卖
524
- case 0: {
525
- const keyMap = new Map([
526
- ["开多", "买"],
527
- ["平多", "卖"],
528
- ["开空", "卖"],
529
- ["平空", "买"],
530
- ]);
531
- return keyMap.get(key);
532
- }
533
- // 开平
534
- case 1: {
535
- return tradeType ?? direction + tradeAction;
536
- }
537
- }
538
- };
539
- // 交易点: 买卖配置数据
540
- const handleSellBuyConfig = (data, baseLineData, klineTimeAry, klineDataAry) => {
541
- return data.reduce((result, next) => {
542
- const tradeType = handleTradeType(next, 0);
543
- // 找寻同一根K线上是否有其它点位类型
544
- const timeTradeList = data.filter((item) => item.klineTime === next.klineTime);
545
- const timeTradeTypes = [...new Set(timeTradeList.map((item) => handleTradeType(item, 0)))];
546
- let symbol = null;
547
- if (timeTradeTypes.length > 1) {
548
- symbol = "image://" + new URL("./images/t.svg", import.meta.url).href;
549
- } else {
550
- symbol = "image://" + new URL(`./images/${tradeType === "买" ? "buy" : "sell"}.svg`, import.meta.url).href;
551
- }
552
- // 获取对应K线索引, 图标Y值永远为: 高, 连线起始Y值为: 低, 末端Y值为: 高
553
- const klineIndex = binarySearch(klineTimeAry, next.klineTime);
554
- const yAxisValue = klineDataAry[klineIndex]?.[3];
555
- baseLineData.forEach((item) => {
556
- const rangeIndex = tradeType === "买" ? 0 : 1;
557
- if (item.range[rangeIndex] === next.klineTime) {
558
- item.rangeValue[rangeIndex] = klineDataAry[klineIndex]?.[tradeType === "买" ? 2 : 3];
559
- }
560
- });
561
- result.push({
562
- symbol,
563
- symbolSize: 25,
564
- symbolRotate: 0,
565
- symbolOffset: [0, 0],
566
- label: {
567
- show: false,
568
- position: "top",
569
- },
570
- coord: [next.klineTime, yAxisValue],
571
- silent: true,
572
- animation: false,
573
- customData: {
574
- tradeType,
575
- amount: next.amount, // 手数
576
- part: next.part, // 份数
577
- profitAndLoss: next.profitAndLoss, // 盈亏
578
- openPriceAll: next.openPriceAll, // 开仓价
579
- closePriceAll: next.closePriceAll, // 收仓价
580
- },
581
- });
582
- return result;
583
- }, []);
584
- };
585
- // 交易点: 开平配置数据 (如果是价格, 则无需偏移, 如果是K线高低价, 则需要偏移)
586
- const handleOpenCloseConfig = (data, baseLineData, klineTimeAry, klineDataAry) => {
587
- const { sellBuyByPrice } = userKlineConfig;
588
- const result = data.reduce((result, next, index) => {
589
- // 1.交易类型
590
- const tradeType = handleTradeType(next, 1);
591
- // 2.图标位置 [开在K线上方,平在K线下方]
592
- const position = ["开多", "开空"].includes(tradeType) ? "top" : "bottom";
593
- // 3.获取对应Y轴值 [根据自定义配置判断, 是按价格还是直接用K线的最高低价]
594
- let yAxisValue = null;
595
- if (sellBuyByPrice) {
596
- yAxisValue = position === "top" ? (next.openPriceAll / next.amount)?.toFixed(2) : (next.closePriceAll / next.amount)?.toFixed(2);
597
- } else {
598
- const klineIndex = binarySearch(klineTimeAry, next.klineTime);
599
- yAxisValue = position === "top" ? klineDataAry[klineIndex]?.[3] : klineDataAry[klineIndex]?.[2];
600
- }
601
- // 4.将Y轴值存到连线的数据中, 提供给连线配置使用
602
- baseLineData.forEach((item) => {
603
- const rangeTime = position === "top" ? item.range[0] : item.range[1];
604
- if (rangeTime === next.klineTime) item.rangeValue[position === "top" ? 0 : 1] = yAxisValue;
605
- });
606
- result.push({
607
- symbol: "triangle",
608
- symbolSize: [10, 12],
609
- symbolRotate: position === "top" ? 180 : 0,
610
- symbolOffset: [0, 0],
611
- label: {
612
- show: true,
613
- position,
614
- color: "#fff",
615
- formatter: `${tradeType} ${position === "top" ? "+" : "-"} ${next.amount}手 ${next.part ? `(${next.part}份)` : ""}`,
616
- },
617
- itemStyle: { color: position === "top" ? "#FF0000" : "#389e0d" },
618
- coord: [next.klineTime, yAxisValue],
619
- silent: true,
620
- animation: false,
621
- customData: {
622
- tradeType,
623
- amount: next.amount, // 手数
624
- part: next.part, // 份数
625
- profitAndLoss: next.profitAndLoss, // 盈亏
626
- openPriceAll: next.openPriceAll, // 开仓价
627
- closePriceAll: next.closePriceAll, // 收仓价
628
- },
629
- });
630
- return result;
631
- }, []);
632
- if (sellBuyByPrice) {
633
- return result;
634
- } else {
635
- return handleMarkPointOffset(result);
636
- }
637
- };
638
- // 交易点: 生成基础点位, 连线数据
639
- const handleTradePointLineData = (tradeLog, cycle, klineTimeArray) => {
640
- // 1. 生成基础数据 { 点位数据, 连线数据 }
641
- const { basePointData, baseLineData } = tradeLog.reduce(
642
- (result, item) => {
643
- // 开仓点
644
- const startPoint = {
645
- pointTime: item.openTime, // 交易时间
646
- tradeAction: "开", // 交易行为
647
- tradeDirection: item.tradeDirection ? "空" : "多", // 交易方向 1:空, 0:多
648
- tradeType: `开${item.tradeDirection ? "空" : "多"}`,
649
- part: null, // 份数,
650
- amount: item.tradeVolume, // 手数
651
- profitAndLoss: item.profitAndLoss, // 盈亏
652
- openPriceAll: item.openPrice * item.tradeVolume, // 开仓总价
653
- closePriceAll: item.closePrice * item.tradeVolume, // 平仓总价
654
-
655
- klineTime: normalizeToKlineTime(klineTimeArray, item.openTime, cycle), // K线时间
656
- };
657
- // 平仓点
658
- const endPoint = {
659
- pointTime: item.closeTime, // 交易时间
660
- tradeAction: "平", // 交易行为
661
- tradeDirection: item.tradeDirection ? "空" : "多", // 交易方向 1:空, 0:多
662
- tradeType: `平${item.tradeDirection ? "空" : "多"}`,
663
- part: null, // 份数,
664
- amount: item.tradeVolume, // 手数
665
- profitAndLoss: item.profitAndLoss, // 盈亏
666
- openPriceAll: item.openPrice * item.tradeVolume, // 开仓总价
667
- closePriceAll: item.closePrice * item.tradeVolume, // 平仓总价
668
-
669
- klineTime: normalizeToKlineTime(klineTimeArray, item.closeTime, cycle), // K线时间
670
- };
671
- // 连线
672
- const line = {
673
- range: [startPoint.klineTime, endPoint.klineTime],
674
- rangeValue: [null, null],
675
- color: endPoint.profitAndLoss > 0 ? "#FF0000" : "#389e0d",
676
- };
677
- result.basePointData.push(startPoint, endPoint);
678
- result.baseLineData.push(line);
679
- return result;
680
- },
681
- {
682
- basePointData: [], // 点位数据
683
- baseLineData: [], // 连线数据
684
- }
685
- );
686
- // 2. 合并同一根K线上的数据, 整体按照时间排序
687
- const basePointDataMergeMap = basePointData.reduce((result, item) => {
688
- const newItem = JSON.parse(JSON.stringify(item));
689
- // 判断这个节点是否已存在数据, 若存在说明重复, 进行数据合并
690
- const key = newItem.klineTime + newItem.tradeType;
691
- if (result.has(key)) {
692
- const oldItem = result.get(key);
693
- newItem.amount += oldItem.amount;
694
- newItem.part += oldItem.part;
695
- newItem.profitAndLoss += oldItem.profitAndLoss;
696
- newItem.openPriceAll += oldItem.openPriceAll;
697
- newItem.closePriceAll += oldItem.closePriceAll;
698
- }
699
- result.set(key, newItem);
700
- return result;
701
- }, new Map([]));
702
- const pointData = [...basePointDataMergeMap.values()].sort((a, b) => new Date(a.klineTime) - new Date(b.klineTime));
703
- // 3. 过滤掉开始和结束都在一根K线上的连线
704
- const lineData = baseLineData.filter(({ range }) => range[0] !== range[1]);
705
- return { pointData, lineData };
706
- };
707
- const { pointData, lineData } = handleTradePointLineData(tradeLog, cycle, klineTimeArray);
708
- const handler = sellBuy === 0 ? handleSellBuyConfig : handleOpenCloseConfig;
709
- return {
710
- tradePointData: handler(pointData, lineData, klineTimeArray, klineDataArray),
711
- tradeLineData: lineData.map(({ range, rangeValue, color }) => {
712
- return [
713
- {
714
- symbol: "none",
715
- coord: [range[0], rangeValue[0]],
716
- lineStyle: { color, width: 2, type: "solid" },
717
- silent: true,
718
- animation: false,
719
- },
720
- {
721
- symbol: "none",
722
- coord: [range[1], rangeValue[1]],
723
- silent: true,
724
- animation: false,
725
- },
726
- ];
727
- }),
728
- };
729
- };
730
-
731
- // 生成图表配置所需数据: 净值曲线 (周, 月不展示)
732
- export const handleNetPositionLine = (netPositionData, cycle) => {
733
- let netPositionLineData = [];
734
- // 分钟线: 时间格式化
735
- if (Number(cycle) <= 5) {
736
- netPositionLineData = netPositionData.map(({ tradeDate, netPositionValue }) => {
737
- return [dayjs(tradeDate).format("YYYY-MM-DD HH:mm:ss"), netPositionValue];
738
- });
739
- }
740
- // 日线: 取每天最后一条净值数据, 且时分秒转换成固定09:00:00
741
- else if (Number(cycle) === 6) {
742
- const netPositionMap = netPositionData.reduce((result, item) => {
743
- const { tradeDate, netPositionValue } = item;
744
- result.set(dayjs(tradeDate).format("YYYY-MM-DD 09:00:00"), netPositionValue);
745
- return result;
746
- }, new Map());
747
- netPositionLineData = Array.from(netPositionMap, ([key, value]) => [key, value]);
748
- }
749
- // 其它: 不展示
750
- else {
751
- netPositionLineData = [];
752
- }
753
- return { netPositionLineData };
754
- };
755
-
756
- // 生成图表配置所需数据: 成交收益率曲线 (仅在日, 周, 月展示)
757
- export const handleTradeIncomeRateLine = (tradeIncomeRateData, cycle, incomeType, klineTimeArray) => {
758
- let tradeIncomeRateLineData = [];
759
- if (["6", "7", "8"].includes(cycle)) {
760
- const data = tradeIncomeRateData.reduce((result, item) => {
761
- const key = normalizeToKlineTime(klineTimeArray, item.date, cycle);
762
- const value = item[incomeType === 0 ? "simple" : "compound"];
763
- result.set(key, value);
764
- return result;
765
- }, new Map());
766
- tradeIncomeRateLineData = Array.from(data, ([key, value]) => [key, value]);
767
- } else {
768
- tradeIncomeRateLineData = [];
769
- }
770
- return { tradeIncomeRateLineData };
771
- };