@invinite-org/chartlang-runtime 1.1.1 → 1.3.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.
Files changed (294) hide show
  1. package/CHANGELOG.md +307 -0
  2. package/dist/barPoint.d.ts +20 -0
  3. package/dist/barPoint.d.ts.map +1 -0
  4. package/dist/barPoint.js +72 -0
  5. package/dist/barPoint.js.map +1 -0
  6. package/dist/bufferSnapshot.d.ts +102 -0
  7. package/dist/bufferSnapshot.d.ts.map +1 -0
  8. package/dist/bufferSnapshot.js +119 -0
  9. package/dist/bufferSnapshot.js.map +1 -0
  10. package/dist/buildComputeContext.d.ts.map +1 -1
  11. package/dist/buildComputeContext.js +6 -1
  12. package/dist/buildComputeContext.js.map +1 -1
  13. package/dist/createScriptRunner.d.ts +6 -3
  14. package/dist/createScriptRunner.d.ts.map +1 -1
  15. package/dist/createScriptRunner.js +65 -11
  16. package/dist/createScriptRunner.js.map +1 -1
  17. package/dist/dep/DepRunner.d.ts +7 -0
  18. package/dist/dep/DepRunner.d.ts.map +1 -1
  19. package/dist/dep/DepRunner.js +4 -0
  20. package/dist/dep/DepRunner.js.map +1 -1
  21. package/dist/emit/barcolor.d.ts +44 -0
  22. package/dist/emit/barcolor.d.ts.map +1 -0
  23. package/dist/emit/barcolor.js +40 -0
  24. package/dist/emit/barcolor.js.map +1 -0
  25. package/dist/emit/bgcolor.d.ts +44 -0
  26. package/dist/emit/bgcolor.d.ts.map +1 -0
  27. package/dist/emit/bgcolor.js +45 -0
  28. package/dist/emit/bgcolor.js.map +1 -0
  29. package/dist/emit/draw/boxes/fillBetween.d.ts +45 -0
  30. package/dist/emit/draw/boxes/fillBetween.d.ts.map +1 -0
  31. package/dist/emit/draw/boxes/fillBetween.js +36 -0
  32. package/dist/emit/draw/boxes/fillBetween.js.map +1 -0
  33. package/dist/emit/draw/handle.d.ts +9 -0
  34. package/dist/emit/draw/handle.d.ts.map +1 -1
  35. package/dist/emit/draw/handle.js +65 -10
  36. package/dist/emit/draw/handle.js.map +1 -1
  37. package/dist/emit/draw/namespace.d.ts +4 -3
  38. package/dist/emit/draw/namespace.d.ts.map +1 -1
  39. package/dist/emit/draw/namespace.js +6 -3
  40. package/dist/emit/draw/namespace.js.map +1 -1
  41. package/dist/emit/index.d.ts +2 -0
  42. package/dist/emit/index.d.ts.map +1 -1
  43. package/dist/emit/index.js +2 -0
  44. package/dist/emit/index.js.map +1 -1
  45. package/dist/emit/plot.d.ts +30 -1
  46. package/dist/emit/plot.d.ts.map +1 -1
  47. package/dist/emit/plot.js +45 -1
  48. package/dist/emit/plot.js.map +1 -1
  49. package/dist/execution/dispose.d.ts.map +1 -1
  50. package/dist/execution/dispose.js +18 -0
  51. package/dist/execution/dispose.js.map +1 -1
  52. package/dist/execution/runComputeStep.d.ts.map +1 -1
  53. package/dist/execution/runComputeStep.js +12 -1
  54. package/dist/execution/runComputeStep.js.map +1 -1
  55. package/dist/index.d.ts +1 -1
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +1 -1
  58. package/dist/index.js.map +1 -1
  59. package/dist/inputs/resolveInputs.js +1 -0
  60. package/dist/inputs/resolveInputs.js.map +1 -1
  61. package/dist/persistentStateStore.runtime.d.ts.map +1 -1
  62. package/dist/persistentStateStore.runtime.js +26 -7
  63. package/dist/persistentStateStore.runtime.js.map +1 -1
  64. package/dist/primitives.d.ts +1 -1
  65. package/dist/primitives.d.ts.map +1 -1
  66. package/dist/primitives.js +7 -1
  67. package/dist/primitives.js.map +1 -1
  68. package/dist/request/index.d.ts +2 -1
  69. package/dist/request/index.d.ts.map +1 -1
  70. package/dist/request/index.js +2 -1
  71. package/dist/request/index.js.map +1 -1
  72. package/dist/request/lowerTf.d.ts.map +1 -1
  73. package/dist/request/lowerTf.js +6 -0
  74. package/dist/request/lowerTf.js.map +1 -1
  75. package/dist/request/requestNamespace.d.ts.map +1 -1
  76. package/dist/request/requestNamespace.js +30 -3
  77. package/dist/request/requestNamespace.js.map +1 -1
  78. package/dist/request/security.d.ts +40 -4
  79. package/dist/request/security.d.ts.map +1 -1
  80. package/dist/request/security.js +114 -40
  81. package/dist/request/security.js.map +1 -1
  82. package/dist/request/securityExprRunner.d.ts +137 -0
  83. package/dist/request/securityExprRunner.d.ts.map +1 -0
  84. package/dist/request/securityExprRunner.js +253 -0
  85. package/dist/request/securityExprRunner.js.map +1 -0
  86. package/dist/request/streamBars.d.ts +14 -1
  87. package/dist/request/streamBars.d.ts.map +1 -1
  88. package/dist/request/streamBars.js +39 -1
  89. package/dist/request/streamBars.js.map +1 -1
  90. package/dist/ringBuffer.d.ts +19 -0
  91. package/dist/ringBuffer.d.ts.map +1 -1
  92. package/dist/ringBuffer.js +23 -0
  93. package/dist/ringBuffer.js.map +1 -1
  94. package/dist/runtimeContext.d.ts +90 -5
  95. package/dist/runtimeContext.d.ts.map +1 -1
  96. package/dist/runtimeContext.js.map +1 -1
  97. package/dist/seriesView.d.ts +42 -17
  98. package/dist/seriesView.d.ts.map +1 -1
  99. package/dist/seriesView.js +65 -42
  100. package/dist/seriesView.js.map +1 -1
  101. package/dist/state/arrayPersistence.d.ts +48 -0
  102. package/dist/state/arrayPersistence.d.ts.map +1 -0
  103. package/dist/state/arrayPersistence.js +88 -0
  104. package/dist/state/arrayPersistence.js.map +1 -0
  105. package/dist/state/arrayStateSlot.d.ts +78 -0
  106. package/dist/state/arrayStateSlot.d.ts.map +1 -0
  107. package/dist/state/arrayStateSlot.js +116 -0
  108. package/dist/state/arrayStateSlot.js.map +1 -0
  109. package/dist/state/index.d.ts +4 -1
  110. package/dist/state/index.d.ts.map +1 -1
  111. package/dist/state/index.js +4 -1
  112. package/dist/state/index.js.map +1 -1
  113. package/dist/state/lifecycle.d.ts +68 -0
  114. package/dist/state/lifecycle.d.ts.map +1 -1
  115. package/dist/state/lifecycle.js +89 -0
  116. package/dist/state/lifecycle.js.map +1 -1
  117. package/dist/state/seriesPersistence.d.ts +48 -0
  118. package/dist/state/seriesPersistence.d.ts.map +1 -0
  119. package/dist/state/seriesPersistence.js +87 -0
  120. package/dist/state/seriesPersistence.js.map +1 -0
  121. package/dist/state/seriesSlot.d.ts +105 -0
  122. package/dist/state/seriesSlot.d.ts.map +1 -0
  123. package/dist/state/seriesSlot.js +123 -0
  124. package/dist/state/seriesSlot.js.map +1 -0
  125. package/dist/state/stateNamespace.d.ts.map +1 -1
  126. package/dist/state/stateNamespace.js +55 -0
  127. package/dist/state/stateNamespace.js.map +1 -1
  128. package/dist/streamState.d.ts +25 -19
  129. package/dist/streamState.d.ts.map +1 -1
  130. package/dist/streamState.js +40 -66
  131. package/dist/streamState.js.map +1 -1
  132. package/dist/ta/adx.d.ts +3 -2
  133. package/dist/ta/adx.d.ts.map +1 -1
  134. package/dist/ta/adx.js +3 -2
  135. package/dist/ta/adx.js.map +1 -1
  136. package/dist/ta/alma.d.ts +6 -4
  137. package/dist/ta/alma.d.ts.map +1 -1
  138. package/dist/ta/alma.js +19 -6
  139. package/dist/ta/alma.js.map +1 -1
  140. package/dist/ta/atr.d.ts +3 -2
  141. package/dist/ta/atr.d.ts.map +1 -1
  142. package/dist/ta/atr.js +3 -2
  143. package/dist/ta/atr.js.map +1 -1
  144. package/dist/ta/bb.d.ts +3 -2
  145. package/dist/ta/bb.d.ts.map +1 -1
  146. package/dist/ta/bb.js +3 -2
  147. package/dist/ta/bb.js.map +1 -1
  148. package/dist/ta/chaikinOsc.d.ts +3 -2
  149. package/dist/ta/chaikinOsc.d.ts.map +1 -1
  150. package/dist/ta/chaikinOsc.js +3 -2
  151. package/dist/ta/chaikinOsc.js.map +1 -1
  152. package/dist/ta/crossover.d.ts +3 -2
  153. package/dist/ta/crossover.d.ts.map +1 -1
  154. package/dist/ta/crossover.js +3 -2
  155. package/dist/ta/crossover.js.map +1 -1
  156. package/dist/ta/crossunder.d.ts +3 -2
  157. package/dist/ta/crossunder.d.ts.map +1 -1
  158. package/dist/ta/crossunder.js +3 -2
  159. package/dist/ta/crossunder.js.map +1 -1
  160. package/dist/ta/dmi.d.ts +4 -3
  161. package/dist/ta/dmi.d.ts.map +1 -1
  162. package/dist/ta/dmi.js +4 -3
  163. package/dist/ta/dmi.js.map +1 -1
  164. package/dist/ta/ema.d.ts +3 -2
  165. package/dist/ta/ema.d.ts.map +1 -1
  166. package/dist/ta/ema.js +3 -2
  167. package/dist/ta/ema.js.map +1 -1
  168. package/dist/ta/eom.d.ts +3 -1
  169. package/dist/ta/eom.d.ts.map +1 -1
  170. package/dist/ta/eom.js +3 -1
  171. package/dist/ta/eom.js.map +1 -1
  172. package/dist/ta/highestbars.d.ts +25 -0
  173. package/dist/ta/highestbars.d.ts.map +1 -0
  174. package/dist/ta/highestbars.js +106 -0
  175. package/dist/ta/highestbars.js.map +1 -0
  176. package/dist/ta/historicalVolatility.d.ts +3 -2
  177. package/dist/ta/historicalVolatility.d.ts.map +1 -1
  178. package/dist/ta/historicalVolatility.js +3 -2
  179. package/dist/ta/historicalVolatility.js.map +1 -1
  180. package/dist/ta/ichimoku.d.ts +3 -1
  181. package/dist/ta/ichimoku.d.ts.map +1 -1
  182. package/dist/ta/ichimoku.js +3 -1
  183. package/dist/ta/ichimoku.js.map +1 -1
  184. package/dist/ta/lowestbars.d.ts +25 -0
  185. package/dist/ta/lowestbars.d.ts.map +1 -0
  186. package/dist/ta/lowestbars.js +102 -0
  187. package/dist/ta/lowestbars.js.map +1 -0
  188. package/dist/ta/macd.d.ts +3 -2
  189. package/dist/ta/macd.d.ts.map +1 -1
  190. package/dist/ta/macd.js +3 -2
  191. package/dist/ta/macd.js.map +1 -1
  192. package/dist/ta/massIndex.d.ts +3 -2
  193. package/dist/ta/massIndex.d.ts.map +1 -1
  194. package/dist/ta/massIndex.js +3 -2
  195. package/dist/ta/massIndex.js.map +1 -1
  196. package/dist/ta/mfi.d.ts +3 -1
  197. package/dist/ta/mfi.d.ts.map +1 -1
  198. package/dist/ta/mfi.js +3 -1
  199. package/dist/ta/mfi.js.map +1 -1
  200. package/dist/ta/netVolume.d.ts +3 -1
  201. package/dist/ta/netVolume.d.ts.map +1 -1
  202. package/dist/ta/netVolume.js +3 -1
  203. package/dist/ta/netVolume.js.map +1 -1
  204. package/dist/ta/nvi.d.ts +3 -1
  205. package/dist/ta/nvi.d.ts.map +1 -1
  206. package/dist/ta/nvi.js +3 -1
  207. package/dist/ta/nvi.js.map +1 -1
  208. package/dist/ta/persistence.d.ts.map +1 -1
  209. package/dist/ta/persistence.js +1 -40
  210. package/dist/ta/persistence.js.map +1 -1
  211. package/dist/ta/ppo.d.ts +3 -2
  212. package/dist/ta/ppo.d.ts.map +1 -1
  213. package/dist/ta/ppo.js +3 -2
  214. package/dist/ta/ppo.js.map +1 -1
  215. package/dist/ta/pvi.d.ts +3 -1
  216. package/dist/ta/pvi.d.ts.map +1 -1
  217. package/dist/ta/pvi.js +3 -1
  218. package/dist/ta/pvi.js.map +1 -1
  219. package/dist/ta/pvo.d.ts +3 -1
  220. package/dist/ta/pvo.d.ts.map +1 -1
  221. package/dist/ta/pvo.js +3 -1
  222. package/dist/ta/pvo.js.map +1 -1
  223. package/dist/ta/pvt.d.ts +3 -1
  224. package/dist/ta/pvt.d.ts.map +1 -1
  225. package/dist/ta/pvt.js +3 -1
  226. package/dist/ta/pvt.js.map +1 -1
  227. package/dist/ta/registry.d.ts +7 -1
  228. package/dist/ta/registry.d.ts.map +1 -1
  229. package/dist/ta/registry.js +4 -0
  230. package/dist/ta/registry.js.map +1 -1
  231. package/dist/ta/rsi.d.ts +3 -2
  232. package/dist/ta/rsi.d.ts.map +1 -1
  233. package/dist/ta/rsi.js +3 -2
  234. package/dist/ta/rsi.js.map +1 -1
  235. package/dist/ta/rvi.d.ts +3 -2
  236. package/dist/ta/rvi.d.ts.map +1 -1
  237. package/dist/ta/rvi.js +3 -2
  238. package/dist/ta/rvi.js.map +1 -1
  239. package/dist/ta/sessionVolumeProfile.d.ts.map +1 -1
  240. package/dist/ta/sessionVolumeProfile.js +1 -17
  241. package/dist/ta/sessionVolumeProfile.js.map +1 -1
  242. package/dist/ta/sma.d.ts +6 -3
  243. package/dist/ta/sma.d.ts.map +1 -1
  244. package/dist/ta/sma.js +6 -3
  245. package/dist/ta/sma.js.map +1 -1
  246. package/dist/ta/stdev.d.ts +3 -2
  247. package/dist/ta/stdev.d.ts.map +1 -1
  248. package/dist/ta/stdev.js +3 -2
  249. package/dist/ta/stdev.js.map +1 -1
  250. package/dist/ta/trendStrengthIndex.d.ts +3 -2
  251. package/dist/ta/trendStrengthIndex.d.ts.map +1 -1
  252. package/dist/ta/trendStrengthIndex.js +3 -2
  253. package/dist/ta/trendStrengthIndex.js.map +1 -1
  254. package/dist/ta/trix.d.ts +4 -3
  255. package/dist/ta/trix.d.ts.map +1 -1
  256. package/dist/ta/trix.js +4 -3
  257. package/dist/ta/trix.js.map +1 -1
  258. package/dist/ta/vortex.d.ts +3 -2
  259. package/dist/ta/vortex.d.ts.map +1 -1
  260. package/dist/ta/vortex.js +3 -2
  261. package/dist/ta/vortex.js.map +1 -1
  262. package/dist/time-accessors/civil.d.ts +73 -0
  263. package/dist/time-accessors/civil.d.ts.map +1 -0
  264. package/dist/time-accessors/civil.js +105 -0
  265. package/dist/time-accessors/civil.js.map +1 -0
  266. package/dist/time-accessors/index.d.ts +8 -0
  267. package/dist/time-accessors/index.d.ts.map +1 -0
  268. package/dist/time-accessors/index.js +9 -0
  269. package/dist/time-accessors/index.js.map +1 -0
  270. package/dist/time-accessors/sessionAccessors.d.ts +50 -0
  271. package/dist/time-accessors/sessionAccessors.d.ts.map +1 -0
  272. package/dist/time-accessors/sessionAccessors.js +79 -0
  273. package/dist/time-accessors/sessionAccessors.js.map +1 -0
  274. package/dist/time-accessors/sessionWindow.d.ts +17 -0
  275. package/dist/time-accessors/sessionWindow.d.ts.map +1 -0
  276. package/dist/time-accessors/sessionWindow.js +41 -0
  277. package/dist/time-accessors/sessionWindow.js.map +1 -0
  278. package/dist/time-accessors/timeAccessors.d.ts +54 -0
  279. package/dist/time-accessors/timeAccessors.d.ts.map +1 -0
  280. package/dist/time-accessors/timeAccessors.js +132 -0
  281. package/dist/time-accessors/timeAccessors.js.map +1 -0
  282. package/dist/time-accessors/tzDiagnostic.d.ts +17 -0
  283. package/dist/time-accessors/tzDiagnostic.d.ts.map +1 -0
  284. package/dist/time-accessors/tzDiagnostic.js +34 -0
  285. package/dist/time-accessors/tzDiagnostic.js.map +1 -0
  286. package/dist/time-accessors/tzOffset.d.ts +31 -0
  287. package/dist/time-accessors/tzOffset.d.ts.map +1 -0
  288. package/dist/time-accessors/tzOffset.js +67 -0
  289. package/dist/time-accessors/tzOffset.js.map +1 -0
  290. package/package.json +3 -3
  291. package/dist/ta/lib/applyOffset.d.ts +0 -19
  292. package/dist/ta/lib/applyOffset.d.ts.map +0 -1
  293. package/dist/ta/lib/applyOffset.js +0 -38
  294. package/dist/ta/lib/applyOffset.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"atr.js","sourceRoot":"","sources":["../../src/ta/atr.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/atr.ts\n// plus lib/tr-series.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. ATR derives from `bar.high`/`bar.low`/\n// `bar.close` directly — no `source` argument per Pine.\n\nimport type { AtrOpts, 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\";\n\ntype AtrSlot = {\n readonly outBuffer: Float64RingBuffer;\n readonly series: Series<number>;\n readonly length: number;\n seedTrSum: number;\n /** Number of TR values folded into the seed so far. */\n trCount: number;\n atr: number;\n /** Close of the prior closed bar — used to compute TR on the next close. */\n prevClose: number;\n /** Close of the bar before the current bar (i.e. the close 2 bars ago). */\n prevPrevClose: number;\n /** ATR as of the prior closed bar — used by tick-mode replay. */\n prevClosedAtr: 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.atr called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(length: number, capacity: number): AtrSlot {\n const outBuffer = new Float64RingBuffer(capacity);\n return {\n outBuffer,\n series: makeSeriesView<number>(outBuffer),\n length,\n seedTrSum: 0,\n trCount: 0,\n atr: Number.NaN,\n prevClose: Number.NaN,\n prevPrevClose: Number.NaN,\n prevClosedAtr: Number.NaN,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: AtrSlot, 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 trueRange(high: number, low: number, prevClose: number): number {\n if (!Number.isFinite(prevClose)) return high - low;\n return Math.max(high - low, Math.abs(high - prevClose), Math.abs(low - prevClose));\n}\n\nfunction closeValue(slot: AtrSlot, high: number, low: number, close: number): number {\n if (!Number.isFinite(high) || !Number.isFinite(low) || !Number.isFinite(close)) {\n if (Number.isFinite(slot.atr)) return slot.atr;\n return Number.NaN;\n }\n const tr = trueRange(high, low, slot.prevClose);\n slot.prevPrevClose = slot.prevClose;\n slot.prevClose = close;\n slot.trCount += 1;\n\n if (slot.trCount < slot.length) {\n slot.seedTrSum += tr;\n return Number.NaN;\n }\n if (slot.trCount === slot.length) {\n slot.seedTrSum += tr;\n slot.atr = slot.seedTrSum / slot.length;\n slot.prevClosedAtr = slot.atr;\n return slot.atr;\n }\n slot.prevClosedAtr = slot.atr;\n slot.atr = wilderStep(slot.atr, tr, slot.length);\n return slot.atr;\n}\n\nfunction tickValue(slot: AtrSlot, high: number, low: number, close: number): number {\n if (!Number.isFinite(high) || !Number.isFinite(low) || !Number.isFinite(close)) {\n return Number.isFinite(slot.atr) ? slot.atr : Number.NaN;\n }\n if (slot.trCount < slot.length) return Number.NaN;\n // Tick TR uses the **bar before the current bar**'s close — frozen\n // by the prior close-side advance as `prevPrevClose`.\n const tr = trueRange(high, low, slot.prevPrevClose);\n if (slot.trCount === slot.length) {\n // We just seeded on the current close; tick replays the same seed\n // (the seed window is fixed once the bar closes).\n return slot.atr;\n }\n return wilderStep(slot.prevClosedAtr, tr, slot.length);\n}\n\n/**\n * Wilder's Average True Range. Sources from `bar.high` / `bar.low` /\n * `bar.close` directly (no `source` arg — matches Pine). Seeds at bar\n * `length − 1` as the simple mean of the first `length` TR values;\n * subsequent slots use the Wilder recurrence with α = 1/length.\n *\n * @formula TR[t] = max(high − low, |high − prevClose|, |low − prevClose|) ;\n * seed at bar length − 1 = mean(TR[0 .. length − 1]) ;\n * ATR[t] = (ATR[t − 1] · (length − 1) + TR[t]) / length\n * @warmup length − 1\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 a = ta.atr(\"slot\", 14);\n * // const head = a.current;\n * // const lagged = ta.atr(\"slot2\", 14, { offset: 5 });\n */\nexport function atr(slotId: string, length: number, opts?: AtrOpts): Series<number> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as AtrSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(length, ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const bar = ctx.stream.bar;\n if (ctx.isTick) {\n slot.outBuffer.replaceHead(tickValue(slot, bar.high, bar.low, bar.close));\n } else {\n slot.outBuffer.append(closeValue(slot, bar.high, bar.low, bar.close));\n }\n return viewForOffset(slot, opts?.offset ?? 0);\n}\n"]}
