@363045841yyt/klinechart-core 0.7.3 → 0.7.5-alpha.2

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 (231) hide show
  1. package/README.md +201 -201
  2. package/README.zh-CN.md +201 -201
  3. package/dist/engine/renderers/webgl/candleSurface.js +47 -47
  4. package/dist/version.d.ts +1 -1
  5. package/dist/version.d.ts.map +1 -1
  6. package/dist/version.js +1 -2
  7. package/dist/version.js.map +1 -1
  8. package/package.json +129 -122
  9. package/src/__tests__/signal.test.ts +124 -124
  10. package/src/config/chartSettings.ts +66 -66
  11. package/src/controllers/__tests__/drawing.test.ts +214 -214
  12. package/src/controllers/__tests__/indicatorSelector.test.ts +481 -481
  13. package/src/controllers/__tests__/toolbar.test.ts +225 -225
  14. package/src/controllers/createChartController.ts +665 -665
  15. package/src/controllers/createDrawingController.ts +96 -96
  16. package/src/controllers/createIndicatorSelectorController.ts +307 -307
  17. package/src/controllers/createToolbarController.ts +146 -146
  18. package/src/controllers/index.ts +19 -19
  19. package/src/controllers/types.ts +284 -284
  20. package/src/engine/__tests__/chart.dpr.test.ts +401 -401
  21. package/src/engine/__tests__/paneRenderer.resize.test.ts +92 -92
  22. package/src/engine/chart-store.ts +121 -121
  23. package/src/engine/chart.d.ts +617 -617
  24. package/src/engine/chart.ts +2815 -2815
  25. package/src/engine/controller/__tests__/interaction.dpr.test.ts +259 -259
  26. package/src/engine/controller/interaction.ts +722 -722
  27. package/src/engine/controller/markerInteraction.ts +130 -130
  28. package/src/engine/controller/pinchTracker.ts +82 -82
  29. package/src/engine/controller/tooltipPosition.ts +48 -48
  30. package/src/engine/draw/__tests__/pixelAlign.spec.ts +176 -176
  31. package/src/engine/draw/pixelAlign.ts +259 -259
  32. package/src/engine/drawing/index.ts +655 -655
  33. package/src/engine/drawing/interaction.ts +842 -842
  34. package/src/engine/drawing/plugin.ts +343 -343
  35. package/src/engine/indicators/__tests__/__fixtures__/golden/atr.json +38 -38
  36. package/src/engine/indicators/__tests__/__fixtures__/golden/dema.json +14 -14
  37. package/src/engine/indicators/__tests__/__fixtures__/golden/hma.json +14 -14
  38. package/src/engine/indicators/__tests__/__fixtures__/golden/index.ts +55 -55
  39. package/src/engine/indicators/__tests__/__fixtures__/golden/kama.json +14 -14
  40. package/src/engine/indicators/__tests__/__fixtures__/golden/tema.json +14 -14
  41. package/src/engine/indicators/__tests__/__fixtures__/golden/wma.json +40 -40
  42. package/src/engine/indicators/__tests__/__fixtures__/synthetic.ts +65 -65
  43. package/src/engine/indicators/__tests__/_propertyAssertions.ts +76 -76
  44. package/src/engine/indicators/__tests__/atr.test.ts +153 -153
  45. package/src/engine/indicators/__tests__/calculators.test.ts +614 -614
  46. package/src/engine/indicators/__tests__/cmf-mfi.test.ts +100 -100
  47. package/src/engine/indicators/__tests__/dema.test.ts +73 -73
  48. package/src/engine/indicators/__tests__/donchian.test.ts +70 -70
  49. package/src/engine/indicators/__tests__/hma.test.ts +73 -73
  50. package/src/engine/indicators/__tests__/ichimoku.test.ts +105 -105
  51. package/src/engine/indicators/__tests__/kama.test.ts +80 -80
  52. package/src/engine/indicators/__tests__/keltner.test.ts +65 -65
  53. package/src/engine/indicators/__tests__/pivot-fib.test.ts +110 -110
  54. package/src/engine/indicators/__tests__/roc.test.ts +68 -68
  55. package/src/engine/indicators/__tests__/sar.test.ts +86 -86
  56. package/src/engine/indicators/__tests__/scheduler.test.ts +831 -831
  57. package/src/engine/indicators/__tests__/soa.test.ts +533 -533
  58. package/src/engine/indicators/__tests__/structure.test.ts +110 -110
  59. package/src/engine/indicators/__tests__/supertrend.test.ts +65 -65
  60. package/src/engine/indicators/__tests__/tema.test.ts +68 -68
  61. package/src/engine/indicators/__tests__/trix.test.ts +70 -70
  62. package/src/engine/indicators/__tests__/volatility.test.ts +117 -117
  63. package/src/engine/indicators/__tests__/volume.test.ts +115 -115
  64. package/src/engine/indicators/__tests__/volumeProfile.test.ts +74 -74
  65. package/src/engine/indicators/__tests__/vwap.test.ts +69 -69
  66. package/src/engine/indicators/__tests__/wma.test.ts +112 -112
  67. package/src/engine/indicators/__tests__/zones.test.ts +95 -95
  68. package/src/engine/indicators/atrState.ts +27 -27
  69. package/src/engine/indicators/bollState.ts +51 -51
  70. package/src/engine/indicators/calculators.ts +2593 -2593
  71. package/src/engine/indicators/cciState.ts +25 -25
  72. package/src/engine/indicators/chaikinVolState.ts +32 -32
  73. package/src/engine/indicators/cmfState.ts +27 -27
  74. package/src/engine/indicators/demaState.ts +27 -27
  75. package/src/engine/indicators/donchianState.ts +43 -43
  76. package/src/engine/indicators/eneState.ts +43 -43
  77. package/src/engine/indicators/expmaState.ts +43 -43
  78. package/src/engine/indicators/fastkState.ts +25 -25
  79. package/src/engine/indicators/fibState.ts +41 -41
  80. package/src/engine/indicators/hmaState.ts +27 -27
  81. package/src/engine/indicators/hvState.ts +28 -28
  82. package/src/engine/indicators/ichimokuState.ts +70 -70
  83. package/src/engine/indicators/indicator.worker.ts +169 -169
  84. package/src/engine/indicators/indicatorDefinitionRegistry.ts +62 -62
  85. package/src/engine/indicators/indicatorMetadata.ts +110 -110
  86. package/src/engine/indicators/indicatorRegistry.ts +106 -106
  87. package/src/engine/indicators/indicatorRuntime.ts +1548 -1548
  88. package/src/engine/indicators/kamaState.ts +34 -34
  89. package/src/engine/indicators/keltnerState.ts +49 -49
  90. package/src/engine/indicators/kstState.ts +42 -42
  91. package/src/engine/indicators/maState.ts +36 -36
  92. package/src/engine/indicators/macdState.ts +76 -76
  93. package/src/engine/indicators/mfiState.ts +27 -27
  94. package/src/engine/indicators/momState.ts +25 -25
  95. package/src/engine/indicators/obvState.ts +25 -25
  96. package/src/engine/indicators/parkinsonState.ts +28 -28
  97. package/src/engine/indicators/pivotState.ts +51 -51
  98. package/src/engine/indicators/pvtState.ts +25 -25
  99. package/src/engine/indicators/rocState.ts +27 -27
  100. package/src/engine/indicators/rsiState.ts +65 -65
  101. package/src/engine/indicators/sarState.ts +41 -41
  102. package/src/engine/indicators/scheduler.ts +1205 -1205
  103. package/src/engine/indicators/soa.ts +352 -352
  104. package/src/engine/indicators/stateComposer.ts +1262 -1262
  105. package/src/engine/indicators/stochState.ts +26 -26
  106. package/src/engine/indicators/structureState.ts +69 -69
  107. package/src/engine/indicators/supertrendState.ts +37 -37
  108. package/src/engine/indicators/temaState.ts +27 -27
  109. package/src/engine/indicators/trixState.ts +35 -35
  110. package/src/engine/indicators/vmaState.ts +27 -27
  111. package/src/engine/indicators/volumeProfileState.ts +63 -63
  112. package/src/engine/indicators/vwapState.ts +29 -29
  113. package/src/engine/indicators/wmaState.ts +27 -27
  114. package/src/engine/indicators/wmsrState.ts +25 -25
  115. package/src/engine/indicators/workerProtocol.ts +613 -613
  116. package/src/engine/indicators/zonesState.ts +47 -47
  117. package/src/engine/layout/pane.ts +161 -161
  118. package/src/engine/marker/registry.ts +265 -265
  119. package/src/engine/paneRenderer.ts +169 -169
  120. package/src/engine/renderers/Indicator/atr.ts +237 -237
  121. package/src/engine/renderers/Indicator/boll.ts +317 -317
  122. package/src/engine/renderers/Indicator/cci.ts +275 -275
  123. package/src/engine/renderers/Indicator/chaikinVol.ts +138 -138
  124. package/src/engine/renderers/Indicator/cmf.ts +137 -137
  125. package/src/engine/renderers/Indicator/dema.ts +136 -136
  126. package/src/engine/renderers/Indicator/donchian.ts +137 -137
  127. package/src/engine/renderers/Indicator/ene.ts +271 -271
  128. package/src/engine/renderers/Indicator/expma.ts +197 -197
  129. package/src/engine/renderers/Indicator/fastk.ts +316 -316
  130. package/src/engine/renderers/Indicator/fib.ts +141 -141
  131. package/src/engine/renderers/Indicator/hma.ts +136 -136
  132. package/src/engine/renderers/Indicator/hv.ts +124 -124
  133. package/src/engine/renderers/Indicator/ichimoku.ts +181 -181
  134. package/src/engine/renderers/Indicator/index.ts +241 -241
  135. package/src/engine/renderers/Indicator/indicatorData.ts +650 -650
  136. package/src/engine/renderers/Indicator/kama.ts +136 -136
  137. package/src/engine/renderers/Indicator/keltner.ts +137 -137
  138. package/src/engine/renderers/Indicator/kst.ts +302 -302
  139. package/src/engine/renderers/Indicator/ma.ts +200 -200
  140. package/src/engine/renderers/Indicator/macd.ts +477 -477
  141. package/src/engine/renderers/Indicator/macdLegend.ts +141 -141
  142. package/src/engine/renderers/Indicator/mainIndicatorLegend.ts +272 -272
  143. package/src/engine/renderers/Indicator/mfi.ts +142 -142
  144. package/src/engine/renderers/Indicator/mom.ts +311 -311
  145. package/src/engine/renderers/Indicator/obv.ts +123 -123
  146. package/src/engine/renderers/Indicator/parkinson.ts +124 -124
  147. package/src/engine/renderers/Indicator/pivot.ts +131 -131
  148. package/src/engine/renderers/Indicator/pvt.ts +123 -123
  149. package/src/engine/renderers/Indicator/roc.ts +143 -143
  150. package/src/engine/renderers/Indicator/rsi.ts +390 -390
  151. package/src/engine/renderers/Indicator/sar.ts +113 -113
  152. package/src/engine/renderers/Indicator/scale/atr_scale.ts +19 -19
  153. package/src/engine/renderers/Indicator/scale/cci_scale.ts +19 -19
  154. package/src/engine/renderers/Indicator/scale/fastk_scale.ts +19 -19
  155. package/src/engine/renderers/Indicator/scale/indicator_scale.ts +204 -204
  156. package/src/engine/renderers/Indicator/scale/kst_scale.ts +19 -19
  157. package/src/engine/renderers/Indicator/scale/macd_scale.ts +22 -22
  158. package/src/engine/renderers/Indicator/scale/mom_scale.ts +19 -19
  159. package/src/engine/renderers/Indicator/scale/rsi_scale.ts +19 -19
  160. package/src/engine/renderers/Indicator/scale/stoch_scale.ts +19 -19
  161. package/src/engine/renderers/Indicator/scale/volume_scale.ts +26 -26
  162. package/src/engine/renderers/Indicator/scale/wmsr_scale.ts +19 -19
  163. package/src/engine/renderers/Indicator/stoch.ts +359 -359
  164. package/src/engine/renderers/Indicator/structure.ts +126 -126
  165. package/src/engine/renderers/Indicator/subPaneConfig.ts +265 -265
  166. package/src/engine/renderers/Indicator/supertrend.ts +115 -115
  167. package/src/engine/renderers/Indicator/tema.ts +136 -136
  168. package/src/engine/renderers/Indicator/trix.ts +158 -158
  169. package/src/engine/renderers/Indicator/vma.ts +124 -124
  170. package/src/engine/renderers/Indicator/volumeProfile.ts +125 -125
  171. package/src/engine/renderers/Indicator/vwap.ts +123 -123
  172. package/src/engine/renderers/Indicator/wma.ts +136 -136
  173. package/src/engine/renderers/Indicator/wmsr.ts +328 -328
  174. package/src/engine/renderers/Indicator/zones.ts +104 -104
  175. package/src/engine/renderers/__tests__/boll.renderer.test.ts +314 -314
  176. package/src/engine/renderers/__tests__/ene.renderer.test.ts +305 -305
  177. package/src/engine/renderers/__tests__/expma.renderer.test.ts +279 -279
  178. package/src/engine/renderers/__tests__/ma.renderer.test.ts +426 -426
  179. package/src/engine/renderers/__tests__/mainIndicatorLegend.renderer.test.ts +502 -502
  180. package/src/engine/renderers/__tests__/yAxis.renderer.test.ts +173 -173
  181. package/src/engine/renderers/candle.ts +459 -459
  182. package/src/engine/renderers/crosshair.ts +69 -69
  183. package/src/engine/renderers/customMarkers.ts +162 -162
  184. package/src/engine/renderers/extremaMarkers.ts +246 -246
  185. package/src/engine/renderers/gridLines.ts +90 -90
  186. package/src/engine/renderers/lastPrice.ts +97 -97
  187. package/src/engine/renderers/paneTitle.ts +136 -136
  188. package/src/engine/renderers/subVolume.ts +236 -236
  189. package/src/engine/renderers/timeAxis.ts +121 -121
  190. package/src/engine/renderers/webgl/candleSurface.ts +955 -955
  191. package/src/engine/renderers/webgl/sharedWebGLSurface.ts +146 -146
  192. package/src/engine/renderers/yAxis.ts +105 -105
  193. package/src/engine/scale/__tests__/logFormula.spec.ts +148 -148
  194. package/src/engine/scale/logFormula.ts +130 -130
  195. package/src/engine/scale/price.ts +39 -39
  196. package/src/engine/scale/priceScale.ts +264 -264
  197. package/src/engine/subPaneManager.ts +427 -427
  198. package/src/engine/theme/colors.ts +642 -642
  199. package/src/engine/theme/fonts.ts +20 -20
  200. package/src/engine/utils/klineConfig.ts +49 -49
  201. package/src/engine/utils/tickCount.ts +11 -11
  202. package/src/engine/utils/tickPosition.ts +214 -214
  203. package/src/engine/utils/zoom.ts +83 -83
  204. package/src/engine/viewport/viewport.ts +67 -67
  205. package/src/index.ts +3 -3
  206. package/src/plugin/ConfigManager.ts +93 -93
  207. package/src/plugin/EventBus.ts +77 -77
  208. package/src/plugin/HookSystem.ts +106 -106
  209. package/src/plugin/PluginHost.ts +243 -243
  210. package/src/plugin/PluginRegistry.ts +92 -92
  211. package/src/plugin/StateStore.ts +73 -73
  212. package/src/plugin/index.ts +19 -19
  213. package/src/plugin/rendererPluginManager.ts +368 -368
  214. package/src/plugin/stateKeys.ts +8 -8
  215. package/src/plugin/types.ts +526 -526
  216. package/src/reactivity/index.ts +2 -2
  217. package/src/reactivity/signal.ts +119 -119
  218. package/src/semantic/controller.ts +251 -251
  219. package/src/semantic/drawShape.ts +260 -260
  220. package/src/semantic/index.ts +28 -28
  221. package/src/semantic/schema.json +256 -256
  222. package/src/semantic/types.ts +251 -251
  223. package/src/semantic/validator.ts +349 -349
  224. package/src/types/kLine.ts +13 -13
  225. package/src/types/price.ts +56 -56
  226. package/src/types/volumePrice.ts +33 -33
  227. package/src/utils/dateFormat.ts +208 -208
  228. package/src/utils/kLineDraw/axis.ts +562 -562
  229. package/src/utils/priceToY.ts +34 -34
  230. package/src/utils/volumePrice.ts +202 -202
  231. package/src/version.ts +1 -1
