@363045841yyt/klinechart-core 0.7.3 → 0.7.5
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.
- package/README.md +201 -201
- package/README.zh-CN.md +201 -201
- package/dist/controllers/index.d.ts +1 -0
- package/dist/controllers/index.d.ts.map +1 -1
- package/dist/controllers/index.js +1 -0
- package/dist/controllers/index.js.map +1 -1
- package/dist/engine/chart.d.ts +11 -19
- package/dist/engine/chart.d.ts.map +1 -1
- package/dist/engine/chart.js +92 -109
- package/dist/engine/chart.js.map +1 -1
- package/dist/engine/renderers/Indicator/indicatorData.d.ts +1 -0
- package/dist/engine/renderers/Indicator/indicatorData.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/indicatorData.js +1 -1
- package/dist/engine/renderers/Indicator/indicatorData.js.map +1 -1
- package/dist/engine/renderers/webgl/candleSurface.js +47 -47
- package/dist/engine/subPaneManager.d.ts +4 -0
- package/dist/engine/subPaneManager.d.ts.map +1 -1
- package/dist/engine/subPaneManager.js +13 -0
- package/dist/engine/subPaneManager.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -2
- package/dist/version.js.map +1 -1
- package/package.json +129 -122
- package/src/__tests__/signal.test.ts +124 -124
- package/src/config/chartSettings.ts +66 -66
- package/src/controllers/__tests__/drawing.test.ts +214 -214
- package/src/controllers/__tests__/indicatorSelector.test.ts +481 -481
- package/src/controllers/__tests__/toolbar.test.ts +225 -225
- package/src/controllers/createChartController.ts +665 -665
- package/src/controllers/createDrawingController.ts +96 -96
- package/src/controllers/createIndicatorSelectorController.ts +307 -307
- package/src/controllers/createToolbarController.ts +146 -146
- package/src/controllers/index.ts +20 -19
- package/src/controllers/types.ts +284 -284
- package/src/engine/__tests__/chart.dpr.test.ts +401 -401
- package/src/engine/__tests__/paneRenderer.resize.test.ts +92 -92
- package/src/engine/chart-store.ts +121 -121
- package/src/engine/chart.d.ts +617 -617
- package/src/engine/chart.ts +2803 -2815
- package/src/engine/controller/__tests__/interaction.dpr.test.ts +259 -259
- package/src/engine/controller/interaction.ts +722 -722
- package/src/engine/controller/markerInteraction.ts +130 -130
- package/src/engine/controller/pinchTracker.ts +82 -82
- package/src/engine/controller/tooltipPosition.ts +48 -48
- package/src/engine/draw/__tests__/pixelAlign.spec.ts +176 -176
- package/src/engine/draw/pixelAlign.ts +259 -259
- package/src/engine/drawing/index.ts +655 -655
- package/src/engine/drawing/interaction.ts +842 -842
- package/src/engine/drawing/plugin.ts +343 -343
- package/src/engine/indicators/__tests__/__fixtures__/golden/atr.json +38 -38
- package/src/engine/indicators/__tests__/__fixtures__/golden/dema.json +14 -14
- package/src/engine/indicators/__tests__/__fixtures__/golden/hma.json +14 -14
- package/src/engine/indicators/__tests__/__fixtures__/golden/index.ts +55 -55
- package/src/engine/indicators/__tests__/__fixtures__/golden/kama.json +14 -14
- package/src/engine/indicators/__tests__/__fixtures__/golden/tema.json +14 -14
- package/src/engine/indicators/__tests__/__fixtures__/golden/wma.json +40 -40
- package/src/engine/indicators/__tests__/__fixtures__/synthetic.ts +65 -65
- package/src/engine/indicators/__tests__/_propertyAssertions.ts +76 -76
- package/src/engine/indicators/__tests__/atr.test.ts +153 -153
- package/src/engine/indicators/__tests__/calculators.test.ts +614 -614
- package/src/engine/indicators/__tests__/cmf-mfi.test.ts +100 -100
- package/src/engine/indicators/__tests__/dema.test.ts +73 -73
- package/src/engine/indicators/__tests__/donchian.test.ts +70 -70
- package/src/engine/indicators/__tests__/hma.test.ts +73 -73
- package/src/engine/indicators/__tests__/ichimoku.test.ts +105 -105
- package/src/engine/indicators/__tests__/kama.test.ts +80 -80
- package/src/engine/indicators/__tests__/keltner.test.ts +65 -65
- package/src/engine/indicators/__tests__/pivot-fib.test.ts +110 -110
- package/src/engine/indicators/__tests__/roc.test.ts +68 -68
- package/src/engine/indicators/__tests__/sar.test.ts +86 -86
- package/src/engine/indicators/__tests__/scheduler.test.ts +831 -831
- package/src/engine/indicators/__tests__/soa.test.ts +533 -533
- package/src/engine/indicators/__tests__/structure.test.ts +110 -110
- package/src/engine/indicators/__tests__/supertrend.test.ts +65 -65
- package/src/engine/indicators/__tests__/tema.test.ts +68 -68
- package/src/engine/indicators/__tests__/trix.test.ts +70 -70
- package/src/engine/indicators/__tests__/volatility.test.ts +117 -117
- package/src/engine/indicators/__tests__/volume.test.ts +115 -115
- package/src/engine/indicators/__tests__/volumeProfile.test.ts +74 -74
- package/src/engine/indicators/__tests__/vwap.test.ts +69 -69
- package/src/engine/indicators/__tests__/wma.test.ts +112 -112
- package/src/engine/indicators/__tests__/zones.test.ts +95 -95
- package/src/engine/indicators/atrState.ts +27 -27
- package/src/engine/indicators/bollState.ts +51 -51
- package/src/engine/indicators/calculators.ts +2593 -2593
- package/src/engine/indicators/cciState.ts +25 -25
- package/src/engine/indicators/chaikinVolState.ts +32 -32
- package/src/engine/indicators/cmfState.ts +27 -27
- package/src/engine/indicators/demaState.ts +27 -27
- package/src/engine/indicators/donchianState.ts +43 -43
- package/src/engine/indicators/eneState.ts +43 -43
- package/src/engine/indicators/expmaState.ts +43 -43
- package/src/engine/indicators/fastkState.ts +25 -25
- package/src/engine/indicators/fibState.ts +41 -41
- package/src/engine/indicators/hmaState.ts +27 -27
- package/src/engine/indicators/hvState.ts +28 -28
- package/src/engine/indicators/ichimokuState.ts +70 -70
- package/src/engine/indicators/indicator.worker.ts +169 -169
- package/src/engine/indicators/indicatorDefinitionRegistry.ts +62 -62
- package/src/engine/indicators/indicatorMetadata.ts +110 -110
- package/src/engine/indicators/indicatorRegistry.ts +106 -106
- package/src/engine/indicators/indicatorRuntime.ts +1548 -1548
- package/src/engine/indicators/kamaState.ts +34 -34
- package/src/engine/indicators/keltnerState.ts +49 -49
- package/src/engine/indicators/kstState.ts +42 -42
- package/src/engine/indicators/maState.ts +36 -36
- package/src/engine/indicators/macdState.ts +76 -76
- package/src/engine/indicators/mfiState.ts +27 -27
- package/src/engine/indicators/momState.ts +25 -25
- package/src/engine/indicators/obvState.ts +25 -25
- package/src/engine/indicators/parkinsonState.ts +28 -28
- package/src/engine/indicators/pivotState.ts +51 -51
- package/src/engine/indicators/pvtState.ts +25 -25
- package/src/engine/indicators/rocState.ts +27 -27
- package/src/engine/indicators/rsiState.ts +65 -65
- package/src/engine/indicators/sarState.ts +41 -41
- package/src/engine/indicators/scheduler.ts +1205 -1205
- package/src/engine/indicators/soa.ts +352 -352
- package/src/engine/indicators/stateComposer.ts +1262 -1262
- package/src/engine/indicators/stochState.ts +26 -26
- package/src/engine/indicators/structureState.ts +69 -69
- package/src/engine/indicators/supertrendState.ts +37 -37
- package/src/engine/indicators/temaState.ts +27 -27
- package/src/engine/indicators/trixState.ts +35 -35
- package/src/engine/indicators/vmaState.ts +27 -27
- package/src/engine/indicators/volumeProfileState.ts +63 -63
- package/src/engine/indicators/vwapState.ts +29 -29
- package/src/engine/indicators/wmaState.ts +27 -27
- package/src/engine/indicators/wmsrState.ts +25 -25
- package/src/engine/indicators/workerProtocol.ts +613 -613
- package/src/engine/indicators/zonesState.ts +47 -47
- package/src/engine/layout/pane.ts +161 -161
- package/src/engine/marker/registry.ts +265 -265
- package/src/engine/paneRenderer.ts +169 -169
- package/src/engine/renderers/Indicator/atr.ts +237 -237
- package/src/engine/renderers/Indicator/boll.ts +317 -317
- package/src/engine/renderers/Indicator/cci.ts +275 -275
- package/src/engine/renderers/Indicator/chaikinVol.ts +138 -138
- package/src/engine/renderers/Indicator/cmf.ts +137 -137
- package/src/engine/renderers/Indicator/dema.ts +136 -136
- package/src/engine/renderers/Indicator/donchian.ts +137 -137
- package/src/engine/renderers/Indicator/ene.ts +271 -271
- package/src/engine/renderers/Indicator/expma.ts +197 -197
- package/src/engine/renderers/Indicator/fastk.ts +316 -316
- package/src/engine/renderers/Indicator/fib.ts +141 -141
- package/src/engine/renderers/Indicator/hma.ts +136 -136
- package/src/engine/renderers/Indicator/hv.ts +124 -124
- package/src/engine/renderers/Indicator/ichimoku.ts +181 -181
- package/src/engine/renderers/Indicator/index.ts +241 -241
- package/src/engine/renderers/Indicator/indicatorData.ts +650 -650
- package/src/engine/renderers/Indicator/kama.ts +136 -136
- package/src/engine/renderers/Indicator/keltner.ts +137 -137
- package/src/engine/renderers/Indicator/kst.ts +302 -302
- package/src/engine/renderers/Indicator/ma.ts +200 -200
- package/src/engine/renderers/Indicator/macd.ts +477 -477
- package/src/engine/renderers/Indicator/macdLegend.ts +141 -141
- package/src/engine/renderers/Indicator/mainIndicatorLegend.ts +272 -272
- package/src/engine/renderers/Indicator/mfi.ts +142 -142
- package/src/engine/renderers/Indicator/mom.ts +311 -311
- package/src/engine/renderers/Indicator/obv.ts +123 -123
- package/src/engine/renderers/Indicator/parkinson.ts +124 -124
- package/src/engine/renderers/Indicator/pivot.ts +131 -131
- package/src/engine/renderers/Indicator/pvt.ts +123 -123
- package/src/engine/renderers/Indicator/roc.ts +143 -143
- package/src/engine/renderers/Indicator/rsi.ts +390 -390
- package/src/engine/renderers/Indicator/sar.ts +113 -113
- package/src/engine/renderers/Indicator/scale/atr_scale.ts +19 -19
- package/src/engine/renderers/Indicator/scale/cci_scale.ts +19 -19
- package/src/engine/renderers/Indicator/scale/fastk_scale.ts +19 -19
- package/src/engine/renderers/Indicator/scale/indicator_scale.ts +204 -204
- package/src/engine/renderers/Indicator/scale/kst_scale.ts +19 -19
- package/src/engine/renderers/Indicator/scale/macd_scale.ts +22 -22
- package/src/engine/renderers/Indicator/scale/mom_scale.ts +19 -19
- package/src/engine/renderers/Indicator/scale/rsi_scale.ts +19 -19
- package/src/engine/renderers/Indicator/scale/stoch_scale.ts +19 -19
- package/src/engine/renderers/Indicator/scale/volume_scale.ts +26 -26
- package/src/engine/renderers/Indicator/scale/wmsr_scale.ts +19 -19
- package/src/engine/renderers/Indicator/stoch.ts +359 -359
- package/src/engine/renderers/Indicator/structure.ts +126 -126
- package/src/engine/renderers/Indicator/subPaneConfig.ts +265 -265
- package/src/engine/renderers/Indicator/supertrend.ts +115 -115
- package/src/engine/renderers/Indicator/tema.ts +136 -136
- package/src/engine/renderers/Indicator/trix.ts +158 -158
- package/src/engine/renderers/Indicator/vma.ts +124 -124
- package/src/engine/renderers/Indicator/volumeProfile.ts +125 -125
- package/src/engine/renderers/Indicator/vwap.ts +123 -123
- package/src/engine/renderers/Indicator/wma.ts +136 -136
- package/src/engine/renderers/Indicator/wmsr.ts +328 -328
- package/src/engine/renderers/Indicator/zones.ts +104 -104
- package/src/engine/renderers/__tests__/boll.renderer.test.ts +314 -314
- package/src/engine/renderers/__tests__/ene.renderer.test.ts +305 -305
- package/src/engine/renderers/__tests__/expma.renderer.test.ts +279 -279
- package/src/engine/renderers/__tests__/ma.renderer.test.ts +426 -426
- package/src/engine/renderers/__tests__/mainIndicatorLegend.renderer.test.ts +502 -502
- package/src/engine/renderers/__tests__/yAxis.renderer.test.ts +173 -173
- package/src/engine/renderers/candle.ts +459 -459
- package/src/engine/renderers/crosshair.ts +69 -69
- package/src/engine/renderers/customMarkers.ts +162 -162
- package/src/engine/renderers/extremaMarkers.ts +246 -246
- package/src/engine/renderers/gridLines.ts +90 -90
- package/src/engine/renderers/lastPrice.ts +97 -97
- package/src/engine/renderers/paneTitle.ts +136 -136
- package/src/engine/renderers/subVolume.ts +236 -236
- package/src/engine/renderers/timeAxis.ts +121 -121
- package/src/engine/renderers/webgl/candleSurface.ts +955 -955
- package/src/engine/renderers/webgl/sharedWebGLSurface.ts +146 -146
- package/src/engine/renderers/yAxis.ts +105 -105
- package/src/engine/scale/__tests__/logFormula.spec.ts +148 -148
- package/src/engine/scale/logFormula.ts +130 -130
- package/src/engine/scale/price.ts +39 -39
- package/src/engine/scale/priceScale.ts +264 -264
- package/src/engine/subPaneManager.ts +442 -427
- package/src/engine/theme/colors.ts +642 -642
- package/src/engine/theme/fonts.ts +20 -20
- package/src/engine/utils/klineConfig.ts +49 -49
- package/src/engine/utils/tickCount.ts +11 -11
- package/src/engine/utils/tickPosition.ts +214 -214
- package/src/engine/utils/zoom.ts +83 -83
- package/src/engine/viewport/viewport.ts +67 -67
- package/src/index.ts +3 -3
- package/src/plugin/ConfigManager.ts +93 -93
- package/src/plugin/EventBus.ts +77 -77
- package/src/plugin/HookSystem.ts +106 -106
- package/src/plugin/PluginHost.ts +243 -243
- package/src/plugin/PluginRegistry.ts +92 -92
- package/src/plugin/StateStore.ts +73 -73
- package/src/plugin/index.ts +19 -19
- package/src/plugin/rendererPluginManager.ts +368 -368
- package/src/plugin/stateKeys.ts +8 -8
- package/src/plugin/types.ts +526 -526
- package/src/reactivity/index.ts +2 -2
- package/src/reactivity/signal.ts +119 -119
- package/src/semantic/controller.ts +251 -251
- package/src/semantic/drawShape.ts +260 -260
- package/src/semantic/index.ts +28 -28
- package/src/semantic/schema.json +256 -256
- package/src/semantic/types.ts +251 -251
- package/src/semantic/validator.ts +349 -349
- package/src/types/kLine.ts +13 -13
- package/src/types/price.ts +56 -56
- package/src/types/volumePrice.ts +33 -33
- package/src/utils/dateFormat.ts +208 -208
- package/src/utils/kLineDraw/axis.ts +562 -562
- package/src/utils/priceToY.ts +34 -34
- package/src/utils/volumePrice.ts +202 -202
- package/src/version.ts +1 -1
package/src/types/kLine.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/types/price.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/types/volumePrice.ts
CHANGED
|
@@ -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
|
+
|
package/src/utils/dateFormat.ts
CHANGED
|
@@ -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
|
+
}
|