@alphacharts/indicators 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -2
  3. package/dist/all-_xzUPrL7.js +21 -0
  4. package/dist/all-_xzUPrL7.js.map +1 -0
  5. package/dist/all.js +10 -0
  6. package/dist/all.js.map +1 -0
  7. package/dist/define-XUgQMhSl.js +687 -0
  8. package/dist/define-XUgQMhSl.js.map +1 -0
  9. package/dist/index.js +744 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/registry-DdYYyZN_.js +53 -0
  12. package/dist/registry-DdYYyZN_.js.map +1 -0
  13. package/dist/runner-B53M0IsJ.js +237 -0
  14. package/dist/runner-B53M0IsJ.js.map +1 -0
  15. package/dist/studies.js +1 -0
  16. package/dist/tv-volume-BYSbfrVk.js +3454 -0
  17. package/dist/tv-volume-BYSbfrVk.js.map +1 -0
  18. package/dist/types/all.d.ts +3 -0
  19. package/dist/types/chart/marker-floor.d.ts +9 -0
  20. package/dist/types/chart/studies.d.ts +192 -0
  21. package/dist/types/define.d.ts +46 -0
  22. package/dist/types/engine/feed.d.ts +88 -0
  23. package/dist/types/engine/graph.d.ts +136 -0
  24. package/dist/types/engine/kernels.d.ts +9 -0
  25. package/dist/types/engine/study.d.ts +40 -0
  26. package/dist/types/index.d.ts +15 -0
  27. package/dist/types/registry.d.ts +7 -0
  28. package/dist/types/runner.d.ts +91 -0
  29. package/dist/types/studies/all.d.ts +2 -0
  30. package/dist/types/studies/cycle.d.ts +7 -0
  31. package/dist/types/studies/index.d.ts +13 -0
  32. package/dist/types/studies/ma.d.ts +26 -0
  33. package/dist/types/studies/math.d.ts +28 -0
  34. package/dist/types/studies/momentum.d.ts +30 -0
  35. package/dist/types/studies/overlap.d.ts +14 -0
  36. package/dist/types/studies/patterns.d.ts +62 -0
  37. package/dist/types/studies/price.d.ts +6 -0
  38. package/dist/types/studies/sar.d.ts +2 -0
  39. package/dist/types/studies/statistic.d.ts +9 -0
  40. package/dist/types/studies/tv-osc.d.ts +18 -0
  41. package/dist/types/studies/tv-trend.d.ts +20 -0
  42. package/dist/types/studies/tv-volume.d.ts +15 -0
  43. package/dist/types/studies/volatility.d.ts +3 -0
  44. package/dist/types/studies/volume.d.ts +3 -0
  45. package/dist/types/types.d.ts +169 -0
  46. package/dist/types/wasm.d.ts +2 -0
  47. package/dist/types/worker.d.ts +1 -0
  48. package/dist/worker.js +8 -0
  49. package/dist/worker.js.map +1 -0
  50. package/package.json +72 -3