@@ -1,13 +1,13 @@
1
- import type { KLineData } from './price'
2
-
3
- export type kLineTrend = 'up' | 'down' | 'flat'
4
-
5
- export function getKLineTrend(KLineData: KLineData): kLineTrend {
6
- if (KLineData.open > KLineData.close) {
7
- return 'down'
8
- } else if (KLineData.open < KLineData.close) {
9
- return 'up'
10
- } else {
11
- return 'flat'
12
- }
13
- }
1
+ import type { KLineData } from './price'
2
+
3
+ export type kLineTrend = 'up' | 'down' | 'flat'
4
+
5
+ export function getKLineTrend(KLineData: KLineData): kLineTrend {
6
+ if (KLineData.open > KLineData.close) {
7
+ return 'down'
8
+ } else if (KLineData.open < KLineData.close) {
9
+ return 'up'
10
+ } else {
11
+ return 'flat'
12
+ }
13
+ }
@@ -1,56 +1,56 @@
1
- export interface KLineData {
2
- /* 时间戳(毫秒) */
3
- timestamp: number
4
- /* 开盘价 */
5
- open: number
6
- /* 最高价 */
7
- high: number
8
- /* 最低价 */
9
- low: number
10
- /* 收盘价 */
11
- close: number
12
- /** 股票代码(东财等数据源会提供) */
13
- stockCode?: string
14
- /** 成交量 */
15
- volume?: number
16
- /** 成交额 */
17
- turnover?: number
18
- /** 振幅 */
19
- amplitude?: number
20
- /** 涨跌幅 */
21
- changePercent?: number
22
- /** 涨跌额 */
23
- changeAmount?: number
24
- /** 换手率 */
25
- turnoverRate?: number
26
- }
27
-
28
- export interface KLineDailyDongCaiResponse extends KLineData {
29
- stockCode: string
30
- volume: number
31
- turnover: number
32
- amplitude: number
33
- changePercent: number
34
- changeAmount: number
35
- turnoverRate: number
36
- }
37
-
38
-
39
- export function toKLineData(arr: KLineDailyDongCaiResponse[]): KLineData[] {
40
- return arr
41
- .map((e) => ({
42
- timestamp: e.timestamp,
43
- open: e.open,
44
- high: e.high,
45
- low: e.low,
46
- close: e.close,
47
- stockCode: e.stockCode,
48
- volume: e.volume,
49
- turnover: e.turnover,
50
- amplitude: e.amplitude,
51
- changePercent: e.changePercent,
52
- changeAmount: e.changeAmount,
53
- turnoverRate: e.turnoverRate,
54
- }))
55
- .sort((a, b) => a.timestamp - b.timestamp)
56
- }
1
+ export interface KLineData {
2
+ /* 时间戳(毫秒) */
3
+ timestamp: number
4
+ /* 开盘价 */
5
+ open: number
6
+ /* 最高价 */
7
+ high: number
8
+ /* 最低价 */
9
+ low: number
10
+ /* 收盘价 */
11
+ close: number
12
+ /** 股票代码(东财等数据源会提供) */
13
+ stockCode?: string
14
+ /** 成交量 */
15
+ volume?: number
16
+ /** 成交额 */
17
+ turnover?: number
18
+ /** 振幅 */
19
+ amplitude?: number
20
+ /** 涨跌幅 */
21
+ changePercent?: number
22
+ /** 涨跌额 */
23
+ changeAmount?: number
24
+ /** 换手率 */
25
+ turnoverRate?: number
26
+ }
27
+
28
+ export interface KLineDailyDongCaiResponse extends KLineData {
29
+ stockCode: string
30
+ volume: number
31
+ turnover: number
32
+ amplitude: number
33
+ changePercent: number
34
+ changeAmount: number
35
+ turnoverRate: number
36
+ }
37
+
38
+
39
+ export function toKLineData(arr: KLineDailyDongCaiResponse[]): KLineData[] {
40
+ return arr
41
+ .map((e) => ({
42
+ timestamp: e.timestamp,
43
+ open: e.open,
44
+ high: e.high,
45
+ low: e.low,
46
+ close: e.close,
47
+ stockCode: e.stockCode,
48
+ volume: e.volume,
49
+ turnover: e.turnover,
50
+ amplitude: e.amplitude,
51
+ changePercent: e.changePercent,
52
+ changeAmount: e.changeAmount,
53
+ turnoverRate: e.turnoverRate,
54
+ }))
55
+ .sort((a, b) => a.timestamp - b.timestamp)
56
+ }
@@ -1,33 +1,33 @@
1
- /**
2
- * 量价关系类型枚举
3
- */
4
- export enum VolumePriceRelation {
5
- /** 量价齐升(放量上涨)- 价格上涨且成交量显著放大 */
6
- RISE_WITH_VOLUME = 'rise_with_volume',
7
- /** 量价背离(缩量上涨)- 价格上涨但成交量萎缩 */
8
- RISE_WITHOUT_VOLUME = 'rise_without_volume',
9
- /** 量增价跌 - 价格下跌且成交量放大 */
10
- FALL_WITH_VOLUME = 'fall_with_volume',
11
- /** 量缩价跌 - 价格下跌且成交量萎缩 */
12
- FALL_WITHOUT_VOLUME = 'fall_without_volume',
13
- /** 中性状态 - 其他情况 */
14
- OTHERS = 'others'
15
- }
16
-
17
- /** 量价关系计算配置 */
18
- export interface VolumePriceConfig {
19
- /** 成交量放大阈值(相对于均值的倍数) */
20
- volumeAmplifyThreshold: number
21
- /** 成交量萎缩阈值(相对于均值的倍数) */
22
- volumeShrinkThreshold: number
23
- /** 计算均值的周期 */
24
- avgPeriod: number
25
- }
26
-
27
- /** 默认量价关系计算配置 */
28
- export const DEFAULT_VOLUME_PRICE_CONFIG: VolumePriceConfig = {
29
- volumeAmplifyThreshold: 1.5,
30
- volumeShrinkThreshold: 0.8,
31
- avgPeriod: 20,
32
- }
33
-
1
+ /**
2
+ * 量价关系类型枚举
3
+ */
4
+ export enum VolumePriceRelation {
5
+ /** 量价齐升(放量上涨)- 价格上涨且成交量显著放大 */
6
+ RISE_WITH_VOLUME = 'rise_with_volume',
7
+ /** 量价背离(缩量上涨)- 价格上涨但成交量萎缩 */
8
+ RISE_WITHOUT_VOLUME = 'rise_without_volume',
9
+ /** 量增价跌 - 价格下跌且成交量放大 */
10
+ FALL_WITH_VOLUME = 'fall_with_volume',
11
+ /** 量缩价跌 - 价格下跌且成交量萎缩 */
12
+ FALL_WITHOUT_VOLUME = 'fall_without_volume',
13
+ /** 中性状态 - 其他情况 */
14
+ OTHERS = 'others'
15
+ }
16
+
17
+ /** 量价关系计算配置 */
18
+ export interface VolumePriceConfig {
19
+ /** 成交量放大阈值(相对于均值的倍数) */
20
+ volumeAmplifyThreshold: number
21
+ /** 成交量萎缩阈值(相对于均值的倍数) */
22
+ volumeShrinkThreshold: number
23
+ /** 计算均值的周期 */
24
+ avgPeriod: number
25
+ }
26
+
27
+ /** 默认量价关系计算配置 */
28
+ export const DEFAULT_VOLUME_PRICE_CONFIG: VolumePriceConfig = {
29
+ volumeAmplifyThreshold: 1.5,
30
+ volumeShrinkThreshold: 0.8,
31
+ avgPeriod: 20,
32
+ }
33
+
@@ -1,208 +1,208 @@
1
- /**
2
- * 日期格式化工具函数集合
3
- * 统一管理项目中所有日期相关的格式化逻辑
4
- */
5
-
6
- // ========== 模块级复用的 Intl.DateTimeFormat 实例 ==========
7
- // Intl.DateTimeFormat 构造极其昂贵(~36ms),必须复用
8
- const YMD_FORMATTER = new Intl.DateTimeFormat('zh-CN', {
9
- timeZone: 'Asia/Shanghai',
10
- year: 'numeric',
11
- month: '2-digit',
12
- day: '2-digit',
13
- })
14
-
15
- // ========== 缓存配置 ==========
16
- const YMD_CACHE_SIZE = 1024
17
- const ymdCache = new Map<number, string>()
18
-
19
- /**
20
- * 将时间戳格式化为 YYYYMMDD 格式(纯数字,无分隔符)
21
- * @param timestamp - 时间戳(毫秒)
22
- * @returns 格式化后的日期字符串,例如 "20250114"
23
- *
24
- * @example
25
- * formatDateToYYYYMMDDNoDash(1736793600000) // "20250114"
26
- */
27
- export function formatDateToYYYYMMDDNoDash(timestamp: number): string {
28
- const d = new Date(timestamp)
29
- const year = d.getFullYear()
30
- const month = String(d.getMonth() + 1).padStart(2, '0')
31
- const day = String(d.getDate()).padStart(2, '0')
32
- return `${year}${month}${day}`
33
- }
34
-
35
- /**
36
- * 获取当前日期的 YYYYMMDD 格式(纯数字,无分隔符)
37
- * @returns 当前日期的格式化字符串,例如 "20250114"
38
- *
39
- * @example
40
- * getCurrentDateYYYYMMDD() // "20250114"(根据实际日期)
41
- */
42
- export function getCurrentDateYYYYMMDD(): string {
43
- const d = new Date()
44
- const year = d.getFullYear()
45
- const month = String(d.getMonth() + 1).padStart(2, '0')
46
- const day = String(d.getDate()).padStart(2, '0')
47
- return `${year}${month}${day}`
48
- }
49
-
50
- /**
51
- * 将时间戳格式化为 YYYY-MM-DD 格式(上海时区)
52
- * @param timestamp - 时间戳(毫秒)
53
- * @returns 格式化后的日期字符串,例如 "2025-01-14"
54
- *
55
- * @example
56
- * formatDateToYYYYMMDD(1736793600000) // "2025-01-14"
57
- */
58
- export function formatDateToYYYYMMDD(timestamp: number): string {
59
- // 缓存命中检查
60
- const cached = ymdCache.get(timestamp)
61
- if (cached !== undefined) return cached
62
-
63
- // 使用复用的 formatter,避免每次构造开销
64
- const parts = YMD_FORMATTER.formatToParts(new Date(timestamp))
65
-
66
- // 用 for 循环替代 .reduce,避免临时对象分配
67
- let y = '', m = '', d = ''
68
- for (let i = 0; i < parts.length; i++) {
69
- const p = parts[i]
70
- if (p.type === 'year') y = p.value
71
- else if (p.type === 'month') m = p.value
72
- else if (p.type === 'day') d = p.value
73
- }
74
-
75
- const result = `${y}-${m}-${d}`
76
-
77
- // 写入缓存,防膨胀
78
- if (ymdCache.size >= YMD_CACHE_SIZE) ymdCache.clear()
79
- ymdCache.set(timestamp, result)
80
-
81
- return result
82
- }
83
-
84
- // ========== formatMonthOrYear 缓存 ==========
85
- const MONTH_YEAR_CACHE_SIZE = 512
86
- const monthYearCache = new Map<number, { text: string; isYear: boolean }>()
87
-
88
- /**
89
- * 格式化月份或年份用于显示
90
- * 当年为 1 月时显示年份,其他月份显示"X月"格式
91
- * @param timestamp - 时间戳(毫秒)
92
- * @returns 包含文本和是否为年份的标志
93
- *
94
- * @example
95
- * formatMonthOrYear(1704067200000) // { text: "2024", isYear: true } (2024年1月)
96
- * formatMonthOrYear(1706745600000) // { text: "2月", isYear: false } (2024年2月)
97
- */
98
- export function formatMonthOrYear(timestamp: number): { text: string; isYear: boolean } {
99
- // 缓存命中检查
100
- const cached = monthYearCache.get(timestamp)
101
- if (cached !== undefined) return cached
102
-
103
- const d = new Date(timestamp)
104
- const year = d.getFullYear()
105
- const month = d.getMonth() + 1
106
- // 当年 1 月:直接标注年份;其它月份:标注"X月"
107
- const result = month === 1 ? { text: String(year), isYear: true } : { text: `${month}月`, isYear: false }
108
-
109
- // 写入缓存,防膨胀
110
- if (monthYearCache.size >= MONTH_YEAR_CACHE_SIZE) monthYearCache.clear()
111
- monthYearCache.set(timestamp, result)
112
-
113
- return result
114
- }
115
-
116
- /**
117
- * 生成月份键值用于比较(YYYY-M 格式)
118
- * 注意:月份未补零,用于快速比较月份是否相同
119
- * @param timestamp - 时间戳(毫秒)
120
- * @returns 月份键值,例如 "2025-1"
121
- *
122
- * @example
123
- * monthKey(1736793600000) // "2025-1"
124
- */
125
- /**
126
- * 生成月份键值用于比较
127
- * 返回数字 year * 12 + month,比字符串比较更快且无分配
128
- * 使用 new Date 保证本地时区正确(与显示一致)
129
- *
130
- * @example
131
- * monthKey(1736793600000) // 24301 (2025*12 + 0)
132
- */
133
- export function monthKey(timestamp: number): number {
134
- const d = new Date(timestamp)
135
- return d.getFullYear() * 12 + d.getMonth()
136
- }
137
-
138
- // ========== 便捷别名 ==========
139
-
140
- /**
141
- * formatDateToYYYYMMDD 的别名,保持与历史代码的兼容性
142
- * timestamp 是"上海时区当天 00:00:00"映射到 UTC 的值;显示时强制按上海时区格式化
143
- * @param ts - 时间戳(毫秒)
144
- * @returns 格式化后的日期字符串,例如 "2025-01-14"
145
- */
146
- export const formatShanghaiDate = formatDateToYYYYMMDD
147
-
148
- /**
149
- * formatDateToYYYYMMDD 的别名,用于十字线日期标签显示
150
- * 按上海时区格式化,避免不同时区出现日期偏移
151
- * @param ts - 时间戳(毫秒)
152
- * @returns 格式化后的日期字符串,例如 "2025-01-14"
153
- */
154
- export const formatYMDShanghai = formatDateToYYYYMMDD
155
-
156
- /**
157
- * 查找每个月份第一个K线的索引
158
- * @param data - K线数据数组(按时间升序排列)
159
- * @returns 月边界索引数组,例如 [0, 30, 60] 表示第0、30、60个K线分别是每月的第一个交易日
160
- *
161
- * @example
162
- * // 假设数据:[1/2, 1/3, 2/1, 2/2, 3/1, 3/2]
163
- * findMonthBoundaries(data) // [0, 2, 4]
164
- * // 解释:第0个K线是1月第一个,第2个K线是2月第一个,第4个K线是3月第一个
165
- */
166
- // findMonthBoundaries 缓存
167
- let _cacheDataRef: Array<{ timestamp: number } | undefined> | null = null
168
- let _cacheLen = 0
169
- let _cacheFirstTs = 0
170
- let _cacheLastTs = 0
171
- let _cacheResult: number[] = []
172
-
173
- /**
174
- * 查找每个月份第一个K线的索引
175
- * 结果按数据引用缓存,同一份数据多次调用直接返回缓存
176
- */
177
- export function findMonthBoundaries(data: Array<{ timestamp: number } | undefined>): number[] {
178
- if (data.length === 0) return []
179
-
180
- // 缓存命中:同一引用 + 同长度 + 首尾时间戳不变
181
- if (_cacheDataRef === data && _cacheLen === data.length) {
182
- const firstTs = data[0]?.timestamp
183
- const lastTs = data[data.length - 1]?.timestamp
184
- if (firstTs === _cacheFirstTs && lastTs === _cacheLastTs) {
185
- return _cacheResult
186
- }
187
- }
188
-
189
- const boundaries: number[] = [0]
190
- let lastKey = monthKey(data[0]!.timestamp)
191
-
192
- for (let i = 1; i < data.length; i++) {
193
- const cur = data[i]
194
- if (!cur) continue
195
- const curKey = monthKey(cur.timestamp)
196
- if (curKey !== lastKey) {
197
- boundaries.push(i)
198
- lastKey = curKey
199
- }
200
- }
201
-
202
- _cacheDataRef = data
203
- _cacheLen = data.length
204
- _cacheFirstTs = data[0]?.timestamp ?? 0
205
- _cacheLastTs = data[data.length - 1]?.timestamp ?? 0
206
- _cacheResult = boundaries
207
- return boundaries
208
- }
1
+ /**
2
+ * 日期格式化工具函数集合
3
+ * 统一管理项目中所有日期相关的格式化逻辑
4
+ */
5
+
6
+ // ========== 模块级复用的 Intl.DateTimeFormat 实例 ==========
7
+ // Intl.DateTimeFormat 构造极其昂贵(~36ms),必须复用
8
+ const YMD_FORMATTER = new Intl.DateTimeFormat('zh-CN', {
9
+ timeZone: 'Asia/Shanghai',
10
+ year: 'numeric',
11
+ month: '2-digit',
12
+ day: '2-digit',
13
+ })
14
+
15
+ // ========== 缓存配置 ==========
16
+ const YMD_CACHE_SIZE = 1024
17
+ const ymdCache = new Map<number, string>()
18
+
19
+ /**
20
+ * 将时间戳格式化为 YYYYMMDD 格式(纯数字,无分隔符)
21
+ * @param timestamp - 时间戳(毫秒)
22
+ * @returns 格式化后的日期字符串,例如 "20250114"
23
+ *
24
+ * @example
25
+ * formatDateToYYYYMMDDNoDash(1736793600000) // "20250114"
26
+ */
27
+ export function formatDateToYYYYMMDDNoDash(timestamp: number): string {
28
+ const d = new Date(timestamp)
29
+ const year = d.getFullYear()
30
+ const month = String(d.getMonth() + 1).padStart(2, '0')
31
+ const day = String(d.getDate()).padStart(2, '0')
32
+ return `${year}${month}${day}`
33
+ }
34
+
35
+ /**
36
+ * 获取当前日期的 YYYYMMDD 格式(纯数字,无分隔符)
37
+ * @returns 当前日期的格式化字符串,例如 "20250114"
38
+ *
39
+ * @example
40
+ * getCurrentDateYYYYMMDD() // "20250114"(根据实际日期)
41
+ */
42
+ export function getCurrentDateYYYYMMDD(): string {
43
+ const d = new Date()
44
+ const year = d.getFullYear()
45
+ const month = String(d.getMonth() + 1).padStart(2, '0')
46
+ const day = String(d.getDate()).padStart(2, '0')
47
+ return `${year}${month}${day}`
48
+ }
49
+
50
+ /**
51
+ * 将时间戳格式化为 YYYY-MM-DD 格式(上海时区)
52
+ * @param timestamp - 时间戳(毫秒)
53
+ * @returns 格式化后的日期字符串,例如 "2025-01-14"
54
+ *
55
+ * @example
56
+ * formatDateToYYYYMMDD(1736793600000) // "2025-01-14"
57
+ */
58
+ export function formatDateToYYYYMMDD(timestamp: number): string {
59
+ // 缓存命中检查
60
+ const cached = ymdCache.get(timestamp)
61
+ if (cached !== undefined) return cached
62
+
63
+ // 使用复用的 formatter,避免每次构造开销
64
+ const parts = YMD_FORMATTER.formatToParts(new Date(timestamp))
65
+
66
+ // 用 for 循环替代 .reduce,避免临时对象分配
67
+ let y = '', m = '', d = ''
68
+ for (let i = 0; i < parts.length; i++) {
69
+ const p = parts[i]
70
+ if (p.type === 'year') y = p.value
71
+ else if (p.type === 'month') m = p.value
72
+ else if (p.type === 'day') d = p.value
73
+ }
74
+
75
+ const result = `${y}-${m}-${d}`
76
+
77
+ // 写入缓存,防膨胀
78
+ if (ymdCache.size >= YMD_CACHE_SIZE) ymdCache.clear()
79
+ ymdCache.set(timestamp, result)
80
+
81
+ return result
82
+ }
83
+
84
+ // ========== formatMonthOrYear 缓存 ==========
85
+ const MONTH_YEAR_CACHE_SIZE = 512
86
+ const monthYearCache = new Map<number, { text: string; isYear: boolean }>()
87
+
88
+ /**
89
+ * 格式化月份或年份用于显示
90
+ * 当年为 1 月时显示年份,其他月份显示"X月"格式
91
+ * @param timestamp - 时间戳(毫秒)
92
+ * @returns 包含文本和是否为年份的标志
93
+ *
94
+ * @example
95
+ * formatMonthOrYear(1704067200000) // { text: "2024", isYear: true } (2024年1月)
96
+ * formatMonthOrYear(1706745600000) // { text: "2月", isYear: false } (2024年2月)
97
+ */
98
+ export function formatMonthOrYear(timestamp: number): { text: string; isYear: boolean } {
99
+ // 缓存命中检查
100
+ const cached = monthYearCache.get(timestamp)
101
+ if (cached !== undefined) return cached
102
+
103
+ const d = new Date(timestamp)
104
+ const year = d.getFullYear()
105
+ const month = d.getMonth() + 1
106
+ // 当年 1 月:直接标注年份;其它月份:标注"X月"
107
+ const result = month === 1 ? { text: String(year), isYear: true } : { text: `${month}月`, isYear: false }
108
+
109
+ // 写入缓存,防膨胀
110
+ if (monthYearCache.size >= MONTH_YEAR_CACHE_SIZE) monthYearCache.clear()
111
+ monthYearCache.set(timestamp, result)
112
+
113
+ return result
114
+ }
115
+
116
+ /**
117
+ * 生成月份键值用于比较(YYYY-M 格式)
118
+ * 注意:月份未补零,用于快速比较月份是否相同
119
+ * @param timestamp - 时间戳(毫秒)
120
+ * @returns 月份键值,例如 "2025-1"
121
+ *
122
+ * @example
123
+ * monthKey(1736793600000) // "2025-1"
124
+ */
125
+ /**
126
+ * 生成月份键值用于比较
127
+ * 返回数字 year * 12 + month,比字符串比较更快且无分配
128
+ * 使用 new Date 保证本地时区正确(与显示一致)
129
+ *
130
+ * @example
131
+ * monthKey(1736793600000) // 24301 (2025*12 + 0)
132
+ */
133
+ export function monthKey(timestamp: number): number {
134
+ const d = new Date(timestamp)
135
+ return d.getFullYear() * 12 + d.getMonth()
136
+ }
137
+
138
+ // ========== 便捷别名 ==========
139
+
140
+ /**
141
+ * formatDateToYYYYMMDD 的别名,保持与历史代码的兼容性
142
+ * timestamp 是"上海时区当天 00:00:00"映射到 UTC 的值;显示时强制按上海时区格式化
143
+ * @param ts - 时间戳(毫秒)
144
+ * @returns 格式化后的日期字符串,例如 "2025-01-14"
145
+ */
146
+ export const formatShanghaiDate = formatDateToYYYYMMDD
147
+
148
+ /**
149
+ * formatDateToYYYYMMDD 的别名,用于十字线日期标签显示
150
+ * 按上海时区格式化,避免不同时区出现日期偏移
151
+ * @param ts - 时间戳(毫秒)
152
+ * @returns 格式化后的日期字符串,例如 "2025-01-14"
153
+ */
154
+ export const formatYMDShanghai = formatDateToYYYYMMDD
155
+
156
+ /**
157
+ * 查找每个月份第一个K线的索引
158
+ * @param data - K线数据数组(按时间升序排列)
159
+ * @returns 月边界索引数组,例如 [0, 30, 60] 表示第0、30、60个K线分别是每月的第一个交易日
160
+ *
161
+ * @example
162
+ * // 假设数据:[1/2, 1/3, 2/1, 2/2, 3/1, 3/2]
163
+ * findMonthBoundaries(data) // [0, 2, 4]
164
+ * // 解释:第0个K线是1月第一个,第2个K线是2月第一个,第4个K线是3月第一个
165
+ */
166
+ // findMonthBoundaries 缓存
167
+ let _cacheDataRef: Array<{ timestamp: number } | undefined> | null = null
168
+ let _cacheLen = 0
169
+ let _cacheFirstTs = 0
170
+ let _cacheLastTs = 0
171
+ let _cacheResult: number[] = []
172
+
173
+ /**
174
+ * 查找每个月份第一个K线的索引
175
+ * 结果按数据引用缓存,同一份数据多次调用直接返回缓存
176
+ */
177
+ export function findMonthBoundaries(data: Array<{ timestamp: number } | undefined>): number[] {
178
+ if (data.length === 0) return []
179
+
180
+ // 缓存命中:同一引用 + 同长度 + 首尾时间戳不变
181
+ if (_cacheDataRef === data && _cacheLen === data.length) {
182
+ const firstTs = data[0]?.timestamp
183
+ const lastTs = data[data.length - 1]?.timestamp
184
+ if (firstTs === _cacheFirstTs && lastTs === _cacheLastTs) {
185
+ return _cacheResult
186
+ }
187
+ }
188
+
189
+ const boundaries: number[] = [0]
190
+ let lastKey = monthKey(data[0]!.timestamp)
191
+
192
+ for (let i = 1; i < data.length; i++) {
193
+ const cur = data[i]
194
+ if (!cur) continue
195
+ const curKey = monthKey(cur.timestamp)
196
+ if (curKey !== lastKey) {
197
+ boundaries.push(i)
198
+ lastKey = curKey
199
+ }
200
+ }
201
+
202
+ _cacheDataRef = data
203
+ _cacheLen = data.length
204
+ _cacheFirstTs = data[0]?.timestamp ?? 0
205
+ _cacheLastTs = data[data.length - 1]?.timestamp ?? 0
206
+ _cacheResult = boundaries
207
+ return boundaries
208
+ }