@363045841yyt/klinechart-core 0.7.12 → 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/indicatorDefinitionRegistry.d.ts +3 -2
- 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 +29 -2
- 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.map +1 -1
- package/dist/engine/indicators/indicatorRuntime.js +5 -4
- package/dist/engine/indicators/indicatorRuntime.js.map +1 -1
- package/dist/engine/indicators/scheduler.d.ts +16 -1
- package/dist/engine/indicators/scheduler.d.ts.map +1 -1
- package/dist/engine/indicators/scheduler.js +26 -7
- package/dist/engine/indicators/scheduler.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 +5 -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 +22 -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 +6 -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 +16 -8
- 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 +15 -8
- 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 +18 -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 +19 -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 +22 -10
- 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 +21 -10
- 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 +6 -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 +25 -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 +18 -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 +17 -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 +26 -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 +18 -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 +19 -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 +11 -10
- 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 +32 -9
- 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 +15 -8
- 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 +6 -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 +14 -8
- 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 +17 -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 +42 -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 +14 -8
- 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 +15 -8
- 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 +9 -10
- 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 +17 -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 +8 -10
- 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 +20 -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 +17 -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 +18 -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 +29 -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 +15 -8
- 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 +27 -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 +14 -8
- 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 +18 -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 +6 -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 +23 -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.js +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 +4 -5
- package/src/engine/indicators/indicatorDefinitionRegistry.ts +35 -2
- package/src/engine/indicators/indicatorMetadata.ts +39 -2
- package/src/engine/indicators/indicatorRuntime.ts +5 -4
- package/src/engine/indicators/scheduler.ts +32 -8
- package/src/engine/renderers/Indicator/atr.ts +8 -11
- package/src/engine/renderers/Indicator/boll.ts +31 -10
- package/src/engine/renderers/Indicator/cci.ts +9 -14
- package/src/engine/renderers/Indicator/chaikinVol.ts +24 -8
- package/src/engine/renderers/Indicator/cmf.ts +23 -8
- package/src/engine/renderers/Indicator/dema.ts +27 -9
- package/src/engine/renderers/Indicator/donchian.ts +27 -9
- package/src/engine/renderers/Indicator/ene.ts +31 -10
- package/src/engine/renderers/Indicator/expma.ts +30 -10
- package/src/engine/renderers/Indicator/fastk.ts +9 -14
- package/src/engine/renderers/Indicator/fib.ts +28 -9
- package/src/engine/renderers/Indicator/hma.ts +27 -9
- package/src/engine/renderers/Indicator/hv.ts +26 -8
- package/src/engine/renderers/Indicator/ichimoku.ts +30 -9
- package/src/engine/renderers/Indicator/index.ts +27 -28
- package/src/engine/renderers/Indicator/kama.ts +27 -9
- package/src/engine/renderers/Indicator/keltner.ts +27 -9
- package/src/engine/renderers/Indicator/kst.ts +14 -18
- package/src/engine/renderers/Indicator/ma.ts +43 -9
- package/src/engine/renderers/Indicator/macd.ts +27 -32
- package/src/engine/renderers/Indicator/mainIndicatorLegend.ts +43 -162
- package/src/engine/renderers/Indicator/mfi.ts +23 -8
- package/src/engine/renderers/Indicator/mom.ts +9 -14
- package/src/engine/renderers/Indicator/obv.ts +22 -8
- package/src/engine/renderers/Indicator/parkinson.ts +26 -8
- package/src/engine/renderers/Indicator/pivot.ts +46 -9
- package/src/engine/renderers/Indicator/pvt.ts +22 -8
- package/src/engine/renderers/Indicator/roc.ts +24 -8
- package/src/engine/renderers/Indicator/rsi.ts +12 -16
- package/src/engine/renderers/Indicator/sar.ts +25 -9
- package/src/engine/renderers/Indicator/stoch.ts +11 -15
- package/src/engine/renderers/Indicator/structure.ts +30 -8
- package/src/engine/renderers/Indicator/supertrend.ts +25 -9
- package/src/engine/renderers/Indicator/tema.ts +27 -9
- package/src/engine/renderers/Indicator/trix.ts +38 -8
- package/src/engine/renderers/Indicator/vma.ts +23 -8
- package/src/engine/renderers/Indicator/volumeProfile.ts +39 -8
- package/src/engine/renderers/Indicator/vwap.ts +22 -8
- package/src/engine/renderers/Indicator/wma.ts +27 -9
- package/src/engine/renderers/Indicator/wmsr.ts +9 -14
- package/src/engine/renderers/Indicator/zones.ts +28 -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,9 +1,10 @@
|
|
|
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'
|
|
8
9
|
import { calcKeltnerData } from '../../indicators/calculators'
|
|
9
10
|
import { createBandVisibleStateComposer } from '../../indicators/visibleStateComposers'
|
|
@@ -123,23 +124,40 @@ function drawLine(ctx: CanvasRenderingContext2D, pts: Point[], color: string): v
|
|
|
123
124
|
ctx.stroke()
|
|
124
125
|
}
|
|
125
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
|
+
|
|
126
150
|
@Indicator({
|
|
127
151
|
name: 'keltner',
|
|
128
152
|
displayName: 'Keltner',
|
|
153
|
+
getTitleInfo: getKeltnerTitleInfo,
|
|
129
154
|
category: 'main',
|
|
130
|
-
stateKey: createKeltnerStateKey,
|
|
131
155
|
defaultPaneId: 'main',
|
|
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).updateIndicatorConfig('keltner', params, paneId)
|
|
138
|
-
},
|
|
139
|
-
applyResult: (host, state, paneId) => {
|
|
140
|
-
host.setSharedState(createKeltnerStateKey(paneId), state as any, 'indicator_scheduler')
|
|
141
|
-
},
|
|
142
|
-
runtime: { configKey:'keltner', 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) },
|
|
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) },
|
|
143
161
|
})
|
|
144
162
|
class KeltnerDefinition {
|
|
145
163
|
static rendererFactory = createKeltnerRendererPlugin
|
|
@@ -10,6 +10,7 @@ import { resolveStateKey } from '../../indicators/indicatorMetadata'
|
|
|
10
10
|
import type { IndicatorScheduler, KSTSchedulerConfig } from '../../indicators/scheduler'
|
|
11
11
|
import { createKstScaleRendererPlugin } from './scale/kst_scale'
|
|
12
12
|
import { calcKSTData } from '../../indicators/calculators'
|
|
13
|
+
import type { KLineData } from '../../../types/price'
|
|
13
14
|
|
|
14
15
|
type LinePoint = { x: number; y: number }
|
|
15
16
|
|
|
@@ -260,18 +261,19 @@ function drawKSTLinesWithCanvas2D(
|
|
|
260
261
|
* 获取 KST 标题信息(供 paneTitle 使用)
|
|
261
262
|
*/
|
|
262
263
|
export function getKSTTitleInfo(
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
roc3: number,
|
|
267
|
-
roc4: number,
|
|
268
|
-
signalPeriod: number,
|
|
264
|
+
_data: KLineData[],
|
|
265
|
+
index: number | null,
|
|
266
|
+
params: Record<string, number | boolean | string>,
|
|
269
267
|
pluginHost: PluginHost,
|
|
270
|
-
paneId: string
|
|
271
|
-
theme: 'light' | 'dark' = 'light',
|
|
272
|
-
isAsiaMarket?: boolean
|
|
268
|
+
paneId: string,
|
|
273
269
|
): { name: string; params: number[]; values: Array<{ label: string; value: number; color: string }> } | null {
|
|
274
|
-
|
|
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')
|
|
275
277
|
const state = pluginHost.getSharedState<KSTRenderState>(createKSTStateKey(paneId))
|
|
276
278
|
if (!state) return null
|
|
277
279
|
|
|
@@ -295,17 +297,11 @@ export function getKSTTitleInfo(
|
|
|
295
297
|
name: 'kst',
|
|
296
298
|
displayName: 'KST',
|
|
297
299
|
category: 'oscillator',
|
|
298
|
-
stateKey: createKSTStateKey,
|
|
299
300
|
defaultPaneId: 'sub_KST',
|
|
300
301
|
scaleRendererFactory: createKstScaleRendererPlugin,
|
|
301
|
-
updateConfig: (scheduler, params, paneId) => {
|
|
302
|
-
(scheduler as IndicatorScheduler).updateIndicatorConfig('kst', params, paneId)
|
|
303
|
-
},
|
|
304
302
|
visibleState: { compose: createPaddedPointVisibleStateComposer('kst', EMPTY_KST_STATE, ['kst', 'signal'] as const) },
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
},
|
|
308
|
-
runtime: { configKey:'kst', 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) },
|
|
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) },
|
|
309
305
|
})
|
|
310
306
|
class KSTIndicatorDefinition {
|
|
311
307
|
static rendererFactory = createKSTRendererPlugin
|
|
@@ -3,7 +3,8 @@ 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
9
|
import { calcMAData, type MAFlags } from '../../indicators/calculators'
|
|
9
10
|
import { alignToPhysicalPixelCenter } from '../../draw/pixelAlign'
|
|
@@ -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).updateIndicatorConfig('ma', params)
|
|
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,10 +161,8 @@ function getMAStateKey(host: PluginHost | null): string | null {
|
|
|
125
161
|
chart.updateRendererConfig('ma', maFlags)
|
|
126
162
|
},
|
|
127
163
|
},
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
},
|
|
131
|
-
runtime: { configKey:'ma', 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} },
|
|
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,
|
|
132
166
|
})
|
|
133
167
|
class MADefinition {
|
|
134
168
|
static rendererFactory = createMARendererPlugin
|
|
@@ -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
474
|
scaleRendererFactory: createMacdScaleRendererPlugin,
|
|
475
475
|
visibleState: { compose: createMACDVisibleStateComposer('macd', EMPTY_MACD_STATE) },
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
},
|
|
479
|
-
applyResult: (host, state, paneId) => {
|
|
480
|
-
host.setSharedState(createMACDStateKey(paneId), state as any, 'indicator_scheduler')
|
|
481
|
-
},
|
|
482
|
-
runtime: { configKey:'macd', 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) },
|
|
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,6 +2,8 @@ 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'
|
|
@@ -128,22 +130,35 @@ export function createMFIRendererPlugin(options: { paneId?: string } = {}): Rend
|
|
|
128
130
|
}
|
|
129
131
|
}
|
|
130
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
|
+
|
|
131
153
|
@Indicator({
|
|
132
154
|
name: 'mfi',
|
|
133
155
|
displayName: 'MFI',
|
|
134
156
|
category: 'volume',
|
|
135
|
-
stateKey: createMFIStateKey,
|
|
136
157
|
defaultPaneId: 'sub_MFI',
|
|
137
158
|
visibleState: { compose: createFixedRangeSparseVisibleStateComposer('mfi', EMPTY_MFI_STATE) },
|
|
138
159
|
scale: { indicatorKey: 'mfi', label: 'MFI', decimals: 2 },
|
|
139
|
-
|
|
140
|
-
(scheduler as IndicatorScheduler).updateIndicatorConfig('mfi', params, paneId)
|
|
141
|
-
},
|
|
142
|
-
applyResult: (host, state, paneId) => {
|
|
143
|
-
host.setSharedState(createMFIStateKey(paneId), state as any, 'indicator_scheduler')
|
|
144
|
-
},
|
|
160
|
+
getTitleInfo: getMFITitleInfo,
|
|
145
161
|
runtime: {
|
|
146
|
-
configKey: 'mfi',
|
|
147
162
|
defaultConfig: { period: 14, showMFI: true },
|
|
148
163
|
computeKey: 'calcMFIData',
|
|
149
164
|
compute: (data, c) => calcMFIData(data, c.period),
|
|
@@ -11,6 +11,7 @@ import { resolveStateKey } from '../../indicators/indicatorMetadata'
|
|
|
11
11
|
import type { IndicatorScheduler, MOMSchedulerConfig } from '../../indicators/scheduler'
|
|
12
12
|
import { createMomScaleRendererPlugin } from './scale/mom_scale'
|
|
13
13
|
import { calcMOMData } from '../../indicators/calculators'
|
|
14
|
+
import type { KLineData } from '../../../types/price'
|
|
14
15
|
|
|
15
16
|
type LinePoint = { x: number; y: number }
|
|
16
17
|
|
|
@@ -277,14 +278,15 @@ function drawMOMLineWithCanvas2D(
|
|
|
277
278
|
* 获取 MOM 标题信息(供 paneTitle 使用)
|
|
278
279
|
*/
|
|
279
280
|
export function getMOMTitleInfo(
|
|
280
|
-
|
|
281
|
-
|
|
281
|
+
_data: KLineData[],
|
|
282
|
+
index: number | null,
|
|
283
|
+
params: Record<string, number | boolean | string>,
|
|
282
284
|
pluginHost: PluginHost,
|
|
283
|
-
paneId: string
|
|
284
|
-
theme: 'light' | 'dark' = 'light',
|
|
285
|
-
isAsiaMarket?: boolean
|
|
285
|
+
paneId: string,
|
|
286
286
|
): { name: string; params: number[]; values: Array<{ label: string; value: number; color: string }> } | null {
|
|
287
|
-
|
|
287
|
+
if (index === null) return null
|
|
288
|
+
const period = (params.period as number) ?? 10
|
|
289
|
+
const colors = resolveThemeColors('light')
|
|
288
290
|
const state = pluginHost.getSharedState<MOMRenderState>(createMOMStateKey(paneId))
|
|
289
291
|
if (!state) return null
|
|
290
292
|
|
|
@@ -304,18 +306,11 @@ export function getMOMTitleInfo(
|
|
|
304
306
|
name: 'mom',
|
|
305
307
|
displayName: 'MOM',
|
|
306
308
|
category: 'oscillator',
|
|
307
|
-
stateKey: createMOMStateKey,
|
|
308
309
|
defaultPaneId: 'sub_MOM',
|
|
309
310
|
scaleRendererFactory: createMomScaleRendererPlugin,
|
|
310
|
-
updateConfig: (scheduler, params, paneId) => {
|
|
311
|
-
(scheduler as IndicatorScheduler).updateIndicatorConfig('mom', params, paneId)
|
|
312
|
-
},
|
|
313
311
|
visibleState: { compose: createPaddedSparseVisibleStateComposer('mom', EMPTY_MOM_STATE) },
|
|
314
|
-
|
|
315
|
-
host.setSharedState(createMOMStateKey(paneId), state as any, 'indicator_scheduler')
|
|
316
|
-
},
|
|
312
|
+
getTitleInfo: getMOMTitleInfo,
|
|
317
313
|
runtime: {
|
|
318
|
-
configKey: 'mom',
|
|
319
314
|
defaultConfig: { period: 10, showMOM: true },
|
|
320
315
|
computeKey: 'calcMOMData',
|
|
321
316
|
compute: (data, c) => calcMOMData(data, c.period),
|