package/dist/index.js ADDED
@@ -0,0 +1,744 @@
1
+ import { S as e, _ as t, b as n, g as r, h as i, i as a, m as o, v as s, x as c, y as l } from "./define-XUgQMhSl.js";
2
+ import { a as u, c as d, i as f, l as p, n as m, o as h, r as g, s as _, t as v } from "./runner-B53M0IsJ.js";
3
+ import { a as y, i as b, n as x, r as S, t as C } from "./registry-DdYYyZN_.js";
4
+ import { BarShading as w, COL_C as T, COL_H as E, COL_L as D, COL_O as O, COL_V as k, cssColor as A, parseColor as j } from "@alphacharts/core";
5
+ import { loadKernels as M } from "@alphacharts/wasm";
6
+ //#region src/chart/marker-floor.ts
7
+ var N = (e, t) => e !== void 0 && e === e && !(t && e === 0);
8
+ function P(e, t, n) {
9
+ let r = n.within === void 0 ? 0 : Math.max(0, t - n.within);
10
+ if (n.last !== void 0) {
11
+ let i = 0;
12
+ for (let a = t - 1; a >= r; a--) if (N(e[a], !!n.text) && ++i === n.last) return a;
13
+ }
14
+ return r;
15
+ }
16
+ //#endregion
17
+ //#region src/chart/studies.ts
18
+ var F = "alphacharts.studies", I = class {
19
+ host;
20
+ id;
21
+ source;
22
+ volume;
23
+ ownRunner;
24
+ onDispose;
25
+ def;
26
+ params;
27
+ engine;
28
+ outs = [];
29
+ lines = [];
30
+ shades = [];
31
+ feeds = /* @__PURE__ */ new Map();
32
+ sameScale = !0;
33
+ styles = {};
34
+ shown = !0;
35
+ pane = 0;
36
+ scaleId = "right";
37
+ version = 0;
38
+ job = null;
39
+ dirty = !1;
40
+ structural = !1;
41
+ error = null;
42
+ ready_ = Promise.resolve();
43
+ disposed = !1;
44
+ decimals = 2;
45
+ persist = !0;
46
+ constructor(e, t, n, r, i, a, o, s, c) {
47
+ this.host = e, this.id = t, this.source = i, this.volume = a, this.ownRunner = s, this.onDispose = c, this.def = n, this.params = d(n, r), this.engine = new _(n, this.params), this.checkSource(), o?.styles && (this.styles = { ...o.styles }), o?.visible === !1 && (this.shown = !1), this.createSeries(), this.recompute();
48
+ }
49
+ inputs() {
50
+ return this.params;
51
+ }
52
+ get visible() {
53
+ return this.shown;
54
+ }
55
+ ready() {
56
+ return this.ready_;
57
+ }
58
+ refresh(e = !0) {
59
+ this.disposed || this.error || this.engine.length === 0 || (e ? this.tickSync() : this.syncAll(), this.host.api?.requestRender(!0));
60
+ }
61
+ series() {
62
+ return this.outs.map((e) => e.series);
63
+ }
64
+ setInputs(e, t = []) {
65
+ let n = { ...this.params };
66
+ for (let e of t) delete n[e];
67
+ let r = d(this.def, {
68
+ ...n,
69
+ ...e
70
+ });
71
+ for (let e of this.def.plots) if (e.kind === "line" && typeof e.offset == "function" && R(e, this.params) !== R(e, r)) throw TypeError(`${e.title}: this input would move its line between the pane and the overlay; add the study again`);
72
+ let i = new _(this.def, r);
73
+ this.params = r;
74
+ for (let e of this.outs) e.plot.kind === "line" && (e.offset = L(e.plot, r));
75
+ this.engine = i, this.retitle(), this.recompute(), this.host.changed();
76
+ }
77
+ setVisible(e) {
78
+ this.shown = e;
79
+ for (let t of this.outs) t.series.applyOptions({ visible: e });
80
+ for (let t of this.shades) t.prim.setVisible(e);
81
+ this.hasBarColor() && this.host.syncBarColors(this.source), this.host.changed();
82
+ }
83
+ setStyle(e, t) {
84
+ t.color !== void 0 && j(t.color), this.styles[e] = {
85
+ ...this.styles[e],
86
+ ...t
87
+ };
88
+ for (let t of this.outs) t.key.split(":")[0] === e && t.series.applyOptions(this.seriesOptions(t.plot, t.key));
89
+ !this.job && this.engine.length > 0 && (this.shades.length > 0 || this.hasBarColor()) && this.syncOverlays(), this.host.changed();
90
+ }
91
+ remove() {
92
+ this.host.removeStudy(this.id);
93
+ }
94
+ lastValues() {
95
+ let e = this.engine.length, t = {};
96
+ return this.def.columns.forEach((n, r) => {
97
+ let i = e > 0 ? this.engine.column(r)[e - 1] : NaN;
98
+ t[n] = i === i ? i : void 0;
99
+ }), t;
100
+ }
101
+ column(e) {
102
+ let t = this.def.columns.indexOf(e);
103
+ if (t < 0) throw RangeError(`${this.def.id} has no column "${e}"`);
104
+ return this.engine.column(t);
105
+ }
106
+ times() {
107
+ return this.engine.graph.time.v.subarray(0, this.engine.length);
108
+ }
109
+ state() {
110
+ return {
111
+ id: this.id,
112
+ study: this.def.id,
113
+ inputs: { ...this.params },
114
+ source: this.source.options().id,
115
+ ...this.volume && { volume: this.volume.options().id },
116
+ visible: this.shown,
117
+ styles: this.styles
118
+ };
119
+ }
120
+ drop() {
121
+ this.disposed || this.onDispose?.(), this.disposed = !0, this.job?.cancel();
122
+ }
123
+ dispose(e) {
124
+ this.drop();
125
+ for (let { series: t, line: n } of this.lines) e.removePriceLine(t, n);
126
+ for (let e of this.shades) e.anchor.detachPrimitive(e.prim);
127
+ for (let t of this.outs) e.removeSeries(t.series);
128
+ this.outs = [], this.lines = [], this.shades = [];
129
+ }
130
+ setFeed(e, t, r) {
131
+ let i = this.feeds.get(e);
132
+ i || this.feeds.set(e, i = new n()), i.load(t, r, `outside series ${e}`), this.recompute(), this.host.changed();
133
+ }
134
+ feedKeys() {
135
+ return [...this.feeds.keys()];
136
+ }
137
+ pushFeedBar(e, t) {
138
+ let n = this.feeds.get(e);
139
+ if (!n) throw RangeError(`${this.def.id}: no outside series "${e}"; give it with setFeed first`);
140
+ if (n.apply(t, `outside series ${e}`), this.disposed || this.error) return;
141
+ if (this.job) {
142
+ this.structural = !0;
143
+ return;
144
+ }
145
+ let r = this.ownRunner ?? this.host.runner;
146
+ r?.canRun(this.def) ? r.feedBar?.(this.def, e, t) : this.engine.pushFeed(e, t) && (this.tickSync(), this.host.api?.requestRender());
147
+ }
148
+ hasBarColor() {
149
+ return this.def.plots.some((e) => e.kind === "barcolor");
150
+ }
151
+ barColorSource() {
152
+ return this.source;
153
+ }
154
+ barColorAt(e) {
155
+ let t = this.engine, n = 0;
156
+ if (e < 0) return n;
157
+ for (let r of this.def.plots) {
158
+ if (r.kind !== "barcolor") continue;
159
+ let i = t.outputs[this.def.columns.indexOf(r.col)].v[e];
160
+ i === i && i !== 0 && (n = j(this.color(r)));
161
+ }
162
+ return n;
163
+ }
164
+ barColors() {
165
+ let e = this.engine.length, t = new Uint32Array(e);
166
+ for (let n = 0; n < e; n++) t[n] = this.barColorAt(n);
167
+ return {
168
+ time: this.engine.graph.time.v.slice(0, e),
169
+ color: t
170
+ };
171
+ }
172
+ rowOf(e) {
173
+ let t = this.engine.length;
174
+ return t > 0 && this.engine.graph.time.v[t - 1] === e ? t - 1 : -1;
175
+ }
176
+ lastTime() {
177
+ let e = this.engine.length;
178
+ return e > 0 ? this.engine.graph.time.v[e - 1] : NaN;
179
+ }
180
+ get isShown() {
181
+ return this.shown && !this.error && !this.disposed;
182
+ }
183
+ get ohlc() {
184
+ return this.source.data.shape === "ohlc";
185
+ }
186
+ checkSource() {
187
+ let e = this.def.needs;
188
+ if (!this.ohlc) {
189
+ if (e !== "value") throw TypeError(`${this.def.id} needs ${e} bars; the source series holds single values`);
190
+ if (this.params.source !== void 0 && this.params.source !== "close") throw RangeError(`${this.def.id}: a single-value source has only "close", not "${this.params.source}"`);
191
+ }
192
+ if (e === "ohlcv" && !this.volume) throw TypeError(`${this.def.id} needs volume: pass the volume series as options.volume`);
193
+ if (!this.ohlc && this.def.plots.some((e) => e.kind === "barcolor")) throw TypeError(`${this.def.id} colours bars; the source series holds single values, not candles or bars`);
194
+ }
195
+ watches(e) {
196
+ return e === this.source.data ? "source" : this.volume && e === this.volume.data ? "volume" : null;
197
+ }
198
+ bars() {
199
+ let e = this.host.chart, t = this.source.data, n = t.store, r = 0;
200
+ for (let e = n.first; e < n.end; e++) t.has(e) && r++;
201
+ let i = new Float64Array(r), a = new Float64Array(r), o = this.ohlc, s = o ? new Float64Array(r) : void 0, c = o ? new Float64Array(r) : void 0, l = o ? new Float64Array(r) : void 0, u = this.volume ? new Float64Array(r) : void 0, d = 0;
202
+ for (let r = n.first; r < n.end; r++) t.has(r) && (i[d] = e.logicalToTime(r), o ? (s[d] = t.get(r, O), c[d] = t.get(r, E), l[d] = t.get(r, D), a[d] = t.get(r, T)) : a[d] = t.get(r, k), u && (u[d] = this.volume.data.get(r, k)), d++);
203
+ return {
204
+ time: i,
205
+ close: a,
206
+ ...o && {
207
+ open: s,
208
+ high: c,
209
+ low: l
210
+ },
211
+ ...u && { volume: u }
212
+ };
213
+ }
214
+ barAt(e) {
215
+ let t = this.source.data, n = NaN;
216
+ return {
217
+ time: this.host.chart.logicalToTime(e),
218
+ open: this.ohlc ? t.get(e, O) : n,
219
+ high: this.ohlc ? t.get(e, E) : n,
220
+ low: this.ohlc ? t.get(e, D) : n,
221
+ close: this.ohlc ? t.get(e, T) : t.get(e, k),
222
+ volume: this.volume ? this.volume.data.get(e, k) : n
223
+ };
224
+ }
225
+ onChange(e) {
226
+ if (this.disposed || this.error || e.kind === "color") return;
227
+ let t = this.watches(e.series);
228
+ if (e.series === null || !t) return;
229
+ if (this.job) {
230
+ e.kind === "update" ? this.dirty = !0 : this.structural = !0;
231
+ return;
232
+ }
233
+ if (e.kind !== "update") {
234
+ this.recompute();
235
+ return;
236
+ }
237
+ let n = this.source.data.lastIndex();
238
+ if (n === void 0) return this.recompute();
239
+ if (t === "volume" && e.lo > n) return;
240
+ if (t === "volume" && e.lo < n) return this.recompute();
241
+ let r = this.barAt(n), i = this.engine, a = i.length, o = a > 0 ? i.graph.time.v[a - 1] : NaN;
242
+ if (a > 0 && r.time === o) i.reviseLast(r);
243
+ else if (a === 0 || r.time > o) i.push(r);
244
+ else return this.recompute();
245
+ this.tickSync(), this.host.api?.requestRender();
246
+ }
247
+ recompute() {
248
+ this.version++, this.job?.cancel(), this.job = null, this.dirty = !1, this.structural = !1, this.error = null;
249
+ let e = this.bars(), t = this.ownRunner ?? this.host.runner;
250
+ if (!t || !t.canRun(this.def)) {
251
+ for (let [e, t] of this.feeds) this.engine.setFeed(e, t.snapshot(), t);
252
+ this.engine.load(e), this.syncAll(), this.ready_ = Promise.resolve();
253
+ return;
254
+ }
255
+ let n = this.version, r = this.feeds.size > 0 ? Object.fromEntries([...this.feeds].map(([e, t]) => [e, {
256
+ align: t.align,
257
+ spanMs: t.spanMs,
258
+ bars: t.snapshot()
259
+ }])) : void 0, i = t.run(this.def, {
260
+ studyId: this.def.id,
261
+ params: this.params,
262
+ bars: e,
263
+ ...r && { feeds: r }
264
+ });
265
+ this.job = i, this.ready_ = i.promise.then((e) => {
266
+ n !== this.version || this.disposed || (this.job = null, this.engine.graph.adopt(e.buffers, e.n), this.structural ? this.recompute() : (this.dirty && (this.dirty = !1, this.catchUp()), this.syncAll()));
267
+ }, (e) => {
268
+ if (!(e instanceof m || n !== this.version || this.disposed)) throw this.job = null, this.error = e instanceof Error ? e : Error(String(e)), this.error;
269
+ });
270
+ }
271
+ catchUp() {
272
+ let e = this.engine, t = this.bars(), n = t.time.length;
273
+ if (e.length === 0 || n === 0) return this.fullLoad(t);
274
+ let r = e.graph.time.v[e.length - 1], i = z(t.time, n, r), a = (e) => ({
275
+ time: t.time[e],
276
+ open: t.open?.[e] ?? NaN,
277
+ high: t.high?.[e] ?? NaN,
278
+ low: t.low?.[e] ?? NaN,
279
+ close: t.close[e],
280
+ volume: t.volume?.[e] ?? NaN
281
+ });
282
+ if (i < n && t.time[i] === r) e.reviseLast(a(i++));
283
+ else if (i < n && i === 0) return this.fullLoad(t);
284
+ for (; i < n; i++) e.push(a(i));
285
+ }
286
+ fullLoad(e) {
287
+ this.engine.load(e);
288
+ }
289
+ title() {
290
+ let e = this.def.label?.(this.params);
291
+ return e ? `${this.def.name} (${e})` : this.def.name;
292
+ }
293
+ retitle() {
294
+ this.outs.forEach((e, t) => e.series.applyOptions({ title: t === 0 ? this.title() : e.plot.title }));
295
+ }
296
+ color(e) {
297
+ return this.styles[e.key]?.color ?? e.color;
298
+ }
299
+ seriesOptions(e, t) {
300
+ let n = this.styles[e.key], r = n?.color;
301
+ switch (e.kind) {
302
+ case "line": return {
303
+ color: r ?? e.color,
304
+ lineWidth: n?.width ?? e.width ?? 1.5
305
+ };
306
+ case "band": return {
307
+ color: r ?? e.color,
308
+ lineWidth: n?.width ?? e.width ?? 1
309
+ };
310
+ case "histogram": return { color: r ?? e.color };
311
+ case "area": {
312
+ let t = r ?? e.color;
313
+ return {
314
+ lineColor: t,
315
+ topColor: B(t, .28),
316
+ bottomColor: B(t, .02),
317
+ lineWidth: n?.width ?? 1.5
318
+ };
319
+ }
320
+ default: return {};
321
+ }
322
+ }
323
+ createSeries() {
324
+ let e = this.host.chart, t = this.source.options();
325
+ this.def.pane === "overlay" ? (this.pane = t.pane, this.scaleId = this.def.scale ?? t.priceScaleId) : (this.pane = this.host.freePane(), this.scaleId = this.def.scale ?? "right");
326
+ let n = this.def.pane === "overlay";
327
+ this.sameScale = n && this.scaleId === t.priceScaleId;
328
+ let r = this.def.columns, i = (n, i, a, o, s) => {
329
+ let c = e.addSeries(a, {
330
+ id: `study:${this.id}:${i}`,
331
+ pane: this.pane,
332
+ priceScaleId: this.scaleId,
333
+ title: this.outs.length === 0 ? this.title() : n.title,
334
+ lastValueVisible: !this.sameScale,
335
+ priceLineVisible: !1,
336
+ visible: this.shown,
337
+ ...this.seriesOptions(n, i),
338
+ priceFormat: this.sameScale ? t.priceFormat : {
339
+ type: "price",
340
+ minMove: this.def.minMove ?? 10 ** -this.decimals
341
+ }
342
+ });
343
+ this.outs.push({
344
+ plot: n,
345
+ key: i,
346
+ col: r.indexOf(o),
347
+ series: c,
348
+ offset: s,
349
+ lastTime: NaN
350
+ });
351
+ };
352
+ for (let e of this.def.plots) switch (e.kind) {
353
+ case "line":
354
+ R(e, this.params) || i(e, e.key, "line", e.col, L(e, this.params));
355
+ break;
356
+ case "histogram":
357
+ i(e, e.key, "histogram", e.col, 0);
358
+ break;
359
+ case "area":
360
+ i(e, e.key, "area", e.col, 0);
361
+ break;
362
+ case "band": i(e, `${e.key}:upper`, "line", e.upper, 0), i(e, `${e.key}:lower`, "line", e.lower, 0);
363
+ }
364
+ let a = this.outs[0]?.series;
365
+ for (let e of this.def.plots) {
366
+ if (e.kind !== "bgcolor") continue;
367
+ let t = n ? this.source : a;
368
+ if (!t) throw TypeError(`${this.def.id}: bgcolor shades the study's pane, and a study in its own pane needs a plot to hold it`);
369
+ let i = new w();
370
+ i.setVisible(this.shown), t.attachPrimitive(i), this.shades.push({
371
+ plot: e,
372
+ col: r.indexOf(e.col),
373
+ prim: i,
374
+ anchor: t
375
+ });
376
+ }
377
+ if (a) for (let t of this.def.plots) {
378
+ if (t.kind !== "hline") continue;
379
+ let n = typeof t.value == "function" ? t.value(this.params) : t.value, r = e.createPriceLine(a, {
380
+ price: n,
381
+ color: t.color,
382
+ lineStyle: t.style ?? "dashed",
383
+ lineWidth: 1,
384
+ axisLabelVisible: !1
385
+ });
386
+ this.lines.push({
387
+ series: a,
388
+ line: r
389
+ });
390
+ }
391
+ }
392
+ syncAll() {
393
+ let e = this.engine, t = e.length, n = e.graph.time.v;
394
+ for (let r of this.outs) this.writeSeries(r, e.outputs[r.col].v, n, t);
395
+ this.syncOverlays(), this.host.api?.requestRender(!0);
396
+ }
397
+ syncOverlays() {
398
+ let e = this.engine, t = e.length, n = e.graph.time.v;
399
+ for (let r of this.shades) {
400
+ let i = e.outputs[r.col].v, a = j(this.color(r.plot)), o = new Uint32Array(t);
401
+ for (let e = 0; e < t; e++) o[e] = i[e] === i[e] && i[e] !== 0 ? a : 0;
402
+ r.prim.set(n.slice(0, t), o);
403
+ }
404
+ this.hasBarColor() && this.host.syncBarColors(this.source);
405
+ }
406
+ writeSeries(e, t, n, r) {
407
+ let i = e.plot.kind === "histogram" && e.plot.colorDown ? {
408
+ up: j(this.color(e.plot)),
409
+ down: j(e.plot.colorDown)
410
+ } : null, a = e.plot.kind === "line" && e.plot.colorBy ? {
411
+ col: this.engine.outputs[this.def.columns.indexOf(e.plot.colorBy.col)].v,
412
+ color: j(e.plot.colorBy.color)
413
+ } : null, o = 0;
414
+ for (let n = 0; n < r; n++) {
415
+ let i = n + e.offset;
416
+ i >= 0 && i < r && t[n] === t[n] && o++;
417
+ }
418
+ let s = new Float64Array(o), c = new Float64Array(o), l = i || a ? new Uint32Array(o) : void 0, u = 0;
419
+ for (let o = 0; o < r; o++) {
420
+ let d = o + e.offset;
421
+ d < 0 || d >= r || t[o] !== t[o] || (s[u] = n[d], c[u] = t[o], i ? l[u] = t[o] >= 0 ? i.up : i.down : a && (l[u] = a.col[o] === a.col[o] && a.col[o] !== 0 ? a.color : 0), u++);
422
+ }
423
+ let d = 0;
424
+ for (let e = 0; e < o; e++) d = Math.max(d, Math.abs(c[e]));
425
+ this.widen(d), e.series.setData({
426
+ time: s,
427
+ value: c,
428
+ ...l && { color: l }
429
+ }), e.lastTime = o > 0 ? s[o - 1] : NaN;
430
+ }
431
+ widen(e) {
432
+ if (this.sameScale || this.def.minMove !== void 0 || !(e > 0) || e >= 1) return;
433
+ let t = Math.min(8, 2 - Math.floor(Math.log10(e)));
434
+ if (!(t <= this.decimals)) {
435
+ this.decimals = t;
436
+ for (let e of this.outs) e.series.applyOptions({ priceFormat: {
437
+ type: "price",
438
+ minMove: 10 ** -t
439
+ } });
440
+ }
441
+ }
442
+ seriesOfColumn(e) {
443
+ let t = this.def.columns.indexOf(e);
444
+ return this.outs.find((e) => e.col === t)?.series;
445
+ }
446
+ tickSync() {
447
+ let e = this.engine, t = e.length, n = e.graph.time.v, r = n[t - 1], i = this.def.columns;
448
+ for (let n of this.shades) {
449
+ let i = e.outputs[n.col].v[t - 1];
450
+ n.prim.setAt(r, i === i && i !== 0 ? j(this.color(n.plot)) : 0);
451
+ }
452
+ this.hasBarColor() && this.host.syncBarColors(this.source, !0);
453
+ for (let a of this.outs) {
454
+ let o = t - 1 - a.offset;
455
+ if (o < 0) continue;
456
+ let s = e.outputs[a.col].v, c = s[o];
457
+ if (c === c) {
458
+ this.widen(Math.abs(c));
459
+ let t = a.plot.kind === "histogram" && a.plot.colorDown, n = a.plot.kind === "line" ? a.plot.colorBy : void 0, s = n ? e.outputs[i.indexOf(n.col)].v[o] : NaN, l = n && s === s && s !== 0 ? n.color : void 0;
460
+ a.series.update({
461
+ time: r,
462
+ value: c,
463
+ ...t && { color: c >= 0 ? this.color(a.plot) : t },
464
+ ...l && { color: l }
465
+ }), a.lastTime = r;
466
+ } else a.lastTime === r && this.writeSeries(a, s, n, t);
467
+ }
468
+ }
469
+ draw(e, t) {
470
+ if (!this.shown || t.pane !== this.pane) return;
471
+ let n = this.engine, r = n.length;
472
+ if (r === 0) return;
473
+ let i = n.graph.time.v, a = Math.max(0, z(i, r, t.xToTime(0)) - 1), o = Math.min(r, z(i, r, t.xToTime(t.width)) + 2);
474
+ if (o <= a) return;
475
+ let s = Math.max(1, Math.floor((o - a) / (t.width * 2))), c = (e) => t.timeToX(i[e]), l = (e) => t.priceToY(e, this.scaleId), u = (e) => n.outputs[this.def.columns.indexOf(e)].v;
476
+ for (let t of this.def.plots) switch (t.kind) {
477
+ case "band":
478
+ V(e, a, o, s, c, l, u(t.upper), u(t.lower), this.styles[t.key]?.color ?? t.fill, 0);
479
+ break;
480
+ case "fill":
481
+ V(e, a, o, s, c, l, u(t.a), u(t.b), this.styles[t.key]?.color ?? t.color, 0);
482
+ break;
483
+ case "line":
484
+ R(t, this.params) && H(e, a, o, s, r, c, l, u(t.col), L(t, this.params), !!t.connect, this.color(t), this.styles[t.key]?.width ?? t.width ?? 1.5);
485
+ break;
486
+ case "markers":
487
+ this.drawMarkers(e, t, a, o, c, l, u(t.col), r);
488
+ break;
489
+ case "zigzag": U(e, a, o, c, l, u(t.price), u(t.back), i, this.color(t), t.width ?? 1.5);
490
+ }
491
+ }
492
+ drawMarkers(e, t, n, r, i, a, o, s) {
493
+ let c = L(t, this.params), l = this.engine.graph.high.v, u = this.engine.graph.low.v, d = this.color(t);
494
+ e.save(), e.fillStyle = d, e.strokeStyle = d, e.font = "10px system-ui, sans-serif", e.textAlign = "center";
495
+ let f = 0, p = Math.max(n, P(o, s, t));
496
+ for (let n = p; n < r && f < 4e3; n++) {
497
+ let r = o[n];
498
+ if (r !== r || t.text && r === 0) continue;
499
+ let d = n + c;
500
+ if (d < 0 || d >= s) continue;
501
+ let p = i(d), m = t.position === "sign" ? r > 0 ? "below" : "above" : t.position, h, g;
502
+ m === "value" ? (h = a(r), g = 1) : m === "above" ? (h = a(l[d]) - 8, g = -1) : (h = a(u[d]) + 8, g = 1), t.text ? (e.textBaseline = g < 0 ? "bottom" : "top", e.fillText(String(Math.round(r)), p, m === "above" ? h - 2 : h + 2)) : W(e, t.shape, p, h, m === "above" ? -1 : 1), f++;
503
+ }
504
+ e.restore();
505
+ }
506
+ };
507
+ function L(e, t) {
508
+ return typeof e.offset == "function" ? e.offset(t) : e.offset ?? 0;
509
+ }
510
+ function R(e, t) {
511
+ return L(e, t) < 0 || !!e.connect;
512
+ }
513
+ function z(e, t, n) {
514
+ let r = 0, i = t;
515
+ for (; r < i;) {
516
+ let t = r + i >>> 1;
517
+ e[t] < n ? r = t + 1 : i = t;
518
+ }
519
+ return r;
520
+ }
521
+ function B(e, t) {
522
+ let n = j(e);
523
+ return A((n & 4294967040 | Math.round(t * 255)) >>> 0);
524
+ }
525
+ function V(e, t, n, r, i, a, o, s, c, l) {
526
+ e.save(), e.fillStyle = c;
527
+ let u = [], d = () => {
528
+ if (u.length > 1) {
529
+ e.beginPath(), e.moveTo(i(u[0]), a(o[u[0]]));
530
+ for (let t = 1; t < u.length; t++) e.lineTo(i(u[t]), a(o[u[t]]));
531
+ for (let t = u.length - 1; t >= 0; t--) e.lineTo(i(u[t]), a(s[u[t]]));
532
+ e.closePath(), e.fill();
533
+ }
534
+ u = [];
535
+ };
536
+ for (let e = t; e < n; e += r) o[e] === o[e] && s[e] === s[e] ? u.push(e) : d();
537
+ d(), e.restore();
538
+ }
539
+ function H(e, t, n, r, i, a, o, s, c, l, u, d) {
540
+ e.save(), e.strokeStyle = u, e.lineWidth = d, e.beginPath();
541
+ let f = !1;
542
+ for (let u = t; u < n; u += r) {
543
+ let t = s[u], n = u + c;
544
+ t !== t || n < 0 || n >= i ? l || (f = !1) : (f ? e.lineTo(a(n), o(t)) : e.moveTo(a(n), o(t)), f = !0);
545
+ }
546
+ e.stroke(), e.restore();
547
+ }
548
+ function U(e, t, n, r, i, a, o, s, c, l) {
549
+ e.save(), e.strokeStyle = c, e.lineWidth = l, e.beginPath();
550
+ let u = !1;
551
+ for (let s = Math.max(0, t - 2e3); s < n; s++) {
552
+ let t = a[s];
553
+ if (t !== t) continue;
554
+ let n = s - o[s];
555
+ u ? e.lineTo(r(n), i(t)) : e.moveTo(r(n), i(t)), u = !0;
556
+ }
557
+ e.stroke(), e.restore();
558
+ }
559
+ function W(e, t, n, r, i) {
560
+ switch (e.beginPath(), t) {
561
+ case "square":
562
+ e.rect(n - 4, r - 4, 8, 8), e.fill();
563
+ return;
564
+ case "diamond":
565
+ e.moveTo(n, r - 4 - 1), e.lineTo(n + 4 + 1, r), e.lineTo(n, r + 4 + 1), e.lineTo(n - 4 - 1, r), e.closePath(), e.fill();
566
+ return;
567
+ case "triangleUp":
568
+ case "arrowUp":
569
+ e.moveTo(n, r - 4), e.lineTo(n + 4, r + 4), e.lineTo(n - 4, r + 4), e.closePath(), e.fill();
570
+ return;
571
+ case "triangleDown":
572
+ case "arrowDown":
573
+ e.moveTo(n, r + 4), e.lineTo(n + 4, r - 4), e.lineTo(n - 4, r - 4), e.closePath(), e.fill();
574
+ return;
575
+ case "cross":
576
+ e.moveTo(n - 4, r - 4), e.lineTo(n + 4, r + 4), e.moveTo(n + 4, r - 4), e.lineTo(n - 4, r + 4), e.stroke();
577
+ return;
578
+ default: e.arc(n, r, 3, 0, Math.PI * 2), e.fill();
579
+ }
580
+ }
581
+ var G = class {
582
+ chart;
583
+ runner;
584
+ resolve;
585
+ id = F;
586
+ api = null;
587
+ studies = /* @__PURE__ */ new Map();
588
+ counter = 0;
589
+ coloured = /* @__PURE__ */ new Set();
590
+ constructor(e, t, n) {
591
+ this.chart = e, this.runner = t, this.resolve = n;
592
+ }
593
+ install(e) {
594
+ this.api = e;
595
+ }
596
+ uninstall() {
597
+ let e = [...this.coloured];
598
+ for (let e of [...this.studies.values()]) e.dispose(this.chart);
599
+ this.studies.clear();
600
+ for (let t of e) this.syncBarColors(t);
601
+ this.api = null;
602
+ }
603
+ syncBarColors(e, t = !1) {
604
+ let n = [...this.studies.values()].filter((t) => t.barColorSource() === e && t.hasBarColor() && t.isShown), r = e;
605
+ if (n.length === 0) {
606
+ this.coloured.delete(e) && r.clearBarColors();
607
+ return;
608
+ }
609
+ if (this.coloured.add(e), t) {
610
+ let e = n[0].lastTime();
611
+ if (e !== e) return;
612
+ let t = 0;
613
+ for (let r of n) r.lastTime() === e && (t = r.barColorAt(r.rowOf(e)) || t);
614
+ r.setBarColors({
615
+ time: Float64Array.of(e),
616
+ color: Uint32Array.of(t)
617
+ });
618
+ return;
619
+ }
620
+ let i = n[0].barColors(), a = i.time, o = i.color;
621
+ for (let e = 1; e < n.length; e++) {
622
+ let t = n[e].barColors(), r = 0;
623
+ for (let e = 0; e < t.time.length; e++) {
624
+ for (; r < a.length && a[r] < t.time[e];) r++;
625
+ r < a.length && a[r] === t.time[e] && t.color[e] !== 0 && (o[r] = t.color[e]);
626
+ }
627
+ }
628
+ r.setBarColors({
629
+ time: a,
630
+ color: o
631
+ });
632
+ }
633
+ dataChanged(e) {
634
+ for (let t of this.studies.values()) t.onChange(e);
635
+ this.reap();
636
+ }
637
+ drawPane(e, t) {
638
+ for (let n of this.studies.values()) n.draw(e, t);
639
+ }
640
+ list() {
641
+ return [...this.studies.values()];
642
+ }
643
+ get(e) {
644
+ return this.studies.get(e);
645
+ }
646
+ changed() {
647
+ this.api?.requestRender(!0);
648
+ }
649
+ freePane() {
650
+ let e = new Set(this.chart.series().map((e) => e.options().pane)), t = 1;
651
+ for (; e.has(t);) t++;
652
+ return t;
653
+ }
654
+ add(e, t, n, r = {}, i) {
655
+ let a = r.id ?? this.nextId();
656
+ if (this.studies.has(a)) throw Error(`alphacharts: a study with id "${a}" already exists`);
657
+ let o = /^s(\d+)$/.exec(a);
658
+ o && (this.counter = Math.max(this.counter, Number(o[1])));
659
+ let s = new I(this, a, e, t, n, r.volume, i, r.runner, r.onDispose);
660
+ return s.persist = r.persist !== !1, this.studies.set(a, s), s.hasBarColor() && this.syncBarColors(n), s;
661
+ }
662
+ removeStudy(e) {
663
+ let t = this.studies.get(e);
664
+ t && (this.studies.delete(e), t.dispose(this.chart), t.hasBarColor() && this.syncBarColors(t.barColorSource()), this.changed());
665
+ }
666
+ reap() {
667
+ let e = new Set(this.chart.series().map((e) => e.data));
668
+ for (let [t, n] of this.studies) {
669
+ let r = n;
670
+ (!e.has(r.source.data) || r.volume && !e.has(r.volume.data)) && (this.studies.delete(t), n.dispose(this.chart), e.has(r.source.data) ? n.hasBarColor() && this.syncBarColors(r.source) : this.coloured.delete(r.source));
671
+ }
672
+ }
673
+ reserveIds(e) {
674
+ this.counter = Math.max(this.counter, e);
675
+ }
676
+ idHighWater() {
677
+ return this.counter;
678
+ }
679
+ nextId() {
680
+ return `s${++this.counter}`;
681
+ }
682
+ toJSON() {
683
+ return {
684
+ version: 1,
685
+ studies: [...this.studies.values()].filter((e) => e.persist).map((e) => e.state())
686
+ };
687
+ }
688
+ validateState(e, t) {
689
+ let n = e;
690
+ if (n?.version !== 1 || !Array.isArray(n.studies)) throw TypeError("alphacharts studies: unrecognised layout state");
691
+ let r = /* @__PURE__ */ new Set();
692
+ for (let e of n.studies) {
693
+ if (r.has(e.id)) throw Error(`alphacharts studies: the layout repeats study id "${e.id}"`);
694
+ if (r.add(e.id), !t.seriesIds.includes(e.source)) throw Error(`alphacharts studies: study "${e.id}" needs series "${e.source}", which the layout does not contain`);
695
+ if (e.volume && !t.seriesIds.includes(e.volume)) throw Error(`alphacharts studies: study "${e.id}" needs volume series "${e.volume}"`);
696
+ d(this.resolve(e.study), e.inputs);
697
+ }
698
+ }
699
+ fromJSON(e) {
700
+ let t = e;
701
+ if (t?.version !== 1 || !Array.isArray(t.studies)) throw TypeError("alphacharts studies: unrecognised layout state");
702
+ for (let e of this.studies.values()) e.drop();
703
+ this.studies.clear();
704
+ let n = new Map(this.chart.series().map((e) => [e.options().id, e]));
705
+ for (let e of t.studies) {
706
+ let t = n.get(e.source);
707
+ if (!t) throw Error(`alphacharts studies: study "${e.id}" needs series "${e.source}", which the layout does not contain`);
708
+ let r = e.volume ? n.get(e.volume) : void 0;
709
+ if (e.volume && !r) throw Error(`alphacharts studies: study "${e.id}" needs volume series "${e.volume}"`);
710
+ for (let t of [...n.values()]) t.options().id.startsWith(`study:${e.id}:`) && this.chart.removeSeries(t);
711
+ this.add(this.resolve(e.study), e.inputs, t, {
712
+ id: e.id,
713
+ ...r && { volume: r }
714
+ }, {
715
+ visible: e.visible,
716
+ styles: e.styles
717
+ });
718
+ }
719
+ let r = new Set([...this.studies.values()].flatMap((e) => e.series()));
720
+ for (let e of this.chart.series()) e.options().id.startsWith("study:") && !r.has(e) && this.chart.removeSeries(e);
721
+ }
722
+ };
723
+ function K(e, t = {}) {
724
+ let n = e.plugin(F);
725
+ if (n) return n;
726
+ let r = new G(e, t.runner, t.resolve ?? C);
727
+ return e.addPlugin(r), r;
728
+ }
729
+ function q(e, t, n, r = {}, i = {}) {
730
+ let a = typeof n == "string" ? C(n) : n;
731
+ return K(e, i.runner ? { runner: i.runner } : {}).add(a, r, t, i);
732
+ }
733
+ //#endregion
734
+ //#region src/wasm.ts
735
+ async function J() {
736
+ s(await M());
737
+ }
738
+ function Y() {
739
+ s(null);
740
+ }
741
+ //#endregion
742
+ export { v as CHUNK, m as CancelledError, o as Col, l as FEED_FIELDS, n as Feed, i as Graph, g as InlineRunner, r as Node, F as PLUGIN_ID, t as SOURCE_NAMES, G as StudiesPlugin, I as Study, _ as StudyEngine, f as WorkerRunner, q as addStudy, u as createRunner, a as defineStudy, c as describeJoin, Y as disableWasm, J as enableWasm, C as getStudy, K as installStudies, e as joinFeed, x as listStudies, P as markerFloor, S as registerStudies, b as registerStudy, d as resolveParams, p as runStudy, h as serveWorker, s as setKernels, y as validateDef };
743
+
744
+ //# sourceMappingURL=index.js.map