1
+ {"version":3,"file":"atr.js","sourceRoot":"","sources":["../../src/ta/atr.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/atr.ts\n// plus lib/tr-series.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. ATR derives from `bar.high`/`bar.low`/\n// `bar.close` directly — no `source` argument per Pine.\n\nimport type { AtrOpts, 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\";\n\ntype AtrSlot = {\n readonly outBuffer: Float64RingBuffer;\n readonly series: Series<number>;\n readonly length: number;\n seedTrSum: number;\n /** Number of TR values folded into the seed so far. */\n trCount: number;\n atr: number;\n /** Close of the prior closed bar — used to compute TR on the next close. */\n prevClose: number;\n /** Close of the bar before the current bar (i.e. the close 2 bars ago). */\n prevPrevClose: number;\n /** ATR as of the prior closed bar — used by tick-mode replay. */\n prevClosedAtr: 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.atr called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(length: number, capacity: number): AtrSlot {\n const outBuffer = new Float64RingBuffer(capacity);\n return {\n outBuffer,\n series: makeSeriesView<number>(outBuffer),\n length,\n seedTrSum: 0,\n trCount: 0,\n atr: Number.NaN,\n prevClose: Number.NaN,\n prevPrevClose: Number.NaN,\n prevClosedAtr: Number.NaN,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: AtrSlot, 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 trueRange(high: number, low: number, prevClose: number): number {\n if (!Number.isFinite(prevClose)) return high - low;\n return Math.max(high - low, Math.abs(high - prevClose), Math.abs(low - prevClose));\n}\n\nfunction closeValue(slot: AtrSlot, high: number, low: number, close: number): number {\n if (!Number.isFinite(high) || !Number.isFinite(low) || !Number.isFinite(close)) {\n if (Number.isFinite(slot.atr)) return slot.atr;\n return Number.NaN;\n }\n const tr = trueRange(high, low, slot.prevClose);\n slot.prevPrevClose = slot.prevClose;\n slot.prevClose = close;\n slot.trCount += 1;\n\n if (slot.trCount < slot.length) {\n slot.seedTrSum += tr;\n return Number.NaN;\n }\n if (slot.trCount === slot.length) {\n slot.seedTrSum += tr;\n slot.atr = slot.seedTrSum / slot.length;\n slot.prevClosedAtr = slot.atr;\n return slot.atr;\n }\n slot.prevClosedAtr = slot.atr;\n slot.atr = wilderStep(slot.atr, tr, slot.length);\n return slot.atr;\n}\n\nfunction tickValue(slot: AtrSlot, high: number, low: number, close: number): number {\n if (!Number.isFinite(high) || !Number.isFinite(low) || !Number.isFinite(close)) {\n return Number.isFinite(slot.atr) ? slot.atr : Number.NaN;\n }\n if (slot.trCount < slot.length) return Number.NaN;\n // Tick TR uses the **bar before the current bar**'s close — frozen\n // by the prior close-side advance as `prevPrevClose`.\n const tr = trueRange(high, low, slot.prevPrevClose);\n if (slot.trCount === slot.length) {\n // We just seeded on the current close; tick replays the same seed\n // (the seed window is fixed once the bar closes).\n return slot.atr;\n }\n return wilderStep(slot.prevClosedAtr, tr, slot.length);\n}\n\n/**\n * Wilder's Average True Range. Sources from `bar.high` / `bar.low` /\n * `bar.close` directly (no `source` arg — matches Pine). Seeds at bar\n * `length − 1` as the simple mean of the first `length` TR values;\n * subsequent slots use the Wilder recurrence with α = 1/length.\n *\n * @formula TR[t] = max(high − low, |high − prevClose|, |low − prevClose|) ;\n * seed at bar length − 1 = mean(TR[0 .. length − 1]) ;\n * ATR[t] = (ATR[t − 1] · (length − 1) + TR[t]) / length\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 a = ta.atr(\"slot\", 14);\n * // const head = a.current;\n * // const lagged = ta.atr(\"slot2\", 14, { offset: 5 });\n */\nexport function atr(slotId: string, length: number, opts?: AtrOpts): Series<number> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as AtrSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(length, ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const bar = ctx.stream.bar;\n if (ctx.isTick) {\n slot.outBuffer.replaceHead(tickValue(slot, bar.high, bar.low, bar.close));\n } else {\n slot.outBuffer.append(closeValue(slot, bar.high, bar.low, bar.close));\n }\n return viewForOffset(slot, opts?.offset ?? 0);\n}\n"]}
package/dist/ta/bb.d.ts CHANGED
@@ -15,8 +15,9 @@ import { type ScalarOrSeries } from "./lib/sourceValue.js";
15
15
  * @since 0.1
