@363045841yyt/klinechart-core 0.7.12-alpha.1 → 0.7.13
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/dist/controllers/createIndicatorSelectorController.d.ts.map +1 -1
- package/dist/controllers/createIndicatorSelectorController.js +4 -6
- package/dist/controllers/createIndicatorSelectorController.js.map +1 -1
- package/dist/controllers/index.d.ts +0 -1
- package/dist/controllers/index.d.ts.map +1 -1
- package/dist/controllers/index.js +0 -1
- package/dist/controllers/index.js.map +1 -1
- package/dist/engine/chart.d.ts +6 -2
- package/dist/engine/chart.d.ts.map +1 -1
- package/dist/engine/chart.js +26 -23
- package/dist/engine/chart.js.map +1 -1
- package/dist/engine/indicators/indicator.worker.js +32 -4
- package/dist/engine/indicators/indicator.worker.js.map +1 -1
- package/dist/engine/indicators/indicatorDefinitionRegistry.d.ts +5 -3
- package/dist/engine/indicators/indicatorDefinitionRegistry.d.ts.map +1 -1
- package/dist/engine/indicators/indicatorDefinitionRegistry.js +26 -1
- package/dist/engine/indicators/indicatorDefinitionRegistry.js.map +1 -1
- package/dist/engine/indicators/indicatorMetadata.d.ts +54 -1
- package/dist/engine/indicators/indicatorMetadata.d.ts.map +1 -1
- package/dist/engine/indicators/indicatorMetadata.js.map +1 -1
- package/dist/engine/indicators/indicatorRuntime.d.ts +12 -117
- package/dist/engine/indicators/indicatorRuntime.d.ts.map +1 -1
- package/dist/engine/indicators/indicatorRuntime.js +124 -1308
- package/dist/engine/indicators/indicatorRuntime.js.map +1 -1
- package/dist/engine/indicators/scheduler.d.ts +19 -143
- package/dist/engine/indicators/scheduler.d.ts.map +1 -1
- package/dist/engine/indicators/scheduler.js +81 -434
- package/dist/engine/indicators/scheduler.js.map +1 -1
- package/dist/engine/indicators/stateComposer.d.ts.map +1 -1
- package/dist/engine/indicators/stateComposer.js +15 -47
- package/dist/engine/indicators/stateComposer.js.map +1 -1
- package/dist/engine/indicators/workerProtocol.d.ts +12 -36
- package/dist/engine/indicators/workerProtocol.d.ts.map +1 -1
- package/dist/engine/indicators/workerProtocol.js.map +1 -1
- package/dist/engine/renderers/Indicator/atr.d.ts +2 -1
- package/dist/engine/renderers/Indicator/atr.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/atr.js +11 -9
- package/dist/engine/renderers/Indicator/atr.js.map +1 -1
- package/dist/engine/renderers/Indicator/boll.d.ts +4 -1
- package/dist/engine/renderers/Indicator/boll.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/boll.js +24 -10
- package/dist/engine/renderers/Indicator/boll.js.map +1 -1
- package/dist/engine/renderers/Indicator/cci.d.ts +2 -1
- package/dist/engine/renderers/Indicator/cci.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/cci.js +12 -10
- package/dist/engine/renderers/Indicator/cci.js.map +1 -1
- package/dist/engine/renderers/Indicator/chaikinVol.d.ts +4 -1
- package/dist/engine/renderers/Indicator/chaikinVol.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/chaikinVol.js +21 -7
- package/dist/engine/renderers/Indicator/chaikinVol.js.map +1 -1
- package/dist/engine/renderers/Indicator/cmf.d.ts +4 -1
- package/dist/engine/renderers/Indicator/cmf.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/cmf.js +20 -7
- package/dist/engine/renderers/Indicator/cmf.js.map +1 -1
- package/dist/engine/renderers/Indicator/dema.d.ts +2 -0
- package/dist/engine/renderers/Indicator/dema.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/dema.js +19 -8
- package/dist/engine/renderers/Indicator/dema.js.map +1 -1
- package/dist/engine/renderers/Indicator/donchian.d.ts +4 -1
- package/dist/engine/renderers/Indicator/donchian.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/donchian.js +20 -8
- package/dist/engine/renderers/Indicator/donchian.js.map +1 -1
- package/dist/engine/renderers/Indicator/ene.d.ts +12 -1
- package/dist/engine/renderers/Indicator/ene.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/ene.js +25 -11
- package/dist/engine/renderers/Indicator/ene.js.map +1 -1
- package/dist/engine/renderers/Indicator/expma.d.ts +4 -1
- package/dist/engine/renderers/Indicator/expma.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/expma.js +22 -9
- package/dist/engine/renderers/Indicator/expma.js.map +1 -1
- package/dist/engine/renderers/Indicator/fastk.d.ts +2 -1
- package/dist/engine/renderers/Indicator/fastk.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/fastk.js +12 -10
- package/dist/engine/renderers/Indicator/fastk.js.map +1 -1
- package/dist/engine/renderers/Indicator/fib.d.ts +2 -0
- package/dist/engine/renderers/Indicator/fib.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/fib.js +26 -8
- package/dist/engine/renderers/Indicator/fib.js.map +1 -1
- package/dist/engine/renderers/Indicator/hma.d.ts +2 -0
- package/dist/engine/renderers/Indicator/hma.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/hma.js +19 -8
- package/dist/engine/renderers/Indicator/hma.js.map +1 -1
- package/dist/engine/renderers/Indicator/hv.d.ts +4 -1
- package/dist/engine/renderers/Indicator/hv.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/hv.js +18 -8
- package/dist/engine/renderers/Indicator/hv.js.map +1 -1
- package/dist/engine/renderers/Indicator/ichimoku.d.ts +4 -1
- package/dist/engine/renderers/Indicator/ichimoku.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/ichimoku.js +27 -8
- package/dist/engine/renderers/Indicator/ichimoku.js.map +1 -1
- package/dist/engine/renderers/Indicator/index.d.ts +27 -28
- package/dist/engine/renderers/Indicator/index.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/index.js +27 -28
- package/dist/engine/renderers/Indicator/index.js.map +1 -1
- package/dist/engine/renderers/Indicator/kama.d.ts +2 -0
- package/dist/engine/renderers/Indicator/kama.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/kama.js +19 -8
- package/dist/engine/renderers/Indicator/kama.js.map +1 -1
- package/dist/engine/renderers/Indicator/keltner.d.ts +4 -1
- package/dist/engine/renderers/Indicator/keltner.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/keltner.js +20 -8
- package/dist/engine/renderers/Indicator/keltner.js.map +1 -1
- package/dist/engine/renderers/Indicator/kst.d.ts +2 -1
- package/dist/engine/renderers/Indicator/kst.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/kst.js +13 -11
- package/dist/engine/renderers/Indicator/kst.js.map +1 -1
- package/dist/engine/renderers/Indicator/ma.d.ts +4 -1
- package/dist/engine/renderers/Indicator/ma.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/ma.js +36 -8
- package/dist/engine/renderers/Indicator/ma.js.map +1 -1
- package/dist/engine/renderers/Indicator/macd.d.ts +1 -1
- package/dist/engine/renderers/Indicator/macd.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/macd.js +9 -10
- package/dist/engine/renderers/Indicator/macd.js.map +1 -1
- package/dist/engine/renderers/Indicator/mainIndicatorLegend.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/mainIndicatorLegend.js +38 -136
- package/dist/engine/renderers/Indicator/mainIndicatorLegend.js.map +1 -1
- package/dist/engine/renderers/Indicator/mfi.d.ts +4 -1
- package/dist/engine/renderers/Indicator/mfi.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/mfi.js +20 -7
- package/dist/engine/renderers/Indicator/mfi.js.map +1 -1
- package/dist/engine/renderers/Indicator/mom.d.ts +2 -1
- package/dist/engine/renderers/Indicator/mom.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/mom.js +12 -10
- package/dist/engine/renderers/Indicator/mom.js.map +1 -1
- package/dist/engine/renderers/Indicator/obv.d.ts +4 -1
- package/dist/engine/renderers/Indicator/obv.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/obv.js +19 -7
- package/dist/engine/renderers/Indicator/obv.js.map +1 -1
- package/dist/engine/renderers/Indicator/parkinson.d.ts +4 -1
- package/dist/engine/renderers/Indicator/parkinson.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/parkinson.js +18 -8
- package/dist/engine/renderers/Indicator/parkinson.js.map +1 -1
- package/dist/engine/renderers/Indicator/pivot.d.ts +2 -0
- package/dist/engine/renderers/Indicator/pivot.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/pivot.js +43 -8
- package/dist/engine/renderers/Indicator/pivot.js.map +1 -1
- package/dist/engine/renderers/Indicator/pvt.d.ts +4 -1
- package/dist/engine/renderers/Indicator/pvt.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/pvt.js +19 -7
- package/dist/engine/renderers/Indicator/pvt.js.map +1 -1
- package/dist/engine/renderers/Indicator/roc.d.ts +4 -1
- package/dist/engine/renderers/Indicator/roc.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/roc.js +20 -7
- package/dist/engine/renderers/Indicator/roc.js.map +1 -1
- package/dist/engine/renderers/Indicator/rsi.d.ts +2 -1
- package/dist/engine/renderers/Indicator/rsi.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/rsi.js +14 -11
- package/dist/engine/renderers/Indicator/rsi.js.map +1 -1
- package/dist/engine/renderers/Indicator/sar.d.ts +4 -1
- package/dist/engine/renderers/Indicator/sar.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/sar.js +18 -8
- package/dist/engine/renderers/Indicator/sar.js.map +1 -1
- package/dist/engine/renderers/Indicator/stoch.d.ts +2 -1
- package/dist/engine/renderers/Indicator/stoch.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/stoch.js +10 -11
- package/dist/engine/renderers/Indicator/stoch.js.map +1 -1
- package/dist/engine/renderers/Indicator/structure.d.ts +4 -1
- package/dist/engine/renderers/Indicator/structure.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/structure.js +21 -8
- package/dist/engine/renderers/Indicator/structure.js.map +1 -1
- package/dist/engine/renderers/Indicator/supertrend.d.ts +4 -1
- package/dist/engine/renderers/Indicator/supertrend.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/supertrend.js +18 -8
- package/dist/engine/renderers/Indicator/supertrend.js.map +1 -1
- package/dist/engine/renderers/Indicator/tema.d.ts +2 -0
- package/dist/engine/renderers/Indicator/tema.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/tema.js +19 -8
- package/dist/engine/renderers/Indicator/tema.js.map +1 -1
- package/dist/engine/renderers/Indicator/trix.d.ts +4 -1
- package/dist/engine/renderers/Indicator/trix.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/trix.js +30 -8
- package/dist/engine/renderers/Indicator/trix.js.map +1 -1
- package/dist/engine/renderers/Indicator/vma.d.ts +4 -1
- package/dist/engine/renderers/Indicator/vma.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/vma.js +20 -7
- package/dist/engine/renderers/Indicator/vma.js.map +1 -1
- package/dist/engine/renderers/Indicator/volumeProfile.d.ts +4 -1
- package/dist/engine/renderers/Indicator/volumeProfile.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/volumeProfile.js +28 -8
- package/dist/engine/renderers/Indicator/volumeProfile.js.map +1 -1
- package/dist/engine/renderers/Indicator/vwap.d.ts +4 -1
- package/dist/engine/renderers/Indicator/vwap.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/vwap.js +19 -7
- package/dist/engine/renderers/Indicator/vwap.js.map +1 -1
- package/dist/engine/renderers/Indicator/wma.d.ts +2 -0
- package/dist/engine/renderers/Indicator/wma.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/wma.js +19 -8
- package/dist/engine/renderers/Indicator/wma.js.map +1 -1
- package/dist/engine/renderers/Indicator/wmsr.d.ts +2 -1
- package/dist/engine/renderers/Indicator/wmsr.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/wmsr.js +12 -10
- package/dist/engine/renderers/Indicator/wmsr.js.map +1 -1
- package/dist/engine/renderers/Indicator/zones.d.ts +2 -0
- package/dist/engine/renderers/Indicator/zones.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/zones.js +24 -8
- package/dist/engine/renderers/Indicator/zones.js.map +1 -1
- package/dist/engine/renderers/paneTitle.d.ts +4 -10
- package/dist/engine/renderers/paneTitle.d.ts.map +1 -1
- package/dist/engine/renderers/paneTitle.js +28 -6
- package/dist/engine/renderers/paneTitle.js.map +1 -1
- package/dist/engine/renderers/subVolume.js +0 -3
- package/dist/engine/renderers/subVolume.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +4 -4
- package/src/controllers/__tests__/indicatorSelector.test.ts +4 -3
- package/src/controllers/createIndicatorSelectorController.ts +4 -6
- package/src/controllers/index.ts +0 -4
- package/src/engine/chart.ts +30 -22
- package/src/engine/indicators/__tests__/registerBuiltins.test.ts +14 -23
- package/src/engine/indicators/__tests__/scheduler.test.ts +14 -14
- package/src/engine/indicators/__tests__/stateComposer.test.ts +7 -4
- package/src/engine/indicators/indicator.worker.ts +36 -4
- package/src/engine/indicators/indicatorDefinitionRegistry.ts +38 -3
- package/src/engine/indicators/indicatorMetadata.ts +66 -1
- package/src/engine/indicators/indicatorRuntime.ts +121 -1447
- package/src/engine/indicators/scheduler.ts +85 -489
- package/src/engine/indicators/stateComposer.ts +16 -60
- package/src/engine/indicators/workerProtocol.ts +14 -36
- package/src/engine/renderers/Indicator/atr.ts +14 -11
- package/src/engine/renderers/Indicator/boll.ts +33 -10
- package/src/engine/renderers/Indicator/cci.ts +15 -14
- package/src/engine/renderers/Indicator/chaikinVol.ts +29 -7
- package/src/engine/renderers/Indicator/cmf.ts +28 -7
- package/src/engine/renderers/Indicator/dema.ts +28 -9
- package/src/engine/renderers/Indicator/donchian.ts +28 -9
- package/src/engine/renderers/Indicator/ene.ts +34 -11
- package/src/engine/renderers/Indicator/expma.ts +31 -9
- package/src/engine/renderers/Indicator/fastk.ts +15 -14
- package/src/engine/renderers/Indicator/fib.ts +29 -9
- package/src/engine/renderers/Indicator/hma.ts +28 -9
- package/src/engine/renderers/Indicator/hv.ts +27 -8
- package/src/engine/renderers/Indicator/ichimoku.ts +31 -9
- package/src/engine/renderers/Indicator/index.ts +27 -28
- package/src/engine/renderers/Indicator/kama.ts +28 -9
- package/src/engine/renderers/Indicator/keltner.ts +28 -9
- package/src/engine/renderers/Indicator/kst.ts +16 -19
- package/src/engine/renderers/Indicator/ma.ts +44 -9
- package/src/engine/renderers/Indicator/macd.ts +31 -36
- package/src/engine/renderers/Indicator/mainIndicatorLegend.ts +43 -162
- package/src/engine/renderers/Indicator/mfi.ts +28 -7
- package/src/engine/renderers/Indicator/mom.ts +15 -14
- package/src/engine/renderers/Indicator/obv.ts +27 -7
- package/src/engine/renderers/Indicator/parkinson.ts +27 -8
- package/src/engine/renderers/Indicator/pivot.ts +47 -9
- package/src/engine/renderers/Indicator/pvt.ts +27 -7
- package/src/engine/renderers/Indicator/roc.ts +29 -7
- package/src/engine/renderers/Indicator/rsi.ts +14 -17
- package/src/engine/renderers/Indicator/sar.ts +26 -9
- package/src/engine/renderers/Indicator/stoch.ts +13 -16
- package/src/engine/renderers/Indicator/structure.ts +31 -8
- package/src/engine/renderers/Indicator/supertrend.ts +26 -9
- package/src/engine/renderers/Indicator/tema.ts +28 -9
- package/src/engine/renderers/Indicator/trix.ts +39 -8
- package/src/engine/renderers/Indicator/vma.ts +28 -7
- package/src/engine/renderers/Indicator/volumeProfile.ts +40 -8
- package/src/engine/renderers/Indicator/vwap.ts +27 -7
- package/src/engine/renderers/Indicator/wma.ts +28 -9
- package/src/engine/renderers/Indicator/wmsr.ts +15 -14
- package/src/engine/renderers/Indicator/zones.ts +29 -9
- package/src/engine/renderers/__tests__/mainIndicatorLegend.renderer.test.ts +142 -79
- package/src/engine/renderers/paneTitle.ts +43 -18
- package/src/engine/renderers/subVolume.ts +0 -2
- package/src/version.ts +1 -1
- package/dist/engine/renderers/Indicator/macdLegend.d.ts +0 -13
- package/dist/engine/renderers/Indicator/macdLegend.d.ts.map +0 -1
- package/dist/engine/renderers/Indicator/macdLegend.js +0 -116
- package/dist/engine/renderers/Indicator/macdLegend.js.map +0 -1
- package/dist/engine/renderers/Indicator/subPaneConfig.d.ts +0 -16
- package/dist/engine/renderers/Indicator/subPaneConfig.d.ts.map +0 -1
- package/dist/engine/renderers/Indicator/subPaneConfig.js +0 -194
- package/dist/engine/renderers/Indicator/subPaneConfig.js.map +0 -1
- package/src/engine/renderers/Indicator/macdLegend.ts +0 -141
- package/src/engine/renderers/Indicator/subPaneConfig.ts +0 -265
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { RendererPluginWithHost, RenderContext, PluginHost } from '../../../plugin'
|
|
2
2
|
import { RENDERER_PRIORITY } from '../../../plugin'
|
|
3
|
+
import type { KLineData } from '../../../types/price'
|
|
3
4
|
import type { KeltnerRenderState } from '../../indicators/keltnerState'
|
|
4
5
|
import { createKeltnerStateKey, EMPTY_KELTNER_STATE } from '../../indicators/keltnerState'
|
|
5
6
|
import { Indicator } from '../../indicators/indicatorDefinitionRegistry'
|
|
6
|
-
import { resolveStateKey } from '../../indicators/indicatorMetadata'
|
|
7
|
+
import { resolveStateKey, type TitleInfo, type GetTitleInfoFn } from '../../indicators/indicatorMetadata'
|
|
7
8
|
import type { IndicatorScheduler, KeltnerSchedulerConfig } from '../../indicators/scheduler'
|
|
9
|
+
import { calcKeltnerData } from '../../indicators/calculators'
|
|
8
10
|
import { createBandVisibleStateComposer } from '../../indicators/visibleStateComposers'
|
|
9
11
|
|
|
10
12
|
const KELTNER_UPPER_COLOR = '#7c3aed'
|
|
@@ -122,23 +124,40 @@ function drawLine(ctx: CanvasRenderingContext2D, pts: Point[], color: string): v
|
|
|
122
124
|
ctx.stroke()
|
|
123
125
|
}
|
|
124
126
|
|
|
127
|
+
export function getKeltnerTitleInfo(
|
|
128
|
+
_data: KLineData[],
|
|
129
|
+
index: number | null,
|
|
130
|
+
params: Record<string, number | boolean | string>,
|
|
131
|
+
host: PluginHost,
|
|
132
|
+
paneId: string,
|
|
133
|
+
): TitleInfo | null {
|
|
134
|
+
if (index === null) return null
|
|
135
|
+
const state = host.getSharedState<KeltnerRenderState>(createKeltnerStateKey(paneId))
|
|
136
|
+
const p = state?.series[index]
|
|
137
|
+
if (!p) return null
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
name: 'Keltner',
|
|
141
|
+
params: [(params.emaPeriod as number) ?? 20, (params.atrPeriod as number) ?? 10, (params.multiplier as number) ?? 2],
|
|
142
|
+
values: [
|
|
143
|
+
{ label: 'Upper', value: p.upper, color: '#7c3aed' },
|
|
144
|
+
{ label: 'Mid', value: p.middle, color: '#f59e0b' },
|
|
145
|
+
{ label: 'Lower', value: p.lower, color: '#7c3aed' },
|
|
146
|
+
],
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
125
150
|
@Indicator({
|
|
126
151
|
name: 'keltner',
|
|
127
152
|
displayName: 'Keltner',
|
|
153
|
+
getTitleInfo: getKeltnerTitleInfo,
|
|
128
154
|
category: 'main',
|
|
129
|
-
stateKey: createKeltnerStateKey,
|
|
130
155
|
defaultPaneId: 'main',
|
|
131
|
-
paneIdField: 'keltnerPaneId',
|
|
132
156
|
allowMainPane: true,
|
|
133
157
|
mainPane: { rendererName: 'keltner_main', toActiveConfig: (params, active) => ({ ...params, showUpper: active, showMiddle: active, showLower: active }) },
|
|
134
158
|
scale: { indicatorKey: 'keltner', label: 'Keltner', decimals: 2 },
|
|
135
159
|
visibleState: { compose: createBandVisibleStateComposer('keltner', EMPTY_KELTNER_STATE, 'lower', 'upper') },
|
|
136
|
-
|
|
137
|
-
(scheduler as IndicatorScheduler).updateKeltnerConfig(params as Partial<KeltnerSchedulerConfig>, paneId)
|
|
138
|
-
},
|
|
139
|
-
applyResult: (host, state, paneId) => {
|
|
140
|
-
host.setSharedState(createKeltnerStateKey(paneId), state as any, 'indicator_scheduler')
|
|
141
|
-
},
|
|
160
|
+
runtime: { defaultConfig:{emaPeriod:20,atrPeriod:10,multiplier:2,showUpper:true,showMiddle:true,showLower:true}, computeKey:'calcKeltnerData', compute:(data,c)=>calcKeltnerData(data,c.emaPeriod,c.atrPeriod,c.multiplier) },
|
|
142
161
|
})
|
|
143
162
|
class KeltnerDefinition {
|
|
144
163
|
static rendererFactory = createKeltnerRendererPlugin
|
|
@@ -9,6 +9,8 @@ import { Indicator } from '../../indicators/indicatorDefinitionRegistry'
|
|
|
9
9
|
import { resolveStateKey } from '../../indicators/indicatorMetadata'
|
|
10
10
|
import type { IndicatorScheduler, KSTSchedulerConfig } from '../../indicators/scheduler'
|
|
11
11
|
import { createKstScaleRendererPlugin } from './scale/kst_scale'
|
|
12
|
+
import { calcKSTData } from '../../indicators/calculators'
|
|
13
|
+
import type { KLineData } from '../../../types/price'
|
|
12
14
|
|
|
13
15
|
type LinePoint = { x: number; y: number }
|
|
14
16
|
|
|
@@ -208,7 +210,7 @@ const { ctx, pane, range, scrollLeft, dpr, kLineCenters, lineWebGLSurface } = co
|
|
|
208
210
|
},
|
|
209
211
|
|
|
210
212
|
setConfig() {
|
|
211
|
-
// no-op: 配置通过 scheduler.
|
|
213
|
+
// no-op: 配置通过 scheduler.updateIndicatorConfig() 更新
|
|
212
214
|
},
|
|
213
215
|
}
|
|
214
216
|
}
|
|
@@ -259,18 +261,19 @@ function drawKSTLinesWithCanvas2D(
|
|
|
259
261
|
* 获取 KST 标题信息(供 paneTitle 使用)
|
|
260
262
|
*/
|
|
261
263
|
export function getKSTTitleInfo(
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
roc3: number,
|
|
266
|
-
roc4: number,
|
|
267
|
-
signalPeriod: number,
|
|
264
|
+
_data: KLineData[],
|
|
265
|
+
index: number | null,
|
|
266
|
+
params: Record<string, number | boolean | string>,
|
|
268
267
|
pluginHost: PluginHost,
|
|
269
|
-
paneId: string
|
|
270
|
-
theme: 'light' | 'dark' = 'light',
|
|
271
|
-
isAsiaMarket?: boolean
|
|
268
|
+
paneId: string,
|
|
272
269
|
): { name: string; params: number[]; values: Array<{ label: string; value: number; color: string }> } | null {
|
|
273
|
-
|
|
270
|
+
if (index === null) return null
|
|
271
|
+
const roc1 = (params.roc1 as number) ?? 10
|
|
272
|
+
const roc2 = (params.roc2 as number) ?? 15
|
|
273
|
+
const roc3 = (params.roc3 as number) ?? 20
|
|
274
|
+
const roc4 = (params.roc4 as number) ?? 30
|
|
275
|
+
const signalPeriod = (params.signalPeriod as number) ?? 9
|
|
276
|
+
const colors = resolveThemeColors('light')
|
|
274
277
|
const state = pluginHost.getSharedState<KSTRenderState>(createKSTStateKey(paneId))
|
|
275
278
|
if (!state) return null
|
|
276
279
|
|
|
@@ -294,17 +297,11 @@ export function getKSTTitleInfo(
|
|
|
294
297
|
name: 'kst',
|
|
295
298
|
displayName: 'KST',
|
|
296
299
|
category: 'oscillator',
|
|
297
|
-
stateKey: createKSTStateKey,
|
|
298
300
|
defaultPaneId: 'sub_KST',
|
|
299
|
-
paneIdField: 'kstPaneId',
|
|
300
301
|
scaleRendererFactory: createKstScaleRendererPlugin,
|
|
301
|
-
updateConfig: (scheduler, params, paneId) => {
|
|
302
|
-
(scheduler as IndicatorScheduler).updateKSTConfig(params as Partial<KSTSchedulerConfig>, paneId)
|
|
303
|
-
},
|
|
304
302
|
visibleState: { compose: createPaddedPointVisibleStateComposer('kst', EMPTY_KST_STATE, ['kst', 'signal'] as const) },
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
},
|
|
303
|
+
getTitleInfo: getKSTTitleInfo,
|
|
304
|
+
runtime: { defaultConfig:{roc1:10,roc2:15,roc3:20,roc4:30,signalPeriod:9,showKST:true,showSignal:true}, computeKey:'calcKSTData', compute:(data,c)=>calcKSTData(data,c.roc1,c.roc2,c.roc3,c.roc4,c.signalPeriod) },
|
|
308
305
|
})
|
|
309
306
|
class KSTIndicatorDefinition {
|
|
310
307
|
static rendererFactory = createKSTRendererPlugin
|
|
@@ -3,9 +3,10 @@ import { RENDERER_PRIORITY } from '../../../plugin'
|
|
|
3
3
|
import { MA_STATE_KEY, type MARenderState } from '../../indicators/maState'
|
|
4
4
|
import { Indicator } from '../../indicators/indicatorDefinitionRegistry'
|
|
5
5
|
import { resolveStateKey } from '../../indicators/indicatorMetadata'
|
|
6
|
-
import type { IndicatorPriceRangeComputer, IndicatorRenderStateComposer } from '../../indicators/indicatorMetadata'
|
|
6
|
+
import type { IndicatorPriceRangeComputer, IndicatorRenderStateComposer, GetTitleInfoFn, TitleInfo, TitleValueItem } from '../../indicators/indicatorMetadata'
|
|
7
|
+
import type { KLineData } from '../../../types/price'
|
|
7
8
|
import type { IndicatorScheduler } from '../../indicators/scheduler'
|
|
8
|
-
import type
|
|
9
|
+
import { calcMAData, type MAFlags } from '../../indicators/calculators'
|
|
9
10
|
import { alignToPhysicalPixelCenter } from '../../draw/pixelAlign'
|
|
10
11
|
import { resolveThemeColors } from '../../../tokens'
|
|
11
12
|
|
|
@@ -93,11 +94,49 @@ function getMAStateKey(host: PluginHost | null): string | null {
|
|
|
93
94
|
return resolveStateKey(meta.stateKey)
|
|
94
95
|
}
|
|
95
96
|
|
|
97
|
+
export function getMATitleInfo(
|
|
98
|
+
_data: KLineData[],
|
|
99
|
+
index: number | null,
|
|
100
|
+
_params: Record<string, number | boolean | string>,
|
|
101
|
+
pluginHost: PluginHost,
|
|
102
|
+
_paneId: string,
|
|
103
|
+
): TitleInfo | null {
|
|
104
|
+
if (index === null) return null
|
|
105
|
+
|
|
106
|
+
const stateKey = getMAStateKey(pluginHost)
|
|
107
|
+
if (!stateKey) return null
|
|
108
|
+
|
|
109
|
+
const state = pluginHost?.getSharedState<MARenderState>(stateKey)
|
|
110
|
+
if (!state || state.visibleMin > state.visibleMax) return null
|
|
111
|
+
|
|
112
|
+
const maColors: Record<number, string> = {
|
|
113
|
+
5: '#f5a623',
|
|
114
|
+
10: '#4ecdc4',
|
|
115
|
+
20: '#45b7d1',
|
|
116
|
+
30: '#96ceb4',
|
|
117
|
+
60: '#dda0dd',
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const values: TitleValueItem[] = []
|
|
121
|
+
for (const period of state.enabledPeriods) {
|
|
122
|
+
const series = state.series[period]
|
|
123
|
+
const value = series?.[index]
|
|
124
|
+
if (value === undefined) continue
|
|
125
|
+
|
|
126
|
+
values.push({
|
|
127
|
+
label: `MA${period}`,
|
|
128
|
+
value,
|
|
129
|
+
color: maColors[period] ?? '#f5a623',
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return { name: 'MA', params: [], values }
|
|
134
|
+
}
|
|
135
|
+
|
|
96
136
|
@Indicator({
|
|
97
137
|
name: 'ma',
|
|
98
138
|
displayName: 'MA',
|
|
99
139
|
category: 'main',
|
|
100
|
-
stateKey: MA_STATE_KEY,
|
|
101
140
|
defaultPaneId: 'main',
|
|
102
141
|
mainPane: {
|
|
103
142
|
rendererName: 'ma',
|
|
@@ -111,9 +150,6 @@ function getMAStateKey(host: PluginHost | null): string | null {
|
|
|
111
150
|
computePriceRange: computeMAPriceRange,
|
|
112
151
|
composeRenderState: composeMARenderState,
|
|
113
152
|
},
|
|
114
|
-
updateConfig: (scheduler, params) => {
|
|
115
|
-
(scheduler as IndicatorScheduler).updateMAConfig(params as MAFlags)
|
|
116
|
-
},
|
|
117
153
|
semantic: {
|
|
118
154
|
apply: (chart, indicator) => {
|
|
119
155
|
const periods = (indicator as { params?: { periods?: number[] } }).params?.periods ?? [5, 10, 20, 30, 60]
|
|
@@ -125,9 +161,8 @@ function getMAStateKey(host: PluginHost | null): string | null {
|
|
|
125
161
|
chart.updateRendererConfig('ma', maFlags)
|
|
126
162
|
},
|
|
127
163
|
},
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
},
|
|
164
|
+
runtime: { defaultConfig:{ma5:true,ma10:true,ma20:true,ma30:true,ma60:true}, computeKey:'calcMAData', compute:(data,c)=>{const p=[5,10,20,30,60];const r:Record<number,(number|undefined)[]>={};for(const o of p){if((c as any)['ma'+o])r[o]=calcMAData(data,o)}return r} },
|
|
165
|
+
getTitleInfo: getMATitleInfo,
|
|
131
166
|
})
|
|
132
167
|
class MADefinition {
|
|
133
168
|
static rendererFactory = createMARendererPlugin
|
|
@@ -345,25 +345,25 @@ function drawMacdBarsWithCanvas2D(
|
|
|
345
345
|
ctx.fillStyle = barUpColor
|
|
346
346
|
for (let i = 0; i < barUpCount; i++) {
|
|
347
347
|
const off = i * 4
|
|
348
|
-
ctx.fillRect(barUpBuf[off]
|
|
348
|
+
ctx.fillRect(barUpBuf[off]!, barUpBuf[off + 1]!, barUpBuf[off + 2]!, barUpBuf[off + 3]!)
|
|
349
349
|
}
|
|
350
350
|
|
|
351
351
|
ctx.fillStyle = barUpLightColor
|
|
352
352
|
for (let i = 0; i < barUpLightCount; i++) {
|
|
353
353
|
const off = i * 4
|
|
354
|
-
ctx.fillRect(barUpLightBuf[off]
|
|
354
|
+
ctx.fillRect(barUpLightBuf[off]!, barUpLightBuf[off + 1]!, barUpLightBuf[off + 2]!, barUpLightBuf[off + 3]!)
|
|
355
355
|
}
|
|
356
356
|
|
|
357
357
|
ctx.fillStyle = barDownColor
|
|
358
358
|
for (let i = 0; i < barDownCount; i++) {
|
|
359
359
|
const off = i * 4
|
|
360
|
-
ctx.fillRect(barDownBuf[off]
|
|
360
|
+
ctx.fillRect(barDownBuf[off]!, barDownBuf[off + 1]!, barDownBuf[off + 2]!, barDownBuf[off + 3]!)
|
|
361
361
|
}
|
|
362
362
|
|
|
363
363
|
ctx.fillStyle = barDownLightColor
|
|
364
364
|
for (let i = 0; i < barDownLightCount; i++) {
|
|
365
365
|
const off = i * 4
|
|
366
|
-
ctx.fillRect(barDownLightBuf[off]
|
|
366
|
+
ctx.fillRect(barDownLightBuf[off]!, barDownLightBuf[off + 1]!, barDownLightBuf[off + 2]!, barDownLightBuf[off + 3]!)
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
ctx.restore()
|
|
@@ -438,48 +438,43 @@ export function calcMACDAtIndex(
|
|
|
438
438
|
* 从 pluginHost 获取已计算好的数据,避免重复计算
|
|
439
439
|
*/
|
|
440
440
|
export function getMACDTitleInfo(
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
paneId: string = 'sub_MACD',
|
|
447
|
-
theme: 'light' | 'dark' = 'light',
|
|
448
|
-
isAsiaMarket?: boolean
|
|
441
|
+
_data: KLineData[],
|
|
442
|
+
index: number | null,
|
|
443
|
+
params: Record<string, number | boolean | string>,
|
|
444
|
+
pluginHost: PluginHost,
|
|
445
|
+
paneId: string,
|
|
449
446
|
): { name: string; params: number[]; values: Array<{ label: string; value: number; color: string }> } | null {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
447
|
+
if (index === null) return null
|
|
448
|
+
const fastPeriod = (params.fastPeriod as number) ?? 12
|
|
449
|
+
const slowPeriod = (params.slowPeriod as number) ?? 26
|
|
450
|
+
const signalPeriod = (params.signalPeriod as number) ?? 9
|
|
451
|
+
const colors = resolveThemeColors('light')
|
|
452
|
+
const state = pluginHost.getSharedState<MACDRenderState>(createMACDStateKey(paneId))
|
|
453
|
+
if (!state) return null
|
|
454
|
+
|
|
455
|
+
const point = state.series[index]
|
|
456
|
+
if (!point) return null
|
|
457
|
+
|
|
458
|
+
return {
|
|
459
|
+
name: 'MACD',
|
|
460
|
+
params: [fastPeriod, slowPeriod, signalPeriod],
|
|
461
|
+
values: [
|
|
462
|
+
{ label: 'DIF', value: point.dif, color: colors.macd.dif },
|
|
463
|
+
{ label: 'DEA', value: point.dea, color: colors.macd.dea },
|
|
464
|
+
{ label: 'MACD', value: point.macd, color: point.macd >= 0 ? colors.macd.barUp : colors.macd.barDown },
|
|
465
|
+
],
|
|
466
|
+
}
|
|
466
467
|
}
|
|
467
468
|
|
|
468
469
|
@Indicator({
|
|
469
470
|
name: 'macd',
|
|
470
471
|
displayName: 'MACD',
|
|
471
472
|
category: 'oscillator',
|
|
472
|
-
stateKey: createMACDStateKey,
|
|
473
473
|
defaultPaneId: 'sub_MACD',
|
|
474
|
-
paneIdField: 'macdPaneId',
|
|
475
474
|
scaleRendererFactory: createMacdScaleRendererPlugin,
|
|
476
475
|
visibleState: { compose: createMACDVisibleStateComposer('macd', EMPTY_MACD_STATE) },
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
},
|
|
480
|
-
applyResult: (host, state, paneId) => {
|
|
481
|
-
host.setSharedState(createMACDStateKey(paneId), state as any, 'indicator_scheduler')
|
|
482
|
-
},
|
|
476
|
+
getTitleInfo: getMACDTitleInfo,
|
|
477
|
+
runtime: { defaultConfig:{fastPeriod:12,slowPeriod:26,signalPeriod:9,showDIF:true,showDEA:true,showBAR:true}, computeKey:'calcMACDData', compute:(data,c)=>calcMACDData(data,c.fastPeriod,c.slowPeriod,c.signalPeriod) },
|
|
483
478
|
})
|
|
484
479
|
class MACDIndicatorDefinition {
|
|
485
480
|
static rendererFactory = createMACDRendererPlugin
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import type { RendererPluginWithHost, PluginHost, RenderContext } from '../../../plugin'
|
|
2
2
|
import { RENDERER_PRIORITY } from '../../../plugin'
|
|
3
3
|
import type { KLineData } from '../../../types/price'
|
|
4
|
-
import { MA_STATE_KEY, type MARenderState } from '../../indicators/maState'
|
|
5
|
-
import { BOLL_STATE_KEY, type BOLLRenderState } from '../../indicators/bollState'
|
|
6
|
-
import { EXPMA_STATE_KEY, type EXPMARenderState } from '../../indicators/expmaState'
|
|
7
|
-
import { ENE_STATE_KEY, type ENERenderState } from '../../indicators/eneState'
|
|
8
4
|
import { resolveThemeColors } from '../../../tokens'
|
|
9
5
|
import { getFont, setCanvasFont } from '../../theme/fonts'
|
|
6
|
+
import type { IndicatorScheduler } from '../../indicators/scheduler'
|
|
10
7
|
|
|
11
8
|
const textWidthCache = new Map<string, number>()
|
|
12
9
|
const TEXT_WIDTH_CACHE_LIMIT = 512
|
|
@@ -26,16 +23,9 @@ function measureTextWidth(ctx: CanvasRenderingContext2D, text: string): number {
|
|
|
26
23
|
return width
|
|
27
24
|
}
|
|
28
25
|
|
|
29
|
-
/** 指标行数据 */
|
|
30
|
-
interface IndicatorRow {
|
|
31
|
-
enabled: boolean
|
|
32
|
-
params: Record<string, unknown>
|
|
33
|
-
}
|
|
34
|
-
|
|
35
26
|
/** 渲染器配置 */
|
|
36
27
|
interface MainIndicatorLegendConfig {
|
|
37
28
|
yPaddingPx: number
|
|
38
|
-
indicators: Record<string, IndicatorRow>
|
|
39
29
|
}
|
|
40
30
|
|
|
41
31
|
/**
|
|
@@ -49,12 +39,6 @@ export function createMainIndicatorLegendRendererPlugin(options: {
|
|
|
49
39
|
}): RendererPluginWithHost {
|
|
50
40
|
const config: MainIndicatorLegendConfig = {
|
|
51
41
|
yPaddingPx: options.yPaddingPx,
|
|
52
|
-
indicators: {
|
|
53
|
-
MA: { enabled: true, params: {} },
|
|
54
|
-
BOLL: { enabled: false, params: { period: 20, multiplier: 2 } },
|
|
55
|
-
EXPMA: { enabled: false, params: { fastPeriod: 12, slowPeriod: 50 } },
|
|
56
|
-
ENE: { enabled: false, params: { period: 10, deviation: 11 } },
|
|
57
|
-
},
|
|
58
42
|
}
|
|
59
43
|
|
|
60
44
|
let pluginHost: PluginHost | null = null
|
|
@@ -74,7 +58,7 @@ export function createMainIndicatorLegendRendererPlugin(options: {
|
|
|
74
58
|
},
|
|
75
59
|
|
|
76
60
|
getDeclaredNamespaces(): string[] {
|
|
77
|
-
return [
|
|
61
|
+
return []
|
|
78
62
|
},
|
|
79
63
|
|
|
80
64
|
draw(context: RenderContext) {
|
|
@@ -87,153 +71,64 @@ export function createMainIndicatorLegendRendererPlugin(options: {
|
|
|
87
71
|
const lineHeight = fontSize + 6
|
|
88
72
|
const legendX = 12
|
|
89
73
|
const gap = 10
|
|
74
|
+
const legendYOffset = 6
|
|
90
75
|
|
|
91
76
|
overlayCtx.save()
|
|
92
77
|
setCanvasFont(overlayCtx, getFont(fontSize))
|
|
93
78
|
overlayCtx.textAlign = 'left'
|
|
79
|
+
overlayCtx.textBaseline = 'top'
|
|
94
80
|
|
|
95
81
|
const targetIndex = crosshairIndex ?? Math.min(range.end - 1, klineData.length - 1)
|
|
96
82
|
const rows: Array<{ draw: (rowIndex: number) => void }> = []
|
|
97
83
|
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
draw: (rowIndex: number) => {
|
|
102
|
-
const items: Array<{ label: string; color: string; value?: number }> = []
|
|
103
|
-
const state = pluginHost?.getSharedState<MARenderState>(MA_STATE_KEY)
|
|
104
|
-
|
|
105
|
-
if (state && state.visibleMin <= state.visibleMax) {
|
|
106
|
-
for (const period of state.enabledPeriods) {
|
|
107
|
-
const colorKey = `ma${period}` as keyof typeof colors.ma
|
|
108
|
-
const series = state.series[period]
|
|
109
|
-
const value = series?.[targetIndex]
|
|
110
|
-
|
|
111
|
-
items.push({
|
|
112
|
-
label: `MA${period}`,
|
|
113
|
-
color: colors.ma[colorKey] || colors.ma.ma5,
|
|
114
|
-
value: value,
|
|
115
|
-
})
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (items.length > 0) {
|
|
120
|
-
let x = legendX
|
|
121
|
-
const y = config.yPaddingPx / 2 + fontSize + rowIndex * lineHeight
|
|
122
|
-
|
|
123
|
-
overlayCtx.fillStyle = colors.text.primary
|
|
124
|
-
overlayCtx.fillText('MA', x, y)
|
|
125
|
-
x += measureTextWidth(overlayCtx, 'MA') + gap
|
|
126
|
-
|
|
127
|
-
for (const it of items) {
|
|
128
|
-
const valText = typeof it.value === 'number' ? ` ${it.value.toFixed(2)}` : ''
|
|
129
|
-
const text = `${it.label}${valText}`
|
|
130
|
-
overlayCtx.fillStyle = it.color
|
|
131
|
-
overlayCtx.fillText(text, x, y)
|
|
132
|
-
x += measureTextWidth(overlayCtx, text) + gap
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
})
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const bollIndicator = config.indicators.BOLL
|
|
140
|
-
if (bollIndicator?.enabled) {
|
|
141
|
-
rows.push({
|
|
142
|
-
draw: (rowIndex: number) => {
|
|
143
|
-
const bollState = pluginHost?.getSharedState<BOLLRenderState>(BOLL_STATE_KEY)
|
|
144
|
-
const boll = bollState?.series[targetIndex]
|
|
145
|
-
const period = bollState?.params.period ?? 20
|
|
146
|
-
const multiplier = bollState?.params.multiplier ?? 2
|
|
147
|
-
|
|
148
|
-
let x = legendX
|
|
149
|
-
const y = config.yPaddingPx / 2 + fontSize + rowIndex * lineHeight
|
|
150
|
-
const titleText = `BOLL(${period},${multiplier})`
|
|
151
|
-
|
|
152
|
-
overlayCtx.fillStyle = colors.text.primary
|
|
153
|
-
overlayCtx.fillText(titleText, x, y)
|
|
154
|
-
x += measureTextWidth(overlayCtx, titleText) + gap
|
|
155
|
-
|
|
156
|
-
if (boll) {
|
|
157
|
-
const upperText = `上轨:${boll.upper.toFixed(2)}`
|
|
158
|
-
overlayCtx.fillStyle = colors.boll.upper
|
|
159
|
-
overlayCtx.fillText(upperText, x, y)
|
|
160
|
-
x += measureTextWidth(overlayCtx, upperText) + gap
|
|
84
|
+
const scheduler = pluginHost && typeof pluginHost.getService === 'function'
|
|
85
|
+
? pluginHost.getService<IndicatorScheduler>('indicatorScheduler')
|
|
86
|
+
: undefined
|
|
161
87
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
88
|
+
const mainIndicators = scheduler?.getMainIndicators() ?? []
|
|
89
|
+
for (const meta of mainIndicators) {
|
|
90
|
+
if (!meta.getTitleInfo) continue
|
|
91
|
+
if (!scheduler?.isMainIndicatorActive(meta.name)) continue
|
|
92
|
+
const params = scheduler?.getMainIndicatorParams(meta.name) ?? {}
|
|
93
|
+
const getTitleInfo = meta.getTitleInfo
|
|
166
94
|
|
|
167
|
-
const lowerText = `下轨:${boll.lower.toFixed(2)}`
|
|
168
|
-
overlayCtx.fillStyle = colors.boll.lower
|
|
169
|
-
overlayCtx.fillText(lowerText, x, y)
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
})
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const expmaIndicator = config.indicators.EXPMA
|
|
176
|
-
if (expmaIndicator?.enabled) {
|
|
177
95
|
rows.push({
|
|
178
96
|
draw: (rowIndex: number) => {
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
97
|
+
const titleInfo = getTitleInfo(
|
|
98
|
+
klineData,
|
|
99
|
+
targetIndex,
|
|
100
|
+
params as Record<string, number | boolean | string>,
|
|
101
|
+
pluginHost!,
|
|
102
|
+
'main',
|
|
103
|
+
)
|
|
104
|
+
if (!titleInfo) return
|
|
183
105
|
|
|
184
106
|
let x = legendX
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
107
|
+
let y = config.yPaddingPx / 2 + legendYOffset + rowIndex * lineHeight
|
|
108
|
+
// 指标名称
|
|
188
109
|
overlayCtx.fillStyle = colors.text.primary
|
|
189
|
-
overlayCtx.fillText(
|
|
190
|
-
x += measureTextWidth(overlayCtx,
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
overlayCtx.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
overlayCtx.fillText(slowText, x, y)
|
|
110
|
+
overlayCtx.fillText(titleInfo.name, x, y)
|
|
111
|
+
x += measureTextWidth(overlayCtx, titleInfo.name)
|
|
112
|
+
|
|
113
|
+
// 指标参数
|
|
114
|
+
if (titleInfo.params && titleInfo.params.length > 0) {
|
|
115
|
+
const paramText = `(${titleInfo.params.join(',')})`
|
|
116
|
+
overlayCtx.fillStyle = colors.text.tertiary
|
|
117
|
+
overlayCtx.fillText(paramText, x, y)
|
|
118
|
+
x += measureTextWidth(overlayCtx, paramText) + gap
|
|
119
|
+
} else {
|
|
120
|
+
x += gap
|
|
201
121
|
}
|
|
202
|
-
}
|
|
203
|
-
})
|
|
204
|
-
}
|
|
205
122
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
let x = legendX
|
|
216
|
-
const y = config.yPaddingPx / 2 + fontSize + rowIndex * lineHeight
|
|
217
|
-
const titleText = `ENE(${period},${deviation})`
|
|
218
|
-
|
|
219
|
-
overlayCtx.fillStyle = colors.text.primary
|
|
220
|
-
overlayCtx.fillText(titleText, x, y)
|
|
221
|
-
x += measureTextWidth(overlayCtx, titleText) + gap
|
|
222
|
-
|
|
223
|
-
if (ene) {
|
|
224
|
-
const upperText = `上轨:${ene.upper.toFixed(2)}`
|
|
225
|
-
overlayCtx.fillStyle = colors.ene.upper
|
|
226
|
-
overlayCtx.fillText(upperText, x, y)
|
|
227
|
-
x += measureTextWidth(overlayCtx, upperText) + gap
|
|
228
|
-
|
|
229
|
-
const middleText = `中轨:${ene.middle.toFixed(2)}`
|
|
230
|
-
overlayCtx.fillStyle = colors.ene.middle
|
|
231
|
-
overlayCtx.fillText(middleText, x, y)
|
|
232
|
-
x += measureTextWidth(overlayCtx, middleText) + gap
|
|
233
|
-
|
|
234
|
-
const lowerText = `下轨:${ene.lower.toFixed(2)}`
|
|
235
|
-
overlayCtx.fillStyle = colors.ene.lower
|
|
236
|
-
overlayCtx.fillText(lowerText, x, y)
|
|
123
|
+
// 指标数值
|
|
124
|
+
if (titleInfo.values) {
|
|
125
|
+
y += 1
|
|
126
|
+
for (const item of titleInfo.values) {
|
|
127
|
+
const valText = `${item.label} ${item.value.toFixed(3)}`
|
|
128
|
+
overlayCtx.fillStyle = item.color
|
|
129
|
+
overlayCtx.fillText(valText, x, y)
|
|
130
|
+
x += measureTextWidth(overlayCtx, valText) + gap
|
|
131
|
+
}
|
|
237
132
|
}
|
|
238
133
|
}
|
|
239
134
|
})
|
|
@@ -246,7 +141,6 @@ export function createMainIndicatorLegendRendererPlugin(options: {
|
|
|
246
141
|
getConfig() {
|
|
247
142
|
return {
|
|
248
143
|
yPaddingPx: config.yPaddingPx,
|
|
249
|
-
indicators: { ...config.indicators },
|
|
250
144
|
}
|
|
251
145
|
},
|
|
252
146
|
|
|
@@ -254,19 +148,6 @@ export function createMainIndicatorLegendRendererPlugin(options: {
|
|
|
254
148
|
if (typeof newConfig.yPaddingPx === 'number') {
|
|
255
149
|
config.yPaddingPx = newConfig.yPaddingPx
|
|
256
150
|
}
|
|
257
|
-
if (newConfig.indicators && typeof newConfig.indicators === 'object') {
|
|
258
|
-
for (const [id, row] of Object.entries(newConfig.indicators) as [string, IndicatorRow][]) {
|
|
259
|
-
if (!config.indicators[id]) {
|
|
260
|
-
config.indicators[id] = { enabled: false, params: {} }
|
|
261
|
-
}
|
|
262
|
-
if (row.enabled !== undefined) {
|
|
263
|
-
config.indicators[id].enabled = row.enabled
|
|
264
|
-
}
|
|
265
|
-
if (row.params) {
|
|
266
|
-
config.indicators[id].params = row.params
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
151
|
},
|
|
271
152
|
}
|
|
272
153
|
}
|
|
@@ -2,10 +2,13 @@ import type { RendererPluginWithHost, RenderContext, PluginHost } from '../../..
|
|
|
2
2
|
import { RENDERER_PRIORITY } from '../../../plugin'
|
|
3
3
|
import type { MFIRenderState } from '../../indicators/mfiState'
|
|
4
4
|
import { createMFIStateKey, EMPTY_MFI_STATE } from '../../indicators/mfiState'
|
|
5
|
+
import type { TitleInfo } from '../../indicators/indicatorMetadata'
|
|
6
|
+
import type { KLineData } from '../../../types/price'
|
|
5
7
|
import { Indicator } from '../../indicators/indicatorDefinitionRegistry'
|
|
6
8
|
import { createFixedRangeSparseVisibleStateComposer } from '../../indicators/visibleStateComposers'
|
|
7
9
|
import { resolveStateKey } from '../../indicators/indicatorMetadata'
|
|
8
10
|
import type { IndicatorScheduler, MFISchedulerConfig } from '../../indicators/scheduler'
|
|
11
|
+
import { calcMFIData } from '../../indicators/calculators'
|
|
9
12
|
|
|
10
13
|
const MFI_COLOR = '#fb923c'
|
|
11
14
|
|
|
@@ -127,20 +130,38 @@ export function createMFIRendererPlugin(options: { paneId?: string } = {}): Rend
|
|
|
127
130
|
}
|
|
128
131
|
}
|
|
129
132
|
|
|
133
|
+
export function getMFITitleInfo(
|
|
134
|
+
_data: KLineData[],
|
|
135
|
+
index: number | null,
|
|
136
|
+
params: Record<string, number | boolean | string>,
|
|
137
|
+
host: PluginHost,
|
|
138
|
+
paneId: string,
|
|
139
|
+
): TitleInfo | null {
|
|
140
|
+
if (index === null) return null
|
|
141
|
+
const period = (params.period as number) ?? 14
|
|
142
|
+
const state = host.getSharedState<MFIRenderState>(createMFIStateKey(paneId))
|
|
143
|
+
const value = state?.series[index]
|
|
144
|
+
if (value === undefined) return null
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
name: 'MFI',
|
|
148
|
+
params: [period],
|
|
149
|
+
values: [{ label: 'MFI', value, color: MFI_COLOR }],
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
130
153
|
@Indicator({
|
|
131
154
|
name: 'mfi',
|
|
132
155
|
displayName: 'MFI',
|
|
133
156
|
category: 'volume',
|
|
134
|
-
stateKey: createMFIStateKey,
|
|
135
157
|
defaultPaneId: 'sub_MFI',
|
|
136
|
-
paneIdField: 'mfiPaneId',
|
|
137
158
|
visibleState: { compose: createFixedRangeSparseVisibleStateComposer('mfi', EMPTY_MFI_STATE) },
|
|
138
159
|
scale: { indicatorKey: 'mfi', label: 'MFI', decimals: 2 },
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
160
|
+
getTitleInfo: getMFITitleInfo,
|
|
161
|
+
runtime: {
|
|
162
|
+
defaultConfig: { period: 14, showMFI: true },
|
|
163
|
+
computeKey: 'calcMFIData',
|
|
164
|
+
compute: (data, c) => calcMFIData(data, c.period),
|
|
144
165
|
},
|
|
145
166
|
})
|
|
146
167
|
class MFIIndicatorDefinition {
|