@invinite-org/chartlang-runtime 1.1.1 → 1.2.0
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/CHANGELOG.md +236 -0
- package/dist/barPoint.d.ts +20 -0
- package/dist/barPoint.d.ts.map +1 -0
- package/dist/barPoint.js +72 -0
- package/dist/barPoint.js.map +1 -0
- package/dist/bufferSnapshot.d.ts +102 -0
- package/dist/bufferSnapshot.d.ts.map +1 -0
- package/dist/bufferSnapshot.js +119 -0
- package/dist/bufferSnapshot.js.map +1 -0
- package/dist/createScriptRunner.d.ts +6 -3
- package/dist/createScriptRunner.d.ts.map +1 -1
- package/dist/createScriptRunner.js +29 -5
- package/dist/createScriptRunner.js.map +1 -1
- package/dist/dep/DepRunner.d.ts.map +1 -1
- package/dist/dep/DepRunner.js +1 -0
- package/dist/dep/DepRunner.js.map +1 -1
- package/dist/emit/draw/boxes/fillBetween.d.ts +45 -0
- package/dist/emit/draw/boxes/fillBetween.d.ts.map +1 -0
- package/dist/emit/draw/boxes/fillBetween.js +36 -0
- package/dist/emit/draw/boxes/fillBetween.js.map +1 -0
- package/dist/emit/draw/handle.d.ts +9 -0
- package/dist/emit/draw/handle.d.ts.map +1 -1
- package/dist/emit/draw/handle.js +65 -10
- package/dist/emit/draw/handle.js.map +1 -1
- package/dist/emit/draw/namespace.d.ts +4 -3
- package/dist/emit/draw/namespace.d.ts.map +1 -1
- package/dist/emit/draw/namespace.js +6 -3
- package/dist/emit/draw/namespace.js.map +1 -1
- package/dist/emit/plot.d.ts +7 -0
- package/dist/emit/plot.d.ts.map +1 -1
- package/dist/emit/plot.js +13 -0
- package/dist/emit/plot.js.map +1 -1
- package/dist/execution/dispose.d.ts.map +1 -1
- package/dist/execution/dispose.js +16 -0
- package/dist/execution/dispose.js.map +1 -1
- package/dist/execution/runComputeStep.d.ts.map +1 -1
- package/dist/execution/runComputeStep.js +10 -1
- package/dist/execution/runComputeStep.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/persistentStateStore.runtime.d.ts.map +1 -1
- package/dist/persistentStateStore.runtime.js +21 -7
- package/dist/persistentStateStore.runtime.js.map +1 -1
- package/dist/request/index.d.ts +2 -1
- package/dist/request/index.d.ts.map +1 -1
- package/dist/request/index.js +2 -1
- package/dist/request/index.js.map +1 -1
- package/dist/request/requestNamespace.d.ts.map +1 -1
- package/dist/request/requestNamespace.js +16 -3
- package/dist/request/requestNamespace.js.map +1 -1
- package/dist/request/security.d.ts +20 -1
- package/dist/request/security.d.ts.map +1 -1
- package/dist/request/security.js +62 -23
- package/dist/request/security.js.map +1 -1
- package/dist/request/securityExprRunner.d.ts +133 -0
- package/dist/request/securityExprRunner.d.ts.map +1 -0
- package/dist/request/securityExprRunner.js +235 -0
- package/dist/request/securityExprRunner.js.map +1 -0
- package/dist/request/streamBars.d.ts +14 -1
- package/dist/request/streamBars.d.ts.map +1 -1
- package/dist/request/streamBars.js +39 -1
- package/dist/request/streamBars.js.map +1 -1
- package/dist/runtimeContext.d.ts +48 -0
- package/dist/runtimeContext.d.ts.map +1 -1
- package/dist/runtimeContext.js.map +1 -1
- package/dist/seriesView.d.ts +42 -17
- package/dist/seriesView.d.ts.map +1 -1
- package/dist/seriesView.js +65 -42
- package/dist/seriesView.js.map +1 -1
- package/dist/state/index.d.ts +2 -1
- package/dist/state/index.d.ts.map +1 -1
- package/dist/state/index.js +2 -1
- package/dist/state/index.js.map +1 -1
- package/dist/state/lifecycle.d.ts +40 -0
- package/dist/state/lifecycle.d.ts.map +1 -1
- package/dist/state/lifecycle.js +53 -0
- package/dist/state/lifecycle.js.map +1 -1
- package/dist/state/seriesPersistence.d.ts +48 -0
- package/dist/state/seriesPersistence.d.ts.map +1 -0
- package/dist/state/seriesPersistence.js +87 -0
- package/dist/state/seriesPersistence.js.map +1 -0
- package/dist/state/seriesSlot.d.ts +105 -0
- package/dist/state/seriesSlot.d.ts.map +1 -0
- package/dist/state/seriesSlot.js +123 -0
- package/dist/state/seriesSlot.js.map +1 -0
- package/dist/state/stateNamespace.d.ts.map +1 -1
- package/dist/state/stateNamespace.js +28 -0
- package/dist/state/stateNamespace.js.map +1 -1
- package/dist/streamState.d.ts +25 -19
- package/dist/streamState.d.ts.map +1 -1
- package/dist/streamState.js +40 -66
- package/dist/streamState.js.map +1 -1
- package/dist/ta/adx.d.ts +3 -2
- package/dist/ta/adx.d.ts.map +1 -1
- package/dist/ta/adx.js +3 -2
- package/dist/ta/adx.js.map +1 -1
- package/dist/ta/alma.d.ts +6 -4
- package/dist/ta/alma.d.ts.map +1 -1
- package/dist/ta/alma.js +19 -6
- package/dist/ta/alma.js.map +1 -1
- package/dist/ta/atr.d.ts +3 -2
- package/dist/ta/atr.d.ts.map +1 -1
- package/dist/ta/atr.js +3 -2
- package/dist/ta/atr.js.map +1 -1
- package/dist/ta/bb.d.ts +3 -2
- package/dist/ta/bb.d.ts.map +1 -1
- package/dist/ta/bb.js +3 -2
- package/dist/ta/bb.js.map +1 -1
- package/dist/ta/chaikinOsc.d.ts +3 -2
- package/dist/ta/chaikinOsc.d.ts.map +1 -1
- package/dist/ta/chaikinOsc.js +3 -2
- package/dist/ta/chaikinOsc.js.map +1 -1
- package/dist/ta/crossover.d.ts +3 -2
- package/dist/ta/crossover.d.ts.map +1 -1
- package/dist/ta/crossover.js +3 -2
- package/dist/ta/crossover.js.map +1 -1
- package/dist/ta/crossunder.d.ts +3 -2
- package/dist/ta/crossunder.d.ts.map +1 -1
- package/dist/ta/crossunder.js +3 -2
- package/dist/ta/crossunder.js.map +1 -1
- package/dist/ta/dmi.d.ts +4 -3
- package/dist/ta/dmi.d.ts.map +1 -1
- package/dist/ta/dmi.js +4 -3
- package/dist/ta/dmi.js.map +1 -1
- package/dist/ta/ema.d.ts +3 -2
- package/dist/ta/ema.d.ts.map +1 -1
- package/dist/ta/ema.js +3 -2
- package/dist/ta/ema.js.map +1 -1
- package/dist/ta/eom.d.ts +3 -1
- package/dist/ta/eom.d.ts.map +1 -1
- package/dist/ta/eom.js +3 -1
- package/dist/ta/eom.js.map +1 -1
- package/dist/ta/highestbars.d.ts +25 -0
- package/dist/ta/highestbars.d.ts.map +1 -0
- package/dist/ta/highestbars.js +106 -0
- package/dist/ta/highestbars.js.map +1 -0
- package/dist/ta/historicalVolatility.d.ts +3 -2
- package/dist/ta/historicalVolatility.d.ts.map +1 -1
- package/dist/ta/historicalVolatility.js +3 -2
- package/dist/ta/historicalVolatility.js.map +1 -1
- package/dist/ta/ichimoku.d.ts +3 -1
- package/dist/ta/ichimoku.d.ts.map +1 -1
- package/dist/ta/ichimoku.js +3 -1
- package/dist/ta/ichimoku.js.map +1 -1
- package/dist/ta/lowestbars.d.ts +25 -0
- package/dist/ta/lowestbars.d.ts.map +1 -0
- package/dist/ta/lowestbars.js +102 -0
- package/dist/ta/lowestbars.js.map +1 -0
- package/dist/ta/macd.d.ts +3 -2
- package/dist/ta/macd.d.ts.map +1 -1
- package/dist/ta/macd.js +3 -2
- package/dist/ta/macd.js.map +1 -1
- package/dist/ta/massIndex.d.ts +3 -2
- package/dist/ta/massIndex.d.ts.map +1 -1
- package/dist/ta/massIndex.js +3 -2
- package/dist/ta/massIndex.js.map +1 -1
- package/dist/ta/mfi.d.ts +3 -1
- package/dist/ta/mfi.d.ts.map +1 -1
- package/dist/ta/mfi.js +3 -1
- package/dist/ta/mfi.js.map +1 -1
- package/dist/ta/netVolume.d.ts +3 -1
- package/dist/ta/netVolume.d.ts.map +1 -1
- package/dist/ta/netVolume.js +3 -1
- package/dist/ta/netVolume.js.map +1 -1
- package/dist/ta/nvi.d.ts +3 -1
- package/dist/ta/nvi.d.ts.map +1 -1
- package/dist/ta/nvi.js +3 -1
- package/dist/ta/nvi.js.map +1 -1
- package/dist/ta/persistence.d.ts.map +1 -1
- package/dist/ta/persistence.js +1 -40
- package/dist/ta/persistence.js.map +1 -1
- package/dist/ta/ppo.d.ts +3 -2
- package/dist/ta/ppo.d.ts.map +1 -1
- package/dist/ta/ppo.js +3 -2
- package/dist/ta/ppo.js.map +1 -1
- package/dist/ta/pvi.d.ts +3 -1
- package/dist/ta/pvi.d.ts.map +1 -1
- package/dist/ta/pvi.js +3 -1
- package/dist/ta/pvi.js.map +1 -1
- package/dist/ta/pvo.d.ts +3 -1
- package/dist/ta/pvo.d.ts.map +1 -1
- package/dist/ta/pvo.js +3 -1
- package/dist/ta/pvo.js.map +1 -1
- package/dist/ta/pvt.d.ts +3 -1
- package/dist/ta/pvt.d.ts.map +1 -1
- package/dist/ta/pvt.js +3 -1
- package/dist/ta/pvt.js.map +1 -1
- package/dist/ta/registry.d.ts +7 -1
- package/dist/ta/registry.d.ts.map +1 -1
- package/dist/ta/registry.js +4 -0
- package/dist/ta/registry.js.map +1 -1
- package/dist/ta/rsi.d.ts +3 -2
- package/dist/ta/rsi.d.ts.map +1 -1
- package/dist/ta/rsi.js +3 -2
- package/dist/ta/rsi.js.map +1 -1
- package/dist/ta/rvi.d.ts +3 -2
- package/dist/ta/rvi.d.ts.map +1 -1
- package/dist/ta/rvi.js +3 -2
- package/dist/ta/rvi.js.map +1 -1
- package/dist/ta/sma.d.ts +6 -3
- package/dist/ta/sma.d.ts.map +1 -1
- package/dist/ta/sma.js +6 -3
- package/dist/ta/sma.js.map +1 -1
- package/dist/ta/stdev.d.ts +3 -2
- package/dist/ta/stdev.d.ts.map +1 -1
- package/dist/ta/stdev.js +3 -2
- package/dist/ta/stdev.js.map +1 -1
- package/dist/ta/trendStrengthIndex.d.ts +3 -2
- package/dist/ta/trendStrengthIndex.d.ts.map +1 -1
- package/dist/ta/trendStrengthIndex.js +3 -2
- package/dist/ta/trendStrengthIndex.js.map +1 -1
- package/dist/ta/trix.d.ts +4 -3
- package/dist/ta/trix.d.ts.map +1 -1
- package/dist/ta/trix.js +4 -3
- package/dist/ta/trix.js.map +1 -1
- package/dist/ta/vortex.d.ts +3 -2
- package/dist/ta/vortex.d.ts.map +1 -1
- package/dist/ta/vortex.js +3 -2
- package/dist/ta/vortex.js.map +1 -1
- package/package.json +3 -3
- package/dist/ta/lib/applyOffset.d.ts +0 -19
- package/dist/ta/lib/applyOffset.d.ts.map +0 -1
- package/dist/ta/lib/applyOffset.js +0 -38
- package/dist/ta/lib/applyOffset.js.map +0 -1
package/dist/ta/rsi.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rsi.js","sourceRoot":"","sources":["../../src/ta/rsi.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n//\n// Ported from invinite/src/components/trading-chart/indicators/rsi.ts\n// (commit d2d1043c1b039f66d2f3674526d303d31cf2f1e0, © Invinite).\n// Re-licensed MIT for chartlang. The math is the reference, the code\n// style is not.\n// Structural choices (callsite-id slot, Series<T> proxy, replaceHead\n// mode) follow chartlang's primitive shape — NOT invinite's\n// IndicatorPlugin shape.\n\nimport type { RsiOpts, Series } from \"@invinite-org/chartlang-core\";\n\nimport { Float64RingBuffer } from \"../ringBuffer.js\";\nimport { ACTIVE_RUNTIME_CONTEXT, type RuntimeContext } from \"../runtimeContext.js\";\nimport { makeSeriesView, makeShiftedSeriesView } from \"../seriesView.js\";\nimport { wilderStep } from \"./lib/wilderSmoothing.js\";\nimport { type ScalarOrSeries, readSourceValue } from \"./lib/sourceValue.js\";\n\ntype RsiSlot = {\n readonly kind: \"ta.rsi\";\n readonly outBuffer: Float64RingBuffer;\n readonly series: Series<number>;\n readonly length: number;\n seedGainSum: number;\n seedLossSum: number;\n /** Number of diffs (= closed bars − 1) seen so far. */\n diffCount: number;\n avgGain: number;\n avgLoss: number;\n prevSrc: number;\n /** Source value as of the prior closed bar — used by tick-mode replay. */\n prevClosedSrc: number;\n /** Per-offset Series-view cache; see `sma.ts` for the convention. */\n readonly shiftedViews: Map<number, Series<number>>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.rsi called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(length: number, capacity: number): RsiSlot {\n const outBuffer = new Float64RingBuffer(capacity);\n return {\n kind: \"ta.rsi\",\n outBuffer,\n series: makeSeriesView<number>(outBuffer),\n length,\n seedGainSum: 0,\n seedLossSum: 0,\n diffCount: 0,\n avgGain: Number.NaN,\n avgLoss: Number.NaN,\n prevSrc: Number.NaN,\n prevClosedSrc: Number.NaN,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: RsiSlot, offset: number): Series<number> {\n if (offset === 0) return slot.series;\n let view = slot.shiftedViews.get(offset);\n if (view === undefined) {\n view = makeShiftedSeriesView<number>(slot.outBuffer, offset);\n slot.shiftedViews.set(offset, view);\n }\n return view;\n}\n\nfunction rsiFromAvgs(avgGain: number, avgLoss: number): number {\n if (avgLoss === 0) return 100;\n return 100 - 100 / (1 + avgGain / avgLoss);\n}\n\nfunction closeValue(slot: RsiSlot, src: number): number {\n if (!Number.isFinite(src)) {\n // Skip the diff; hold prior values forward.\n if (Number.isFinite(slot.avgGain) && Number.isFinite(slot.avgLoss)) {\n return rsiFromAvgs(slot.avgGain, slot.avgLoss);\n }\n return Number.NaN;\n }\n if (!Number.isFinite(slot.prevSrc)) {\n slot.prevSrc = src;\n slot.prevClosedSrc = src;\n return Number.NaN;\n }\n const diff = src - slot.prevSrc;\n const gain = diff > 0 ? diff : 0;\n const loss = diff < 0 ? -diff : 0;\n slot.prevClosedSrc = slot.prevSrc;\n slot.prevSrc = src;\n slot.diffCount += 1;\n\n if (slot.diffCount < slot.length) {\n slot.seedGainSum += gain;\n slot.seedLossSum += loss;\n return Number.NaN;\n }\n if (slot.diffCount === slot.length) {\n slot.seedGainSum += gain;\n slot.seedLossSum += loss;\n slot.avgGain = slot.seedGainSum / slot.length;\n slot.avgLoss = slot.seedLossSum / slot.length;\n return rsiFromAvgs(slot.avgGain, slot.avgLoss);\n }\n slot.avgGain = wilderStep(slot.avgGain, gain, slot.length);\n slot.avgLoss = wilderStep(slot.avgLoss, loss, slot.length);\n return rsiFromAvgs(slot.avgGain, slot.avgLoss);\n}\n\nfunction tickValue(slot: RsiSlot, src: number): number {\n if (!Number.isFinite(src) || !Number.isFinite(slot.prevClosedSrc)) {\n if (Number.isFinite(slot.avgGain) && Number.isFinite(slot.avgLoss)) {\n return rsiFromAvgs(slot.avgGain, slot.avgLoss);\n }\n return Number.NaN;\n }\n // Replay the most recent diff using the (frozen) prior closed avgs.\n // We need pre-update avgs: at close we already overwrote `avgGain` /\n // `avgLoss`. So we reverse the Wilder step to recover them.\n if (slot.diffCount < slot.length) {\n // During seeding: simulate the seed completing with this tick.\n const diff = src - slot.prevClosedSrc;\n const gain = diff > 0 ? diff : 0;\n const loss = diff < 0 ? -diff : 0;\n const provisionalCount = slot.diffCount + 1;\n if (provisionalCount < slot.length) return Number.NaN;\n const provGain = (slot.seedGainSum + gain) / slot.length;\n const provLoss = (slot.seedLossSum + loss) / slot.length;\n return rsiFromAvgs(provGain, provLoss);\n }\n // Post-warmup: reverse the most recent Wilder step to get the prior-\n // close avgs, then apply this tick's diff against those.\n const diffClosed = slot.prevSrc - slot.prevClosedSrc;\n const closedGain = diffClosed > 0 ? diffClosed : 0;\n const closedLoss = diffClosed < 0 ? -diffClosed : 0;\n const priorAvgGain = (slot.avgGain * slot.length - closedGain) / (slot.length - 1);\n const priorAvgLoss = (slot.avgLoss * slot.length - closedLoss) / (slot.length - 1);\n const diff = src - slot.prevClosedSrc;\n const gain = diff > 0 ? diff : 0;\n const loss = diff < 0 ? -diff : 0;\n const provGain = wilderStep(priorAvgGain, gain, slot.length);\n const provLoss = wilderStep(priorAvgLoss, loss, slot.length);\n return rsiFromAvgs(provGain, provLoss);\n}\n\n/**\n * Wilder's Relative Strength Index. Output range `[0, 100]`. First\n * `length` bars NaN (no diff for bar 0, then a seed window of\n * `length` diffs). Output is `100 − 100 / (1 + RS)` with\n * `RS = avgGain / avgLoss`; `avgLoss = 0` → RSI = 100.\n *\n * @formula diff[t] = source[t] − source[t − 1] ;\n * seed at bar `length` = simple mean of first `length` diffs ;\n * avgGain[t] = (avgGain[t − 1] · (length − 1) + gain[t]) / length ;\n * same for avgLoss ;\n * RSI = 100 − 100 / (1 + avgGain / avgLoss)\n * @warmup length\n * @since 0.1\n * @stable\n *\n * `opts.offset` shifts the returned series so `series.current` reads\n * the value `offset` bars ago.\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-runtime\";\n * // const r = ta.rsi(\"slot\", bar.close, 14);\n * // const head = r.current;\n * // const lagged = ta.rsi(\"slot2\", bar.close, 14, { offset: 5 });\n */\nexport function rsi(\n slotId: string,\n source: ScalarOrSeries,\n length: number,\n opts?: RsiOpts,\n): Series<number> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as RsiSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(length, ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const src = readSourceValue(source);\n if (ctx.isTick) {\n slot.outBuffer.replaceHead(tickValue(slot, src));\n } else {\n slot.outBuffer.append(closeValue(slot, src));\n }\n return viewForOffset(slot, opts?.offset ?? 0);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"rsi.js","sourceRoot":"","sources":["../../src/ta/rsi.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n//\n// Ported from invinite/src/components/trading-chart/indicators/rsi.ts\n// (commit d2d1043c1b039f66d2f3674526d303d31cf2f1e0, © Invinite).\n// Re-licensed MIT for chartlang. The math is the reference, the code\n// style is not.\n// Structural choices (callsite-id slot, Series<T> proxy, replaceHead\n// mode) follow chartlang's primitive shape — NOT invinite's\n// IndicatorPlugin shape.\n\nimport type { RsiOpts, Series } from \"@invinite-org/chartlang-core\";\n\nimport { Float64RingBuffer } from \"../ringBuffer.js\";\nimport { ACTIVE_RUNTIME_CONTEXT, type RuntimeContext } from \"../runtimeContext.js\";\nimport { makeSeriesView, makeShiftedSeriesView } from \"../seriesView.js\";\nimport { wilderStep } from \"./lib/wilderSmoothing.js\";\nimport { type ScalarOrSeries, readSourceValue } from \"./lib/sourceValue.js\";\n\ntype RsiSlot = {\n readonly kind: \"ta.rsi\";\n readonly outBuffer: Float64RingBuffer;\n readonly series: Series<number>;\n readonly length: number;\n seedGainSum: number;\n seedLossSum: number;\n /** Number of diffs (= closed bars − 1) seen so far. */\n diffCount: number;\n avgGain: number;\n avgLoss: number;\n prevSrc: number;\n /** Source value as of the prior closed bar — used by tick-mode replay. */\n prevClosedSrc: number;\n /** Per-offset Series-view cache; see `sma.ts` for the convention. */\n readonly shiftedViews: Map<number, Series<number>>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.rsi called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(length: number, capacity: number): RsiSlot {\n const outBuffer = new Float64RingBuffer(capacity);\n return {\n kind: \"ta.rsi\",\n outBuffer,\n series: makeSeriesView<number>(outBuffer),\n length,\n seedGainSum: 0,\n seedLossSum: 0,\n diffCount: 0,\n avgGain: Number.NaN,\n avgLoss: Number.NaN,\n prevSrc: Number.NaN,\n prevClosedSrc: Number.NaN,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: RsiSlot, offset: number): Series<number> {\n if (offset === 0) return slot.series;\n let view = slot.shiftedViews.get(offset);\n if (view === undefined) {\n view = makeShiftedSeriesView<number>(slot.outBuffer, offset);\n slot.shiftedViews.set(offset, view);\n }\n return view;\n}\n\nfunction rsiFromAvgs(avgGain: number, avgLoss: number): number {\n if (avgLoss === 0) return 100;\n return 100 - 100 / (1 + avgGain / avgLoss);\n}\n\nfunction closeValue(slot: RsiSlot, src: number): number {\n if (!Number.isFinite(src)) {\n // Skip the diff; hold prior values forward.\n if (Number.isFinite(slot.avgGain) && Number.isFinite(slot.avgLoss)) {\n return rsiFromAvgs(slot.avgGain, slot.avgLoss);\n }\n return Number.NaN;\n }\n if (!Number.isFinite(slot.prevSrc)) {\n slot.prevSrc = src;\n slot.prevClosedSrc = src;\n return Number.NaN;\n }\n const diff = src - slot.prevSrc;\n const gain = diff > 0 ? diff : 0;\n const loss = diff < 0 ? -diff : 0;\n slot.prevClosedSrc = slot.prevSrc;\n slot.prevSrc = src;\n slot.diffCount += 1;\n\n if (slot.diffCount < slot.length) {\n slot.seedGainSum += gain;\n slot.seedLossSum += loss;\n return Number.NaN;\n }\n if (slot.diffCount === slot.length) {\n slot.seedGainSum += gain;\n slot.seedLossSum += loss;\n slot.avgGain = slot.seedGainSum / slot.length;\n slot.avgLoss = slot.seedLossSum / slot.length;\n return rsiFromAvgs(slot.avgGain, slot.avgLoss);\n }\n slot.avgGain = wilderStep(slot.avgGain, gain, slot.length);\n slot.avgLoss = wilderStep(slot.avgLoss, loss, slot.length);\n return rsiFromAvgs(slot.avgGain, slot.avgLoss);\n}\n\nfunction tickValue(slot: RsiSlot, src: number): number {\n if (!Number.isFinite(src) || !Number.isFinite(slot.prevClosedSrc)) {\n if (Number.isFinite(slot.avgGain) && Number.isFinite(slot.avgLoss)) {\n return rsiFromAvgs(slot.avgGain, slot.avgLoss);\n }\n return Number.NaN;\n }\n // Replay the most recent diff using the (frozen) prior closed avgs.\n // We need pre-update avgs: at close we already overwrote `avgGain` /\n // `avgLoss`. So we reverse the Wilder step to recover them.\n if (slot.diffCount < slot.length) {\n // During seeding: simulate the seed completing with this tick.\n const diff = src - slot.prevClosedSrc;\n const gain = diff > 0 ? diff : 0;\n const loss = diff < 0 ? -diff : 0;\n const provisionalCount = slot.diffCount + 1;\n if (provisionalCount < slot.length) return Number.NaN;\n const provGain = (slot.seedGainSum + gain) / slot.length;\n const provLoss = (slot.seedLossSum + loss) / slot.length;\n return rsiFromAvgs(provGain, provLoss);\n }\n // Post-warmup: reverse the most recent Wilder step to get the prior-\n // close avgs, then apply this tick's diff against those.\n const diffClosed = slot.prevSrc - slot.prevClosedSrc;\n const closedGain = diffClosed > 0 ? diffClosed : 0;\n const closedLoss = diffClosed < 0 ? -diffClosed : 0;\n const priorAvgGain = (slot.avgGain * slot.length - closedGain) / (slot.length - 1);\n const priorAvgLoss = (slot.avgLoss * slot.length - closedLoss) / (slot.length - 1);\n const diff = src - slot.prevClosedSrc;\n const gain = diff > 0 ? diff : 0;\n const loss = diff < 0 ? -diff : 0;\n const provGain = wilderStep(priorAvgGain, gain, slot.length);\n const provLoss = wilderStep(priorAvgLoss, loss, slot.length);\n return rsiFromAvgs(provGain, provLoss);\n}\n\n/**\n * Wilder's Relative Strength Index. Output range `[0, 100]`. First\n * `length` bars NaN (no diff for bar 0, then a seed window of\n * `length` diffs). Output is `100 − 100 / (1 + RS)` with\n * `RS = avgGain / avgLoss`; `avgLoss = 0` → RSI = 100.\n *\n * @formula diff[t] = source[t] − source[t − 1] ;\n * seed at bar `length` = simple mean of first `length` diffs ;\n * avgGain[t] = (avgGain[t − 1] · (length − 1) + gain[t]) / length ;\n * same for avgLoss ;\n * RSI = 100 − 100 / (1 + avgGain / avgLoss)\n * @warmup length\n * @since 0.1\n * @stable\n *\n * `opts.offset` is a presentation display shift carried to the plot\n * emission as `xShift` (`+n` right / future, `−n` left / past); the\n * series value is unshifted.\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-runtime\";\n * // const r = ta.rsi(\"slot\", bar.close, 14);\n * // const head = r.current;\n * // const lagged = ta.rsi(\"slot2\", bar.close, 14, { offset: 5 });\n */\nexport function rsi(\n slotId: string,\n source: ScalarOrSeries,\n length: number,\n opts?: RsiOpts,\n): Series<number> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as RsiSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(length, ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const src = readSourceValue(source);\n if (ctx.isTick) {\n slot.outBuffer.replaceHead(tickValue(slot, src));\n } else {\n slot.outBuffer.append(closeValue(slot, src));\n }\n return viewForOffset(slot, opts?.offset ?? 0);\n}\n"]}
|
package/dist/ta/rvi.d.ts
CHANGED
|
@@ -19,8 +19,9 @@ import { type ScalarOrSeries } from "./lib/sourceValue.js";
|
|
|
19
19
|
* @since 0.2
|
|
20
20
|
* @stable
|
|
21
21
|
*
|
|
22
|
-
* `opts.offset`
|
|
23
|
-
*
|
|
22
|
+
* `opts.offset` is a presentation display shift carried to the plot
|
|
23
|
+
* emission as `xShift` (`+n` right / future, `−n` left / past); the
|
|
24
|
+
* series value is unshifted.
|
|
24
25
|
*
|
|
25
26
|
* @example
|
|
26
27
|
* // import { ta } from "@invinite-org/chartlang-core";
|
package/dist/ta/rvi.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rvi.d.ts","sourceRoot":"","sources":["../../src/ta/rvi.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAMpE,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AA8H5E
|
|
1
|
+
{"version":3,"file":"rvi.d.ts","sourceRoot":"","sources":["../../src/ta/rvi.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAMpE,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AA8H5E;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,GAAG,CACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,OAAO,GACf,MAAM,CAAC,MAAM,CAAC,CAoChB"}
|
package/dist/ta/rvi.js
CHANGED
|
@@ -146,8 +146,9 @@ function rviValue(upEma, downEma) {
|
|
|
146
146
|
* @since 0.2
|
|
147
147
|
* @stable
|
|
148
148
|
*
|
|
149
|
-
* `opts.offset`
|
|
150
|
-
*
|
|
149
|
+
* `opts.offset` is a presentation display shift carried to the plot
|
|
150
|
+
* emission as `xShift` (`+n` right / future, `−n` left / past); the
|
|
151
|
+
* series value is unshifted.
|
|
151
152
|
*
|
|
152
153
|
* @example
|
|
153
154
|
* // import { ta } from "@invinite-org/chartlang-core";
|
package/dist/ta/rvi.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rvi.js","sourceRoot":"","sources":["../../src/ta/rvi.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n//\n// Ported from invinite/src/components/trading-chart/indicators/rvi.ts\n// (commit 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite).\n// Re-licensed MIT for chartlang. The math is the reference, the code\n// style is not.\n// Structural choices (callsite-id slot, Series<T> proxy, replaceHead\n// mode) follow chartlang's primitive shape — NOT invinite's\n// IndicatorPlugin shape. The up/down EMA arms compose `ta.ema` via\n// sub-slots `${slotId}/upEma` / `${slotId}/downEma` so the EMA\n// recurrence + warmup semantics flow in by reference.\n\nimport type { RviOpts, Series } from \"@invinite-org/chartlang-core\";\n\nimport { Float64RingBuffer } from \"../ringBuffer.js\";\nimport { ACTIVE_RUNTIME_CONTEXT, type RuntimeContext } from \"../runtimeContext.js\";\nimport { makeSeriesView, makeShiftedSeriesView } from \"../seriesView.js\";\nimport { ema } from \"./ema.js\";\nimport { type ScalarOrSeries, readSourceValue } from \"./lib/sourceValue.js\";\n\ntype RviSlot = {\n readonly outBuffer: Float64RingBuffer;\n readonly series: Series<number>;\n readonly length: number;\n readonly sigmaWindow: Float64RingBuffer;\n sumX: number;\n sumX2: number;\n /** Last closed source value (basis of next bar's up/down classification). */\n prevSrc: number;\n /** Per-offset Series-view cache; see `sma.ts` for the convention. */\n readonly shiftedViews: Map<number, Series<number>>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.rvi called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(length: number, capacity: number): RviSlot {\n const outBuffer = new Float64RingBuffer(capacity);\n return {\n outBuffer,\n series: makeSeriesView<number>(outBuffer),\n length,\n sigmaWindow: new Float64RingBuffer(length),\n sumX: 0,\n sumX2: 0,\n prevSrc: Number.NaN,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: RviSlot, offset: number): Series<number> {\n if (offset === 0) return slot.series;\n let view = slot.shiftedViews.get(offset);\n if (view === undefined) {\n view = makeShiftedSeriesView<number>(slot.outBuffer, offset);\n slot.shiftedViews.set(offset, view);\n }\n return view;\n}\n\nfunction windowStdDev(n: number, sumX: number, sumX2: number): number {\n const mean = sumX / n;\n const variance = sumX2 / n - mean * mean;\n return Math.sqrt(Math.max(0, variance));\n}\n\n/** Fold a new source value into the sigma-window running sums. */\nfunction appendToSigmaWindow(slot: RviSlot, src: number): number {\n if (slot.sigmaWindow.length < slot.sigmaWindow.capacity) {\n slot.sigmaWindow.append(src);\n if (Number.isFinite(src)) {\n slot.sumX += src;\n slot.sumX2 += src * src;\n } else {\n slot.sumX = Number.NaN;\n slot.sumX2 = Number.NaN;\n }\n if (slot.sigmaWindow.length < slot.sigmaWindow.capacity) return Number.NaN;\n if (!Number.isFinite(slot.sumX)) return Number.NaN;\n return windowStdDev(slot.sigmaWindow.length, slot.sumX, slot.sumX2);\n }\n const outgoing = slot.sigmaWindow.at(slot.sigmaWindow.length - 1);\n slot.sigmaWindow.append(src);\n if (!Number.isFinite(src)) {\n slot.sumX = Number.NaN;\n slot.sumX2 = Number.NaN;\n return Number.NaN;\n }\n if (!Number.isFinite(slot.sumX) || !Number.isFinite(outgoing)) {\n // A previous NaN poisoned the running sums; rebuild from the\n // live window (NaN values short-circuit the result to NaN).\n let sumX = 0;\n let sumX2 = 0;\n for (let i = 0; i < slot.sigmaWindow.length; i += 1) {\n const v = slot.sigmaWindow.at(i);\n if (!Number.isFinite(v)) {\n slot.sumX = Number.NaN;\n slot.sumX2 = Number.NaN;\n return Number.NaN;\n }\n sumX += v;\n sumX2 += v * v;\n }\n slot.sumX = sumX;\n slot.sumX2 = sumX2;\n } else {\n slot.sumX = slot.sumX - outgoing + src;\n slot.sumX2 = slot.sumX2 - outgoing * outgoing + src * src;\n }\n return windowStdDev(slot.sigmaWindow.length, slot.sumX, slot.sumX2);\n}\n\n/** Sigma at the tick boundary against the closed sigma-window state. */\nfunction tickSigma(slot: RviSlot, src: number): number {\n if (slot.sigmaWindow.length < slot.sigmaWindow.capacity) return Number.NaN;\n if (!Number.isFinite(src)) return Number.NaN;\n const oldestInHead = slot.sigmaWindow.at(0);\n const sumX = slot.sumX - oldestInHead + src;\n const sumX2 = slot.sumX2 - oldestInHead * oldestInHead + src * src;\n return windowStdDev(slot.sigmaWindow.length, sumX, sumX2);\n}\n\nfunction classify(sigma: number, diff: number): { up: number; down: number } {\n if (!Number.isFinite(sigma) || !Number.isFinite(diff)) {\n return { up: Number.NaN, down: Number.NaN };\n }\n return {\n up: diff > 0 ? sigma : 0,\n down: diff < 0 ? sigma : 0,\n };\n}\n\nfunction rviValue(upEma: number, downEma: number): number {\n if (!Number.isFinite(upEma) || !Number.isFinite(downEma)) return Number.NaN;\n const total = upEma + downEma;\n if (total === 0) return Number.NaN;\n return (100 * upEma) / total;\n}\n\n/**\n * Relative Volatility Index — sub-pane oscillator bounded `[0, 100]`.\n * Like RSI but uses rolling stddev of the source instead of absolute\n * close changes for the magnitude, EMA-smoothed per TradingView's\n * `ta.rvi` reference. Composes `ta.ema` via two sub-slots\n * (`${slotId}/upEma`, `${slotId}/downEma`) — a fix to EMA's\n * recurrence flows in for free. NaN when either EMA arm is NaN or\n * when both arms are zero (zero-denominator).\n *\n * @formula sigma[t] = stddev(source[t − length + 1..= t]) ;\n * upRaw[t] = source[t] > source[t − 1] ? sigma[t] : 0 ;\n * downRaw[t] = source[t] < source[t − 1] ? sigma[t] : 0 ;\n * upEma = EMA(length)(upRaw) ;\n * downEma = EMA(length)(downRaw) ;\n * rvi[t] = 100 · upEma[t] / (upEma[t] + downEma[t])\n * @warmup 2 · length − 1\n * @since 0.2\n * @stable\n *\n * `opts.offset` shifts the returned series so `series.current` reads\n * the value `offset` bars ago.\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-core\";\n * // const r = ta.rvi(bar.close, 10);\n * // plot(r);\n */\nexport function rvi(\n slotId: string,\n source: ScalarOrSeries,\n length: number,\n opts?: RviOpts,\n): Series<number> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as RviSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(length, ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const src = readSourceValue(source);\n if (ctx.isTick) {\n const sigma = tickSigma(slot, src);\n const diff = src - slot.prevSrc;\n const { up, down } = classify(sigma, diff);\n // Still drive the sub-slot EMAs so their tick-mode head stays\n // consistent with the closed state on a subsequent close.\n const upSeries = ema(`${slotId}/upEma`, up, slot.length);\n const downSeries = ema(`${slotId}/downEma`, down, slot.length);\n // NaN source short-circuits to NaN output regardless of how the\n // EMA arms forward-fill internally — RVI is undefined when the\n // current sample isn't measurable.\n const value = Number.isFinite(src)\n ? rviValue(upSeries.current, downSeries.current)\n : Number.NaN;\n slot.outBuffer.replaceHead(value);\n } else {\n const sigma = appendToSigmaWindow(slot, src);\n const diff = src - slot.prevSrc;\n const { up, down } = classify(sigma, diff);\n const upSeries = ema(`${slotId}/upEma`, up, slot.length);\n const downSeries = ema(`${slotId}/downEma`, down, slot.length);\n const value = Number.isFinite(src)\n ? rviValue(upSeries.current, downSeries.current)\n : Number.NaN;\n slot.outBuffer.append(value);\n slot.prevSrc = src;\n }\n return viewForOffset(slot, opts?.offset ?? 0);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"rvi.js","sourceRoot":"","sources":["../../src/ta/rvi.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n//\n// Ported from invinite/src/components/trading-chart/indicators/rvi.ts\n// (commit 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite).\n// Re-licensed MIT for chartlang. The math is the reference, the code\n// style is not.\n// Structural choices (callsite-id slot, Series<T> proxy, replaceHead\n// mode) follow chartlang's primitive shape — NOT invinite's\n// IndicatorPlugin shape. The up/down EMA arms compose `ta.ema` via\n// sub-slots `${slotId}/upEma` / `${slotId}/downEma` so the EMA\n// recurrence + warmup semantics flow in by reference.\n\nimport type { RviOpts, Series } from \"@invinite-org/chartlang-core\";\n\nimport { Float64RingBuffer } from \"../ringBuffer.js\";\nimport { ACTIVE_RUNTIME_CONTEXT, type RuntimeContext } from \"../runtimeContext.js\";\nimport { makeSeriesView, makeShiftedSeriesView } from \"../seriesView.js\";\nimport { ema } from \"./ema.js\";\nimport { type ScalarOrSeries, readSourceValue } from \"./lib/sourceValue.js\";\n\ntype RviSlot = {\n readonly outBuffer: Float64RingBuffer;\n readonly series: Series<number>;\n readonly length: number;\n readonly sigmaWindow: Float64RingBuffer;\n sumX: number;\n sumX2: number;\n /** Last closed source value (basis of next bar's up/down classification). */\n prevSrc: number;\n /** Per-offset Series-view cache; see `sma.ts` for the convention. */\n readonly shiftedViews: Map<number, Series<number>>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.rvi called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(length: number, capacity: number): RviSlot {\n const outBuffer = new Float64RingBuffer(capacity);\n return {\n outBuffer,\n series: makeSeriesView<number>(outBuffer),\n length,\n sigmaWindow: new Float64RingBuffer(length),\n sumX: 0,\n sumX2: 0,\n prevSrc: Number.NaN,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: RviSlot, offset: number): Series<number> {\n if (offset === 0) return slot.series;\n let view = slot.shiftedViews.get(offset);\n if (view === undefined) {\n view = makeShiftedSeriesView<number>(slot.outBuffer, offset);\n slot.shiftedViews.set(offset, view);\n }\n return view;\n}\n\nfunction windowStdDev(n: number, sumX: number, sumX2: number): number {\n const mean = sumX / n;\n const variance = sumX2 / n - mean * mean;\n return Math.sqrt(Math.max(0, variance));\n}\n\n/** Fold a new source value into the sigma-window running sums. */\nfunction appendToSigmaWindow(slot: RviSlot, src: number): number {\n if (slot.sigmaWindow.length < slot.sigmaWindow.capacity) {\n slot.sigmaWindow.append(src);\n if (Number.isFinite(src)) {\n slot.sumX += src;\n slot.sumX2 += src * src;\n } else {\n slot.sumX = Number.NaN;\n slot.sumX2 = Number.NaN;\n }\n if (slot.sigmaWindow.length < slot.sigmaWindow.capacity) return Number.NaN;\n if (!Number.isFinite(slot.sumX)) return Number.NaN;\n return windowStdDev(slot.sigmaWindow.length, slot.sumX, slot.sumX2);\n }\n const outgoing = slot.sigmaWindow.at(slot.sigmaWindow.length - 1);\n slot.sigmaWindow.append(src);\n if (!Number.isFinite(src)) {\n slot.sumX = Number.NaN;\n slot.sumX2 = Number.NaN;\n return Number.NaN;\n }\n if (!Number.isFinite(slot.sumX) || !Number.isFinite(outgoing)) {\n // A previous NaN poisoned the running sums; rebuild from the\n // live window (NaN values short-circuit the result to NaN).\n let sumX = 0;\n let sumX2 = 0;\n for (let i = 0; i < slot.sigmaWindow.length; i += 1) {\n const v = slot.sigmaWindow.at(i);\n if (!Number.isFinite(v)) {\n slot.sumX = Number.NaN;\n slot.sumX2 = Number.NaN;\n return Number.NaN;\n }\n sumX += v;\n sumX2 += v * v;\n }\n slot.sumX = sumX;\n slot.sumX2 = sumX2;\n } else {\n slot.sumX = slot.sumX - outgoing + src;\n slot.sumX2 = slot.sumX2 - outgoing * outgoing + src * src;\n }\n return windowStdDev(slot.sigmaWindow.length, slot.sumX, slot.sumX2);\n}\n\n/** Sigma at the tick boundary against the closed sigma-window state. */\nfunction tickSigma(slot: RviSlot, src: number): number {\n if (slot.sigmaWindow.length < slot.sigmaWindow.capacity) return Number.NaN;\n if (!Number.isFinite(src)) return Number.NaN;\n const oldestInHead = slot.sigmaWindow.at(0);\n const sumX = slot.sumX - oldestInHead + src;\n const sumX2 = slot.sumX2 - oldestInHead * oldestInHead + src * src;\n return windowStdDev(slot.sigmaWindow.length, sumX, sumX2);\n}\n\nfunction classify(sigma: number, diff: number): { up: number; down: number } {\n if (!Number.isFinite(sigma) || !Number.isFinite(diff)) {\n return { up: Number.NaN, down: Number.NaN };\n }\n return {\n up: diff > 0 ? sigma : 0,\n down: diff < 0 ? sigma : 0,\n };\n}\n\nfunction rviValue(upEma: number, downEma: number): number {\n if (!Number.isFinite(upEma) || !Number.isFinite(downEma)) return Number.NaN;\n const total = upEma + downEma;\n if (total === 0) return Number.NaN;\n return (100 * upEma) / total;\n}\n\n/**\n * Relative Volatility Index — sub-pane oscillator bounded `[0, 100]`.\n * Like RSI but uses rolling stddev of the source instead of absolute\n * close changes for the magnitude, EMA-smoothed per TradingView's\n * `ta.rvi` reference. Composes `ta.ema` via two sub-slots\n * (`${slotId}/upEma`, `${slotId}/downEma`) — a fix to EMA's\n * recurrence flows in for free. NaN when either EMA arm is NaN or\n * when both arms are zero (zero-denominator).\n *\n * @formula sigma[t] = stddev(source[t − length + 1..= t]) ;\n * upRaw[t] = source[t] > source[t − 1] ? sigma[t] : 0 ;\n * downRaw[t] = source[t] < source[t − 1] ? sigma[t] : 0 ;\n * upEma = EMA(length)(upRaw) ;\n * downEma = EMA(length)(downRaw) ;\n * rvi[t] = 100 · upEma[t] / (upEma[t] + downEma[t])\n * @warmup 2 · length − 1\n * @since 0.2\n * @stable\n *\n * `opts.offset` is a presentation display shift carried to the plot\n * emission as `xShift` (`+n` right / future, `−n` left / past); the\n * series value is unshifted.\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-core\";\n * // const r = ta.rvi(bar.close, 10);\n * // plot(r);\n */\nexport function rvi(\n slotId: string,\n source: ScalarOrSeries,\n length: number,\n opts?: RviOpts,\n): Series<number> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as RviSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(length, ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const src = readSourceValue(source);\n if (ctx.isTick) {\n const sigma = tickSigma(slot, src);\n const diff = src - slot.prevSrc;\n const { up, down } = classify(sigma, diff);\n // Still drive the sub-slot EMAs so their tick-mode head stays\n // consistent with the closed state on a subsequent close.\n const upSeries = ema(`${slotId}/upEma`, up, slot.length);\n const downSeries = ema(`${slotId}/downEma`, down, slot.length);\n // NaN source short-circuits to NaN output regardless of how the\n // EMA arms forward-fill internally — RVI is undefined when the\n // current sample isn't measurable.\n const value = Number.isFinite(src)\n ? rviValue(upSeries.current, downSeries.current)\n : Number.NaN;\n slot.outBuffer.replaceHead(value);\n } else {\n const sigma = appendToSigmaWindow(slot, src);\n const diff = src - slot.prevSrc;\n const { up, down } = classify(sigma, diff);\n const upSeries = ema(`${slotId}/upEma`, up, slot.length);\n const downSeries = ema(`${slotId}/downEma`, down, slot.length);\n const value = Number.isFinite(src)\n ? rviValue(upSeries.current, downSeries.current)\n : Number.NaN;\n slot.outBuffer.append(value);\n slot.prevSrc = src;\n }\n return viewForOffset(slot, opts?.offset ?? 0);\n}\n"]}
|
package/dist/ta/sma.d.ts
CHANGED
|
@@ -5,8 +5,11 @@ import { type ScalarOrSeries } from "./lib/sourceValue.js";
|
|
|
5
5
|
* values. Warmup of `length − 1` bars returns `NaN`. Tick-mode replays
|
|
6
6
|
* the head as `(window_sum − window_head + tick_value) / length` so a
|
|
7
7
|
* partial-bar tick doesn't pollute the next close's running sum.
|
|
8
|
-
* `opts.offset`
|
|
9
|
-
* the
|
|
8
|
+
* `opts.offset` is a presentation display shift carried to the plot
|
|
9
|
+
* emission as `xShift` (`+n` renders the series `n` bars right / future,
|
|
10
|
+
* `−n` `n` bars left / past); it does NOT transform the value —
|
|
11
|
+
* `series.current` is unshifted, so alerts and `state.*` see the value
|
|
12
|
+
* computed at the current bar.
|
|
10
13
|
*
|
|
11
14
|
* @formula out[t] = (source[t] + source[t − 1] + … + source[t − length + 1]) / length
|
|
12
15
|
* @warmup length − 1
|
|
@@ -17,7 +20,7 @@ import { type ScalarOrSeries } from "./lib/sourceValue.js";
|
|
|
17
20
|
* // import { ta } from "@invinite-org/chartlang-runtime";
|
|
18
21
|
* // const s = ta.sma("slot", bar.close, 20);
|
|
19
22
|
* // const head = s.current; // NaN until bar length-1
|
|
20
|
-
* // const
|
|
23
|
+
* // const shifted = ta.sma("slot2", bar.close, 20, { offset: 5 }); // renders 5 bars right
|
|
21
24
|
*/
|
|
22
25
|
export declare function sma(slotId: string, source: ScalarOrSeries, length: number, opts?: SmaOpts): Series<number>;
|
|
23
26
|
//# sourceMappingURL=sma.d.ts.map
|
package/dist/ta/sma.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sma.d.ts","sourceRoot":"","sources":["../../src/ta/sma.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AAKpE,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AAqF5E
|
|
1
|
+
{"version":3,"file":"sma.d.ts","sourceRoot":"","sources":["../../src/ta/sma.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AAKpE,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AAqF5E;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,GAAG,CACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,OAAO,GACf,MAAM,CAAC,MAAM,CAAC,CAchB"}
|
package/dist/ta/sma.js
CHANGED
|
@@ -79,8 +79,11 @@ function closeValue(slot, src) {
|
|
|
79
79
|
* values. Warmup of `length − 1` bars returns `NaN`. Tick-mode replays
|
|
80
80
|
* the head as `(window_sum − window_head + tick_value) / length` so a
|
|
81
81
|
* partial-bar tick doesn't pollute the next close's running sum.
|
|
82
|
-
* `opts.offset`
|
|
83
|
-
* the
|
|
82
|
+
* `opts.offset` is a presentation display shift carried to the plot
|
|
83
|
+
* emission as `xShift` (`+n` renders the series `n` bars right / future,
|
|
84
|
+
* `−n` `n` bars left / past); it does NOT transform the value —
|
|
85
|
+
* `series.current` is unshifted, so alerts and `state.*` see the value
|
|
86
|
+
* computed at the current bar.
|
|
84
87
|
*
|
|
85
88
|
* @formula out[t] = (source[t] + source[t − 1] + … + source[t − length + 1]) / length
|
|
86
89
|
* @warmup length − 1
|
|
@@ -91,7 +94,7 @@ function closeValue(slot, src) {
|
|
|
91
94
|
* // import { ta } from "@invinite-org/chartlang-runtime";
|
|
92
95
|
* // const s = ta.sma("slot", bar.close, 20);
|
|
93
96
|
* // const head = s.current; // NaN until bar length-1
|
|
94
|
-
* // const
|
|
97
|
+
* // const shifted = ta.sma("slot2", bar.close, 20, { offset: 5 }); // renders 5 bars right
|
|
95
98
|
*/
|
|
96
99
|
export function sma(slotId, source, length, opts) {
|
|
97
100
|
const ctx = getCtx();
|
package/dist/ta/sma.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sma.js","sourceRoot":"","sources":["../../src/ta/sma.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"sma.js","sourceRoot":"","sources":["../../src/ta/sma.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n//\n// Ported from invinite/src/components/trading-chart/indicators/sma.ts\n// plus lib/sma-of-float64.ts\n// (commit d2d1043c1b039f66d2f3674526d303d31cf2f1e0, © Invinite).\n// Re-licensed MIT for chartlang. The math is the reference, the code\n// style is not.\n// Structural choices (callsite-id slot, Series<T> proxy, replaceHead\n// mode) follow chartlang's primitive shape — NOT invinite's\n// IndicatorPlugin shape.\n\nimport type { Series, SmaOpts } from \"@invinite-org/chartlang-core\";\n\nimport { Float64RingBuffer } from \"../ringBuffer.js\";\nimport { ACTIVE_RUNTIME_CONTEXT, type RuntimeContext } from \"../runtimeContext.js\";\nimport { makeSeriesView, makeShiftedSeriesView } from \"../seriesView.js\";\nimport { type ScalarOrSeries, readSourceValue } from \"./lib/sourceValue.js\";\n\ntype SmaSlot = {\n readonly kind: \"ta.sma\";\n readonly outBuffer: Float64RingBuffer;\n readonly series: Series<number>;\n readonly length: number;\n /**\n * Window of the **closed** source values across the last `length` bars.\n * Holds bars `[t-length+1 .. t]` for the latest closed bar t. Ticks\n * compute a hypothetical \"head replaced\" mean from `windowSum -\n * window.at(0) + tickValue`; closes pop the oldest and push the new.\n */\n readonly window: Float64RingBuffer;\n sum: number;\n /**\n * Lazy cache of offset-shifted Series views keyed by `opts.offset`.\n * `offset === 0` callers bypass this map and return `series`\n * directly — identity-preserving. Populated on first call per\n * non-zero offset; identity is stable per offset thereafter.\n */\n readonly shiftedViews: Map<number, Series<number>>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.sma called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(length: number, capacity: number): SmaSlot {\n const outBuffer = new Float64RingBuffer(capacity);\n return {\n kind: \"ta.sma\",\n outBuffer,\n series: makeSeriesView<number>(outBuffer),\n length,\n window: new Float64RingBuffer(length),\n sum: 0,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: SmaSlot, offset: number): Series<number> {\n if (offset === 0) return slot.series;\n let view = slot.shiftedViews.get(offset);\n if (view === undefined) {\n view = makeShiftedSeriesView<number>(slot.outBuffer, offset);\n slot.shiftedViews.set(offset, view);\n }\n return view;\n}\n\nfunction tickValue(slot: SmaSlot, src: number): number {\n // `window` currently holds the close-side values `[t-length+1 .. t]` for\n // the most-recent closed bar. The tick replaces bar `t`'s value with\n // `src`, so the hypothetical mean is `(sum - window.at(0)) + src`.\n if (!Number.isFinite(src)) return Number.NaN;\n if (slot.window.length < slot.length) return Number.NaN;\n const oldestInHead = slot.window.at(0);\n return (slot.sum - oldestInHead + src) / slot.length;\n}\n\nfunction closeValue(slot: SmaSlot, src: number): number {\n if (!Number.isFinite(src)) {\n // Skip the window update; emit the prior closed mean (or NaN when\n // unwarmed). The window's contents are unchanged so future closes\n // continue against the last valid set.\n if (slot.window.length < slot.length) return Number.NaN;\n return slot.sum / slot.length;\n }\n if (slot.window.length < slot.length) {\n slot.window.append(src);\n slot.sum += src;\n if (slot.window.length < slot.length) return Number.NaN;\n return slot.sum / slot.length;\n }\n const outgoing = slot.window.at(slot.length - 1);\n slot.window.append(src);\n slot.sum = slot.sum + src - outgoing;\n return slot.sum / slot.length;\n}\n\n/**\n * Simple moving average — rolling mean of the last `length` source\n * values. Warmup of `length − 1` bars returns `NaN`. Tick-mode replays\n * the head as `(window_sum − window_head + tick_value) / length` so a\n * partial-bar tick doesn't pollute the next close's running sum.\n * `opts.offset` is a presentation display shift carried to the plot\n * emission as `xShift` (`+n` renders the series `n` bars right / future,\n * `−n` `n` bars left / past); it does NOT transform the value —\n * `series.current` is unshifted, so alerts and `state.*` see the value\n * computed at the current bar.\n *\n * @formula out[t] = (source[t] + source[t − 1] + … + source[t − length + 1]) / length\n * @warmup length − 1\n * @since 0.1\n * @stable\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-runtime\";\n * // const s = ta.sma(\"slot\", bar.close, 20);\n * // const head = s.current; // NaN until bar length-1\n * // const shifted = ta.sma(\"slot2\", bar.close, 20, { offset: 5 }); // renders 5 bars right\n */\nexport function sma(\n slotId: string,\n source: ScalarOrSeries,\n length: number,\n opts?: SmaOpts,\n): Series<number> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as SmaSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(length, ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const src = readSourceValue(source);\n if (ctx.isTick) {\n slot.outBuffer.replaceHead(tickValue(slot, src));\n } else {\n slot.outBuffer.append(closeValue(slot, src));\n }\n return viewForOffset(slot, opts?.offset ?? 0);\n}\n"]}
|
package/dist/ta/stdev.d.ts
CHANGED
|
@@ -12,8 +12,9 @@ import { type ScalarOrSeries } from "./lib/sourceValue.js";
|
|
|
12
12
|
* @since 0.1
|
|
13
13
|
* @stable
|
|
14
14
|
*
|
|
15
|
-
* `opts.offset`
|
|
16
|
-
*
|
|
15
|
+
* `opts.offset` is a presentation display shift carried to the plot
|
|
16
|
+
* emission as `xShift` (`+n` right / future, `−n` left / past); the
|
|
17
|
+
* series value is unshifted.
|
|
17
18
|
*
|
|
18
19
|
* @example
|
|
19
20
|
* // import { ta } from "@invinite-org/chartlang-runtime";
|
package/dist/ta/stdev.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdev.d.ts","sourceRoot":"","sources":["../../src/ta/stdev.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAKtE,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AAuF5E
|
|
1
|
+
{"version":3,"file":"stdev.d.ts","sourceRoot":"","sources":["../../src/ta/stdev.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAKtE,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AAuF5E;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,KAAK,CACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,SAAS,GACjB,MAAM,CAAC,MAAM,CAAC,CAehB"}
|
package/dist/ta/stdev.js
CHANGED
|
@@ -96,8 +96,9 @@ function tickValue(slot, src) {
|
|
|
96
96
|
* @since 0.1
|
|
97
97
|
* @stable
|
|
98
98
|
*
|
|
99
|
-
* `opts.offset`
|
|
100
|
-
*
|
|
99
|
+
* `opts.offset` is a presentation display shift carried to the plot
|
|
100
|
+
* emission as `xShift` (`+n` right / future, `−n` left / past); the
|
|
101
|
+
* series value is unshifted.
|
|
101
102
|
*
|
|
102
103
|
* @example
|
|
103
104
|
* // import { ta } from "@invinite-org/chartlang-runtime";
|
package/dist/ta/stdev.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdev.js","sourceRoot":"","sources":["../../src/ta/stdev.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"stdev.js","sourceRoot":"","sources":["../../src/ta/stdev.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n//\n// Ported from invinite/src/components/trading-chart/indicators/lib/rolling-stddev.ts\n// (commit d2d1043c1b039f66d2f3674526d303d31cf2f1e0, © Invinite).\n// Re-licensed MIT for chartlang. The math is the reference, the code\n// style is not.\n// Structural choices (callsite-id slot, Series<T> proxy, replaceHead\n// mode) follow chartlang's primitive shape — NOT invinite's\n// IndicatorPlugin shape.\n\nimport type { Series, StdevOpts } from \"@invinite-org/chartlang-core\";\n\nimport { Float64RingBuffer } from \"../ringBuffer.js\";\nimport { ACTIVE_RUNTIME_CONTEXT, type RuntimeContext } from \"../runtimeContext.js\";\nimport { makeSeriesView, makeShiftedSeriesView } from \"../seriesView.js\";\nimport { type ScalarOrSeries, readSourceValue } from \"./lib/sourceValue.js\";\n\ntype StdevSlot = {\n readonly outBuffer: Float64RingBuffer;\n readonly series: Series<number>;\n readonly length: number;\n readonly biased: boolean;\n readonly window: Float64RingBuffer;\n sumX: number;\n sumX2: number;\n /** Per-offset Series-view cache; see `sma.ts` for the convention. */\n readonly shiftedViews: Map<number, Series<number>>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.stdev called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(length: number, capacity: number, biased: boolean): StdevSlot {\n const outBuffer = new Float64RingBuffer(capacity);\n return {\n outBuffer,\n series: makeSeriesView<number>(outBuffer),\n length,\n biased,\n window: new Float64RingBuffer(length),\n sumX: 0,\n sumX2: 0,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: StdevSlot, offset: number): Series<number> {\n if (offset === 0) return slot.series;\n let view = slot.shiftedViews.get(offset);\n if (view === undefined) {\n view = makeShiftedSeriesView<number>(slot.outBuffer, offset);\n slot.shiftedViews.set(offset, view);\n }\n return view;\n}\n\nfunction denominator(slot: StdevSlot): number {\n return slot.biased ? slot.length : slot.length - 1;\n}\n\nfunction stddevFromSums(sumX: number, sumX2: number, slot: StdevSlot): number {\n const denom = denominator(slot);\n if (denom <= 0) return Number.NaN;\n const mean = sumX / slot.length;\n const variance = (sumX2 - slot.length * mean * mean) / denom;\n // Numerical: clamp tiny negatives from accumulated rounding error.\n return Math.sqrt(Math.max(0, variance));\n}\n\nfunction closeValue(slot: StdevSlot, src: number): number {\n if (!Number.isFinite(src)) {\n if (slot.window.length < slot.length) return Number.NaN;\n return stddevFromSums(slot.sumX, slot.sumX2, slot);\n }\n if (slot.window.length < slot.length) {\n slot.window.append(src);\n slot.sumX += src;\n slot.sumX2 += src * src;\n if (slot.window.length < slot.length) return Number.NaN;\n return stddevFromSums(slot.sumX, slot.sumX2, slot);\n }\n const outgoing = slot.window.at(slot.length - 1);\n slot.window.append(src);\n slot.sumX = slot.sumX + src - outgoing;\n slot.sumX2 = slot.sumX2 + src * src - outgoing * outgoing;\n return stddevFromSums(slot.sumX, slot.sumX2, slot);\n}\n\nfunction tickValue(slot: StdevSlot, src: number): number {\n if (!Number.isFinite(src)) return Number.NaN;\n if (slot.window.length < slot.length) return Number.NaN;\n const oldestInHead = slot.window.at(0);\n const sumX = slot.sumX - oldestInHead + src;\n const sumX2 = slot.sumX2 - oldestInHead * oldestInHead + src * src;\n return stddevFromSums(sumX, sumX2, slot);\n}\n\n/**\n * Rolling sample / population standard deviation over the last\n * `length` source values. Defaults to **biased = false** (sample\n * stddev, denominator `length − 1`) to match core's `StdevOpts`.\n * `biased = true` switches to population (denominator `length`).\n *\n * @formula μ = mean(window) ;\n * σ = sqrt(Σ(x − μ)² / N), N = length (biased) or length − 1 (sample)\n * @warmup length − 1\n * @since 0.1\n * @stable\n *\n * `opts.offset` is a presentation display shift carried to the plot\n * emission as `xShift` (`+n` right / future, `−n` left / past); the\n * series value is unshifted.\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-runtime\";\n * // const s = ta.stdev(\"slot\", bar.close, 20, { biased: false });\n * // const head = s.current;\n * // const lagged = ta.stdev(\"slot2\", bar.close, 20, { offset: 5 });\n */\nexport function stdev(\n slotId: string,\n source: ScalarOrSeries,\n length: number,\n opts?: StdevOpts,\n): Series<number> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as StdevSlot | undefined;\n if (slot === undefined) {\n const biased = opts?.biased === true;\n slot = initSlot(length, ctx.stream.ohlcv.close.capacity, biased);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const src = readSourceValue(source);\n if (ctx.isTick) {\n slot.outBuffer.replaceHead(tickValue(slot, src));\n } else {\n slot.outBuffer.append(closeValue(slot, src));\n }\n return viewForOffset(slot, opts?.offset ?? 0);\n}\n"]}
|
|
@@ -23,8 +23,9 @@ import { type ScalarOrSeries } from "./lib/sourceValue.js";
|
|
|
23
23
|
* @since 0.2
|
|
24
24
|
* @stable
|
|
25
25
|
*
|
|
26
|
-
* `opts.offset`
|
|
27
|
-
*
|
|
26
|
+
* `opts.offset` is a presentation display shift carried to the plot
|
|
27
|
+
* emission as `xShift` (`+n` right / future, `−n` left / past); the
|
|
28
|
+
* series value is unshifted.
|
|
28
29
|
*
|
|
29
30
|
* @example
|
|
30
31
|
* // import { ta } from "@invinite-org/chartlang-runtime";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trendStrengthIndex.d.ts","sourceRoot":"","sources":["../../src/ta/trendStrengthIndex.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAKnF,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AAyI5E
|
|
1
|
+
{"version":3,"file":"trendStrengthIndex.d.ts","sourceRoot":"","sources":["../../src/ta/trendStrengthIndex.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAKnF,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AAyI5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,kBAAkB,CAC9B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,sBAAsB,GAC9B,MAAM,CAAC,MAAM,CAAC,CAchB"}
|
|
@@ -156,8 +156,9 @@ function tickStep(slot, src) {
|
|
|
156
156
|
* @since 0.2
|
|
157
157
|
* @stable
|
|
158
158
|
*
|
|
159
|
-
* `opts.offset`
|
|
160
|
-
*
|
|
159
|
+
* `opts.offset` is a presentation display shift carried to the plot
|
|
160
|
+
* emission as `xShift` (`+n` right / future, `−n` left / past); the
|
|
161
|
+
* series value is unshifted.
|
|
161
162
|
*
|
|
162
163
|
* @example
|
|
163
164
|
* // import { ta } from "@invinite-org/chartlang-runtime";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trendStrengthIndex.js","sourceRoot":"","sources":["../../src/ta/trendStrengthIndex.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n//\n// Ported from invinite/src/components/trading-chart/indicators/trend-strength-index.ts\n// (commit 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite).\n// Re-licensed MIT for chartlang. The math is the reference, the code\n// style is not.\n// Structural choices (callsite-id slot, Series<T> proxy, replaceHead\n// mode) follow chartlang's primitive shape — NOT invinite's\n// IndicatorPlugin shape. Named `trendStrengthIndex` to disambiguate\n// from the existing `ta.tsi` (Task 14 momentum True Strength Index).\n// The math is TradingView's documented Pearson-of-price-vs-bar-index\n// formulation — `lib/pearson.ts` (Task 4) is the reference helper.\n\nimport type { Series, TrendStrengthIndexOpts } from \"@invinite-org/chartlang-core\";\n\nimport { Float64RingBuffer } from \"../ringBuffer.js\";\nimport { ACTIVE_RUNTIME_CONTEXT, type RuntimeContext } from \"../runtimeContext.js\";\nimport { makeSeriesView, makeShiftedSeriesView } from \"../seriesView.js\";\nimport { type ScalarOrSeries, readSourceValue } from \"./lib/sourceValue.js\";\n\ntype TrendStrengthIndexSlot = {\n readonly outBuffer: Float64RingBuffer;\n readonly series: Series<number>;\n readonly length: number;\n /** Rolling window of recent source values, most-recent first\n * (`at(0)` = head, `at(length - 1)` = oldest). */\n readonly sourceWindow: Float64RingBuffer;\n /** Number of CLOSED bars folded into the slot so far. */\n barCount: number;\n /** Number of NaN values currently in the window — when > 0 the\n * Pearson denominator is undefined and the primitive emits NaN. */\n nanCount: number;\n /** The source value evicted on the current close (the tail value\n * popped when the window was full at append time). Used by tick\n * replay to restore the window to its pre-close state. */\n evictedSource: number;\n /** `nanCount` AS OF THE PRIOR CLOSE — restored by tick replay\n * before substituting the tick's contribution. */\n prevClosedNanCount: number;\n readonly shiftedViews: Map<number, Series<number>>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.trendStrengthIndex called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(length: number, capacity: number): TrendStrengthIndexSlot {\n const outBuffer = new Float64RingBuffer(capacity);\n return {\n outBuffer,\n series: makeSeriesView<number>(outBuffer),\n length,\n sourceWindow: new Float64RingBuffer(length),\n barCount: 0,\n nanCount: 0,\n evictedSource: Number.NaN,\n prevClosedNanCount: 0,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: TrendStrengthIndexSlot, offset: number): Series<number> {\n if (offset === 0) return slot.series;\n let view = slot.shiftedViews.get(offset);\n if (view === undefined) {\n view = makeShiftedSeriesView<number>(slot.outBuffer, offset);\n slot.shiftedViews.set(offset, view);\n }\n return view;\n}\n\n/**\n * Compute Pearson correlation between the trailing source window and a\n * matching length-`n` linear bar-index series `[0, 1, ..., n-1]`.\n * Mirrors `lib/pearson.ts`'s two-pass mean/covariance formulation\n * exactly (sum then mean, then per-slot deviations) so the property\n * test's full-recompute reference and the incremental head agree\n * within Float64 noise. Returns NaN if any slot is non-finite or the\n * source-side window variance is exactly zero.\n */\nfunction pearsonHead(window: Float64RingBuffer, length: number, headSource: number): number {\n let sumX = 0;\n let sumY = 0;\n for (let k = 0; k < length; k += 1) {\n const x = k === length - 1 ? headSource : window.at(length - 1 - k);\n // Defensive: callers gate on `nanCount === 0` so every window\n // slot is finite when we get here; the `headSource` is also\n // guarded upstream.\n /* c8 ignore next */\n if (!Number.isFinite(x)) return Number.NaN;\n sumX += x;\n sumY += k;\n }\n const meanX = sumX / length;\n const meanY = sumY / length;\n let sumXY = 0;\n let sumXX = 0;\n let sumYY = 0;\n for (let k = 0; k < length; k += 1) {\n const x = k === length - 1 ? headSource : window.at(length - 1 - k);\n const dX = x - meanX;\n const dY = k - meanY;\n sumXY += dX * dY;\n sumXX += dX * dX;\n sumYY += dY * dY;\n }\n if (sumXX === 0 || sumYY === 0) return Number.NaN;\n const r = sumXY / Math.sqrt(sumXX * sumYY);\n if (r < -1) return -1;\n if (r > 1) return 1;\n return r;\n}\n\nfunction closeStep(slot: TrendStrengthIndexSlot, src: number): number {\n slot.prevClosedNanCount = slot.nanCount;\n\n // Update the rolling window. If the window is full, the tail\n // (oldest) value is about to be evicted by `append` — capture it\n // and adjust the NaN count.\n if (slot.sourceWindow.length >= slot.length) {\n slot.evictedSource = slot.sourceWindow.at(slot.length - 1);\n if (Number.isNaN(slot.evictedSource)) slot.nanCount -= 1;\n } else {\n slot.evictedSource = Number.NaN;\n }\n slot.sourceWindow.append(src);\n if (!Number.isFinite(src)) slot.nanCount += 1;\n\n slot.barCount += 1;\n\n if (slot.barCount < slot.length) return Number.NaN;\n if (slot.nanCount > 0) return Number.NaN;\n return pearsonHead(slot.sourceWindow, slot.length, src);\n}\n\nfunction tickStep(slot: TrendStrengthIndexSlot, src: number): number {\n if (slot.barCount < slot.length) return Number.NaN;\n // Re-derive NaN count: start from the prior closed count,\n // un-account for the value evicted by the current close, and\n // account for the tick's substituted value at age 0.\n let nanCount = slot.prevClosedNanCount;\n // Defensive: `evictedSource` is only NaN when the close-side advance\n // evicted a NaN, requiring an earlier NaN bar in the stream that\n // we then tick on. Reachable but rare.\n /* c8 ignore next */\n if (Number.isNaN(slot.evictedSource)) nanCount -= 1;\n if (!Number.isFinite(src)) nanCount += 1;\n if (nanCount > 0) return Number.NaN;\n return pearsonHead(slot.sourceWindow, slot.length, src);\n}\n\n/**\n * Trend Strength Index — Pearson correlation between `source` and the\n * bar index over each trailing `length`-bar window. Bounded `[-1, +1]`:\n * `+1` = clean uptrend (price rises monotonically with bar index), `−1`\n * = clean downtrend, `0` = no linear trend. Distinct from\n * `ta.tsi` (the True Strength Index — a momentum oscillator).\n * The math is TradingView's documented Trend Strength Index\n * (https://www.tradingview.com/support/solutions/43000730926-trend-strength-index/).\n *\n * Default `length = 20` per chartlang task spec (invinite plugin\n * default is `14`).\n *\n * @formula meanX = Σx / n ; meanY = Σy / n ; n = length ;\n * num = Σ((x − meanX)(y − meanY)) ;\n * den = sqrt(Σ(x − meanX)² · Σ(y − meanY)²) ;\n * tsi = clamp(num / den, −1, +1) ;\n * NaN if the source window has zero variance, the index\n * variance is zero (`length < 2`), or any window slot is\n * non-finite.\n * @warmup length − 1\n * @since 0.2\n * @stable\n *\n * `opts.offset` shifts the returned series so `series.current` reads\n * the value `offset` bars ago.\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-runtime\";\n * // const t = ta.trendStrengthIndex(\"slot\", bar.close, 20);\n * // plot(t);\n */\nexport function trendStrengthIndex(\n slotId: string,\n source: ScalarOrSeries,\n length: number,\n opts?: TrendStrengthIndexOpts,\n): Series<number> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as TrendStrengthIndexSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(length, ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const src = readSourceValue(source);\n if (ctx.isTick) {\n slot.outBuffer.replaceHead(tickStep(slot, src));\n } else {\n slot.outBuffer.append(closeStep(slot, src));\n }\n return viewForOffset(slot, opts?.offset ?? 0);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"trendStrengthIndex.js","sourceRoot":"","sources":["../../src/ta/trendStrengthIndex.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n//\n// Ported from invinite/src/components/trading-chart/indicators/trend-strength-index.ts\n// (commit 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite).\n// Re-licensed MIT for chartlang. The math is the reference, the code\n// style is not.\n// Structural choices (callsite-id slot, Series<T> proxy, replaceHead\n// mode) follow chartlang's primitive shape — NOT invinite's\n// IndicatorPlugin shape. Named `trendStrengthIndex` to disambiguate\n// from the existing `ta.tsi` (Task 14 momentum True Strength Index).\n// The math is TradingView's documented Pearson-of-price-vs-bar-index\n// formulation — `lib/pearson.ts` (Task 4) is the reference helper.\n\nimport type { Series, TrendStrengthIndexOpts } from \"@invinite-org/chartlang-core\";\n\nimport { Float64RingBuffer } from \"../ringBuffer.js\";\nimport { ACTIVE_RUNTIME_CONTEXT, type RuntimeContext } from \"../runtimeContext.js\";\nimport { makeSeriesView, makeShiftedSeriesView } from \"../seriesView.js\";\nimport { type ScalarOrSeries, readSourceValue } from \"./lib/sourceValue.js\";\n\ntype TrendStrengthIndexSlot = {\n readonly outBuffer: Float64RingBuffer;\n readonly series: Series<number>;\n readonly length: number;\n /** Rolling window of recent source values, most-recent first\n * (`at(0)` = head, `at(length - 1)` = oldest). */\n readonly sourceWindow: Float64RingBuffer;\n /** Number of CLOSED bars folded into the slot so far. */\n barCount: number;\n /** Number of NaN values currently in the window — when > 0 the\n * Pearson denominator is undefined and the primitive emits NaN. */\n nanCount: number;\n /** The source value evicted on the current close (the tail value\n * popped when the window was full at append time). Used by tick\n * replay to restore the window to its pre-close state. */\n evictedSource: number;\n /** `nanCount` AS OF THE PRIOR CLOSE — restored by tick replay\n * before substituting the tick's contribution. */\n prevClosedNanCount: number;\n readonly shiftedViews: Map<number, Series<number>>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.trendStrengthIndex called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(length: number, capacity: number): TrendStrengthIndexSlot {\n const outBuffer = new Float64RingBuffer(capacity);\n return {\n outBuffer,\n series: makeSeriesView<number>(outBuffer),\n length,\n sourceWindow: new Float64RingBuffer(length),\n barCount: 0,\n nanCount: 0,\n evictedSource: Number.NaN,\n prevClosedNanCount: 0,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: TrendStrengthIndexSlot, offset: number): Series<number> {\n if (offset === 0) return slot.series;\n let view = slot.shiftedViews.get(offset);\n if (view === undefined) {\n view = makeShiftedSeriesView<number>(slot.outBuffer, offset);\n slot.shiftedViews.set(offset, view);\n }\n return view;\n}\n\n/**\n * Compute Pearson correlation between the trailing source window and a\n * matching length-`n` linear bar-index series `[0, 1, ..., n-1]`.\n * Mirrors `lib/pearson.ts`'s two-pass mean/covariance formulation\n * exactly (sum then mean, then per-slot deviations) so the property\n * test's full-recompute reference and the incremental head agree\n * within Float64 noise. Returns NaN if any slot is non-finite or the\n * source-side window variance is exactly zero.\n */\nfunction pearsonHead(window: Float64RingBuffer, length: number, headSource: number): number {\n let sumX = 0;\n let sumY = 0;\n for (let k = 0; k < length; k += 1) {\n const x = k === length - 1 ? headSource : window.at(length - 1 - k);\n // Defensive: callers gate on `nanCount === 0` so every window\n // slot is finite when we get here; the `headSource` is also\n // guarded upstream.\n /* c8 ignore next */\n if (!Number.isFinite(x)) return Number.NaN;\n sumX += x;\n sumY += k;\n }\n const meanX = sumX / length;\n const meanY = sumY / length;\n let sumXY = 0;\n let sumXX = 0;\n let sumYY = 0;\n for (let k = 0; k < length; k += 1) {\n const x = k === length - 1 ? headSource : window.at(length - 1 - k);\n const dX = x - meanX;\n const dY = k - meanY;\n sumXY += dX * dY;\n sumXX += dX * dX;\n sumYY += dY * dY;\n }\n if (sumXX === 0 || sumYY === 0) return Number.NaN;\n const r = sumXY / Math.sqrt(sumXX * sumYY);\n if (r < -1) return -1;\n if (r > 1) return 1;\n return r;\n}\n\nfunction closeStep(slot: TrendStrengthIndexSlot, src: number): number {\n slot.prevClosedNanCount = slot.nanCount;\n\n // Update the rolling window. If the window is full, the tail\n // (oldest) value is about to be evicted by `append` — capture it\n // and adjust the NaN count.\n if (slot.sourceWindow.length >= slot.length) {\n slot.evictedSource = slot.sourceWindow.at(slot.length - 1);\n if (Number.isNaN(slot.evictedSource)) slot.nanCount -= 1;\n } else {\n slot.evictedSource = Number.NaN;\n }\n slot.sourceWindow.append(src);\n if (!Number.isFinite(src)) slot.nanCount += 1;\n\n slot.barCount += 1;\n\n if (slot.barCount < slot.length) return Number.NaN;\n if (slot.nanCount > 0) return Number.NaN;\n return pearsonHead(slot.sourceWindow, slot.length, src);\n}\n\nfunction tickStep(slot: TrendStrengthIndexSlot, src: number): number {\n if (slot.barCount < slot.length) return Number.NaN;\n // Re-derive NaN count: start from the prior closed count,\n // un-account for the value evicted by the current close, and\n // account for the tick's substituted value at age 0.\n let nanCount = slot.prevClosedNanCount;\n // Defensive: `evictedSource` is only NaN when the close-side advance\n // evicted a NaN, requiring an earlier NaN bar in the stream that\n // we then tick on. Reachable but rare.\n /* c8 ignore next */\n if (Number.isNaN(slot.evictedSource)) nanCount -= 1;\n if (!Number.isFinite(src)) nanCount += 1;\n if (nanCount > 0) return Number.NaN;\n return pearsonHead(slot.sourceWindow, slot.length, src);\n}\n\n/**\n * Trend Strength Index — Pearson correlation between `source` and the\n * bar index over each trailing `length`-bar window. Bounded `[-1, +1]`:\n * `+1` = clean uptrend (price rises monotonically with bar index), `−1`\n * = clean downtrend, `0` = no linear trend. Distinct from\n * `ta.tsi` (the True Strength Index — a momentum oscillator).\n * The math is TradingView's documented Trend Strength Index\n * (https://www.tradingview.com/support/solutions/43000730926-trend-strength-index/).\n *\n * Default `length = 20` per chartlang task spec (invinite plugin\n * default is `14`).\n *\n * @formula meanX = Σx / n ; meanY = Σy / n ; n = length ;\n * num = Σ((x − meanX)(y − meanY)) ;\n * den = sqrt(Σ(x − meanX)² · Σ(y − meanY)²) ;\n * tsi = clamp(num / den, −1, +1) ;\n * NaN if the source window has zero variance, the index\n * variance is zero (`length < 2`), or any window slot is\n * non-finite.\n * @warmup length − 1\n * @since 0.2\n * @stable\n *\n * `opts.offset` is a presentation display shift carried to the plot\n * emission as `xShift` (`+n` right / future, `−n` left / past); the\n * series value is unshifted.\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-runtime\";\n * // const t = ta.trendStrengthIndex(\"slot\", bar.close, 20);\n * // plot(t);\n */\nexport function trendStrengthIndex(\n slotId: string,\n source: ScalarOrSeries,\n length: number,\n opts?: TrendStrengthIndexOpts,\n): Series<number> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as TrendStrengthIndexSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(length, ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const src = readSourceValue(source);\n if (ctx.isTick) {\n slot.outBuffer.replaceHead(tickStep(slot, src));\n } else {\n slot.outBuffer.append(closeStep(slot, src));\n }\n return viewForOffset(slot, opts?.offset ?? 0);\n}\n"]}
|
package/dist/ta/trix.d.ts
CHANGED
|
@@ -20,9 +20,10 @@ import { type ScalarOrSeries } from "./lib/sourceValue.js";
|
|
|
20
20
|
* @since 0.2
|
|
21
21
|
* @stable
|
|
22
22
|
*
|
|
23
|
-
* `opts.offset`
|
|
24
|
-
* `
|
|
25
|
-
*
|
|
23
|
+
* `opts.offset` is a presentation display shift carried to the plot
|
|
24
|
+
* emission as `xShift` for both outputs in lockstep (`+n` right / future,
|
|
25
|
+
* `−n` left / past); the series values are unshifted, so
|
|
26
|
+
* `series.current` on each output returns the value at the current bar.
|
|
26
27
|
*
|
|
27
28
|
* @example
|
|
28
29
|
* // import { ta } from "@invinite-org/chartlang-runtime";
|
package/dist/ta/trix.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trix.d.ts","sourceRoot":"","sources":["../../src/ta/trix.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAU,QAAQ,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAMjF,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AA0D5E
|
|
1
|
+
{"version":3,"file":"trix.d.ts","sourceRoot":"","sources":["../../src/ta/trix.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAU,QAAQ,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAMjF,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AA0D5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,IAAI,CAChB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,QAAQ,GAChB,UAAU,CAqDZ"}
|
package/dist/ta/trix.js
CHANGED
|
@@ -70,9 +70,10 @@ function resultForOffset(slot, offset, signalBuf) {
|
|
|
70
70
|
* @since 0.2
|
|
71
71
|
* @stable
|
|
72
72
|
*
|
|
73
|
-
* `opts.offset`
|
|
74
|
-
* `
|
|
75
|
-
*
|
|
73
|
+
* `opts.offset` is a presentation display shift carried to the plot
|
|
74
|
+
* emission as `xShift` for both outputs in lockstep (`+n` right / future,
|
|
75
|
+
* `−n` left / past); the series values are unshifted, so
|
|
76
|
+
* `series.current` on each output returns the value at the current bar.
|
|
76
77
|
*
|
|
77
78
|
* @example
|
|
78
79
|
* // import { ta } from "@invinite-org/chartlang-runtime";
|
package/dist/ta/trix.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trix.js","sourceRoot":"","sources":["../../src/ta/trix.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AAC/D,EAAE;AACF,uEAAuE;AACvE,mEAAmE;AACnE,qEAAqE;AACrE,gBAAgB;AAChB,qEAAqE;AACrE,4DAA4D;AAC5D,mEAAmE;AACnE,qEAAqE;AACrE,kEAAkE;AAClE,qEAAqE;AAIrE,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAuB,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAuB,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5E,MAAM,cAAc,GAAG,CAAC,CAAC;AAqBzB,SAAS,MAAM;IACX,MAAM,GAAG,GAAG,sBAAsB,CAAC,OAAO,CAAC;IAC3C,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,QAAgB,EAAE,YAA4B;IAC5D,MAAM,UAAU,GAAG,IAAI,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACnD,OAAO;QACH,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;YAClB,IAAI,EAAE,cAAc,CAAS,UAAU,CAAC;YACxC,MAAM,EAAE,YAAY;SACvB,CAAC;QACF,UAAU;QACV,cAAc,EAAE,MAAM,CAAC,GAAG;QAC1B,kBAAkB,EAAE,MAAM,CAAC,GAAG;QAC9B,cAAc,EAAE,IAAI,GAAG,EAAE;KAC5B,CAAC;AACN,CAAC;AAED,SAAS,eAAe,CAAC,IAAc,EAAE,MAAc,EAAE,SAA4B;IACjF,IAAI,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,MAAM,CAAC;IACrC,IAAI,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;YACnB,IAAI,EAAE,qBAAqB,CAAS,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC;YAC5D,MAAM,EAAE,qBAAqB,CAAS,SAAS,EAAE,MAAM,CAAC;SAC3D,CAAC,CAAC;QACH,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,IAAI,CAChB,MAAc,EACd,MAAsB,EACtB,MAAc,EACd,IAAe;IAEf,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,MAAM,YAAY,GAAG,IAAI,EAAE,YAAY,IAAI,cAAc,CAAC;IAC1D,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,CAAC;IACjC,MAAM,GAAG,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAEpC,+DAA+D;IAC/D,qBAAqB;IACrB,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,MAAM,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC;IACtD,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,MAAM,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC;IACrD,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,MAAM,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC;IAErD,IAAI,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAyB,CAAC;IAClE,kEAAkE;IAClE,mEAAmE;IACnE,iEAAiE;IACjE,gEAAgE;IAChE,iEAAiE;IACjE,yCAAyC;IACzC,IAAI,MAAc,CAAC;IACnB,IAAI,IAAI,KAAK,SAAS;QAAE,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC;SACvC,IAAI,GAAG,CAAC,MAAM;QAAE,MAAM,GAAG,IAAI,CAAC,kBAAkB,CAAC;;QACjD,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC;IAClC,MAAM,SAAS,GACX,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,KAAK,CAAC;QAC1D,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,MAAM;QAChC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;IACrB,2DAA2D;IAC3D,+DAA+D;IAC/D,yCAAyC;IACzC,MAAM,YAAY,GAAG,GAAG,CAAC,GAAG,MAAM,SAAS,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IACtE,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACrB,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAC/D,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC;IACD,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,SAAS,CAE9D,CAAC;IAEF,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QACb,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACvC,+DAA+D;IACnE,CAAC;SAAM,CAAC;QACJ,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClC,yDAAyD;QACzD,4DAA4D;QAC5D,iCAAiC;QACjC,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,cAAc,CAAC;QAC9C,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC;QAC7B,CAAC;IACL,CAAC;IACD,OAAO,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;AAClE,CAAC","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n//\n// Ported from invinite/src/components/trading-chart/indicators/trix.ts\n// (commit 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite).\n// Re-licensed MIT for chartlang. The math is the reference, the code\n// style is not.\n// Structural choices (callsite-id slot, Series<T> proxy, replaceHead\n// mode) follow chartlang's primitive shape — NOT invinite's\n// IndicatorPlugin shape. TRIX composes three EMA sub-slots derived\n// from the parent slot id (`${slotId}/ema1` / `/ema2` / `/ema3`) for\n// the triple-smoothing chain plus a fourth `${slotId}/signal` EMA\n// over the TRIX line. Mirrors the MACD sub-slot composition pattern.\n\nimport type { Series, TrixOpts, TrixResult } from \"@invinite-org/chartlang-core\";\n\nimport { ema } from \"./ema.js\";\nimport { Float64RingBuffer } from \"../ringBuffer.js\";\nimport { ACTIVE_RUNTIME_CONTEXT, type RuntimeContext } from \"../runtimeContext.js\";\nimport { makeSeriesView, makeShiftedSeriesView } from \"../seriesView.js\";\nimport { type ScalarOrSeries, readSourceValue } from \"./lib/sourceValue.js\";\n\nconst DEFAULT_SIGNAL = 9;\n\ntype TrixSlot = {\n readonly result: TrixResult;\n readonly trixBuffer: Float64RingBuffer;\n /** Closed `ema3` as of the prior closed bar — divisor for the\n * next close's TRIX. */\n prevClosedEma3: number;\n /** Closed `ema3` as of the bar BEFORE the prior closed bar —\n * used by tick replay (the current bar's \"prior\" is two closes\n * back from a tick on the in-progress bar). */\n prevPrevClosedEma3: number;\n /**\n * Per-offset frozen `TrixResult` cache. `offset === 0` returns\n * `result` by identity. Non-zero offsets get a frozen result\n * whose two Series are `makeShiftedSeriesView` proxies over the\n * same two underlying ring buffers.\n */\n readonly shiftedResults: Map<number, TrixResult>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.trix called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(capacity: number, signalSeries: Series<number>): TrixSlot {\n const trixBuffer = new Float64RingBuffer(capacity);\n return {\n result: Object.freeze({\n trix: makeSeriesView<number>(trixBuffer),\n signal: signalSeries,\n }),\n trixBuffer,\n prevClosedEma3: Number.NaN,\n prevPrevClosedEma3: Number.NaN,\n shiftedResults: new Map(),\n };\n}\n\nfunction resultForOffset(slot: TrixSlot, offset: number, signalBuf: Float64RingBuffer): TrixResult {\n if (offset === 0) return slot.result;\n let cached = slot.shiftedResults.get(offset);\n if (cached === undefined) {\n cached = Object.freeze({\n trix: makeShiftedSeriesView<number>(slot.trixBuffer, offset),\n signal: makeShiftedSeriesView<number>(signalBuf, offset),\n });\n slot.shiftedResults.set(offset, cached);\n }\n return cached;\n}\n\n/**\n * TRIX — triple-smoothed EMA rate-of-change momentum oscillator\n * with an EMA-signal line. Composes three EMA sub-slots derived\n * from the parent slot id (`${slotId}/ema1` / `/ema2` / `/ema3`)\n * for the triple-smoothing chain, then computes\n * `100 · (ema3[t] − ema3[t−1]) / ema3[t−1]` per bar, and folds the\n * result into a fourth EMA sub-slot (`${slotId}/signal`) for the\n * signal line.\n *\n * @formula ema1 = EMA(source, length) ;\n * ema2 = EMA(ema1, length) ;\n * ema3 = EMA(ema2, length) ;\n * trix[t] = ema3[t-1] === 0 ? NaN : 100 · (ema3[t] − ema3[t-1]) / ema3[t-1] ;\n * signal[t] = EMA(trix, signalLength)\n * @warmup 3 · length + signalLength − 3 (first defined `signal` index ;\n * trix line first defined at `3 · length − 2`)\n * @anchors length, signalLength\n * @since 0.2\n * @stable\n *\n * `opts.offset` shifts both outputs in lockstep —\n * `series.current` on each output returns the value `offset` bars\n * ago.\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-runtime\";\n * // const t = ta.trix(\"slot\", bar.close, 18);\n * // plot(t.trix);\n * // plot(t.signal);\n */\nexport function trix(\n slotId: string,\n source: ScalarOrSeries,\n length: number,\n opts?: TrixOpts,\n): TrixResult {\n const ctx = getCtx();\n const signalLength = opts?.signalLength ?? DEFAULT_SIGNAL;\n const offset = opts?.offset ?? 0;\n const src = readSourceValue(source);\n\n // Triple-smoothing chain. Each outer EMA reads the prior EMA's\n // `.current` scalar.\n const e1 = ema(`${slotId}/ema1`, src, length).current;\n const e2 = ema(`${slotId}/ema2`, e1, length).current;\n const e3 = ema(`${slotId}/ema3`, e2, length).current;\n\n let slot = ctx.stream.taSlots.get(slotId) as TrixSlot | undefined;\n // The TRIX divisor on the current bar is the prior closed `ema3`.\n // On close-side we use `prevClosedEma3` (set at the previous close\n // — this is `ema3[t-1]` from the script-author's view). On ticks\n // we use `prevPrevClosedEma3` (set two closes back) because the\n // CURRENT bar's close has not yet happened — tick replay's \"prev\n // closed ema3\" is still two closes back.\n let prevE3: number;\n if (slot === undefined) prevE3 = Number.NaN;\n else if (ctx.isTick) prevE3 = slot.prevPrevClosedEma3;\n else prevE3 = slot.prevClosedEma3;\n const trixValue =\n Number.isFinite(e3) && Number.isFinite(prevE3) && prevE3 !== 0\n ? (100 * (e3 - prevE3)) / prevE3\n : Number.NaN;\n // Feed the TRIX value into the signal EMA. Always read the\n // un-shifted view; offset shifting for the composite result is\n // handled locally via `resultForOffset`.\n const signalSeries = ema(`${slotId}/signal`, trixValue, signalLength);\n if (slot === undefined) {\n slot = initSlot(ctx.stream.ohlcv.close.capacity, signalSeries);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const signalSubSlot = ctx.stream.taSlots.get(`${slotId}/signal`) as {\n outBuffer: Float64RingBuffer;\n };\n\n if (ctx.isTick) {\n slot.trixBuffer.replaceHead(trixValue);\n // Signal EMA's tick was handled by its own `ema()` call above.\n } else {\n slot.trixBuffer.append(trixValue);\n // Roll the prev-prev snapshot forward BEFORE overwriting\n // `prevClosedEma3` so tick replay on the next bar reads the\n // correct two-closes-back value.\n slot.prevPrevClosedEma3 = slot.prevClosedEma3;\n if (Number.isFinite(e3)) {\n slot.prevClosedEma3 = e3;\n }\n }\n return resultForOffset(slot, offset, signalSubSlot.outBuffer);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"trix.js","sourceRoot":"","sources":["../../src/ta/trix.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AAC/D,EAAE;AACF,uEAAuE;AACvE,mEAAmE;AACnE,qEAAqE;AACrE,gBAAgB;AAChB,qEAAqE;AACrE,4DAA4D;AAC5D,mEAAmE;AACnE,qEAAqE;AACrE,kEAAkE;AAClE,qEAAqE;AAIrE,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAuB,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAuB,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5E,MAAM,cAAc,GAAG,CAAC,CAAC;AAqBzB,SAAS,MAAM;IACX,MAAM,GAAG,GAAG,sBAAsB,CAAC,OAAO,CAAC;IAC3C,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,QAAgB,EAAE,YAA4B;IAC5D,MAAM,UAAU,GAAG,IAAI,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACnD,OAAO;QACH,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;YAClB,IAAI,EAAE,cAAc,CAAS,UAAU,CAAC;YACxC,MAAM,EAAE,YAAY;SACvB,CAAC;QACF,UAAU;QACV,cAAc,EAAE,MAAM,CAAC,GAAG;QAC1B,kBAAkB,EAAE,MAAM,CAAC,GAAG;QAC9B,cAAc,EAAE,IAAI,GAAG,EAAE;KAC5B,CAAC;AACN,CAAC;AAED,SAAS,eAAe,CAAC,IAAc,EAAE,MAAc,EAAE,SAA4B;IACjF,IAAI,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,MAAM,CAAC;IACrC,IAAI,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;YACnB,IAAI,EAAE,qBAAqB,CAAS,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC;YAC5D,MAAM,EAAE,qBAAqB,CAAS,SAAS,EAAE,MAAM,CAAC;SAC3D,CAAC,CAAC;QACH,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,IAAI,CAChB,MAAc,EACd,MAAsB,EACtB,MAAc,EACd,IAAe;IAEf,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,MAAM,YAAY,GAAG,IAAI,EAAE,YAAY,IAAI,cAAc,CAAC;IAC1D,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,CAAC;IACjC,MAAM,GAAG,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAEpC,+DAA+D;IAC/D,qBAAqB;IACrB,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,MAAM,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC;IACtD,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,MAAM,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC;IACrD,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,MAAM,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC;IAErD,IAAI,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAyB,CAAC;IAClE,kEAAkE;IAClE,mEAAmE;IACnE,iEAAiE;IACjE,gEAAgE;IAChE,iEAAiE;IACjE,yCAAyC;IACzC,IAAI,MAAc,CAAC;IACnB,IAAI,IAAI,KAAK,SAAS;QAAE,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC;SACvC,IAAI,GAAG,CAAC,MAAM;QAAE,MAAM,GAAG,IAAI,CAAC,kBAAkB,CAAC;;QACjD,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC;IAClC,MAAM,SAAS,GACX,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,KAAK,CAAC;QAC1D,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,MAAM;QAChC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;IACrB,2DAA2D;IAC3D,+DAA+D;IAC/D,yCAAyC;IACzC,MAAM,YAAY,GAAG,GAAG,CAAC,GAAG,MAAM,SAAS,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IACtE,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACrB,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAC/D,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC;IACD,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,SAAS,CAE9D,CAAC;IAEF,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QACb,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACvC,+DAA+D;IACnE,CAAC;SAAM,CAAC;QACJ,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClC,yDAAyD;QACzD,4DAA4D;QAC5D,iCAAiC;QACjC,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,cAAc,CAAC;QAC9C,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC;QAC7B,CAAC;IACL,CAAC;IACD,OAAO,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;AAClE,CAAC","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n//\n// Ported from invinite/src/components/trading-chart/indicators/trix.ts\n// (commit 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite).\n// Re-licensed MIT for chartlang. The math is the reference, the code\n// style is not.\n// Structural choices (callsite-id slot, Series<T> proxy, replaceHead\n// mode) follow chartlang's primitive shape — NOT invinite's\n// IndicatorPlugin shape. TRIX composes three EMA sub-slots derived\n// from the parent slot id (`${slotId}/ema1` / `/ema2` / `/ema3`) for\n// the triple-smoothing chain plus a fourth `${slotId}/signal` EMA\n// over the TRIX line. Mirrors the MACD sub-slot composition pattern.\n\nimport type { Series, TrixOpts, TrixResult } from \"@invinite-org/chartlang-core\";\n\nimport { ema } from \"./ema.js\";\nimport { Float64RingBuffer } from \"../ringBuffer.js\";\nimport { ACTIVE_RUNTIME_CONTEXT, type RuntimeContext } from \"../runtimeContext.js\";\nimport { makeSeriesView, makeShiftedSeriesView } from \"../seriesView.js\";\nimport { type ScalarOrSeries, readSourceValue } from \"./lib/sourceValue.js\";\n\nconst DEFAULT_SIGNAL = 9;\n\ntype TrixSlot = {\n readonly result: TrixResult;\n readonly trixBuffer: Float64RingBuffer;\n /** Closed `ema3` as of the prior closed bar — divisor for the\n * next close's TRIX. */\n prevClosedEma3: number;\n /** Closed `ema3` as of the bar BEFORE the prior closed bar —\n * used by tick replay (the current bar's \"prior\" is two closes\n * back from a tick on the in-progress bar). */\n prevPrevClosedEma3: number;\n /**\n * Per-offset frozen `TrixResult` cache. `offset === 0` returns\n * `result` by identity. Non-zero offsets get a frozen result\n * whose two Series are `makeShiftedSeriesView` proxies over the\n * same two underlying ring buffers.\n */\n readonly shiftedResults: Map<number, TrixResult>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.trix called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(capacity: number, signalSeries: Series<number>): TrixSlot {\n const trixBuffer = new Float64RingBuffer(capacity);\n return {\n result: Object.freeze({\n trix: makeSeriesView<number>(trixBuffer),\n signal: signalSeries,\n }),\n trixBuffer,\n prevClosedEma3: Number.NaN,\n prevPrevClosedEma3: Number.NaN,\n shiftedResults: new Map(),\n };\n}\n\nfunction resultForOffset(slot: TrixSlot, offset: number, signalBuf: Float64RingBuffer): TrixResult {\n if (offset === 0) return slot.result;\n let cached = slot.shiftedResults.get(offset);\n if (cached === undefined) {\n cached = Object.freeze({\n trix: makeShiftedSeriesView<number>(slot.trixBuffer, offset),\n signal: makeShiftedSeriesView<number>(signalBuf, offset),\n });\n slot.shiftedResults.set(offset, cached);\n }\n return cached;\n}\n\n/**\n * TRIX — triple-smoothed EMA rate-of-change momentum oscillator\n * with an EMA-signal line. Composes three EMA sub-slots derived\n * from the parent slot id (`${slotId}/ema1` / `/ema2` / `/ema3`)\n * for the triple-smoothing chain, then computes\n * `100 · (ema3[t] − ema3[t−1]) / ema3[t−1]` per bar, and folds the\n * result into a fourth EMA sub-slot (`${slotId}/signal`) for the\n * signal line.\n *\n * @formula ema1 = EMA(source, length) ;\n * ema2 = EMA(ema1, length) ;\n * ema3 = EMA(ema2, length) ;\n * trix[t] = ema3[t-1] === 0 ? NaN : 100 · (ema3[t] − ema3[t-1]) / ema3[t-1] ;\n * signal[t] = EMA(trix, signalLength)\n * @warmup 3 · length + signalLength − 3 (first defined `signal` index ;\n * trix line first defined at `3 · length − 2`)\n * @anchors length, signalLength\n * @since 0.2\n * @stable\n *\n * `opts.offset` is a presentation display shift carried to the plot\n * emission as `xShift` for both outputs in lockstep (`+n` right / future,\n * `−n` left / past); the series values are unshifted, so\n * `series.current` on each output returns the value at the current bar.\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-runtime\";\n * // const t = ta.trix(\"slot\", bar.close, 18);\n * // plot(t.trix);\n * // plot(t.signal);\n */\nexport function trix(\n slotId: string,\n source: ScalarOrSeries,\n length: number,\n opts?: TrixOpts,\n): TrixResult {\n const ctx = getCtx();\n const signalLength = opts?.signalLength ?? DEFAULT_SIGNAL;\n const offset = opts?.offset ?? 0;\n const src = readSourceValue(source);\n\n // Triple-smoothing chain. Each outer EMA reads the prior EMA's\n // `.current` scalar.\n const e1 = ema(`${slotId}/ema1`, src, length).current;\n const e2 = ema(`${slotId}/ema2`, e1, length).current;\n const e3 = ema(`${slotId}/ema3`, e2, length).current;\n\n let slot = ctx.stream.taSlots.get(slotId) as TrixSlot | undefined;\n // The TRIX divisor on the current bar is the prior closed `ema3`.\n // On close-side we use `prevClosedEma3` (set at the previous close\n // — this is `ema3[t-1]` from the script-author's view). On ticks\n // we use `prevPrevClosedEma3` (set two closes back) because the\n // CURRENT bar's close has not yet happened — tick replay's \"prev\n // closed ema3\" is still two closes back.\n let prevE3: number;\n if (slot === undefined) prevE3 = Number.NaN;\n else if (ctx.isTick) prevE3 = slot.prevPrevClosedEma3;\n else prevE3 = slot.prevClosedEma3;\n const trixValue =\n Number.isFinite(e3) && Number.isFinite(prevE3) && prevE3 !== 0\n ? (100 * (e3 - prevE3)) / prevE3\n : Number.NaN;\n // Feed the TRIX value into the signal EMA. Always read the\n // un-shifted view; offset shifting for the composite result is\n // handled locally via `resultForOffset`.\n const signalSeries = ema(`${slotId}/signal`, trixValue, signalLength);\n if (slot === undefined) {\n slot = initSlot(ctx.stream.ohlcv.close.capacity, signalSeries);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const signalSubSlot = ctx.stream.taSlots.get(`${slotId}/signal`) as {\n outBuffer: Float64RingBuffer;\n };\n\n if (ctx.isTick) {\n slot.trixBuffer.replaceHead(trixValue);\n // Signal EMA's tick was handled by its own `ema()` call above.\n } else {\n slot.trixBuffer.append(trixValue);\n // Roll the prev-prev snapshot forward BEFORE overwriting\n // `prevClosedEma3` so tick replay on the next bar reads the\n // correct two-closes-back value.\n slot.prevPrevClosedEma3 = slot.prevClosedEma3;\n if (Number.isFinite(e3)) {\n slot.prevClosedEma3 = e3;\n }\n }\n return resultForOffset(slot, offset, signalSubSlot.outBuffer);\n}\n"]}
|
package/dist/ta/vortex.d.ts
CHANGED
|
@@ -17,8 +17,9 @@ import type { VortexOpts, VortexResult } from "@invinite-org/chartlang-core";
|
|
|
17
17
|
* @since 0.2
|
|
18
18
|
* @stable
|
|
19
19
|
*
|
|
20
|
-
* `opts.offset`
|
|
21
|
-
* `
|
|
20
|
+
* `opts.offset` is a presentation display shift carried to the plot
|
|
21
|
+
* emission as `xShift` for both series in lockstep (`+n` right / future,
|
|
22
|
+
* `−n` left / past); the series values are unshifted.
|
|
22
23
|
*
|
|
23
24
|
* @example
|
|
24
25
|
* // import { ta } from "@invinite-org/chartlang-runtime";
|
package/dist/ta/vortex.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vortex.d.ts","sourceRoot":"","sources":["../../src/ta/vortex.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AA4M7E
|
|
1
|
+
{"version":3,"file":"vortex.d.ts","sourceRoot":"","sources":["../../src/ta/vortex.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AA4M7E;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,YAAY,CAkBtF"}
|
package/dist/ta/vortex.js
CHANGED
|
@@ -178,8 +178,9 @@ function tickStep(slot, high, low, close) {
|
|
|
178
178
|
* @since 0.2
|
|
179
179
|
* @stable
|
|
180
180
|
*
|
|
181
|
-
* `opts.offset`
|
|
182
|
-
* `
|
|
181
|
+
* `opts.offset` is a presentation display shift carried to the plot
|
|
182
|
+
* emission as `xShift` for both series in lockstep (`+n` right / future,
|
|
183
|
+
* `−n` left / past); the series values are unshifted.
|
|
183
184
|
*
|
|
184
185
|
* @example
|
|
185
186
|
* // import { ta } from "@invinite-org/chartlang-runtime";
|