@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.
- package/README.md +201 -201
- package/README.zh-CN.md +201 -201
- package/dist/engine/renderers/webgl/candleSurface.js +47 -47
- 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 +19 -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 +2815 -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 +427 -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
|
@@ -1,352 +1,352 @@
|
|
|
1
|
-
import type { KLineData } from '../../types/price'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* KLineData 的 SoA (Structure of Arrays) 布局
|
|
5
|
-
* 用于零拷贝传输到 Web Worker
|
|
6
|
-
*
|
|
7
|
-
* 内存布局:
|
|
8
|
-
* | timestamps | opens | highs | lows | closes | volumes | turnovers |
|
|
9
|
-
* | 8*N | 8*N | 8*N | 8*N | 8*N | 8*N | 8*N |
|
|
10
|
-
*
|
|
11
|
-
* 其中 N 为数据长度,每列 8 字节(Float64)
|
|
12
|
-
*/
|
|
13
|
-
export interface KLineSoALayout {
|
|
14
|
-
/** 底层缓冲区(SharedArrayBuffer 或 ArrayBuffer) */
|
|
15
|
-
buffer: SharedArrayBuffer | ArrayBuffer
|
|
16
|
-
/** 数据长度 */
|
|
17
|
-
length: number
|
|
18
|
-
/** 是否使用 SharedArrayBuffer */
|
|
19
|
-
isShared: boolean
|
|
20
|
-
/** 是否有成交量数据 */
|
|
21
|
-
hasVolume: boolean
|
|
22
|
-
/** 是否有成交额数据 */
|
|
23
|
-
hasTurnover: boolean
|
|
24
|
-
/** 时间戳数组(毫秒) */
|
|
25
|
-
timestamps: Float64Array
|
|
26
|
-
/** 开盘价数组 */
|
|
27
|
-
opens: Float64Array
|
|
28
|
-
/** 最高价数组 */
|
|
29
|
-
highs: Float64Array
|
|
30
|
-
/** 最低价数组 */
|
|
31
|
-
lows: Float64Array
|
|
32
|
-
/** 收盘价数组 */
|
|
33
|
-
closes: Float64Array
|
|
34
|
-
/** 成交量数组(无值时为 0) */
|
|
35
|
-
volumes: Float64Array
|
|
36
|
-
/** 成交额数组(无值时为 0) */
|
|
37
|
-
turnovers: Float64Array
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** 列索引定义(用于计算 offset) */
|
|
41
|
-
const enum ColumnIndex {
|
|
42
|
-
TIMESTAMP = 0,
|
|
43
|
-
OPEN = 1,
|
|
44
|
-
HIGH = 2,
|
|
45
|
-
LOW = 3,
|
|
46
|
-
CLOSE = 4,
|
|
47
|
-
VOLUME = 5,
|
|
48
|
-
TURNOVER = 6,
|
|
49
|
-
COUNT = 7,
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** 每列的字节数 */
|
|
53
|
-
const BYTES_PER_COLUMN = 8 // Float64
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* SharedKLineBuffer - K线数据的 SoA 管理类
|
|
57
|
-
*
|
|
58
|
-
* 提供 AoS (KLineData[]) 与 SoA 布局之间的转换,
|
|
59
|
-
* 支持 SharedArrayBuffer(零拷贝)和 ArrayBuffer(降级)
|
|
60
|
-
*/
|
|
61
|
-
export class SharedKLineBuffer {
|
|
62
|
-
/**
|
|
63
|
-
* 检测 SharedArrayBuffer 是否可用
|
|
64
|
-
* 需要页面有 COOP/COEP 头支持
|
|
65
|
-
*/
|
|
66
|
-
static detectSupport(): boolean {
|
|
67
|
-
try {
|
|
68
|
-
if (typeof SharedArrayBuffer === 'undefined') {
|
|
69
|
-
return false
|
|
70
|
-
}
|
|
71
|
-
// 尝试创建并检测能否成功创建视图
|
|
72
|
-
const testSab = new SharedArrayBuffer(8)
|
|
73
|
-
const testView = new Float64Array(testSab)
|
|
74
|
-
testView[0] = 1.0
|
|
75
|
-
return testView[0] === 1.0
|
|
76
|
-
} catch {
|
|
77
|
-
return false
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* 计算 SoA 布局所需的总字节数
|
|
83
|
-
*/
|
|
84
|
-
static calculateByteLength(length: number): number {
|
|
85
|
-
return length * BYTES_PER_COLUMN * ColumnIndex.COUNT
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* 将 KLineData[] 转换为 SoA 布局
|
|
90
|
-
* @param data K线数据数组(AoS 格式)
|
|
91
|
-
* @param preferShared 是否优先使用 SharedArrayBuffer(默认 true)
|
|
92
|
-
* @returns SoA 布局对象
|
|
93
|
-
*/
|
|
94
|
-
static fromKLineData(
|
|
95
|
-
data: KLineData[],
|
|
96
|
-
preferShared: boolean = true
|
|
97
|
-
): KLineSoALayout {
|
|
98
|
-
const length = data.length
|
|
99
|
-
const byteLength = SharedKLineBuffer.calculateByteLength(length)
|
|
100
|
-
const useShared = preferShared && SharedKLineBuffer.detectSupport()
|
|
101
|
-
|
|
102
|
-
// 检测是否有 volume 和 turnover 数据
|
|
103
|
-
let hasVolume = false
|
|
104
|
-
let hasTurnover = false
|
|
105
|
-
for (const item of data) {
|
|
106
|
-
if (item.volume !== undefined && item.volume !== 0) {
|
|
107
|
-
hasVolume = true
|
|
108
|
-
}
|
|
109
|
-
if (item.turnover !== undefined && item.turnover !== 0) {
|
|
110
|
-
hasTurnover = true
|
|
111
|
-
}
|
|
112
|
-
if (hasVolume && hasTurnover) break
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// 创建缓冲区
|
|
116
|
-
const buffer = useShared
|
|
117
|
-
? new SharedArrayBuffer(byteLength)
|
|
118
|
-
: new ArrayBuffer(byteLength)
|
|
119
|
-
|
|
120
|
-
// 创建列视图
|
|
121
|
-
const timestamps = new Float64Array(buffer, length * BYTES_PER_COLUMN * ColumnIndex.TIMESTAMP, length)
|
|
122
|
-
const opens = new Float64Array(buffer, length * BYTES_PER_COLUMN * ColumnIndex.OPEN, length)
|
|
123
|
-
const highs = new Float64Array(buffer, length * BYTES_PER_COLUMN * ColumnIndex.HIGH, length)
|
|
124
|
-
const lows = new Float64Array(buffer, length * BYTES_PER_COLUMN * ColumnIndex.LOW, length)
|
|
125
|
-
const closes = new Float64Array(buffer, length * BYTES_PER_COLUMN * ColumnIndex.CLOSE, length)
|
|
126
|
-
const volumes = new Float64Array(buffer, length * BYTES_PER_COLUMN * ColumnIndex.VOLUME, length)
|
|
127
|
-
const turnovers = new Float64Array(buffer, length * BYTES_PER_COLUMN * ColumnIndex.TURNOVER, length)
|
|
128
|
-
|
|
129
|
-
// 填充数据
|
|
130
|
-
for (let i = 0; i < length; i++) {
|
|
131
|
-
const item = data[i]!
|
|
132
|
-
timestamps[i] = item.timestamp
|
|
133
|
-
opens[i] = item.open
|
|
134
|
-
highs[i] = item.high
|
|
135
|
-
lows[i] = item.low
|
|
136
|
-
closes[i] = item.close
|
|
137
|
-
volumes[i] = item.volume ?? 0
|
|
138
|
-
turnovers[i] = item.turnover ?? 0
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return {
|
|
142
|
-
buffer,
|
|
143
|
-
length,
|
|
144
|
-
isShared: useShared,
|
|
145
|
-
hasVolume,
|
|
146
|
-
hasTurnover,
|
|
147
|
-
timestamps,
|
|
148
|
-
opens,
|
|
149
|
-
highs,
|
|
150
|
-
lows,
|
|
151
|
-
closes,
|
|
152
|
-
volumes,
|
|
153
|
-
turnovers,
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* 更新现有 SoA 布局的数据(尽可能复用缓冲区)
|
|
159
|
-
* 如果新数据长度超过原缓冲区,会创建新缓冲区
|
|
160
|
-
*
|
|
161
|
-
* @param layout 现有 SoA 布局
|
|
162
|
-
* @param data 新的 K线数据
|
|
163
|
-
* @returns 更新后的 SoA 布局(可能是新对象)
|
|
164
|
-
*/
|
|
165
|
-
static updateExisting(layout: KLineSoALayout, data: KLineData[]): KLineSoALayout {
|
|
166
|
-
const newLength = data.length
|
|
167
|
-
const oldLength = layout.length
|
|
168
|
-
|
|
169
|
-
// 如果长度变化或缓冲区类型不匹配,创建新布局
|
|
170
|
-
if (newLength !== oldLength) {
|
|
171
|
-
return SharedKLineBuffer.fromKLineData(data, layout.isShared)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// 检测是否有 volume 和 turnover 数据
|
|
175
|
-
let hasVolume = false
|
|
176
|
-
let hasTurnover = false
|
|
177
|
-
for (const item of data) {
|
|
178
|
-
if (item.volume !== undefined && item.volume !== 0) {
|
|
179
|
-
hasVolume = true
|
|
180
|
-
}
|
|
181
|
-
if (item.turnover !== undefined && item.turnover !== 0) {
|
|
182
|
-
hasTurnover = true
|
|
183
|
-
}
|
|
184
|
-
if (hasVolume && hasTurnover) break
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// 复用现有视图,直接更新数据
|
|
188
|
-
const { timestamps, opens, highs, lows, closes, volumes, turnovers } = layout
|
|
189
|
-
|
|
190
|
-
for (let i = 0; i < newLength; i++) {
|
|
191
|
-
const item = data[i]!
|
|
192
|
-
timestamps[i] = item.timestamp
|
|
193
|
-
opens[i] = item.open
|
|
194
|
-
highs[i] = item.high
|
|
195
|
-
lows[i] = item.low
|
|
196
|
-
closes[i] = item.close
|
|
197
|
-
volumes[i] = item.volume ?? 0
|
|
198
|
-
turnovers[i] = item.turnover ?? 0
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return {
|
|
202
|
-
...layout,
|
|
203
|
-
hasVolume,
|
|
204
|
-
hasTurnover,
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* 将 SoA 布局转换回 KLineData[](用于测试和兼容性)
|
|
210
|
-
* @param layout SoA 布局
|
|
211
|
-
* @returns K线数据数组
|
|
212
|
-
*/
|
|
213
|
-
static toKLineData(layout: KLineSoALayout): KLineData[] {
|
|
214
|
-
const result: KLineData[] = new Array(layout.length)
|
|
215
|
-
const { timestamps, opens, highs, lows, closes, volumes, turnovers, hasVolume, hasTurnover } = layout
|
|
216
|
-
|
|
217
|
-
for (let i = 0; i < layout.length; i++) {
|
|
218
|
-
const item: KLineData = {
|
|
219
|
-
timestamp: timestamps[i]!,
|
|
220
|
-
open: opens[i]!,
|
|
221
|
-
high: highs[i]!,
|
|
222
|
-
low: lows[i]!,
|
|
223
|
-
close: closes[i]!,
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
if (hasVolume) {
|
|
227
|
-
const vol = volumes[i]!
|
|
228
|
-
if (vol !== 0) item.volume = vol
|
|
229
|
-
}
|
|
230
|
-
if (hasTurnover) {
|
|
231
|
-
const to = turnovers[i]!
|
|
232
|
-
if (to !== 0) item.turnover = to
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
result[i] = item
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return result
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* 创建子视图(用于 Worker 中处理部分数据范围)
|
|
243
|
-
* @param layout 原 SoA 布局
|
|
244
|
-
* @param start 起始索引(包含)
|
|
245
|
-
* @param end 结束索引(不包含)
|
|
246
|
-
* @returns 子视图对象(共享同一缓冲区)
|
|
247
|
-
*/
|
|
248
|
-
static createSubview(layout: KLineSoALayout, start: number, end: number): KLineSoALayout {
|
|
249
|
-
if (start < 0) start = 0
|
|
250
|
-
if (end > layout.length) end = layout.length
|
|
251
|
-
if (start >= end) {
|
|
252
|
-
throw new Error(`Invalid subview range: [${start}, ${end})`)
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const length = end - start
|
|
256
|
-
// 每列的总字节数 = 数据长度 * 每元素字节数
|
|
257
|
-
const columnByteLength = layout.length * BYTES_PER_COLUMN
|
|
258
|
-
|
|
259
|
-
return {
|
|
260
|
-
buffer: layout.buffer,
|
|
261
|
-
length,
|
|
262
|
-
isShared: layout.isShared,
|
|
263
|
-
hasVolume: layout.hasVolume,
|
|
264
|
-
hasTurnover: layout.hasTurnover,
|
|
265
|
-
timestamps: new Float64Array(
|
|
266
|
-
layout.buffer,
|
|
267
|
-
start * BYTES_PER_COLUMN + columnByteLength * ColumnIndex.TIMESTAMP,
|
|
268
|
-
length
|
|
269
|
-
),
|
|
270
|
-
opens: new Float64Array(
|
|
271
|
-
layout.buffer,
|
|
272
|
-
start * BYTES_PER_COLUMN + columnByteLength * ColumnIndex.OPEN,
|
|
273
|
-
length
|
|
274
|
-
),
|
|
275
|
-
highs: new Float64Array(
|
|
276
|
-
layout.buffer,
|
|
277
|
-
start * BYTES_PER_COLUMN + columnByteLength * ColumnIndex.HIGH,
|
|
278
|
-
length
|
|
279
|
-
),
|
|
280
|
-
lows: new Float64Array(
|
|
281
|
-
layout.buffer,
|
|
282
|
-
start * BYTES_PER_COLUMN + columnByteLength * ColumnIndex.LOW,
|
|
283
|
-
length
|
|
284
|
-
),
|
|
285
|
-
closes: new Float64Array(
|
|
286
|
-
layout.buffer,
|
|
287
|
-
start * BYTES_PER_COLUMN + columnByteLength * ColumnIndex.CLOSE,
|
|
288
|
-
length
|
|
289
|
-
),
|
|
290
|
-
volumes: new Float64Array(
|
|
291
|
-
layout.buffer,
|
|
292
|
-
start * BYTES_PER_COLUMN + columnByteLength * ColumnIndex.VOLUME,
|
|
293
|
-
length
|
|
294
|
-
),
|
|
295
|
-
turnovers: new Float64Array(
|
|
296
|
-
layout.buffer,
|
|
297
|
-
start * BYTES_PER_COLUMN + columnByteLength * ColumnIndex.TURNOVER,
|
|
298
|
-
length
|
|
299
|
-
),
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* 获取缓冲区信息(用于调试和序列化)
|
|
305
|
-
*/
|
|
306
|
-
static getBufferInfo(layout: KLineSoALayout): {
|
|
307
|
-
byteLength: number
|
|
308
|
-
isShared: boolean
|
|
309
|
-
length: number
|
|
310
|
-
columns: string[]
|
|
311
|
-
} {
|
|
312
|
-
return {
|
|
313
|
-
byteLength: layout.buffer.byteLength,
|
|
314
|
-
isShared: layout.isShared,
|
|
315
|
-
length: layout.length,
|
|
316
|
-
columns: ['timestamp', 'open', 'high', 'low', 'close', 'volume', 'turnover'],
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* 获取 SoA 布局中 closes 列的视图(最常用列)
|
|
323
|
-
* 用于指标计算中快速访问收盘价
|
|
324
|
-
*/
|
|
325
|
-
export function getClosesView(layout: KLineSoALayout): Float64Array {
|
|
326
|
-
return layout.closes
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
* 获取 SoA 布局中 highs/lows 列的视图
|
|
331
|
-
* 用于需要高低价的指标(如 BOLL、STOCH、WMSR)
|
|
332
|
-
*/
|
|
333
|
-
export function getHighsLowsViews(layout: KLineSoALayout): { highs: Float64Array; lows: Float64Array } {
|
|
334
|
-
return { highs: layout.highs, lows: layout.lows }
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* 获取 SoA 布局中 OHLC 四价视图
|
|
339
|
-
*/
|
|
340
|
-
export function getOHLCViews(layout: KLineSoALayout): {
|
|
341
|
-
opens: Float64Array
|
|
342
|
-
highs: Float64Array
|
|
343
|
-
lows: Float64Array
|
|
344
|
-
closes: Float64Array
|
|
345
|
-
} {
|
|
346
|
-
return {
|
|
347
|
-
opens: layout.opens,
|
|
348
|
-
highs: layout.highs,
|
|
349
|
-
lows: layout.lows,
|
|
350
|
-
closes: layout.closes,
|
|
351
|
-
}
|
|
352
|
-
}
|
|
1
|
+
import type { KLineData } from '../../types/price'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* KLineData 的 SoA (Structure of Arrays) 布局
|
|
5
|
+
* 用于零拷贝传输到 Web Worker
|
|
6
|
+
*
|
|
7
|
+
* 内存布局:
|
|
8
|
+
* | timestamps | opens | highs | lows | closes | volumes | turnovers |
|
|
9
|
+
* | 8*N | 8*N | 8*N | 8*N | 8*N | 8*N | 8*N |
|
|
10
|
+
*
|
|
11
|
+
* 其中 N 为数据长度,每列 8 字节(Float64)
|
|
12
|
+
*/
|
|
13
|
+
export interface KLineSoALayout {
|
|
14
|
+
/** 底层缓冲区(SharedArrayBuffer 或 ArrayBuffer) */
|
|
15
|
+
buffer: SharedArrayBuffer | ArrayBuffer
|
|
16
|
+
/** 数据长度 */
|
|
17
|
+
length: number
|
|
18
|
+
/** 是否使用 SharedArrayBuffer */
|
|
19
|
+
isShared: boolean
|
|
20
|
+
/** 是否有成交量数据 */
|
|
21
|
+
hasVolume: boolean
|
|
22
|
+
/** 是否有成交额数据 */
|
|
23
|
+
hasTurnover: boolean
|
|
24
|
+
/** 时间戳数组(毫秒) */
|
|
25
|
+
timestamps: Float64Array
|
|
26
|
+
/** 开盘价数组 */
|
|
27
|
+
opens: Float64Array
|
|
28
|
+
/** 最高价数组 */
|
|
29
|
+
highs: Float64Array
|
|
30
|
+
/** 最低价数组 */
|
|
31
|
+
lows: Float64Array
|
|
32
|
+
/** 收盘价数组 */
|
|
33
|
+
closes: Float64Array
|
|
34
|
+
/** 成交量数组(无值时为 0) */
|
|
35
|
+
volumes: Float64Array
|
|
36
|
+
/** 成交额数组(无值时为 0) */
|
|
37
|
+
turnovers: Float64Array
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** 列索引定义(用于计算 offset) */
|
|
41
|
+
const enum ColumnIndex {
|
|
42
|
+
TIMESTAMP = 0,
|
|
43
|
+
OPEN = 1,
|
|
44
|
+
HIGH = 2,
|
|
45
|
+
LOW = 3,
|
|
46
|
+
CLOSE = 4,
|
|
47
|
+
VOLUME = 5,
|
|
48
|
+
TURNOVER = 6,
|
|
49
|
+
COUNT = 7,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** 每列的字节数 */
|
|
53
|
+
const BYTES_PER_COLUMN = 8 // Float64
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* SharedKLineBuffer - K线数据的 SoA 管理类
|
|
57
|
+
*
|
|
58
|
+
* 提供 AoS (KLineData[]) 与 SoA 布局之间的转换,
|
|
59
|
+
* 支持 SharedArrayBuffer(零拷贝)和 ArrayBuffer(降级)
|
|
60
|
+
*/
|
|
61
|
+
export class SharedKLineBuffer {
|
|
62
|
+
/**
|
|
63
|
+
* 检测 SharedArrayBuffer 是否可用
|
|
64
|
+
* 需要页面有 COOP/COEP 头支持
|
|
65
|
+
*/
|
|
66
|
+
static detectSupport(): boolean {
|
|
67
|
+
try {
|
|
68
|
+
if (typeof SharedArrayBuffer === 'undefined') {
|
|
69
|
+
return false
|
|
70
|
+
}
|
|
71
|
+
// 尝试创建并检测能否成功创建视图
|
|
72
|
+
const testSab = new SharedArrayBuffer(8)
|
|
73
|
+
const testView = new Float64Array(testSab)
|
|
74
|
+
testView[0] = 1.0
|
|
75
|
+
return testView[0] === 1.0
|
|
76
|
+
} catch {
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 计算 SoA 布局所需的总字节数
|
|
83
|
+
*/
|
|
84
|
+
static calculateByteLength(length: number): number {
|
|
85
|
+
return length * BYTES_PER_COLUMN * ColumnIndex.COUNT
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 将 KLineData[] 转换为 SoA 布局
|
|
90
|
+
* @param data K线数据数组(AoS 格式)
|
|
91
|
+
* @param preferShared 是否优先使用 SharedArrayBuffer(默认 true)
|
|
92
|
+
* @returns SoA 布局对象
|
|
93
|
+
*/
|
|
94
|
+
static fromKLineData(
|
|
95
|
+
data: KLineData[],
|
|
96
|
+
preferShared: boolean = true
|
|
97
|
+
): KLineSoALayout {
|
|
98
|
+
const length = data.length
|
|
99
|
+
const byteLength = SharedKLineBuffer.calculateByteLength(length)
|
|
100
|
+
const useShared = preferShared && SharedKLineBuffer.detectSupport()
|
|
101
|
+
|
|
102
|
+
// 检测是否有 volume 和 turnover 数据
|
|
103
|
+
let hasVolume = false
|
|
104
|
+
let hasTurnover = false
|
|
105
|
+
for (const item of data) {
|
|
106
|
+
if (item.volume !== undefined && item.volume !== 0) {
|
|
107
|
+
hasVolume = true
|
|
108
|
+
}
|
|
109
|
+
if (item.turnover !== undefined && item.turnover !== 0) {
|
|
110
|
+
hasTurnover = true
|
|
111
|
+
}
|
|
112
|
+
if (hasVolume && hasTurnover) break
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 创建缓冲区
|
|
116
|
+
const buffer = useShared
|
|
117
|
+
? new SharedArrayBuffer(byteLength)
|
|
118
|
+
: new ArrayBuffer(byteLength)
|
|
119
|
+
|
|
120
|
+
// 创建列视图
|
|
121
|
+
const timestamps = new Float64Array(buffer, length * BYTES_PER_COLUMN * ColumnIndex.TIMESTAMP, length)
|
|
122
|
+
const opens = new Float64Array(buffer, length * BYTES_PER_COLUMN * ColumnIndex.OPEN, length)
|
|
123
|
+
const highs = new Float64Array(buffer, length * BYTES_PER_COLUMN * ColumnIndex.HIGH, length)
|
|
124
|
+
const lows = new Float64Array(buffer, length * BYTES_PER_COLUMN * ColumnIndex.LOW, length)
|
|
125
|
+
const closes = new Float64Array(buffer, length * BYTES_PER_COLUMN * ColumnIndex.CLOSE, length)
|
|
126
|
+
const volumes = new Float64Array(buffer, length * BYTES_PER_COLUMN * ColumnIndex.VOLUME, length)
|
|
127
|
+
const turnovers = new Float64Array(buffer, length * BYTES_PER_COLUMN * ColumnIndex.TURNOVER, length)
|
|
128
|
+
|
|
129
|
+
// 填充数据
|
|
130
|
+
for (let i = 0; i < length; i++) {
|
|
131
|
+
const item = data[i]!
|
|
132
|
+
timestamps[i] = item.timestamp
|
|
133
|
+
opens[i] = item.open
|
|
134
|
+
highs[i] = item.high
|
|
135
|
+
lows[i] = item.low
|
|
136
|
+
closes[i] = item.close
|
|
137
|
+
volumes[i] = item.volume ?? 0
|
|
138
|
+
turnovers[i] = item.turnover ?? 0
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
buffer,
|
|
143
|
+
length,
|
|
144
|
+
isShared: useShared,
|
|
145
|
+
hasVolume,
|
|
146
|
+
hasTurnover,
|
|
147
|
+
timestamps,
|
|
148
|
+
opens,
|
|
149
|
+
highs,
|
|
150
|
+
lows,
|
|
151
|
+
closes,
|
|
152
|
+
volumes,
|
|
153
|
+
turnovers,
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 更新现有 SoA 布局的数据(尽可能复用缓冲区)
|
|
159
|
+
* 如果新数据长度超过原缓冲区,会创建新缓冲区
|
|
160
|
+
*
|
|
161
|
+
* @param layout 现有 SoA 布局
|
|
162
|
+
* @param data 新的 K线数据
|
|
163
|
+
* @returns 更新后的 SoA 布局(可能是新对象)
|
|
164
|
+
*/
|
|
165
|
+
static updateExisting(layout: KLineSoALayout, data: KLineData[]): KLineSoALayout {
|
|
166
|
+
const newLength = data.length
|
|
167
|
+
const oldLength = layout.length
|
|
168
|
+
|
|
169
|
+
// 如果长度变化或缓冲区类型不匹配,创建新布局
|
|
170
|
+
if (newLength !== oldLength) {
|
|
171
|
+
return SharedKLineBuffer.fromKLineData(data, layout.isShared)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 检测是否有 volume 和 turnover 数据
|
|
175
|
+
let hasVolume = false
|
|
176
|
+
let hasTurnover = false
|
|
177
|
+
for (const item of data) {
|
|
178
|
+
if (item.volume !== undefined && item.volume !== 0) {
|
|
179
|
+
hasVolume = true
|
|
180
|
+
}
|
|
181
|
+
if (item.turnover !== undefined && item.turnover !== 0) {
|
|
182
|
+
hasTurnover = true
|
|
183
|
+
}
|
|
184
|
+
if (hasVolume && hasTurnover) break
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// 复用现有视图,直接更新数据
|
|
188
|
+
const { timestamps, opens, highs, lows, closes, volumes, turnovers } = layout
|
|
189
|
+
|
|
190
|
+
for (let i = 0; i < newLength; i++) {
|
|
191
|
+
const item = data[i]!
|
|
192
|
+
timestamps[i] = item.timestamp
|
|
193
|
+
opens[i] = item.open
|
|
194
|
+
highs[i] = item.high
|
|
195
|
+
lows[i] = item.low
|
|
196
|
+
closes[i] = item.close
|
|
197
|
+
volumes[i] = item.volume ?? 0
|
|
198
|
+
turnovers[i] = item.turnover ?? 0
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
...layout,
|
|
203
|
+
hasVolume,
|
|
204
|
+
hasTurnover,
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* 将 SoA 布局转换回 KLineData[](用于测试和兼容性)
|
|
210
|
+
* @param layout SoA 布局
|
|
211
|
+
* @returns K线数据数组
|
|
212
|
+
*/
|
|
213
|
+
static toKLineData(layout: KLineSoALayout): KLineData[] {
|
|
214
|
+
const result: KLineData[] = new Array(layout.length)
|
|
215
|
+
const { timestamps, opens, highs, lows, closes, volumes, turnovers, hasVolume, hasTurnover } = layout
|
|
216
|
+
|
|
217
|
+
for (let i = 0; i < layout.length; i++) {
|
|
218
|
+
const item: KLineData = {
|
|
219
|
+
timestamp: timestamps[i]!,
|
|
220
|
+
open: opens[i]!,
|
|
221
|
+
high: highs[i]!,
|
|
222
|
+
low: lows[i]!,
|
|
223
|
+
close: closes[i]!,
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (hasVolume) {
|
|
227
|
+
const vol = volumes[i]!
|
|
228
|
+
if (vol !== 0) item.volume = vol
|
|
229
|
+
}
|
|
230
|
+
if (hasTurnover) {
|
|
231
|
+
const to = turnovers[i]!
|
|
232
|
+
if (to !== 0) item.turnover = to
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
result[i] = item
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return result
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* 创建子视图(用于 Worker 中处理部分数据范围)
|
|
243
|
+
* @param layout 原 SoA 布局
|
|
244
|
+
* @param start 起始索引(包含)
|
|
245
|
+
* @param end 结束索引(不包含)
|
|
246
|
+
* @returns 子视图对象(共享同一缓冲区)
|
|
247
|
+
*/
|
|
248
|
+
static createSubview(layout: KLineSoALayout, start: number, end: number): KLineSoALayout {
|
|
249
|
+
if (start < 0) start = 0
|
|
250
|
+
if (end > layout.length) end = layout.length
|
|
251
|
+
if (start >= end) {
|
|
252
|
+
throw new Error(`Invalid subview range: [${start}, ${end})`)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const length = end - start
|
|
256
|
+
// 每列的总字节数 = 数据长度 * 每元素字节数
|
|
257
|
+
const columnByteLength = layout.length * BYTES_PER_COLUMN
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
buffer: layout.buffer,
|
|
261
|
+
length,
|
|
262
|
+
isShared: layout.isShared,
|
|
263
|
+
hasVolume: layout.hasVolume,
|
|
264
|
+
hasTurnover: layout.hasTurnover,
|
|
265
|
+
timestamps: new Float64Array(
|
|
266
|
+
layout.buffer,
|
|
267
|
+
start * BYTES_PER_COLUMN + columnByteLength * ColumnIndex.TIMESTAMP,
|
|
268
|
+
length
|
|
269
|
+
),
|
|
270
|
+
opens: new Float64Array(
|
|
271
|
+
layout.buffer,
|
|
272
|
+
start * BYTES_PER_COLUMN + columnByteLength * ColumnIndex.OPEN,
|
|
273
|
+
length
|
|
274
|
+
),
|
|
275
|
+
highs: new Float64Array(
|
|
276
|
+
layout.buffer,
|
|
277
|
+
start * BYTES_PER_COLUMN + columnByteLength * ColumnIndex.HIGH,
|
|
278
|
+
length
|
|
279
|
+
),
|
|
280
|
+
lows: new Float64Array(
|
|
281
|
+
layout.buffer,
|
|
282
|
+
start * BYTES_PER_COLUMN + columnByteLength * ColumnIndex.LOW,
|
|
283
|
+
length
|
|
284
|
+
),
|
|
285
|
+
closes: new Float64Array(
|
|
286
|
+
layout.buffer,
|
|
287
|
+
start * BYTES_PER_COLUMN + columnByteLength * ColumnIndex.CLOSE,
|
|
288
|
+
length
|
|
289
|
+
),
|
|
290
|
+
volumes: new Float64Array(
|
|
291
|
+
layout.buffer,
|
|
292
|
+
start * BYTES_PER_COLUMN + columnByteLength * ColumnIndex.VOLUME,
|
|
293
|
+
length
|
|
294
|
+
),
|
|
295
|
+
turnovers: new Float64Array(
|
|
296
|
+
layout.buffer,
|
|
297
|
+
start * BYTES_PER_COLUMN + columnByteLength * ColumnIndex.TURNOVER,
|
|
298
|
+
length
|
|
299
|
+
),
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* 获取缓冲区信息(用于调试和序列化)
|
|
305
|
+
*/
|
|
306
|
+
static getBufferInfo(layout: KLineSoALayout): {
|
|
307
|
+
byteLength: number
|
|
308
|
+
isShared: boolean
|
|
309
|
+
length: number
|
|
310
|
+
columns: string[]
|
|
311
|
+
} {
|
|
312
|
+
return {
|
|
313
|
+
byteLength: layout.buffer.byteLength,
|
|
314
|
+
isShared: layout.isShared,
|
|
315
|
+
length: layout.length,
|
|
316
|
+
columns: ['timestamp', 'open', 'high', 'low', 'close', 'volume', 'turnover'],
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* 获取 SoA 布局中 closes 列的视图(最常用列)
|
|
323
|
+
* 用于指标计算中快速访问收盘价
|
|
324
|
+
*/
|
|
325
|
+
export function getClosesView(layout: KLineSoALayout): Float64Array {
|
|
326
|
+
return layout.closes
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* 获取 SoA 布局中 highs/lows 列的视图
|
|
331
|
+
* 用于需要高低价的指标(如 BOLL、STOCH、WMSR)
|
|
332
|
+
*/
|
|
333
|
+
export function getHighsLowsViews(layout: KLineSoALayout): { highs: Float64Array; lows: Float64Array } {
|
|
334
|
+
return { highs: layout.highs, lows: layout.lows }
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* 获取 SoA 布局中 OHLC 四价视图
|
|
339
|
+
*/
|
|
340
|
+
export function getOHLCViews(layout: KLineSoALayout): {
|
|
341
|
+
opens: Float64Array
|
|
342
|
+
highs: Float64Array
|
|
343
|
+
lows: Float64Array
|
|
344
|
+
closes: Float64Array
|
|
345
|
+
} {
|
|
346
|
+
return {
|
|
347
|
+
opens: layout.opens,
|
|
348
|
+
highs: layout.highs,
|
|
349
|
+
lows: layout.lows,
|
|
350
|
+
closes: layout.closes,
|
|
351
|
+
}
|
|
352
|
+
}
|