Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,6 @@ describe('builtin indicator registration', () => {
showUpper: false,
showMiddle: false,
showLower: false,
showBand: false,
})
expect(
getRegisteredIndicatorDefinition('EXPMA')?.mainPane?.toActiveConfig?.({}, false),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,6 @@ describe('BOLL State in scheduler', () => {
expect(state!.params.showUpper).toBe(true)
expect(state!.params.showMiddle).toBe(true)
expect(state!.params.showLower).toBe(true)
expect(state!.params.showBand).toBe(true)
})

it('should update BOLL config via updateBOLLConfig', () => {
Expand Down Expand Up @@ -755,7 +754,6 @@ describe('EMPTY_BOLL_STATE', () => {
showUpper: true,
showMiddle: true,
showLower: true,
showBand: true,
},
visibleMin: Infinity,
visibleMax: -Infinity,
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/engine/indicators/indicatorMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import { KLineChartError } from '../../errors'
import type { PluginHost, RendererPluginWithHost } from '../../foundation/plugin/index'
import type { ColorTokens } from '../../foundation/tokens/index'
import type { KLineData } from '../../foundation/types/price'

import type { IndicatorConfigSnapshot, IndicatorSeriesBundle } from './workerProtocol'
Expand Down Expand Up @@ -158,6 +159,7 @@ export type GetTitleInfoFn = (
params: Record<string, number | boolean | string>,
host: PluginHost,
paneId: string,
colors: ColorTokens,
) => TitleInfo | null

/**
Expand Down
4 changes: 1 addition & 3 deletions packages/core/src/engine/indicators/state/bollState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@ export interface BOLLRenderState extends BaseIndicatorState {
timestamp: number
/** 全量 BOLL 数组(稀疏:前 period-1 个为 undefined) */
series: BOLLPoint[]
/** 计算和渲染参数(渲染器从此读取 showUpper/showMiddle/showLower/showBand) */
/** 计算和渲染参数(渲染器从此读取 showUpper/showMiddle/showLower) */
params: {
period: number
multiplier: number
showUpper: boolean
showMiddle: boolean
showLower: boolean
showBand: boolean
}
/** 视口内所有 BOLL 线的最低价 */
visibleMin: number
Expand All @@ -47,7 +46,6 @@ export const EMPTY_BOLL_STATE: BOLLRenderState = {
showUpper: true,
showMiddle: true,
showLower: true,
showBand: true,
},
visibleMin: Infinity,
visibleMax: -Infinity,
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/engine/indicators/workerProtocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ export interface BOLLSchedulerConfig {
showUpper: boolean
showMiddle: boolean
showLower: boolean
showBand: boolean
}

export interface EXPMASchedulerConfig {
Expand Down
17 changes: 11 additions & 6 deletions packages/core/src/engine/renderers/Indicator/alma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
PluginHost,
} from '../../../foundation/plugin/index'
import { RENDERER_PRIORITY } from '../../../foundation/plugin/index'
import { resolveThemeColors } from '../../../foundation/tokens/index'
import { calcALMAData } from '../../indicators/calculators'
import { Indicator } from '../../indicators/indicatorDefinitionRegistry'
import { resolveStateKey } from '../../indicators/indicatorMetadata'
Expand All @@ -19,8 +20,6 @@ import { tryDrawLinesGpu } from '../linesViaRenderer'

import { createSingleLineTitleInfo } from './shared/titleInfo'

const ALMA_COLOR = '#22c55e'

type Point = { x: number; y: number }

interface ALMARendererOptions {
Expand Down Expand Up @@ -55,7 +54,7 @@ function createALMARendererPlugin(options: ALMARendererOptions = {}): RendererPl
description: 'ALMA Arnaud Legoux 移动均线渲染器(WebGL + Canvas2D 回退)',
debugName: 'ALMA',
paneId,
priority: RENDERER_PRIORITY.MAIN,
priority: RENDERER_PRIORITY.INDICATOR,

onInstall(host: PluginHost) {
pluginHost = host
Expand All @@ -68,6 +67,11 @@ function createALMARendererPlugin(options: ALMARendererOptions = {}): RendererPl

draw(context: RenderContext) {
const { ctx, pane, range, scrollLeft, kLineCenters } = context
const colors = resolveThemeColors(
context.theme,
context.isAsiaMarket,
context.colorPresetSettings,
)

const stateKey = resolveKey()
if (!stateKey) return
Expand All @@ -89,11 +93,12 @@ function createALMARendererPlugin(options: ALMARendererOptions = {}): RendererPl

if (points.length < 2) return

if (tryDrawLinesGpu(context, [{ points, width: 1, color: ALMA_COLOR }], scrollLeft)) return
if (tryDrawLinesGpu(context, [{ points, width: 1, color: colors.palette.i3 }], scrollLeft))
return

ctx.save()
ctx.translate(-scrollLeft, 0)
ctx.strokeStyle = ALMA_COLOR
ctx.strokeStyle = colors.palette.i3
ctx.lineWidth = 1
ctx.lineJoin = 'round'
ctx.lineCap = 'round'
Expand Down Expand Up @@ -123,7 +128,7 @@ const getALMATitleInfo = createSingleLineTitleInfo({
createStateKey: createALMAStateKey,
name: 'ALMA',
getParams: (p) => [p.period as number, p.offset as number, p.sigma as number],
color: ALMA_COLOR,
getColor: (colors) => colors.palette.i3,
})

@Indicator({
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/engine/renderers/Indicator/atr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ function createATRRendererPlugin(options: ATRRendererOptions = {}): RendererPlug
description: 'ATR 平均真实波幅渲染器(Wilder 平滑)',
debugName: 'ATR',
paneId: paneId,
priority: RENDERER_PRIORITY.MAIN,
priority: RENDERER_PRIORITY.INDICATOR,

onInstall(host: PluginHost) {
pluginHost = host
Expand Down Expand Up @@ -129,7 +129,8 @@ function createATRRendererPlugin(options: ATRRendererOptions = {}): RendererPlug
ctx.save()
ctx.translate(-scrollLeft, 0)

ctx.strokeStyle = 'rgba(0, 0, 0, 0.1)'
// 零线使用主题 wmsrGrid token,避免硬编码颜色
ctx.strokeStyle = colors.wmsrGrid
ctx.lineWidth = 1
ctx.setLineDash([4, 4])
ctx.beginPath()
Expand Down
81 changes: 11 additions & 70 deletions packages/core/src/engine/renderers/Indicator/boll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type {
RenderContext,
} from '../../../foundation/plugin/index'
import { RENDERER_PRIORITY } from '../../../foundation/plugin/index'
import { resolveThemeColors } from '../../../foundation/tokens/index'
import { resolveThemeColors, type ColorTokens } from '../../../foundation/tokens/index'
import type { KLineData } from '../../../foundation/types/price'
import { alignToPhysicalPixelCenter } from '../../../foundation/utils/pixelAlign'
import { calcBOLLData } from '../../indicators/calculators'
Expand All @@ -20,8 +20,7 @@ import type {
import type { BOLLSchedulerConfig, IndicatorScheduler } from '../../indicators/scheduler'
import { BOLL_STATE_KEY, type BOLLRenderState } from '../../indicators/state/bollState'

import { getRgbaAlpha, toOpaqueRgba } from './shared/webglBand'
import { tryDrawFilledBandGpu, tryDrawLinesGpu } from '../linesViaRenderer'
import { tryDrawLinesGpu } from '../linesViaRenderer'

type LinePoint = { x: number; y: number }

Expand All @@ -34,40 +33,24 @@ interface PriceData {
}

/**
* BOLL GPU:先 band fill(半透明 composite)再三轨折线。
* 仅 sceneRenderer;失败返回 false 走 2D。
* BOLL GPU:三轨折线;仅 sceneRenderer,失败返回 false 走 2D。
*/
function drawBOLLWithWebGL(
context: RenderContext,
data: {
showUpper: boolean
showMiddle: boolean
showLower: boolean
showBand: boolean
upperPoints: LinePoint[]
middlePoints: LinePoint[]
lowerPoints: LinePoint[]
bandUpperPoints: LinePoint[]
bandLowerPoints: LinePoint[]
},
): boolean {
const colors = resolveThemeColors(
context.theme,
context.isAsiaMarket,
context.colorPresetSettings,
)
// band:画完立即 composite(alpha),再画线(MSAA 会 clear FBO,band 已在 2D)
let bandOk = false
if (data.showBand && data.bandUpperPoints.length >= 2 && data.bandLowerPoints.length >= 2) {
bandOk = tryDrawFilledBandGpu(
context,
data.bandUpperPoints,
data.bandLowerPoints,
toOpaqueRgba(colors.boll.bandFill),
context.scrollLeft,
getRgbaAlpha(colors.boll.bandFill),
)
}

const lineStrips: Array<{ points: LinePoint[]; width: number; color: string }> = []
if (data.showUpper && data.upperPoints.length >= 2) {
Expand All @@ -84,7 +67,7 @@ function drawBOLLWithWebGL(
lineStrips.push({ points: data.lowerPoints, width: BOLL_LINE_WIDTH, color: colors.boll.lower })
}

if (lineStrips.length === 0) return bandOk
if (lineStrips.length === 0) return false
return tryDrawLinesGpu(context, lineStrips, context.scrollLeft)
}

Expand Down Expand Up @@ -152,6 +135,7 @@ const getBOLLTitleInfo: GetTitleInfoFn = (
_params: Record<string, number | boolean | string>,
pluginHost: PluginHost,
_paneId: string,
colors: ColorTokens,
): TitleInfo | null => {
if (index === null) return null

Expand All @@ -165,9 +149,9 @@ const getBOLLTitleInfo: GetTitleInfoFn = (
if (!bollPoint) return null

const values: TitleValueItem[] = [
{ label: 'UP', value: bollPoint.upper, color: '#C83C3C' },
{ label: 'MID', value: bollPoint.middle, color: '#5A8CFF' },
{ label: 'DN', value: bollPoint.lower, color: '#32AA3C' },
{ label: 'UP', value: bollPoint.upper, color: colors.boll.upper },
{ label: 'MID', value: bollPoint.middle, color: colors.boll.middle },
{ label: 'DN', value: bollPoint.lower, color: colors.boll.lower },
]

return { name: 'BOLL', params: [state.params.period, state.params.multiplier], values }
Expand All @@ -182,9 +166,7 @@ const getBOLLTitleInfo: GetTitleInfoFn = (
mainPane: {
rendererName: 'boll',
toActiveConfig: (params, active) =>
active
? params
: { ...params, showUpper: false, showMiddle: false, showLower: false, showBand: false },
active ? params : { ...params, showUpper: false, showMiddle: false, showLower: false },
computePriceRange: computeBOLLPriceRange,
composeRenderState: composeBOLLRenderState,
},
Expand All @@ -204,7 +186,6 @@ const getBOLLTitleInfo: GetTitleInfoFn = (
showUpper: true,
showMiddle: true,
showLower: true,
showBand: true,
},
computeKey: 'calcBOLLData',
compute: (data, c) => calcBOLLData(data, c.period, c.multiplier),
Expand All @@ -222,8 +203,6 @@ export function createBOLLRendererPlugin(): RendererPluginWithHost {
const _upperPool: LinePoint[] = []
const _middlePool: LinePoint[] = []
const _lowerPool: LinePoint[] = []
const _bandUpperPool: LinePoint[] = []
const _bandLowerPool: LinePoint[] = []
let _poolSize = 0

function _growPool(size: number) {
Expand All @@ -232,8 +211,6 @@ export function createBOLLRendererPlugin(): RendererPluginWithHost {
_upperPool[i] = { x: 0, y: 0 }
_middlePool[i] = { x: 0, y: 0 }
_lowerPool[i] = { x: 0, y: 0 }
_bandUpperPool[i] = { x: 0, y: 0 }
_bandLowerPool[i] = { x: 0, y: 0 }
}
_poolSize = size
}
Expand Down Expand Up @@ -275,7 +252,7 @@ export function createBOLLRendererPlugin(): RendererPluginWithHost {
return
}

const { period, showUpper, showMiddle, showLower, showBand } = state.params
const { period, showUpper, showMiddle, showLower } = state.params
const bollData = state.series

if (klineData.length < period) return
Expand All @@ -295,13 +272,10 @@ export function createBOLLRendererPlugin(): RendererPluginWithHost {
const upperPoints: LinePoint[] = new Array(pointCount)
const middlePoints: LinePoint[] = new Array(pointCount)
const lowerPoints: LinePoint[] = new Array(pointCount)
const bandUpperPoints: LinePoint[] = showBand ? new Array(pointCount) : []
const bandLowerPoints: LinePoint[] = showBand ? new Array(pointCount) : []

let upperIdx = 0,
middleIdx = 0,
lowerIdx = 0,
bandIdx = 0
lowerIdx = 0

for (let i = drawStart; i < drawEnd; i++) {
const boll = bollData[i]
Expand All @@ -328,41 +302,22 @@ export function createBOLLRendererPlugin(): RendererPluginWithHost {
p.x = centerX
p.y = lowerY
lowerPoints[lowerIdx++] = p

if (showBand) {
p = _bandUpperPool[bandIdx]
p.x = centerX
p.y = upperY
bandUpperPoints[bandIdx] = p
p = _bandLowerPool[bandIdx]
p.x = centerX
p.y = lowerY
bandLowerPoints[bandIdx] = p
bandIdx++
}
}

// 截断到实际长度
upperPoints.length = upperIdx
middlePoints.length = middleIdx
lowerPoints.length = lowerIdx
if (showBand) {
bandUpperPoints.length = bandIdx
bandLowerPoints.length = bandIdx
}

// ====== 渲染 ======
if (
drawBOLLWithWebGL(context, {
showUpper,
showMiddle,
showLower,
showBand,
upperPoints,
middlePoints,
lowerPoints,
bandUpperPoints,
bandLowerPoints,
})
) {
return
Expand All @@ -375,20 +330,6 @@ export function createBOLLRendererPlugin(): RendererPluginWithHost {
ctx.lineJoin = 'round'
ctx.lineCap = 'round'

if (showBand && bandUpperPoints.length >= 2) {
const bandPath = new Path2D()
bandPath.moveTo(bandUpperPoints[0].x, bandUpperPoints[0].y)
for (let i = 1; i < bandUpperPoints.length; i++) {
bandPath.lineTo(bandUpperPoints[i].x, bandUpperPoints[i].y)
}
for (let i = bandLowerPoints.length - 1; i >= 0; i--) {
bandPath.lineTo(bandLowerPoints[i].x, bandLowerPoints[i].y)
}
bandPath.closePath()
ctx.fillStyle = colors.boll.bandFill
ctx.fill(bandPath)
}

const drawLine = (points: LinePoint[], color: string) => {
if (points.length < 2) return
ctx.beginPath()
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/engine/renderers/Indicator/cci.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ function createCCIRendererPlugin(options: CCIRendererOptions = {}): RendererPlug
description: 'CCI 顺势指标渲染器(WebGL + Canvas2D 回退)',
debugName: 'CCI',
paneId: paneId,
priority: RENDERER_PRIORITY.MAIN,
priority: RENDERER_PRIORITY.INDICATOR,

onInstall(host: PluginHost) {
pluginHost = host
Expand Down Expand Up @@ -151,8 +151,8 @@ function createCCIRendererPlugin(options: CCIRendererOptions = {}): RendererPlug
ctx.lineTo(lineEndX, yNeg100)
ctx.stroke()

// 零轴
ctx.strokeStyle = 'rgba(0, 0, 0, 0.1)'
// 零轴(使用主题 wmsrGrid token,避免硬编码颜色)
ctx.strokeStyle = colors.wmsrGrid
ctx.beginPath()
ctx.moveTo(lineStartX, zeroY)
ctx.lineTo(lineEndX, zeroY)
Expand Down
Loading
Loading