@363045841yyt/klinechart-core 0.7.12 → 0.8.1-alpha.1
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/config/chartSettings.d.ts +0 -6
- package/dist/config/chartSettings.d.ts.map +1 -1
- package/dist/config/chartSettings.js +0 -1
- package/dist/config/chartSettings.js.map +1 -1
- package/dist/controllers/createChartController.d.ts.map +1 -1
- package/dist/controllers/createChartController.js +22 -0
- package/dist/controllers/createChartController.js.map +1 -1
- 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 +4 -4
- package/dist/controllers/index.d.ts.map +1 -1
- package/dist/controllers/index.js +3 -2
- package/dist/controllers/index.js.map +1 -1
- package/dist/controllers/types.d.ts +21 -0
- package/dist/controllers/types.d.ts.map +1 -1
- package/dist/data-fetchers/baostock.d.ts +3 -0
- package/dist/data-fetchers/baostock.d.ts.map +1 -0
- package/dist/data-fetchers/baostock.js +34 -0
- package/dist/data-fetchers/baostock.js.map +1 -0
- package/dist/data-fetchers/hundred-mock.d.ts +3 -0
- package/dist/data-fetchers/hundred-mock.d.ts.map +1 -0
- package/dist/data-fetchers/hundred-mock.js +30 -0
- package/dist/data-fetchers/hundred-mock.js.map +1 -0
- package/dist/data-fetchers/index.d.ts +5 -0
- package/dist/data-fetchers/index.d.ts.map +1 -0
- package/dist/data-fetchers/index.js +5 -0
- package/dist/data-fetchers/index.js.map +1 -0
- package/dist/data-fetchers/router.d.ts +3 -0
- package/dist/data-fetchers/router.d.ts.map +1 -0
- package/dist/data-fetchers/router.js +16 -0
- package/dist/data-fetchers/router.js.map +1 -0
- package/dist/data-fetchers/thousand-mock.d.ts +3 -0
- package/dist/data-fetchers/thousand-mock.d.ts.map +1 -0
- package/dist/data-fetchers/thousand-mock.js +29 -0
- package/dist/data-fetchers/thousand-mock.js.map +1 -0
- package/dist/engine/chart.d.ts +20 -2
- package/dist/engine/chart.d.ts.map +1 -1
- package/dist/engine/chart.js +81 -24
- 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/{indicatorData.d.ts → indicatorCatalog.d.ts} +1 -1
- package/dist/engine/renderers/Indicator/indicatorCatalog.d.ts.map +1 -0
- package/dist/engine/renderers/Indicator/{indicatorData.js → indicatorCatalog.js} +94 -406
- package/dist/engine/renderers/Indicator/indicatorCatalog.js.map +1 -0
- 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 +21 -9
- 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 -9
- 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 +30 -7
- 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/engine/subPaneManager.d.ts.map +1 -1
- package/dist/engine/subPaneManager.js +2 -1
- package/dist/engine/subPaneManager.js.map +1 -1
- package/dist/semantic/controller.d.ts +3 -14
- package/dist/semantic/controller.d.ts.map +1 -1
- package/dist/semantic/controller.js +9 -43
- package/dist/semantic/controller.js.map +1 -1
- package/dist/semantic/index.d.ts +3 -2
- package/dist/semantic/index.d.ts.map +1 -1
- package/dist/semantic/index.js +1 -1
- package/dist/semantic/index.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 +7 -7
- package/src/config/chartSettings.ts +0 -1
- package/src/controllers/__tests__/indicatorSelector.test.ts +5 -4
- package/src/controllers/createChartController.ts +28 -1
- package/src/controllers/createIndicatorSelectorController.ts +4 -6
- package/src/controllers/index.ts +7 -6
- package/src/controllers/types.ts +30 -0
- package/src/data-fetchers/baostock.ts +34 -0
- package/src/data-fetchers/hundred-mock.ts +31 -0
- package/src/data-fetchers/index.ts +4 -0
- package/src/data-fetchers/router.ts +17 -0
- package/src/data-fetchers/thousand-mock.ts +30 -0
- package/src/engine/chart.ts +91 -23
- 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/indicatorCatalog.ts +346 -0
- 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 +31 -9
- package/src/engine/renderers/Indicator/supertrend.ts +26 -10
- 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 +45 -19
- package/src/engine/renderers/subVolume.ts +0 -2
- package/src/engine/subPaneManager.ts +2 -1
- package/src/semantic/__tests__/controller.test.ts +19 -7
- package/src/semantic/controller.ts +9 -57
- package/src/semantic/index.ts +3 -2
- package/src/version.ts +1 -1
- package/dist/engine/renderers/Indicator/indicatorData.d.ts.map +0 -1
- package/dist/engine/renderers/Indicator/indicatorData.js.map +0 -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/indicatorData.ts +0 -650
- package/src/engine/renderers/Indicator/macdLegend.ts +0 -141
- package/src/engine/renderers/Indicator/subPaneConfig.ts +0 -265
|
@@ -7,6 +7,8 @@ import { resolveStateKey } from '../../indicators/indicatorMetadata'
|
|
|
7
7
|
import { createSparseVisibleStateComposer } from '../../indicators/visibleStateComposers'
|
|
8
8
|
import type { IndicatorScheduler, VWAPSchedulerConfig } from '../../indicators/scheduler'
|
|
9
9
|
import { calcVWAPData } from '../../indicators/calculators'
|
|
10
|
+
import type { TitleInfo } from '../../indicators/indicatorMetadata'
|
|
11
|
+
import type { KLineData } from '../../../types/price'
|
|
10
12
|
|
|
11
13
|
const VWAP_COLOR = '#ec4899'
|
|
12
14
|
|
|
@@ -109,22 +111,34 @@ export function createVWAPRendererPlugin(options: { paneId?: string } = {}): Ren
|
|
|
109
111
|
}
|
|
110
112
|
}
|
|
111
113
|
|
|
114
|
+
export function getVWAPTitleInfo(
|
|
115
|
+
_data: KLineData[],
|
|
116
|
+
index: number | null,
|
|
117
|
+
_params: Record<string, number | boolean | string>,
|
|
118
|
+
host: PluginHost,
|
|
119
|
+
paneId: string,
|
|
120
|
+
): TitleInfo | null {
|
|
121
|
+
if (index === null) return null
|
|
122
|
+
const state = host.getSharedState<VWAPRenderState>(createVWAPStateKey(paneId))
|
|
123
|
+
const value = state?.series[index]
|
|
124
|
+
if (value === undefined) return null
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
name: 'VWAP',
|
|
128
|
+
params: [],
|
|
129
|
+
values: [{ label: 'VWAP', value, color: VWAP_COLOR }],
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
112
133
|
@Indicator({
|
|
113
134
|
name: 'vwap',
|
|
114
135
|
displayName: 'VWAP',
|
|
115
136
|
category: 'volume',
|
|
116
|
-
stateKey: createVWAPStateKey,
|
|
117
137
|
defaultPaneId: 'sub_VWAP',
|
|
118
138
|
visibleState: { compose: createSparseVisibleStateComposer('vwap', EMPTY_VWAP_STATE) },
|
|
119
139
|
scale: { indicatorKey: 'vwap', label: 'VWAP', decimals: 2 },
|
|
120
|
-
|
|
121
|
-
(scheduler as IndicatorScheduler).updateIndicatorConfig('vwap', params, paneId)
|
|
122
|
-
},
|
|
123
|
-
applyResult: (host, state, paneId) => {
|
|
124
|
-
host.setSharedState(createVWAPStateKey(paneId), state as any, 'indicator_scheduler')
|
|
125
|
-
},
|
|
140
|
+
getTitleInfo: getVWAPTitleInfo,
|
|
126
141
|
runtime: {
|
|
127
|
-
configKey: 'vwap',
|
|
128
142
|
defaultConfig: { sessionResetGapMs: 0, showVWAP: true },
|
|
129
143
|
computeKey: 'calcVWAPData',
|
|
130
144
|
compute: (data, c) => calcVWAPData(data, c.sessionResetGapMs),
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { RendererPluginWithHost, RenderContext, PluginHost } from '../../../plugin'
|
|
2
|
+
import type { KLineData } from '../../../types/price'
|
|
2
3
|
import { RENDERER_PRIORITY } from '../../../plugin'
|
|
3
4
|
import type { WMARenderState } from '../../indicators/wmaState'
|
|
4
5
|
import { createWMAStateKey, EMPTY_WMA_STATE } from '../../indicators/wmaState'
|
|
5
6
|
import { Indicator } from '../../indicators/indicatorDefinitionRegistry'
|
|
6
|
-
import { resolveStateKey } from '../../indicators/indicatorMetadata'
|
|
7
|
+
import { resolveStateKey, type TitleInfo, type TitleValueItem, type GetTitleInfoFn } from '../../indicators/indicatorMetadata'
|
|
7
8
|
import { createSparseVisibleStateComposer } from '../../indicators/visibleStateComposers'
|
|
8
9
|
import type { IndicatorScheduler, WMASchedulerConfig } from '../../indicators/scheduler'
|
|
9
10
|
import { calcWMAData } from '../../indicators/calculators'
|
|
@@ -121,23 +122,40 @@ export function createWMARendererPlugin(options: WMARendererOptions = {}): Rende
|
|
|
121
122
|
}
|
|
122
123
|
}
|
|
123
124
|
|
|
125
|
+
export const getWMATitleInfo: GetTitleInfoFn = (
|
|
126
|
+
_data: KLineData[],
|
|
127
|
+
index: number | null,
|
|
128
|
+
_params: Record<string, number | boolean | string>,
|
|
129
|
+
pluginHost: PluginHost,
|
|
130
|
+
paneId: string,
|
|
131
|
+
): TitleInfo | null => {
|
|
132
|
+
if (index === null) return null
|
|
133
|
+
|
|
134
|
+
const stateKey = createWMAStateKey(paneId)
|
|
135
|
+
const state = pluginHost?.getSharedState<WMARenderState>(stateKey)
|
|
136
|
+
if (!state || state.visibleMin > state.visibleMax) return null
|
|
137
|
+
|
|
138
|
+
const value = state.series[index]
|
|
139
|
+
if (value === undefined) return null
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
name: 'WMA',
|
|
143
|
+
params: [state.params.period],
|
|
144
|
+
values: [{ label: 'WMA', value, color: '#10b981' }],
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
124
148
|
@Indicator({
|
|
125
149
|
name: 'wma',
|
|
126
150
|
displayName: 'WMA',
|
|
151
|
+
getTitleInfo: getWMATitleInfo,
|
|
127
152
|
category: 'main',
|
|
128
|
-
stateKey: createWMAStateKey,
|
|
129
153
|
defaultPaneId: 'main',
|
|
130
154
|
allowMainPane: true,
|
|
131
155
|
mainPane: { rendererName: 'wma_main', toActiveConfig: (params, active) => ({ ...params, showWMA: active }) },
|
|
132
156
|
visibleState: { compose: createSparseVisibleStateComposer('wma', EMPTY_WMA_STATE) },
|
|
133
157
|
scale: { indicatorKey: 'wma', label: 'WMA', decimals: 2 },
|
|
134
|
-
|
|
135
|
-
(scheduler as IndicatorScheduler).updateIndicatorConfig('wma', params, paneId)
|
|
136
|
-
},
|
|
137
|
-
applyResult: (host, state, paneId) => {
|
|
138
|
-
host.setSharedState(createWMAStateKey(paneId), state as any, 'indicator_scheduler')
|
|
139
|
-
},
|
|
140
|
-
runtime: { configKey:'wma', defaultConfig:{period:10,showWMA:true}, computeKey:'calcWMAData', compute:(data,c)=>calcWMAData(data,c.period) },
|
|
158
|
+
runtime: { defaultConfig:{period:10,showWMA:true}, computeKey:'calcWMAData', compute:(data,c)=>calcWMAData(data,c.period) },
|
|
141
159
|
})
|
|
142
160
|
class WMADefinition {
|
|
143
161
|
static rendererFactory = createWMARendererPlugin
|
|
@@ -10,6 +10,7 @@ import { resolveStateKey } from '../../indicators/indicatorMetadata'
|
|
|
10
10
|
import type { IndicatorScheduler, WMSRSchedulerConfig } from '../../indicators/scheduler'
|
|
11
11
|
import { createWmsrScaleRendererPlugin } from './scale/wmsr_scale'
|
|
12
12
|
import { calcWMSRData } from '../../indicators/calculators'
|
|
13
|
+
import type { KLineData } from '../../../types/price'
|
|
13
14
|
|
|
14
15
|
type LinePoint = { x: number; y: number }
|
|
15
16
|
|
|
@@ -293,14 +294,15 @@ function drawWMSRLineWithCanvas2D(
|
|
|
293
294
|
* 获取 WMSR 标题信息(供 paneTitle 使用)
|
|
294
295
|
*/
|
|
295
296
|
export function getWMSRTitleInfo(
|
|
296
|
-
|
|
297
|
-
|
|
297
|
+
_data: KLineData[],
|
|
298
|
+
index: number | null,
|
|
299
|
+
params: Record<string, number | boolean | string>,
|
|
298
300
|
pluginHost: PluginHost,
|
|
299
|
-
paneId: string
|
|
300
|
-
theme: 'light' | 'dark' = 'light',
|
|
301
|
-
isAsiaMarket?: boolean
|
|
301
|
+
paneId: string,
|
|
302
302
|
): { name: string; params: number[]; values: Array<{ label: string; value: number; color: string }> } | null {
|
|
303
|
-
|
|
303
|
+
if (index === null) return null
|
|
304
|
+
const period = (params.period as number) ?? 14
|
|
305
|
+
const colors = resolveThemeColors('light')
|
|
304
306
|
const state = pluginHost.getSharedState<WMSRRenderState>(createWMSRStateKey(paneId))
|
|
305
307
|
if (!state) return null
|
|
306
308
|
|
|
@@ -320,18 +322,11 @@ export function getWMSRTitleInfo(
|
|
|
320
322
|
name: 'wmsr',
|
|
321
323
|
displayName: 'WMSR',
|
|
322
324
|
category: 'oscillator',
|
|
323
|
-
stateKey: createWMSRStateKey,
|
|
324
325
|
defaultPaneId: 'sub_WMSR',
|
|
325
326
|
visibleState: { compose: createFixedRangeSparseVisibleStateComposer('wmsr', EMPTY_WMSR_STATE) },
|
|
326
327
|
scaleRendererFactory: createWmsrScaleRendererPlugin,
|
|
327
|
-
|
|
328
|
-
(scheduler as IndicatorScheduler).updateIndicatorConfig('wmsr', params, paneId)
|
|
329
|
-
},
|
|
330
|
-
applyResult: (host, state, paneId) => {
|
|
331
|
-
host.setSharedState(createWMSRStateKey(paneId), state as any, 'indicator_scheduler')
|
|
332
|
-
},
|
|
328
|
+
getTitleInfo: getWMSRTitleInfo,
|
|
333
329
|
runtime: {
|
|
334
|
-
configKey: 'wmsr',
|
|
335
330
|
defaultConfig: { period: 14, showWMSR: true },
|
|
336
331
|
computeKey: 'calcWMSRData',
|
|
337
332
|
compute: (data, c) => calcWMSRData(data, c.period),
|
|
@@ -5,7 +5,7 @@ import type { ZonesRenderState } from '../../indicators/zonesState'
|
|
|
5
5
|
import { createZonesStateKey, EMPTY_ZONES_STATE } from '../../indicators/zonesState'
|
|
6
6
|
import { Indicator } from '../../indicators/indicatorDefinitionRegistry'
|
|
7
7
|
import { createFixedUnitVisibleStateComposer } from '../../indicators/visibleStateComposers'
|
|
8
|
-
import { resolveStateKey } from '../../indicators/indicatorMetadata'
|
|
8
|
+
import { resolveStateKey, type TitleInfo, type TitleValueItem, type GetTitleInfoFn } from '../../indicators/indicatorMetadata'
|
|
9
9
|
import type { IndicatorScheduler, ZonesSchedulerConfig } from '../../indicators/scheduler'
|
|
10
10
|
import { calcZonesData } from '../../indicators/calculators'
|
|
11
11
|
|
|
@@ -90,23 +90,42 @@ export function createZonesRendererPlugin(options: { paneId?: string } = {}): Re
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
export const getZonesTitleInfo: GetTitleInfoFn = (_data, index, _params, host, paneId) => {
|
|
94
|
+
if (index === null) return null
|
|
95
|
+
|
|
96
|
+
const stateKey = createZonesStateKey(paneId)
|
|
97
|
+
const state = host?.getSharedState<ZonesRenderState>(stateKey)
|
|
98
|
+
if (!state) return null
|
|
99
|
+
|
|
100
|
+
const activeZones = state.series.filter(
|
|
101
|
+
z => z.startIndex <= index && (z.endIndex === undefined || z.endIndex >= index)
|
|
102
|
+
)
|
|
103
|
+
if (activeZones.length === 0) return null
|
|
104
|
+
|
|
105
|
+
const values: TitleValueItem[] = activeZones.slice(0, 5).map(z => ({
|
|
106
|
+
label: z.kind,
|
|
107
|
+
value: z.high,
|
|
108
|
+
color: z.kind.includes('Bull') ? '#22c55e' : '#ef4444',
|
|
109
|
+
}))
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
name: 'Zones',
|
|
113
|
+
params: [activeZones.length],
|
|
114
|
+
values,
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
93
118
|
@Indicator({
|
|
94
119
|
name: 'zones',
|
|
95
120
|
displayName: 'Zones',
|
|
121
|
+
getTitleInfo: getZonesTitleInfo,
|
|
96
122
|
category: 'main',
|
|
97
|
-
stateKey: createZonesStateKey,
|
|
98
123
|
defaultPaneId: 'main',
|
|
99
124
|
allowMainPane: true,
|
|
100
125
|
mainPane: { rendererName: 'zones_main', toActiveConfig: (params, active) => ({ ...params, showFVG: active, showOB: active, showFilledZones: active }) },
|
|
101
126
|
scale: { indicatorKey: 'zones', label: 'Zones', decimals: 2 },
|
|
102
127
|
visibleState: { compose: createFixedUnitVisibleStateComposer('zones', EMPTY_ZONES_STATE) },
|
|
103
|
-
|
|
104
|
-
(scheduler as IndicatorScheduler).updateIndicatorConfig('zones', params, paneId)
|
|
105
|
-
},
|
|
106
|
-
applyResult: (host, state, paneId) => {
|
|
107
|
-
host.setSharedState(createZonesStateKey(paneId), state as any, 'indicator_scheduler')
|
|
108
|
-
},
|
|
109
|
-
runtime: { configKey:'zones', defaultConfig:{showFVG:true,showOB:true,showFilledZones:true,obLookback:20}, computeKey:'calcZonesData', compute:(data,c)=>calcZonesData(data,c.obLookback,5,2,'close') },
|
|
128
|
+
runtime: { defaultConfig:{showFVG:true,showOB:true,showFilledZones:true,obLookback:20}, computeKey:'calcZonesData', compute:(data,c)=>calcZonesData(data,c.obLookback,5,2,'close') },
|
|
110
129
|
})
|
|
111
130
|
class ZonesDefinition {
|
|
112
131
|
static rendererFactory = createZonesRendererPlugin
|
|
@@ -8,11 +8,13 @@ import { ENE_STATE_KEY } from '@/core/indicators/eneState'
|
|
|
8
8
|
import type { PluginHost, RenderContext, RendererPluginWithHost } from '@/plugin'
|
|
9
9
|
import type { KLineData } from '@/types/price'
|
|
10
10
|
import type { Pane } from '@/core/layout/pane'
|
|
11
|
+
import type { GetTitleInfoFn, TitleInfo, TitleValueItem } from '@/engine/indicators/indicatorMetadata'
|
|
12
|
+
import type { IndicatorScheduler } from '@/engine/indicators/indicatorScheduler'
|
|
11
13
|
|
|
12
14
|
// Type helper for tests - we know these methods exist on the implementation
|
|
13
15
|
interface TestableLegendRenderer extends RendererPluginWithHost {
|
|
14
16
|
draw: (context: RenderContext) => void
|
|
15
|
-
getConfig: () => { yPaddingPx: number
|
|
17
|
+
getConfig: () => { yPaddingPx: number }
|
|
16
18
|
setConfig: (config: Record<string, unknown>) => void
|
|
17
19
|
}
|
|
18
20
|
|
|
@@ -33,10 +35,73 @@ function createMockCanvasContext(): CanvasRenderingContext2D {
|
|
|
33
35
|
} as unknown as CanvasRenderingContext2D
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Create a mock scheduler that returns indicator metadata with getTitleInfo.
|
|
40
|
+
* Keys are case-insensitive (matching real IndicatorScheduler behavior).
|
|
41
|
+
*/
|
|
42
|
+
function createMockScheduler(
|
|
43
|
+
metadataMap: Record<string, { getTitleInfo: GetTitleInfoFn }>,
|
|
44
|
+
activeMainIndicators?: string[]
|
|
45
|
+
): IndicatorScheduler {
|
|
46
|
+
const activeSet = new Set((activeMainIndicators ?? ['ma']).map((i: string) => i.toLowerCase()))
|
|
47
|
+
return {
|
|
48
|
+
getIndicatorMetadata: vi.fn((id: string) => metadataMap[id.toLowerCase()] ?? null),
|
|
49
|
+
getMainIndicators: vi.fn(() => Object.entries(metadataMap).map(([id, meta]) => ({
|
|
50
|
+
name: id,
|
|
51
|
+
getTitleInfo: meta.getTitleInfo,
|
|
52
|
+
category: 'main',
|
|
53
|
+
}))),
|
|
54
|
+
isMainIndicatorActive: vi.fn((id: string) => activeSet.has(id.toLowerCase())),
|
|
55
|
+
getMainIndicatorParams: vi.fn(() => ({})),
|
|
56
|
+
} as unknown as IndicatorScheduler
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Create a mock getTitleInfo for MA that reads from shared state
|
|
61
|
+
*/
|
|
62
|
+
function createMAGetTitleInfo(): GetTitleInfoFn {
|
|
63
|
+
return (data, index, params, host, paneId): TitleInfo => {
|
|
64
|
+
const state = host.getSharedState<MARenderState>(MA_STATE_KEY)
|
|
65
|
+
if (!state) return null
|
|
66
|
+
|
|
67
|
+
const ci = index ?? (state.series[5]?.length ?? 100) - 1
|
|
68
|
+
const values: TitleValueItem[] = []
|
|
69
|
+
for (const period of state.enabledPeriods) {
|
|
70
|
+
const v = state.series[period]?.[ci]
|
|
71
|
+
if (v !== undefined) {
|
|
72
|
+
values.push({
|
|
73
|
+
label: `MA${period}`,
|
|
74
|
+
value: v,
|
|
75
|
+
color: '#888888',
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return { name: 'MA', values: values.length > 0 ? values : undefined }
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Create simple mock getTitleInfo for BOLL/EXPMA/ENE
|
|
85
|
+
*/
|
|
86
|
+
function createSimpleGetTitleInfo(name: string): GetTitleInfoFn {
|
|
87
|
+
return (): TitleInfo => ({
|
|
88
|
+
name,
|
|
89
|
+
params: [20, 2],
|
|
90
|
+
values: [
|
|
91
|
+
{ label: 'MID', value: 100.00, color: '#FF0000' },
|
|
92
|
+
{ label: 'UP', value: 120.00, color: '#00FF00' },
|
|
93
|
+
{ label: 'DN', value: 80.00, color: '#0000FF' },
|
|
94
|
+
],
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
36
98
|
/**
|
|
37
99
|
* 创建 mock PluginHost
|
|
38
100
|
*/
|
|
39
|
-
function createMockPluginHost(
|
|
101
|
+
function createMockPluginHost(
|
|
102
|
+
state?: MARenderState,
|
|
103
|
+
scheduler?: IndicatorScheduler
|
|
104
|
+
): PluginHost {
|
|
40
105
|
return {
|
|
41
106
|
setSharedState: vi.fn(),
|
|
42
107
|
getSharedState: vi.fn(<T>(key: string): T | undefined => {
|
|
@@ -59,6 +124,10 @@ function createMockPluginHost(state?: MARenderState): PluginHost {
|
|
|
59
124
|
off: vi.fn(),
|
|
60
125
|
once: vi.fn(),
|
|
61
126
|
emit: vi.fn(),
|
|
127
|
+
getService: vi.fn((name: string) => {
|
|
128
|
+
if (name === 'indicatorScheduler') return scheduler
|
|
129
|
+
return undefined
|
|
130
|
+
}),
|
|
62
131
|
} as unknown as PluginHost
|
|
63
132
|
}
|
|
64
133
|
|
|
@@ -149,14 +218,9 @@ describe('createMainIndicatorLegendRendererPlugin', () => {
|
|
|
149
218
|
expect(typeof plugin.onInstall).toBe('function')
|
|
150
219
|
})
|
|
151
220
|
|
|
152
|
-
it('should declare
|
|
221
|
+
it('should not declare any namespace keys (individual renderers own their state)', () => {
|
|
153
222
|
const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
|
|
154
|
-
expect(plugin.getDeclaredNamespaces()).toEqual([
|
|
155
|
-
MA_STATE_KEY,
|
|
156
|
-
BOLL_STATE_KEY,
|
|
157
|
-
EXPMA_STATE_KEY,
|
|
158
|
-
ENE_STATE_KEY,
|
|
159
|
-
])
|
|
223
|
+
expect(plugin.getDeclaredNamespaces()).toEqual([])
|
|
160
224
|
})
|
|
161
225
|
})
|
|
162
226
|
|
|
@@ -168,17 +232,13 @@ describe('MainIndicatorLegend draw', () => {
|
|
|
168
232
|
ctx = createMockCanvasContext()
|
|
169
233
|
})
|
|
170
234
|
|
|
171
|
-
it('should not draw MA when MA is
|
|
235
|
+
it('should not draw MA when MA is not active', () => {
|
|
172
236
|
const state = createTestMARenderState()
|
|
173
|
-
const
|
|
237
|
+
const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, [])
|
|
238
|
+
const mockHost = createMockPluginHost(state, scheduler)
|
|
174
239
|
plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
|
|
175
240
|
plugin.onInstall(mockHost)
|
|
176
241
|
|
|
177
|
-
// Disable MA
|
|
178
|
-
plugin.setConfig({
|
|
179
|
-
indicators: { MA: { enabled: false, params: {} } },
|
|
180
|
-
})
|
|
181
|
-
|
|
182
242
|
const context = createMockRenderContext(ctx)
|
|
183
243
|
plugin.draw(context)
|
|
184
244
|
|
|
@@ -190,7 +250,8 @@ describe('MainIndicatorLegend draw', () => {
|
|
|
190
250
|
|
|
191
251
|
it('should draw MA values from StateStore', () => {
|
|
192
252
|
const state = createTestMARenderState()
|
|
193
|
-
const
|
|
253
|
+
const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
|
|
254
|
+
const mockHost = createMockPluginHost(state, scheduler)
|
|
194
255
|
plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
|
|
195
256
|
plugin.onInstall(mockHost)
|
|
196
257
|
|
|
@@ -215,7 +276,8 @@ describe('MainIndicatorLegend draw', () => {
|
|
|
215
276
|
},
|
|
216
277
|
enabledPeriods: [5],
|
|
217
278
|
})
|
|
218
|
-
const
|
|
279
|
+
const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
|
|
280
|
+
const mockHost = createMockPluginHost(state, scheduler)
|
|
219
281
|
plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
|
|
220
282
|
plugin.onInstall(mockHost)
|
|
221
283
|
|
|
@@ -227,7 +289,7 @@ describe('MainIndicatorLegend draw', () => {
|
|
|
227
289
|
|
|
228
290
|
// Should show value 150 at index 50 (100 + 50)
|
|
229
291
|
const maValueCalls = fillTextCalls.filter(call =>
|
|
230
|
-
String(call[0]).includes('150.
|
|
292
|
+
String(call[0]).includes('150.000')
|
|
231
293
|
)
|
|
232
294
|
expect(maValueCalls.length).toBeGreaterThan(0)
|
|
233
295
|
})
|
|
@@ -239,7 +301,8 @@ describe('MainIndicatorLegend draw', () => {
|
|
|
239
301
|
},
|
|
240
302
|
enabledPeriods: [5],
|
|
241
303
|
})
|
|
242
|
-
const
|
|
304
|
+
const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
|
|
305
|
+
const mockHost = createMockPluginHost(state, scheduler)
|
|
243
306
|
plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
|
|
244
307
|
plugin.onInstall(mockHost)
|
|
245
308
|
|
|
@@ -261,7 +324,7 @@ describe('MainIndicatorLegend draw', () => {
|
|
|
261
324
|
|
|
262
325
|
// Should show last value (109) at index 9
|
|
263
326
|
const maValueCalls = fillTextCalls.filter(call =>
|
|
264
|
-
String(call[0]).includes('109.
|
|
327
|
+
String(call[0]).includes('109.000')
|
|
265
328
|
)
|
|
266
329
|
expect(maValueCalls.length).toBeGreaterThan(0)
|
|
267
330
|
})
|
|
@@ -283,27 +346,29 @@ describe('MainIndicatorLegend draw', () => {
|
|
|
283
346
|
visibleMax: -Infinity,
|
|
284
347
|
enabledPeriods: [],
|
|
285
348
|
})
|
|
286
|
-
const
|
|
349
|
+
const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
|
|
350
|
+
const mockHost = createMockPluginHost(state, scheduler)
|
|
287
351
|
plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
|
|
288
352
|
plugin.onInstall(mockHost)
|
|
289
353
|
|
|
290
354
|
const context = createMockRenderContext(ctx)
|
|
291
355
|
plugin.draw(context)
|
|
292
356
|
|
|
293
|
-
// Should not draw any MA values
|
|
357
|
+
// Should not draw any MA period values (name 'MA' may still appear but no period texts)
|
|
294
358
|
const fillTextCalls = vi.mocked(ctx.fillText).mock.calls
|
|
295
359
|
const ma5Calls = fillTextCalls.filter(call => String(call[0]).includes('MA5'))
|
|
296
360
|
expect(ma5Calls).toHaveLength(0)
|
|
297
361
|
})
|
|
298
362
|
|
|
299
|
-
it('should display values with
|
|
363
|
+
it('should display values with 3 decimal places', () => {
|
|
300
364
|
const state = createTestMARenderState({
|
|
301
365
|
series: {
|
|
302
366
|
5: Array.from({ length: 100 }, () => 123.4567),
|
|
303
367
|
},
|
|
304
368
|
enabledPeriods: [5],
|
|
305
369
|
})
|
|
306
|
-
const
|
|
370
|
+
const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
|
|
371
|
+
const mockHost = createMockPluginHost(state, scheduler)
|
|
307
372
|
plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
|
|
308
373
|
plugin.onInstall(mockHost)
|
|
309
374
|
|
|
@@ -314,29 +379,31 @@ describe('MainIndicatorLegend draw', () => {
|
|
|
314
379
|
|
|
315
380
|
// Should show formatted value
|
|
316
381
|
const formattedValueCalls = fillTextCalls.filter(call =>
|
|
317
|
-
String(call[0]).includes('123.
|
|
382
|
+
String(call[0]).includes('123.457')
|
|
318
383
|
)
|
|
319
384
|
expect(formattedValueCalls.length).toBeGreaterThan(0)
|
|
320
385
|
})
|
|
321
386
|
|
|
322
387
|
it('should use correct colors for each MA period', () => {
|
|
323
388
|
const state = createTestMARenderState()
|
|
324
|
-
const
|
|
389
|
+
const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
|
|
390
|
+
const mockHost = createMockPluginHost(state, scheduler)
|
|
325
391
|
plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
|
|
326
392
|
plugin.onInstall(mockHost)
|
|
327
393
|
|
|
328
394
|
const context = createMockRenderContext(ctx)
|
|
329
395
|
plugin.draw(context)
|
|
330
396
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
expect(
|
|
397
|
+
// Should have drawn MA period values with proper colors
|
|
398
|
+
const fillTextCalls = vi.mocked(ctx.fillText).mock.calls
|
|
399
|
+
const ma5Calls = fillTextCalls.filter(call => String(call[0]).includes('MA5'))
|
|
400
|
+
expect(ma5Calls.length).toBeGreaterThan(0)
|
|
335
401
|
})
|
|
336
402
|
|
|
337
403
|
it('should save and restore context', () => {
|
|
338
404
|
const state = createTestMARenderState()
|
|
339
|
-
const
|
|
405
|
+
const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
|
|
406
|
+
const mockHost = createMockPluginHost(state, scheduler)
|
|
340
407
|
plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
|
|
341
408
|
plugin.onInstall(mockHost)
|
|
342
409
|
|
|
@@ -357,10 +424,15 @@ describe('MainIndicatorLegend MA data source', () => {
|
|
|
357
424
|
enabledPeriods: [5],
|
|
358
425
|
})
|
|
359
426
|
const mockGetSharedState = vi.fn().mockReturnValue(state)
|
|
427
|
+
const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
|
|
360
428
|
const mockHost = {
|
|
361
429
|
setSharedState: vi.fn(),
|
|
362
430
|
getSharedState: mockGetSharedState,
|
|
363
431
|
clearByOwner: vi.fn(),
|
|
432
|
+
getService: vi.fn((name: string) => {
|
|
433
|
+
if (name === 'indicatorScheduler') return scheduler
|
|
434
|
+
return undefined
|
|
435
|
+
}),
|
|
364
436
|
} as unknown as PluginHost
|
|
365
437
|
|
|
366
438
|
const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
|
|
@@ -373,7 +445,7 @@ describe('MainIndicatorLegend MA data source', () => {
|
|
|
373
445
|
})
|
|
374
446
|
plugin.draw(context)
|
|
375
447
|
|
|
376
|
-
// Verify it read from StateStore
|
|
448
|
+
// Verify it read from StateStore (via getTitleInfo calling getSharedState)
|
|
377
449
|
expect(mockGetSharedState).toHaveBeenCalledWith(MA_STATE_KEY)
|
|
378
450
|
|
|
379
451
|
const fillTextCalls = vi.mocked(ctx.fillText).mock.calls
|
|
@@ -387,14 +459,12 @@ describe('MainIndicatorLegend MA data source', () => {
|
|
|
387
459
|
})
|
|
388
460
|
|
|
389
461
|
describe('MainIndicatorLegend config management', () => {
|
|
390
|
-
it('getConfig should return current
|
|
462
|
+
it('getConfig should return current yPaddingPx', () => {
|
|
391
463
|
const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
|
|
392
464
|
|
|
393
465
|
const config = plugin.getConfig()
|
|
394
466
|
|
|
395
467
|
expect(config.yPaddingPx).toBe(20)
|
|
396
|
-
expect(config.indicators.MA.enabled).toBe(true)
|
|
397
|
-
expect(config.indicators.BOLL.enabled).toBe(false)
|
|
398
468
|
})
|
|
399
469
|
|
|
400
470
|
it('setConfig should update yPaddingPx', () => {
|
|
@@ -405,37 +475,18 @@ describe('MainIndicatorLegend config management', () => {
|
|
|
405
475
|
const config = plugin.getConfig()
|
|
406
476
|
expect(config.yPaddingPx).toBe(30)
|
|
407
477
|
})
|
|
408
|
-
|
|
409
|
-
it('setConfig should merge indicator config', () => {
|
|
410
|
-
const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
|
|
411
|
-
|
|
412
|
-
plugin.setConfig({
|
|
413
|
-
indicators: {
|
|
414
|
-
MA: { enabled: false, params: {} },
|
|
415
|
-
BOLL: { enabled: true, params: { period: 26 } },
|
|
416
|
-
},
|
|
417
|
-
})
|
|
418
|
-
|
|
419
|
-
const config = plugin.getConfig()
|
|
420
|
-
expect(config.indicators.MA.enabled).toBe(false)
|
|
421
|
-
expect(config.indicators.BOLL.enabled).toBe(true)
|
|
422
|
-
expect(config.indicators.BOLL.params.period).toBe(26)
|
|
423
|
-
})
|
|
424
478
|
})
|
|
425
479
|
|
|
426
480
|
describe('MainIndicatorLegend with other indicators', () => {
|
|
427
|
-
it('should draw BOLL when
|
|
428
|
-
const
|
|
481
|
+
it('should draw BOLL when active', () => {
|
|
482
|
+
const scheduler = createMockScheduler(
|
|
483
|
+
{ boll: { getTitleInfo: createSimpleGetTitleInfo('BOLL') } },
|
|
484
|
+
['boll']
|
|
485
|
+
)
|
|
486
|
+
const mockHost = createMockPluginHost(undefined, scheduler)
|
|
429
487
|
const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
|
|
430
488
|
plugin.onInstall(mockHost)
|
|
431
489
|
|
|
432
|
-
plugin.setConfig({
|
|
433
|
-
indicators: {
|
|
434
|
-
MA: { enabled: false, params: {} },
|
|
435
|
-
BOLL: { enabled: true, params: { period: 20, multiplier: 2 } },
|
|
436
|
-
},
|
|
437
|
-
})
|
|
438
|
-
|
|
439
490
|
const ctx = createMockCanvasContext()
|
|
440
491
|
const context = createMockRenderContext(ctx)
|
|
441
492
|
plugin.draw(context)
|
|
@@ -449,18 +500,15 @@ describe('MainIndicatorLegend with other indicators', () => {
|
|
|
449
500
|
expect(bollLabelCalls.length).toBeGreaterThan(0)
|
|
450
501
|
})
|
|
451
502
|
|
|
452
|
-
it('should draw EXPMA when
|
|
453
|
-
const
|
|
503
|
+
it('should draw EXPMA when active', () => {
|
|
504
|
+
const scheduler = createMockScheduler(
|
|
505
|
+
{ expma: { getTitleInfo: createSimpleGetTitleInfo('EXPMA') } },
|
|
506
|
+
['expma']
|
|
507
|
+
)
|
|
508
|
+
const mockHost = createMockPluginHost(undefined, scheduler)
|
|
454
509
|
const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
|
|
455
510
|
plugin.onInstall(mockHost)
|
|
456
511
|
|
|
457
|
-
plugin.setConfig({
|
|
458
|
-
indicators: {
|
|
459
|
-
MA: { enabled: false, params: {} },
|
|
460
|
-
EXPMA: { enabled: true, params: { fastPeriod: 12, slowPeriod: 50 } },
|
|
461
|
-
},
|
|
462
|
-
})
|
|
463
|
-
|
|
464
512
|
const ctx = createMockCanvasContext()
|
|
465
513
|
const context = createMockRenderContext(ctx)
|
|
466
514
|
plugin.draw(context)
|
|
@@ -474,18 +522,15 @@ describe('MainIndicatorLegend with other indicators', () => {
|
|
|
474
522
|
expect(expmaLabelCalls.length).toBeGreaterThan(0)
|
|
475
523
|
})
|
|
476
524
|
|
|
477
|
-
it('should draw ENE when
|
|
478
|
-
const
|
|
525
|
+
it('should draw ENE when active', () => {
|
|
526
|
+
const scheduler = createMockScheduler(
|
|
527
|
+
{ ene: { getTitleInfo: createSimpleGetTitleInfo('ENE') } },
|
|
528
|
+
['ene']
|
|
529
|
+
)
|
|
530
|
+
const mockHost = createMockPluginHost(undefined, scheduler)
|
|
479
531
|
const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
|
|
480
532
|
plugin.onInstall(mockHost)
|
|
481
533
|
|
|
482
|
-
plugin.setConfig({
|
|
483
|
-
indicators: {
|
|
484
|
-
MA: { enabled: false, params: {} },
|
|
485
|
-
ENE: { enabled: true, params: { period: 10, deviation: 11 } },
|
|
486
|
-
},
|
|
487
|
-
})
|
|
488
|
-
|
|
489
534
|
const ctx = createMockCanvasContext()
|
|
490
535
|
const context = createMockRenderContext(ctx)
|
|
491
536
|
plugin.draw(context)
|
|
@@ -498,4 +543,22 @@ describe('MainIndicatorLegend with other indicators', () => {
|
|
|
498
543
|
)
|
|
499
544
|
expect(eneLabelCalls.length).toBeGreaterThan(0)
|
|
500
545
|
})
|
|
546
|
+
|
|
547
|
+
it('should draw any registered main indicator when active (WMA example)', () => {
|
|
548
|
+
const scheduler = createMockScheduler(
|
|
549
|
+
{ wma: { getTitleInfo: createSimpleGetTitleInfo('WMA') } },
|
|
550
|
+
['wma']
|
|
551
|
+
)
|
|
552
|
+
const mockHost = createMockPluginHost(undefined, scheduler)
|
|
553
|
+
const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
|
|
554
|
+
plugin.onInstall(mockHost)
|
|
555
|
+
|
|
556
|
+
const ctx = createMockCanvasContext()
|
|
557
|
+
const context = createMockRenderContext(ctx)
|
|
558
|
+
plugin.draw(context)
|
|
559
|
+
|
|
560
|
+
const fillTextCalls = vi.mocked(ctx.fillText).mock.calls
|
|
561
|
+
const wmaLabelCalls = fillTextCalls.filter(call => String(call[0]).includes('WMA'))
|
|
562
|
+
expect(wmaLabelCalls.length).toBeGreaterThan(0)
|
|
563
|
+
})
|
|
501
564
|
})
|