16
16
  * @stable
17
17
  *
18
- * `opts.offset` shifts all three bands in lockstep
19
- * `series.current` on each band returns the value `offset` bars ago.
18
+ * `opts.offset` is a presentation display shift carried to the plot
19
+ * emission as `xShift` for all three bands in lockstep (`+n` right / future,
20
+ * `−n` left / past); the series values are unshifted.
20
21
  *
21
22
  * @example
22
23
  * // import { ta } from "@invinite-org/chartlang-runtime";
@@ -1 +1 @@
1
- {"version":3,"file":"bb.d.ts","sourceRoot":"","sources":["../../src/ta/bb.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAU,MAAM,8BAA8B,CAAC;AAM7E,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AA8D5E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,EAAE,CACd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,MAAM,GACd,QAAQ,CA4CV"}
1
+ {"version":3,"file":"bb.d.ts","sourceRoot":"","sources":["../../src/ta/bb.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAU,MAAM,8BAA8B,CAAC;AAM7E,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AA8D5E;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,EAAE,CACd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,MAAM,GACd,QAAQ,CA4CV"}
package/dist/ta/bb.js CHANGED
@@ -66,8 +66,9 @@ function resultForOffset(slot, offset) {
66
66
  * @since 0.1
67
67
  * @stable
68
68
  *
69
- * `opts.offset` shifts all three bands in lockstep
70
- * `series.current` on each band returns the value `offset` bars ago.
69
+ * `opts.offset` is a presentation display shift carried to the plot
70
+ * emission as `xShift` for all three bands in lockstep (`+n` right / future,
71
+ * `−n` left / past); the series values are unshifted.
71
72
  *
72
73
  * @example
73
74
  * // import { ta } from "@invinite-org/chartlang-runtime";
package/dist/ta/bb.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bb.js","sourceRoot":"","sources":["../../src/ta/bb.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/bb.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. BB is composed from `sma` + `stdev` via\n// sub-slot ids so a fix to either primitive flows in for free.\n\nimport type { BbOpts, BbResult, 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 { sma } from \"./sma.js\";\nimport { type ScalarOrSeries, readSourceValue } from \"./lib/sourceValue.js\";\nimport { stdev } from \"./stdev.js\";\n\nconst DEFAULT_MULTIPLIER = 2;\n\ntype BbSlot = {\n readonly result: BbResult;\n readonly upper: Float64RingBuffer;\n readonly middle: Series<number>;\n readonly lower: Float64RingBuffer;\n /**\n * Reference to the SMA sub-slot's output ring buffer. Captured at\n * first call so per-offset shifted middle views can be constructed\n * without re-entering `sma()` (which would double-advance the\n * sub-slot's compute on every bar).\n */\n readonly middleBuf: Float64RingBuffer;\n /**\n * Per-offset frozen `BbResult` cache. `offset === 0` returns\n * `result` directly (identity-preserving). Each cached result\n * proxies the same three underlying buffers via shifted views.\n */\n readonly shiftedResults: Map<number, BbResult>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.bb called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(capacity: number, middle: Series<number>, middleBuf: Float64RingBuffer): BbSlot {\n const upper = new Float64RingBuffer(capacity);\n const lower = new Float64RingBuffer(capacity);\n const upperView = makeSeriesView<number>(upper);\n const lowerView = makeSeriesView<number>(lower);\n return {\n result: Object.freeze({ upper: upperView, middle, lower: lowerView }),\n upper,\n middle,\n lower,\n middleBuf,\n shiftedResults: new Map(),\n };\n}\n\nfunction resultForOffset(slot: BbSlot, offset: number): BbResult {\n if (offset === 0) return slot.result;\n let cached = slot.shiftedResults.get(offset);\n if (cached === undefined) {\n cached = Object.freeze({\n upper: makeShiftedSeriesView<number>(slot.upper, offset),\n middle: makeShiftedSeriesView<number>(slot.middleBuf, offset),\n lower: makeShiftedSeriesView<number>(slot.lower, offset),\n });\n slot.shiftedResults.set(offset, cached);\n }\n return cached;\n}\n\n/**\n * Bollinger Bands — `multiplier × σ` envelope around an SMA(length)\n * middle band. Default `multiplier = 2` per Pine. Returns a cached\n * `{ upper, middle, lower }` record (same identity every bar) backed\n * by three `Series<number>` Proxies. The middle band is the\n * underlying SMA primitive's output (identity-shared).\n *\n * @formula middle = sma(source, length) ;\n * σ = stdev(source, length, { biased: true }) ;\n * upper = middle + multiplier · σ ;\n * lower = middle − multiplier · σ\n * @warmup length − 1\n * @since 0.1\n * @stable\n *\n * `opts.offset` shifts all three bands in lockstep —\n * `series.current` on each band returns the value `offset` bars ago.\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-runtime\";\n * // const bands = ta.bb(\"slot\", bar.close, 20, { multiplier: 2 });\n * // const u = bands.upper.current;\n * // const lagged = ta.bb(\"slot2\", bar.close, 20, { offset: 5 });\n */\nexport function bb(\n slotId: string,\n source: ScalarOrSeries,\n length: number,\n opts?: BbOpts,\n): BbResult {\n const ctx = getCtx();\n const multiplier = opts?.multiplier ?? DEFAULT_MULTIPLIER;\n const src = readSourceValue(source);\n const middleSlotId = `${slotId}/sma`;\n const stdevSlotId = `${slotId}/stdev`;\n // Compose: sma updates the middle band; stdev updates a separate\n // rolling-sigma series. Both primitives respect ctx.isTick. The\n // un-shifted middle (no offset) drives the per-bar math; the\n // shifted middle for non-zero offset is composed lazily in\n // `resultForOffset` to keep the close-path tight.\n const middleSeries = sma(middleSlotId, src, length);\n // BB's invinite math uses population sigma (denominator length); we\n // pass `biased: true` so the helper matches.\n const sigmaSeries = stdev(stdevSlotId, src, length, { biased: true });\n\n let slot = ctx.stream.taSlots.get(slotId) as BbSlot | undefined;\n if (slot === undefined) {\n // Capture the SMA sub-slot's output ring buffer so future\n // shifted-view lookups don't need to re-enter `sma()`.\n const smaSlot = ctx.stream.taSlots.get(middleSlotId) as { outBuffer: Float64RingBuffer };\n slot = initSlot(ctx.stream.ohlcv.close.capacity, middleSeries, smaSlot.outBuffer);\n ctx.stream.taSlots.set(slotId, slot);\n }\n\n const mid = middleSeries.current;\n const sigma = sigmaSeries.current;\n let upperValue: number;\n let lowerValue: number;\n if (Number.isFinite(mid) && Number.isFinite(sigma)) {\n upperValue = mid + multiplier * sigma;\n lowerValue = mid - multiplier * sigma;\n } else {\n upperValue = Number.NaN;\n lowerValue = Number.NaN;\n }\n if (ctx.isTick) {\n slot.upper.replaceHead(upperValue);\n slot.lower.replaceHead(lowerValue);\n } else {\n slot.upper.append(upperValue);\n slot.lower.append(lowerValue);\n }\n return resultForOffset(slot, opts?.offset ?? 0);\n}\n"]}
1
+ {"version":3,"file":"bb.js","sourceRoot":"","sources":["../../src/ta/bb.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/bb.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. BB is composed from `sma` + `stdev` via\n// sub-slot ids so a fix to either primitive flows in for free.\n\nimport type { BbOpts, BbResult, 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 { sma } from \"./sma.js\";\nimport { type ScalarOrSeries, readSourceValue } from \"./lib/sourceValue.js\";\nimport { stdev } from \"./stdev.js\";\n\nconst DEFAULT_MULTIPLIER = 2;\n\ntype BbSlot = {\n readonly result: BbResult;\n readonly upper: Float64RingBuffer;\n readonly middle: Series<number>;\n readonly lower: Float64RingBuffer;\n /**\n * Reference to the SMA sub-slot's output ring buffer. Captured at\n * first call so per-offset shifted middle views can be constructed\n * without re-entering `sma()` (which would double-advance the\n * sub-slot's compute on every bar).\n */\n readonly middleBuf: Float64RingBuffer;\n /**\n * Per-offset frozen `BbResult` cache. `offset === 0` returns\n * `result` directly (identity-preserving). Each cached result\n * proxies the same three underlying buffers via shifted views.\n */\n readonly shiftedResults: Map<number, BbResult>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.bb called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(capacity: number, middle: Series<number>, middleBuf: Float64RingBuffer): BbSlot {\n const upper = new Float64RingBuffer(capacity);\n const lower = new Float64RingBuffer(capacity);\n const upperView = makeSeriesView<number>(upper);\n const lowerView = makeSeriesView<number>(lower);\n return {\n result: Object.freeze({ upper: upperView, middle, lower: lowerView }),\n upper,\n middle,\n lower,\n middleBuf,\n shiftedResults: new Map(),\n };\n}\n\nfunction resultForOffset(slot: BbSlot, offset: number): BbResult {\n if (offset === 0) return slot.result;\n let cached = slot.shiftedResults.get(offset);\n if (cached === undefined) {\n cached = Object.freeze({\n upper: makeShiftedSeriesView<number>(slot.upper, offset),\n middle: makeShiftedSeriesView<number>(slot.middleBuf, offset),\n lower: makeShiftedSeriesView<number>(slot.lower, offset),\n });\n slot.shiftedResults.set(offset, cached);\n }\n return cached;\n}\n\n/**\n * Bollinger Bands — `multiplier × σ` envelope around an SMA(length)\n * middle band. Default `multiplier = 2` per Pine. Returns a cached\n * `{ upper, middle, lower }` record (same identity every bar) backed\n * by three `Series<number>` Proxies. The middle band is the\n * underlying SMA primitive's output (identity-shared).\n *\n * @formula middle = sma(source, length) ;\n * σ = stdev(source, length, { biased: true }) ;\n * upper = middle + multiplier · σ ;\n * lower = middle − multiplier · σ\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` for all three bands in lockstep (`+n` right / future,\n * `−n` left / past); the series values are unshifted.\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-runtime\";\n * // const bands = ta.bb(\"slot\", bar.close, 20, { multiplier: 2 });\n * // const u = bands.upper.current;\n * // const lagged = ta.bb(\"slot2\", bar.close, 20, { offset: 5 });\n */\nexport function bb(\n slotId: string,\n source: ScalarOrSeries,\n length: number,\n opts?: BbOpts,\n): BbResult {\n const ctx = getCtx();\n const multiplier = opts?.multiplier ?? DEFAULT_MULTIPLIER;\n const src = readSourceValue(source);\n const middleSlotId = `${slotId}/sma`;\n const stdevSlotId = `${slotId}/stdev`;\n // Compose: sma updates the middle band; stdev updates a separate\n // rolling-sigma series. Both primitives respect ctx.isTick. The\n // un-shifted middle (no offset) drives the per-bar math; the\n // shifted middle for non-zero offset is composed lazily in\n // `resultForOffset` to keep the close-path tight.\n const middleSeries = sma(middleSlotId, src, length);\n // BB's invinite math uses population sigma (denominator length); we\n // pass `biased: true` so the helper matches.\n const sigmaSeries = stdev(stdevSlotId, src, length, { biased: true });\n\n let slot = ctx.stream.taSlots.get(slotId) as BbSlot | undefined;\n if (slot === undefined) {\n // Capture the SMA sub-slot's output ring buffer so future\n // shifted-view lookups don't need to re-enter `sma()`.\n const smaSlot = ctx.stream.taSlots.get(middleSlotId) as { outBuffer: Float64RingBuffer };\n slot = initSlot(ctx.stream.ohlcv.close.capacity, middleSeries, smaSlot.outBuffer);\n ctx.stream.taSlots.set(slotId, slot);\n }\n\n const mid = middleSeries.current;\n const sigma = sigmaSeries.current;\n let upperValue: number;\n let lowerValue: number;\n if (Number.isFinite(mid) && Number.isFinite(sigma)) {\n upperValue = mid + multiplier * sigma;\n lowerValue = mid - multiplier * sigma;\n } else {\n upperValue = Number.NaN;\n lowerValue = Number.NaN;\n }\n if (ctx.isTick) {\n slot.upper.replaceHead(upperValue);\n slot.lower.replaceHead(lowerValue);\n } else {\n slot.upper.append(upperValue);\n slot.lower.append(lowerValue);\n }\n return resultForOffset(slot, opts?.offset ?? 0);\n}\n"]}
@@ -21,8 +21,9 @@ import type { ChaikinOscOpts, Series } from "@invinite-org/chartlang-core";
21
21
  * @since 0.2
22
22
  * @stable
23
23
  *
24
- * `opts.offset` shifts the returned series so `series.current` reads
25
- * the value `offset` bars ago.
24
+ * `opts.offset` is a presentation display shift carried to the plot
25
+ * emission as `xShift` (`+n` right / future, `−n` left / past); the
26
+ * series value is unshifted.
26
27
  *
27
28
  * @example
28
29
  * // import { ta, plot } from "@invinite-org/chartlang-core";
@@ -1 +1 @@
1
- {"version":3,"file":"chaikinOsc.d.ts","sourceRoot":"","sources":["../../src/ta/chaikinOsc.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAiD3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,CAmBhF"}
1
+ {"version":3,"file":"chaikinOsc.d.ts","sourceRoot":"","sources":["../../src/ta/chaikinOsc.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAiD3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,CAmBhF"}
@@ -69,8 +69,9 @@ function diff(fast, slow) {
69
69
  * @since 0.2
70
70
  * @stable
71
71
  *
72
- * `opts.offset` shifts the returned series so `series.current` reads
73
- * the value `offset` bars ago.
72
+ * `opts.offset` is a presentation display shift carried to the plot
73
+ * emission as `xShift` (`+n` right / future, `−n` left / past); the
74
+ * series value is unshifted.
74
75
  *
75
76
  * @example
76
77
  * // import { ta, plot } from "@invinite-org/chartlang-core";
@@ -1 +1 @@
1
- {"version":3,"file":"chaikinOsc.js","sourceRoot":"","sources":["../../src/ta/chaikinOsc.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/chaikin-osc.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. Per §9.4 we fold invinite's private ADL +\n// EMA copies onto the canonical `ta.adl` + `ta.ema` primitives via\n// three sub-slots (`${slotId}/adl`, `${slotId}/fast`, `${slotId}/slow`).\n\nimport type { ChaikinOscOpts, 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 { adl } from \"./adl.js\";\nimport { ema } from \"./ema.js\";\n\nconst DEFAULT_FAST = 3;\nconst DEFAULT_SLOW = 10;\n\ntype ChaikinOscSlot = {\n readonly outBuffer: Float64RingBuffer;\n readonly series: Series<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.chaikinOsc called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(capacity: number): ChaikinOscSlot {\n const outBuffer = new Float64RingBuffer(capacity);\n return {\n outBuffer,\n series: makeSeriesView<number>(outBuffer),\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: ChaikinOscSlot, 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 diff(fast: number, slow: number): number {\n if (!Number.isFinite(fast) || !Number.isFinite(slow)) return Number.NaN;\n return fast - slow;\n}\n\n/**\n * Chaikin Oscillator — `EMA(ADL, fastLength) − EMA(ADL, slowLength)`.\n * Composes one `ta.adl` sub-slot (cumulative money-flow volume) plus\n * two `ta.ema` sub-slots over the ADL series; a fix to `ta.adl` or\n * `ta.ema` flows in for free. Renders in its own pane (volume\n * category, oscillator-shape around zero).\n *\n * Defaults `{ fastLength: 3, slowLength: 10 }` (TradingView /\n * invinite canonical). ADL has warmup 0; the slow EMA seeds at bar\n * `slowLength − 1`, so the oscillator first emits a finite value at\n * that bar.\n *\n * **Tick mode.** The sub-slots handle their own tick replay (ADL\n * snapshots `prevClosedCumAdl`; EMA snapshots `prevClosedEma`); this\n * primitive's parent slot just re-evaluates `fastEma − slowEma`\n * against the live sub-slot heads and `replaceHead`s its own output.\n *\n * @formula chaikinOsc[t] = ema(adl(t), fastLength) − ema(adl(t), slowLength)\n * @warmup slowLength − 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, plot } from \"@invinite-org/chartlang-core\";\n * // const c = ta.chaikinOsc();\n * // plot(c);\n */\nexport function chaikinOsc(slotId: string, opts?: ChaikinOscOpts): Series<number> {\n const ctx = getCtx();\n const fastLength = opts?.fastLength ?? DEFAULT_FAST;\n const slowLength = opts?.slowLength ?? DEFAULT_SLOW;\n const offset = opts?.offset ?? 0;\n\n const adlSeries = adl(`${slotId}/adl`);\n const fastSeries = ema(`${slotId}/fast`, adlSeries.current, fastLength);\n const slowSeries = ema(`${slotId}/slow`, adlSeries.current, slowLength);\n\n let slot = ctx.stream.taSlots.get(slotId) as ChaikinOscSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const value = diff(fastSeries.current, slowSeries.current);\n if (ctx.isTick) slot.outBuffer.replaceHead(value);\n else slot.outBuffer.append(value);\n return viewForOffset(slot, offset);\n}\n"]}
1
+ {"version":3,"file":"chaikinOsc.js","sourceRoot":"","sources":["../../src/ta/chaikinOsc.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/chaikin-osc.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. Per §9.4 we fold invinite's private ADL +\n// EMA copies onto the canonical `ta.adl` + `ta.ema` primitives via\n// three sub-slots (`${slotId}/adl`, `${slotId}/fast`, `${slotId}/slow`).\n\nimport type { ChaikinOscOpts, 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 { adl } from \"./adl.js\";\nimport { ema } from \"./ema.js\";\n\nconst DEFAULT_FAST = 3;\nconst DEFAULT_SLOW = 10;\n\ntype ChaikinOscSlot = {\n readonly outBuffer: Float64RingBuffer;\n readonly series: Series<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.chaikinOsc called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(capacity: number): ChaikinOscSlot {\n const outBuffer = new Float64RingBuffer(capacity);\n return {\n outBuffer,\n series: makeSeriesView<number>(outBuffer),\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: ChaikinOscSlot, 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 diff(fast: number, slow: number): number {\n if (!Number.isFinite(fast) || !Number.isFinite(slow)) return Number.NaN;\n return fast - slow;\n}\n\n/**\n * Chaikin Oscillator — `EMA(ADL, fastLength) − EMA(ADL, slowLength)`.\n * Composes one `ta.adl` sub-slot (cumulative money-flow volume) plus\n * two `ta.ema` sub-slots over the ADL series; a fix to `ta.adl` or\n * `ta.ema` flows in for free. Renders in its own pane (volume\n * category, oscillator-shape around zero).\n *\n * Defaults `{ fastLength: 3, slowLength: 10 }` (TradingView /\n * invinite canonical). ADL has warmup 0; the slow EMA seeds at bar\n * `slowLength − 1`, so the oscillator first emits a finite value at\n * that bar.\n *\n * **Tick mode.** The sub-slots handle their own tick replay (ADL\n * snapshots `prevClosedCumAdl`; EMA snapshots `prevClosedEma`); this\n * primitive's parent slot just re-evaluates `fastEma − slowEma`\n * against the live sub-slot heads and `replaceHead`s its own output.\n *\n * @formula chaikinOsc[t] = ema(adl(t), fastLength) − ema(adl(t), slowLength)\n * @warmup slowLength − 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, plot } from \"@invinite-org/chartlang-core\";\n * // const c = ta.chaikinOsc();\n * // plot(c);\n */\nexport function chaikinOsc(slotId: string, opts?: ChaikinOscOpts): Series<number> {\n const ctx = getCtx();\n const fastLength = opts?.fastLength ?? DEFAULT_FAST;\n const slowLength = opts?.slowLength ?? DEFAULT_SLOW;\n const offset = opts?.offset ?? 0;\n\n const adlSeries = adl(`${slotId}/adl`);\n const fastSeries = ema(`${slotId}/fast`, adlSeries.current, fastLength);\n const slowSeries = ema(`${slotId}/slow`, adlSeries.current, slowLength);\n\n let slot = ctx.stream.taSlots.get(slotId) as ChaikinOscSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const value = diff(fastSeries.current, slowSeries.current);\n if (ctx.isTick) slot.outBuffer.replaceHead(value);\n else slot.outBuffer.append(value);\n return viewForOffset(slot, offset);\n}\n"]}
@@ -16,8 +16,9 @@ import { type ScalarOrSeries } from "./lib/sourceValue.js";
16
16
  * @since 0.1
17
17
  * @stable
18
18
  *
19
- * `opts.offset` shifts the boolean series so `series.current` returns
20
- * the crossover detection `offset` bars ago.
19
+ * `opts.offset` is a presentation display shift carried to the plot
20
+ * emission as `xShift` (`+n` right / future, `−n` left / past); the
21
+ * boolean crossover series value is unshifted.
21
22
  *
22
23
  * @example
23
24
  * // import { ta } from "@invinite-org/chartlang-runtime";
@@ -1 +1 @@
1
- {"version":3,"file":"crossover.d.ts","sourceRoot":"","sources":["../../src/ta/crossover.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAK1E,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AA4D5E;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,SAAS,CACrB,MAAM,EAAE,MAAM,EACd,CAAC,EAAE,cAAc,EACjB,CAAC,EAAE,cAAc,EACjB,IAAI,CAAC,EAAE,aAAa,GACrB,MAAM,CAAC,OAAO,CAAC,CA+BjB"}
1
+ {"version":3,"file":"crossover.d.ts","sourceRoot":"","sources":["../../src/ta/crossover.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAK1E,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AA4D5E;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,SAAS,CACrB,MAAM,EAAE,MAAM,EACd,CAAC,EAAE,cAAc,EACjB,CAAC,EAAE,cAAc,EACjB,IAAI,CAAC,EAAE,aAAa,GACrB,MAAM,CAAC,OAAO,CAAC,CA+BjB"}
@@ -64,8 +64,9 @@ function detect(prevA, prevB, currA, currB) {
64
64
  * @since 0.1
65
65
  * @stable
66
66
  *
67
- * `opts.offset` shifts the boolean series so `series.current` returns
68
- * the crossover detection `offset` bars ago.
67
+ * `opts.offset` is a presentation display shift carried to the plot
68
+ * emission as `xShift` (`+n` right / future, `−n` left / past); the
69
+ * boolean crossover series value is unshifted.
69
70
  *
70
71
  * @example
71
72
  * // import { ta } from "@invinite-org/chartlang-runtime";
@@ -1 +1 @@
1
- {"version":3,"file":"crossover.js","sourceRoot":"","sources":["../../src/ta/crossover.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// No invinite source — Phase-1 new code, semantics per Pine\n// `ta.crossover` / `ta.crossunder`.\n// Structural choices (callsite-id slot, Series<T> proxy, replaceHead\n// mode) follow chartlang's primitive shape.\n\nimport type { CrossoverOpts, Series } from \"@invinite-org/chartlang-core\";\n\nimport { RingBuffer } 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 CrossSlot = {\n readonly outBuffer: RingBuffer<boolean>;\n readonly series: Series<boolean>;\n /** Prior closed-bar values of `a` and `b` (rolling 2-slot history). */\n prevA: number;\n prevB: number;\n /** As-of-current-close values, frozen so ticks replay against prior. */\n currA: number;\n currB: number;\n initialised: boolean;\n /** Per-offset Series-view cache; see `sma.ts` for the convention. */\n readonly shiftedViews: Map<number, Series<boolean>>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.crossover called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(capacity: number): CrossSlot {\n const outBuffer = new RingBuffer<boolean>(capacity);\n return {\n outBuffer,\n series: makeSeriesView<boolean>(outBuffer) as Series<boolean>,\n prevA: Number.NaN,\n prevB: Number.NaN,\n currA: Number.NaN,\n currB: Number.NaN,\n initialised: false,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: CrossSlot, offset: number): Series<boolean> {\n if (offset === 0) return slot.series;\n let view = slot.shiftedViews.get(offset);\n if (view === undefined) {\n view = makeShiftedSeriesView<boolean>(slot.outBuffer, offset) as Series<boolean>;\n slot.shiftedViews.set(offset, view);\n }\n return view;\n}\n\nfunction detect(prevA: number, prevB: number, currA: number, currB: number): boolean {\n if (\n !Number.isFinite(prevA) ||\n !Number.isFinite(prevB) ||\n !Number.isFinite(currA) ||\n !Number.isFinite(currB)\n ) {\n return false;\n }\n return currA > currB && prevA <= prevB;\n}\n\n/**\n * `true` exactly at the bar where `a` crosses above `b`: `a.current >\n * b.current && a.prev <= b.prev`. `b` may be a scalar (treated as a\n * constant series). NaN inputs yield `false` — Pine semantics for\n * Boolean series (NaN doesn't bubble through booleans).\n *\n * The slot keeps a 2-slot history of both `a` and `b` so scalar\n * sources work without the caller wrapping them. Tick-mode replays\n * the head with the prior closed-bar's `(a, b)` pair so a partial-\n * bar value doesn't seed the next close's comparison.\n *\n * @formula out[t] = a[t] > b[t] && a[t − 1] ≤ b[t − 1] (else false)\n * @warmup 1 (need a prior bar)\n * @since 0.1\n * @stable\n *\n * `opts.offset` shifts the boolean series so `series.current` returns\n * the crossover detection `offset` bars ago.\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-runtime\";\n * // const c = ta.crossover(\"slot\", fastEma, slowEma);\n * // if (c.current) { ... }\n * // const lagged = ta.crossover(\"slot2\", fastEma, slowEma, { offset: 1 });\n */\nexport function crossover(\n slotId: string,\n a: ScalarOrSeries,\n b: ScalarOrSeries,\n opts?: CrossoverOpts,\n): Series<boolean> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as CrossSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const aValue = readSourceValue(a);\n const bValue = readSourceValue(b);\n const offset = opts?.offset ?? 0;\n if (ctx.isTick) {\n const out = detect(slot.prevA, slot.prevB, aValue, bValue);\n slot.outBuffer.replaceHead(out);\n return viewForOffset(slot, offset);\n }\n if (!slot.initialised) {\n slot.initialised = true;\n slot.prevA = aValue;\n slot.prevB = bValue;\n slot.currA = aValue;\n slot.currB = bValue;\n slot.outBuffer.append(false);\n return viewForOffset(slot, offset);\n }\n // Standard close-side advance: prev becomes currA/B, currA/B become the new sample.\n slot.prevA = slot.currA;\n slot.prevB = slot.currB;\n slot.currA = aValue;\n slot.currB = bValue;\n slot.outBuffer.append(detect(slot.prevA, slot.prevB, slot.currA, slot.currB));\n return viewForOffset(slot, offset);\n}\n"]}
1
+ {"version":3,"file":"crossover.js","sourceRoot":"","sources":["../../src/ta/crossover.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// No invinite source — Phase-1 new code, semantics per Pine\n// `ta.crossover` / `ta.crossunder`.\n// Structural choices (callsite-id slot, Series<T> proxy, replaceHead\n// mode) follow chartlang's primitive shape.\n\nimport type { CrossoverOpts, Series } from \"@invinite-org/chartlang-core\";\n\nimport { RingBuffer } 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 CrossSlot = {\n readonly outBuffer: RingBuffer<boolean>;\n readonly series: Series<boolean>;\n /** Prior closed-bar values of `a` and `b` (rolling 2-slot history). */\n prevA: number;\n prevB: number;\n /** As-of-current-close values, frozen so ticks replay against prior. */\n currA: number;\n currB: number;\n initialised: boolean;\n /** Per-offset Series-view cache; see `sma.ts` for the convention. */\n readonly shiftedViews: Map<number, Series<boolean>>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.crossover called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(capacity: number): CrossSlot {\n const outBuffer = new RingBuffer<boolean>(capacity);\n return {\n outBuffer,\n series: makeSeriesView<boolean>(outBuffer) as Series<boolean>,\n prevA: Number.NaN,\n prevB: Number.NaN,\n currA: Number.NaN,\n currB: Number.NaN,\n initialised: false,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: CrossSlot, offset: number): Series<boolean> {\n if (offset === 0) return slot.series;\n let view = slot.shiftedViews.get(offset);\n if (view === undefined) {\n view = makeShiftedSeriesView<boolean>(slot.outBuffer, offset) as Series<boolean>;\n slot.shiftedViews.set(offset, view);\n }\n return view;\n}\n\nfunction detect(prevA: number, prevB: number, currA: number, currB: number): boolean {\n if (\n !Number.isFinite(prevA) ||\n !Number.isFinite(prevB) ||\n !Number.isFinite(currA) ||\n !Number.isFinite(currB)\n ) {\n return false;\n }\n return currA > currB && prevA <= prevB;\n}\n\n/**\n * `true` exactly at the bar where `a` crosses above `b`: `a.current >\n * b.current && a.prev <= b.prev`. `b` may be a scalar (treated as a\n * constant series). NaN inputs yield `false` — Pine semantics for\n * Boolean series (NaN doesn't bubble through booleans).\n *\n * The slot keeps a 2-slot history of both `a` and `b` so scalar\n * sources work without the caller wrapping them. Tick-mode replays\n * the head with the prior closed-bar's `(a, b)` pair so a partial-\n * bar value doesn't seed the next close's comparison.\n *\n * @formula out[t] = a[t] > b[t] && a[t − 1] ≤ b[t − 1] (else false)\n * @warmup 1 (need a prior bar)\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 * boolean crossover series value is unshifted.\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-runtime\";\n * // const c = ta.crossover(\"slot\", fastEma, slowEma);\n * // if (c.current) { ... }\n * // const lagged = ta.crossover(\"slot2\", fastEma, slowEma, { offset: 1 });\n */\nexport function crossover(\n slotId: string,\n a: ScalarOrSeries,\n b: ScalarOrSeries,\n opts?: CrossoverOpts,\n): Series<boolean> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as CrossSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const aValue = readSourceValue(a);\n const bValue = readSourceValue(b);\n const offset = opts?.offset ?? 0;\n if (ctx.isTick) {\n const out = detect(slot.prevA, slot.prevB, aValue, bValue);\n slot.outBuffer.replaceHead(out);\n return viewForOffset(slot, offset);\n }\n if (!slot.initialised) {\n slot.initialised = true;\n slot.prevA = aValue;\n slot.prevB = bValue;\n slot.currA = aValue;\n slot.currB = bValue;\n slot.outBuffer.append(false);\n return viewForOffset(slot, offset);\n }\n // Standard close-side advance: prev becomes currA/B, currA/B become the new sample.\n slot.prevA = slot.currA;\n slot.prevB = slot.currB;\n slot.currA = aValue;\n slot.currB = bValue;\n slot.outBuffer.append(detect(slot.prevA, slot.prevB, slot.currA, slot.currB));\n return viewForOffset(slot, offset);\n}\n"]}
@@ -10,8 +10,9 @@ import { type ScalarOrSeries } from "./lib/sourceValue.js";
10
10
  * @since 0.1
11
11
  * @stable
12
12
  *
13
- * `opts.offset` shifts the boolean series so `series.current` returns
14
- * the crossunder detection `offset` bars ago.
13
+ * `opts.offset` is a presentation display shift carried to the plot
14
+ * emission as `xShift` (`+n` right / future, `−n` left / past); the
15
+ * boolean crossunder series value is unshifted.
15
16
  *
16
17
  * @example
17
18
  * // import { ta } from "@invinite-org/chartlang-runtime";
@@ -1 +1 @@
1
- {"version":3,"file":"crossunder.d.ts","sourceRoot":"","sources":["../../src/ta/crossunder.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAK3E,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AA0D5E;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CACtB,MAAM,EAAE,MAAM,EACd,CAAC,EAAE,cAAc,EACjB,CAAC,EAAE,cAAc,EACjB,IAAI,CAAC,EAAE,cAAc,GACtB,MAAM,CAAC,OAAO,CAAC,CA8BjB"}
1
+ {"version":3,"file":"crossunder.d.ts","sourceRoot":"","sources":["../../src/ta/crossunder.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAK3E,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AA0D5E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CACtB,MAAM,EAAE,MAAM,EACd,CAAC,EAAE,cAAc,EACjB,CAAC,EAAE,cAAc,EACjB,IAAI,CAAC,EAAE,cAAc,GACtB,MAAM,CAAC,OAAO,CAAC,CA8BjB"}
@@ -58,8 +58,9 @@ function detect(prevA, prevB, currA, currB) {
58
58
  * @since 0.1
59
59
  * @stable
60
60
  *
61
- * `opts.offset` shifts the boolean series so `series.current` returns
62
- * the crossunder detection `offset` bars ago.
61
+ * `opts.offset` is a presentation display shift carried to the plot
62
+ * emission as `xShift` (`+n` right / future, `−n` left / past); the
63
+ * boolean crossunder series value is unshifted.
63
64
  *
64
65
  * @example
65
66
  * // import { ta } from "@invinite-org/chartlang-runtime";
@@ -1 +1 @@
1
- {"version":3,"file":"crossunder.js","sourceRoot":"","sources":["../../src/ta/crossunder.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// No invinite source — Phase-1 new code, semantics per Pine\n// `ta.crossover` / `ta.crossunder`.\n// Structural choices (callsite-id slot, Series<T> proxy, replaceHead\n// mode) follow chartlang's primitive shape.\n\nimport type { CrossunderOpts, Series } from \"@invinite-org/chartlang-core\";\n\nimport { RingBuffer } 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 CrossSlot = {\n readonly outBuffer: RingBuffer<boolean>;\n readonly series: Series<boolean>;\n prevA: number;\n prevB: number;\n currA: number;\n currB: number;\n initialised: boolean;\n /** Per-offset Series-view cache; see `sma.ts` for the convention. */\n readonly shiftedViews: Map<number, Series<boolean>>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.crossunder called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(capacity: number): CrossSlot {\n const outBuffer = new RingBuffer<boolean>(capacity);\n return {\n outBuffer,\n series: makeSeriesView<boolean>(outBuffer) as Series<boolean>,\n prevA: Number.NaN,\n prevB: Number.NaN,\n currA: Number.NaN,\n currB: Number.NaN,\n initialised: false,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: CrossSlot, offset: number): Series<boolean> {\n if (offset === 0) return slot.series;\n let view = slot.shiftedViews.get(offset);\n if (view === undefined) {\n view = makeShiftedSeriesView<boolean>(slot.outBuffer, offset) as Series<boolean>;\n slot.shiftedViews.set(offset, view);\n }\n return view;\n}\n\nfunction detect(prevA: number, prevB: number, currA: number, currB: number): boolean {\n if (\n !Number.isFinite(prevA) ||\n !Number.isFinite(prevB) ||\n !Number.isFinite(currA) ||\n !Number.isFinite(currB)\n ) {\n return false;\n }\n return currA < currB && prevA >= prevB;\n}\n\n/**\n * `true` exactly at the bar where `a` crosses below `b`: `a.current <\n * b.current && a.prev >= b.prev`. Mirror of {@link crossover}; NaN\n * inputs yield `false`.\n *\n * @formula out[t] = a[t] < b[t] && a[t − 1] ≥ b[t − 1] (else false)\n * @warmup 1\n * @since 0.1\n * @stable\n *\n * `opts.offset` shifts the boolean series so `series.current` returns\n * the crossunder detection `offset` bars ago.\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-runtime\";\n * // const c = ta.crossunder(\"slot\", fastEma, slowEma);\n * // if (c.current) { ... }\n * // const lagged = ta.crossunder(\"slot2\", fastEma, slowEma, { offset: 1 });\n */\nexport function crossunder(\n slotId: string,\n a: ScalarOrSeries,\n b: ScalarOrSeries,\n opts?: CrossunderOpts,\n): Series<boolean> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as CrossSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const aValue = readSourceValue(a);\n const bValue = readSourceValue(b);\n const offset = opts?.offset ?? 0;\n if (ctx.isTick) {\n const out = detect(slot.prevA, slot.prevB, aValue, bValue);\n slot.outBuffer.replaceHead(out);\n return viewForOffset(slot, offset);\n }\n if (!slot.initialised) {\n slot.initialised = true;\n slot.prevA = aValue;\n slot.prevB = bValue;\n slot.currA = aValue;\n slot.currB = bValue;\n slot.outBuffer.append(false);\n return viewForOffset(slot, offset);\n }\n slot.prevA = slot.currA;\n slot.prevB = slot.currB;\n slot.currA = aValue;\n slot.currB = bValue;\n slot.outBuffer.append(detect(slot.prevA, slot.prevB, slot.currA, slot.currB));\n return viewForOffset(slot, offset);\n}\n"]}
1
+ {"version":3,"file":"crossunder.js","sourceRoot":"","sources":["../../src/ta/crossunder.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// No invinite source — Phase-1 new code, semantics per Pine\n// `ta.crossover` / `ta.crossunder`.\n// Structural choices (callsite-id slot, Series<T> proxy, replaceHead\n// mode) follow chartlang's primitive shape.\n\nimport type { CrossunderOpts, Series } from \"@invinite-org/chartlang-core\";\n\nimport { RingBuffer } 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 CrossSlot = {\n readonly outBuffer: RingBuffer<boolean>;\n readonly series: Series<boolean>;\n prevA: number;\n prevB: number;\n currA: number;\n currB: number;\n initialised: boolean;\n /** Per-offset Series-view cache; see `sma.ts` for the convention. */\n readonly shiftedViews: Map<number, Series<boolean>>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.crossunder called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(capacity: number): CrossSlot {\n const outBuffer = new RingBuffer<boolean>(capacity);\n return {\n outBuffer,\n series: makeSeriesView<boolean>(outBuffer) as Series<boolean>,\n prevA: Number.NaN,\n prevB: Number.NaN,\n currA: Number.NaN,\n currB: Number.NaN,\n initialised: false,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: CrossSlot, offset: number): Series<boolean> {\n if (offset === 0) return slot.series;\n let view = slot.shiftedViews.get(offset);\n if (view === undefined) {\n view = makeShiftedSeriesView<boolean>(slot.outBuffer, offset) as Series<boolean>;\n slot.shiftedViews.set(offset, view);\n }\n return view;\n}\n\nfunction detect(prevA: number, prevB: number, currA: number, currB: number): boolean {\n if (\n !Number.isFinite(prevA) ||\n !Number.isFinite(prevB) ||\n !Number.isFinite(currA) ||\n !Number.isFinite(currB)\n ) {\n return false;\n }\n return currA < currB && prevA >= prevB;\n}\n\n/**\n * `true` exactly at the bar where `a` crosses below `b`: `a.current <\n * b.current && a.prev >= b.prev`. Mirror of {@link crossover}; NaN\n * inputs yield `false`.\n *\n * @formula out[t] = a[t] < b[t] && a[t − 1] ≥ b[t − 1] (else false)\n * @warmup 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 * boolean crossunder series value is unshifted.\n *\n * @example\n * // import { ta } from \"@invinite-org/chartlang-runtime\";\n * // const c = ta.crossunder(\"slot\", fastEma, slowEma);\n * // if (c.current) { ... }\n * // const lagged = ta.crossunder(\"slot2\", fastEma, slowEma, { offset: 1 });\n */\nexport function crossunder(\n slotId: string,\n a: ScalarOrSeries,\n b: ScalarOrSeries,\n opts?: CrossunderOpts,\n): Series<boolean> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as CrossSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const aValue = readSourceValue(a);\n const bValue = readSourceValue(b);\n const offset = opts?.offset ?? 0;\n if (ctx.isTick) {\n const out = detect(slot.prevA, slot.prevB, aValue, bValue);\n slot.outBuffer.replaceHead(out);\n return viewForOffset(slot, offset);\n }\n if (!slot.initialised) {\n slot.initialised = true;\n slot.prevA = aValue;\n slot.prevB = bValue;\n slot.currA = aValue;\n slot.currB = bValue;\n slot.outBuffer.append(false);\n return viewForOffset(slot, offset);\n }\n slot.prevA = slot.currA;\n slot.prevB = slot.currB;\n slot.currA = aValue;\n slot.currB = bValue;\n slot.outBuffer.append(detect(slot.prevA, slot.prevB, slot.currA, slot.currB));\n return viewForOffset(slot, offset);\n}\n"]}
package/dist/ta/dmi.d.ts CHANGED
@@ -22,9 +22,10 @@ import type { DmiOpts, DmiResult } from "@invinite-org/chartlang-core";
22
22
  * @since 0.2
23
23
  * @stable
24
24
  *
25
- * `opts.offset` shifts both series in lockstep
26
- * `series.current` on each output returns the value `offset` bars
27
- * ago.
25
+ * `opts.offset` is a presentation display shift carried to the plot
26
+ * emission as `xShift` for both series in lockstep (`+n` right / future,
27
+ * `−n` left / past); the series values are unshifted, so
28
+ * `series.current` on each output returns the value at the current bar.
28
29
  *
29
30
  * @example
30
31
  * // import { ta } from "@invinite-org/chartlang-runtime";
@@ -1 +1 @@
1
- {"version":3,"file":"dmi.d.ts","sourceRoot":"","sources":["../../src/ta/dmi.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AA8DvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAuB7E"}
1
+ {"version":3,"file":"dmi.d.ts","sourceRoot":"","sources":["../../src/ta/dmi.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AA8DvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAuB7E"}
package/dist/ta/dmi.js CHANGED
@@ -74,9 +74,10 @@ function resultForOffset(slot, offset) {
74
74
  * @since 0.2
75
75
  * @stable
76
76
  *
77
- * `opts.offset` shifts both series in lockstep
78
- * `series.current` on each output returns the value `offset` bars
79
- * ago.
77
+ * `opts.offset` is a presentation display shift carried to the plot
78
+ * emission as `xShift` for both series in lockstep (`+n` right / future,
79
+ * `−n` left / past); the series values are unshifted, so
80
+ * `series.current` on each output returns the value at the current bar.
80
81
  *
81
82
  * @example
82
83
  * // import { ta } from "@invinite-org/chartlang-runtime";
@@ -1 +1 @@
1
- {"version":3,"file":"dmi.js","sourceRoot":"","sources":["../../src/ta/dmi.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/dmi.ts\n// plus lib/wilder-directional.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. DMI reads `bar.high` / `bar.low` / `bar.close`\n// directly (mirrors Pine's `ta.dmi(length)` which has no source param)\n// and runs the Wilder +DM / -DM / TR smoothing incrementally via\n// `wilderStep` (the same per-step recurrence the reference\n// `lib/wilderDirectional.ts` uses internally).\n\nimport type { DmiOpts, DmiResult } 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 {\n advanceDirectionalClose,\n type DirectionalState,\n initDirectionalState,\n tickDirectional,\n} from \"./lib/directionalState.js\";\n\ntype DmiSlot = {\n readonly result: DmiResult;\n readonly plusDiBuffer: Float64RingBuffer;\n readonly minusDiBuffer: Float64RingBuffer;\n readonly dirState: DirectionalState;\n /**\n * Per-offset frozen `DmiResult` 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, DmiResult>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.dmi called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(length: number, capacity: number): DmiSlot {\n const plusDiBuffer = new Float64RingBuffer(capacity);\n const minusDiBuffer = new Float64RingBuffer(capacity);\n return {\n result: Object.freeze({\n plusDi: makeSeriesView<number>(plusDiBuffer),\n minusDi: makeSeriesView<number>(minusDiBuffer),\n }),\n plusDiBuffer,\n minusDiBuffer,\n dirState: initDirectionalState(length),\n shiftedResults: new Map(),\n };\n}\n\nfunction resultForOffset(slot: DmiSlot, offset: number): DmiResult {\n if (offset === 0) return slot.result;\n let cached = slot.shiftedResults.get(offset);\n if (cached === undefined) {\n cached = Object.freeze({\n plusDi: makeShiftedSeriesView<number>(slot.plusDiBuffer, offset),\n minusDi: makeShiftedSeriesView<number>(slot.minusDiBuffer, offset),\n });\n slot.shiftedResults.set(offset, cached);\n }\n return cached;\n}\n\n/**\n * Wilder's Directional Movement Index — `+DI` / `−DI` pair derived\n * from the Wilder-smoothed `+DM` / `−DM` over the smoothed True\n * Range. Reads `bar.high` / `bar.low` / `bar.close` directly\n * (mirrors Pine's `ta.dmi(length)` — no source param). Both series\n * ∈ [0, 100] when defined; NaN until `length` closed bars have\n * folded into the seed window. The first defined value lands at\n * bar index `length` (counted zero-based — matches the\n * full-recompute reference in `lib/wilderDirectional.ts`).\n *\n * @formula TR[t] = max(high − low, |high − prevClose|, |low − prevClose|) ;\n * upMove = high[t] − high[t−1] ; downMove = low[t−1] − low[t] ;\n * +DM = upMove > downMove && upMove > 0 ? upMove : 0 ;\n * −DM = downMove > upMove && downMove > 0 ? downMove : 0 ;\n * seed at bar `length` = simple sum over the seed window ;\n * smoothed via wilderStep(α = 1/length) thereafter ;\n * +DI = 100 · smoothed+DM / smoothedTR ;\n * −DI = 100 · smoothed−DM / smoothedTR ;\n * DI falls back to 0 when smoothedTR is 0 (matches invinite).\n * @warmup length\n * @since 0.2\n * @stable\n *\n * `opts.offset` shifts both series 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 d = ta.dmi(\"slot\", 14);\n * // plot(d.plusDi);\n * // plot(d.minusDi);\n */\nexport function dmi(slotId: string, length: number, opts?: DmiOpts): DmiResult {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as DmiSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(length, ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const bar = ctx.stream.bar;\n if (ctx.isTick) {\n const { plusDi, minusDi } = tickDirectional(slot.dirState, bar.high, bar.low, bar.close);\n slot.plusDiBuffer.replaceHead(plusDi);\n slot.minusDiBuffer.replaceHead(minusDi);\n } else {\n const { plusDi, minusDi } = advanceDirectionalClose(\n slot.dirState,\n bar.high,\n bar.low,\n bar.close,\n );\n slot.plusDiBuffer.append(plusDi);\n slot.minusDiBuffer.append(minusDi);\n }\n return resultForOffset(slot, opts?.offset ?? 0);\n}\n"]}
1
+ {"version":3,"file":"dmi.js","sourceRoot":"","sources":["../../src/ta/dmi.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/dmi.ts\n// plus lib/wilder-directional.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. DMI reads `bar.high` / `bar.low` / `bar.close`\n// directly (mirrors Pine's `ta.dmi(length)` which has no source param)\n// and runs the Wilder +DM / -DM / TR smoothing incrementally via\n// `wilderStep` (the same per-step recurrence the reference\n// `lib/wilderDirectional.ts` uses internally).\n\nimport type { DmiOpts, DmiResult } 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 {\n advanceDirectionalClose,\n type DirectionalState,\n initDirectionalState,\n tickDirectional,\n} from \"./lib/directionalState.js\";\n\ntype DmiSlot = {\n readonly result: DmiResult;\n readonly plusDiBuffer: Float64RingBuffer;\n readonly minusDiBuffer: Float64RingBuffer;\n readonly dirState: DirectionalState;\n /**\n * Per-offset frozen `DmiResult` 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, DmiResult>;\n};\n\nfunction getCtx(): RuntimeContext {\n const ctx = ACTIVE_RUNTIME_CONTEXT.current;\n if (ctx === null) {\n throw new Error(\"ta.dmi called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(length: number, capacity: number): DmiSlot {\n const plusDiBuffer = new Float64RingBuffer(capacity);\n const minusDiBuffer = new Float64RingBuffer(capacity);\n return {\n result: Object.freeze({\n plusDi: makeSeriesView<number>(plusDiBuffer),\n minusDi: makeSeriesView<number>(minusDiBuffer),\n }),\n plusDiBuffer,\n minusDiBuffer,\n dirState: initDirectionalState(length),\n shiftedResults: new Map(),\n };\n}\n\nfunction resultForOffset(slot: DmiSlot, offset: number): DmiResult {\n if (offset === 0) return slot.result;\n let cached = slot.shiftedResults.get(offset);\n if (cached === undefined) {\n cached = Object.freeze({\n plusDi: makeShiftedSeriesView<number>(slot.plusDiBuffer, offset),\n minusDi: makeShiftedSeriesView<number>(slot.minusDiBuffer, offset),\n });\n slot.shiftedResults.set(offset, cached);\n }\n return cached;\n}\n\n/**\n * Wilder's Directional Movement Index — `+DI` / `−DI` pair derived\n * from the Wilder-smoothed `+DM` / `−DM` over the smoothed True\n * Range. Reads `bar.high` / `bar.low` / `bar.close` directly\n * (mirrors Pine's `ta.dmi(length)` — no source param). Both series\n * ∈ [0, 100] when defined; NaN until `length` closed bars have\n * folded into the seed window. The first defined value lands at\n * bar index `length` (counted zero-based — matches the\n * full-recompute reference in `lib/wilderDirectional.ts`).\n *\n * @formula TR[t] = max(high − low, |high − prevClose|, |low − prevClose|) ;\n * upMove = high[t] − high[t−1] ; downMove = low[t−1] − low[t] ;\n * +DM = upMove > downMove && upMove > 0 ? upMove : 0 ;\n * −DM = downMove > upMove && downMove > 0 ? downMove : 0 ;\n * seed at bar `length` = simple sum over the seed window ;\n * smoothed via wilderStep(α = 1/length) thereafter ;\n * +DI = 100 · smoothed+DM / smoothedTR ;\n * −DI = 100 · smoothed−DM / smoothedTR ;\n * DI falls back to 0 when smoothedTR is 0 (matches invinite).\n * @warmup length\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 series 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 d = ta.dmi(\"slot\", 14);\n * // plot(d.plusDi);\n * // plot(d.minusDi);\n */\nexport function dmi(slotId: string, length: number, opts?: DmiOpts): DmiResult {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as DmiSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(length, ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const bar = ctx.stream.bar;\n if (ctx.isTick) {\n const { plusDi, minusDi } = tickDirectional(slot.dirState, bar.high, bar.low, bar.close);\n slot.plusDiBuffer.replaceHead(plusDi);\n slot.minusDiBuffer.replaceHead(minusDi);\n } else {\n const { plusDi, minusDi } = advanceDirectionalClose(\n slot.dirState,\n bar.high,\n bar.low,\n bar.close,\n );\n slot.plusDiBuffer.append(plusDi);\n slot.minusDiBuffer.append(minusDi);\n }\n return resultForOffset(slot, opts?.offset ?? 0);\n}\n"]}
package/dist/ta/ema.d.ts CHANGED
@@ -14,8 +14,9 @@ import { type ScalarOrSeries } from "./lib/sourceValue.js";
14
14
  * @since 0.1
15
15
  * @stable
16
16
  *
17
- * `opts.offset` shifts the returned series so `series.current` reads
18
- * the value `offset` bars ago.
17
+ * `opts.offset` is a presentation display shift carried to the plot
18
+ * emission as `xShift` (`+n` right / future, `−n` left / past); the
19
+ * series value is unshifted.
19
20
  *
20
21
  * @example
21
22
  * // import { ta } from "@invinite-org/chartlang-runtime";
@@ -1 +1 @@
1
- {"version":3,"file":"ema.d.ts","sourceRoot":"","sources":["../../src/ta/ema.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAKpE,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AAiF5E;;;;;;;;;;;;;;;;;;;;;;GAsBG;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,CAWhB"}
1
+ {"version":3,"file":"ema.d.ts","sourceRoot":"","sources":["../../src/ta/ema.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAKpE,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AAiF5E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;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,CAWhB"}
package/dist/ta/ema.js CHANGED
@@ -90,8 +90,9 @@ function compute(slot, src, isTick) {
90
90
  * @since 0.1
91
91
  * @stable
92
92
  *
93
- * `opts.offset` shifts the returned series so `series.current` reads
94
- * the value `offset` bars ago.
93
+ * `opts.offset` is a presentation display shift carried to the plot
94
+ * emission as `xShift` (`+n` right / future, `−n` left / past); the
95
+ * series value is unshifted.
95
96
  *
96
97
  * @example
97
98
  * // import { ta } from "@invinite-org/chartlang-runtime";
@@ -1 +1 @@
1
- {"version":3,"file":"ema.js","sourceRoot":"","sources":["../../src/ta/ema.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/ema.ts\n// plus lib/ema-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 { EmaOpts, 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 { type ScalarOrSeries, readSourceValue } from \"./lib/sourceValue.js\";\n\ntype EmaSlot = {\n readonly kind: \"ta.ema\";\n readonly outBuffer: Float64RingBuffer;\n readonly series: Series<number>;\n readonly alpha: number;\n readonly length: number;\n seedSum: number;\n seedCount: number;\n prevEma: number;\n prevClosedEma: 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.ema called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(length: number, capacity: number): EmaSlot {\n const outBuffer = new Float64RingBuffer(capacity);\n return {\n kind: \"ta.ema\",\n outBuffer,\n series: makeSeriesView<number>(outBuffer),\n alpha: 2 / (length + 1),\n length,\n seedSum: 0,\n seedCount: 0,\n prevEma: Number.NaN,\n prevClosedEma: Number.NaN,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: EmaSlot, 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 compute(slot: EmaSlot, src: number, isTick: boolean): number {\n if (!Number.isFinite(src)) {\n return isTick ? slot.prevEma : slot.prevClosedEma;\n }\n if (slot.seedCount < slot.length) {\n if (isTick) {\n const nextSum = slot.seedSum + src;\n const nextCount = slot.seedCount + 1;\n if (nextCount < slot.length) return Number.NaN;\n return nextSum / slot.length;\n }\n slot.seedSum += src;\n slot.seedCount += 1;\n if (slot.seedCount < slot.length) {\n slot.prevClosedEma = Number.NaN;\n return Number.NaN;\n }\n const seedValue = slot.seedSum / slot.length;\n slot.prevClosedEma = seedValue;\n slot.prevEma = seedValue;\n return seedValue;\n }\n const prev = slot.prevClosedEma;\n const next = src * slot.alpha + prev * (1 - slot.alpha);\n if (!isTick) {\n slot.prevClosedEma = next;\n slot.prevEma = next;\n }\n return next;\n}\n\n/**\n * Exponential moving average. Recurrence `EMA[t] = α·x[t] + (1 − α)·EMA[t − 1]`\n * with `α = 2 / (length + 1)` after a seed of `simple mean of the first\n * `length` finite source values`. Tick-mode (`onBarTick`) recomputes the\n * head from the previous closed EMA so partial-bar values don't bleed\n * into the next close's recurrence.\n *\n * @formula α = 2 / (length + 1) ;\n * seed at bar length−1 = mean(source[0..length−1]) ;\n * EMA[t] = source[t]·α + EMA[t−1]·(1−α)\n * @warmup length − 1\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 e = ta.ema(\"slot-id\", bar.close, 20);\n * // const head = e.current; // NaN until bar length-1\n * // const projected = ta.ema(\"slot2\", bar.close, 20, { offset: 5 });\n */\nexport function ema(\n slotId: string,\n source: ScalarOrSeries,\n length: number,\n opts?: EmaOpts,\n): Series<number> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as EmaSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(length, ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const value = compute(slot, readSourceValue(source), ctx.isTick);\n if (ctx.isTick) slot.outBuffer.replaceHead(value);\n else slot.outBuffer.append(value);\n return viewForOffset(slot, opts?.offset ?? 0);\n}\n"]}
1
+ {"version":3,"file":"ema.js","sourceRoot":"","sources":["../../src/ta/ema.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/ema.ts\n// plus lib/ema-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 { EmaOpts, 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 { type ScalarOrSeries, readSourceValue } from \"./lib/sourceValue.js\";\n\ntype EmaSlot = {\n readonly kind: \"ta.ema\";\n readonly outBuffer: Float64RingBuffer;\n readonly series: Series<number>;\n readonly alpha: number;\n readonly length: number;\n seedSum: number;\n seedCount: number;\n prevEma: number;\n prevClosedEma: 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.ema called outside an active script step\");\n }\n return ctx;\n}\n\nfunction initSlot(length: number, capacity: number): EmaSlot {\n const outBuffer = new Float64RingBuffer(capacity);\n return {\n kind: \"ta.ema\",\n outBuffer,\n series: makeSeriesView<number>(outBuffer),\n alpha: 2 / (length + 1),\n length,\n seedSum: 0,\n seedCount: 0,\n prevEma: Number.NaN,\n prevClosedEma: Number.NaN,\n shiftedViews: new Map(),\n };\n}\n\nfunction viewForOffset(slot: EmaSlot, 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 compute(slot: EmaSlot, src: number, isTick: boolean): number {\n if (!Number.isFinite(src)) {\n return isTick ? slot.prevEma : slot.prevClosedEma;\n }\n if (slot.seedCount < slot.length) {\n if (isTick) {\n const nextSum = slot.seedSum + src;\n const nextCount = slot.seedCount + 1;\n if (nextCount < slot.length) return Number.NaN;\n return nextSum / slot.length;\n }\n slot.seedSum += src;\n slot.seedCount += 1;\n if (slot.seedCount < slot.length) {\n slot.prevClosedEma = Number.NaN;\n return Number.NaN;\n }\n const seedValue = slot.seedSum / slot.length;\n slot.prevClosedEma = seedValue;\n slot.prevEma = seedValue;\n return seedValue;\n }\n const prev = slot.prevClosedEma;\n const next = src * slot.alpha + prev * (1 - slot.alpha);\n if (!isTick) {\n slot.prevClosedEma = next;\n slot.prevEma = next;\n }\n return next;\n}\n\n/**\n * Exponential moving average. Recurrence `EMA[t] = α·x[t] + (1 − α)·EMA[t − 1]`\n * with `α = 2 / (length + 1)` after a seed of `simple mean of the first\n * `length` finite source values`. Tick-mode (`onBarTick`) recomputes the\n * head from the previous closed EMA so partial-bar values don't bleed\n * into the next close's recurrence.\n *\n * @formula α = 2 / (length + 1) ;\n * seed at bar length−1 = mean(source[0..length−1]) ;\n * EMA[t] = source[t]·α + EMA[t−1]·(1−α)\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 e = ta.ema(\"slot-id\", bar.close, 20);\n * // const head = e.current; // NaN until bar length-1\n * // const projected = ta.ema(\"slot2\", bar.close, 20, { offset: 5 });\n */\nexport function ema(\n slotId: string,\n source: ScalarOrSeries,\n length: number,\n opts?: EmaOpts,\n): Series<number> {\n const ctx = getCtx();\n let slot = ctx.stream.taSlots.get(slotId) as EmaSlot | undefined;\n if (slot === undefined) {\n slot = initSlot(length, ctx.stream.ohlcv.close.capacity);\n ctx.stream.taSlots.set(slotId, slot);\n }\n const value = compute(slot, readSourceValue(source), ctx.isTick);\n if (ctx.isTick) slot.outBuffer.replaceHead(value);\n else slot.outBuffer.append(value);\n return viewForOffset(slot, opts?.offset ?? 0);\n}\n"]}
package/dist/ta/eom.d.ts CHANGED
@@ -24,7 +24,9 @@ import type { EomOpts, Series } from "@invinite-org/chartlang-core";
24
24
  * @since 0.2
25
25
  * @stable
26
26
  *
27
- * `opts.offset` shifts the returned series.
27
+ * `opts.offset` is a presentation display shift carried to the plot
28
+ * emission as `xShift` (`+n` right / future, `−n` left / past); the
29
+ * series value is unshifted.
28
30
  *
29
31
  * @example
30
32
  * // import { ta, plot } from "@invinite-org/chartlang-core";
@@ -1 +1 @@
1
- {"version":3,"file":"eom.d.ts","sourceRoot":"","sources":["../../src/ta/eom.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAyGpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAiElF"}
1
+ {"version":3,"file":"eom.d.ts","sourceRoot":"","sources":["../../src/ta/eom.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAyGpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAiElF"}
package/dist/ta/eom.js CHANGED
@@ -111,7 +111,9 @@ function emit(slot, ready) {
111
111
  * @since 0.2
112
112
  * @stable
113
113
  *
114
- * `opts.offset` shifts the returned series.
114
+ * `opts.offset` is a presentation display shift carried to the plot
115
+ * emission as `xShift` (`+n` right / future, `−n` left / past); the
116
+ * series value is unshifted.
115
117
  *
116
118
  * @example
117
119
  * // import { ta, plot } from "@invinite-org/chartlang-core";