oakscriptjs 0.1.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -25,12 +25,15 @@ __export(src_exports, {
25
25
  Series: () => Series,
26
26
  SimpleInputAdapter: () => SimpleInputAdapter,
27
27
  VERSION: () => VERSION,
28
+ ZigZag: () => ZigZag,
28
29
  abs: () => abs,
30
+ alertcondition: () => alertcondition,
29
31
  array: () => array_exports,
30
32
  atr: () => atr2,
31
33
  avg: () => avg,
32
34
  bb: () => bb2,
33
35
  box: () => box_exports,
36
+ calculateZigZag: () => calculateZigZag,
34
37
  ceil: () => ceil,
35
38
  change: () => change2,
36
39
  chartPoint: () => chartpoint_exports,
@@ -51,6 +54,7 @@ __export(src_exports, {
51
54
  getHigh: () => getHigh,
52
55
  getLow: () => getLow,
53
56
  getOpen: () => getOpen,
57
+ getSourceSeries: () => getSourceSeries,
54
58
  hline: () => hline,
55
59
  indicator: () => indicator,
56
60
  info: () => info,
@@ -69,8 +73,9 @@ __export(src_exports, {
69
73
  matrix: () => matrix_exports,
70
74
  max: () => max2,
71
75
  min: () => min2,
72
- na: () => na,
76
+ na: () => isNA,
73
77
  new_color: () => new_color2,
78
+ nz: () => nz,
74
79
  ohlcFromBars: () => ohlcFromBars,
75
80
  plot: () => plot2,
76
81
  plotHelper: () => plot,
@@ -94,12 +99,12 @@ __export(src_exports, {
94
99
  time: () => time_exports,
95
100
  tr: () => tr2,
96
101
  vwap: () => vwap2,
97
- xloc: () => xloc
102
+ xloc: () => xloc,
103
+ zigZagDefaults: () => defaultSettings
98
104
  });
99
105
  module.exports = __toCommonJS(src_exports);
100
106
 
101
107
  // src/types/index.ts
102
- var na = null;
103
108
  var xloc = {
104
109
  /** X-coordinates are bar indices */
105
110
  bar_index: "bar_index",
@@ -174,34 +179,51 @@ __export(ta_exports, {
174
179
  });
175
180
  function sma(source, length2) {
176
181
  const result = [];
182
+ const len = Math.floor(length2);
177
183
  for (let i = 0; i < source.length; i++) {
178
- if (i < length2 - 1) {
184
+ if (i < len - 1) {
179
185
  result.push(NaN);
180
186
  } else {
181
187
  let sum4 = 0;
182
- for (let j = 0; j < length2; j++) {
188
+ for (let j = 0; j < len; j++) {
183
189
  sum4 += source[i - j];
184
190
  }
185
- result.push(sum4 / length2);
191
+ result.push(sum4 / len);
186
192
  }
187
193
  }
188
194
  return result;
189
195
  }
190
196
  function ema(source, length2) {
191
197
  const result = [];
192
- const multiplier = 2 / (length2 + 1);
193
- let ema3 = 0;
194
- for (let i = 0; i < Math.min(length2, source.length); i++) {
195
- ema3 += source[i];
198
+ const len = Math.floor(length2);
199
+ const multiplier = 2 / (len + 1);
200
+ let firstValidIndex = -1;
201
+ let validCount = 0;
202
+ let initSum = 0;
203
+ for (let i = 0; i < source.length; i++) {
204
+ const val = source[i];
205
+ if (val !== void 0 && !isNaN(val)) {
206
+ initSum += val;
207
+ validCount++;
208
+ if (validCount === len) {
209
+ firstValidIndex = i;
210
+ break;
211
+ }
212
+ }
196
213
  }
197
- ema3 = ema3 / Math.min(length2, source.length);
214
+ let emaValue = validCount > 0 ? initSum / validCount : NaN;
215
+ let emaInitialized = firstValidIndex >= 0;
198
216
  for (let i = 0; i < source.length; i++) {
199
- if (i === 0) {
200
- result.push(source[i]);
201
- ema3 = source[i];
217
+ if (!emaInitialized || i < firstValidIndex) {
218
+ result.push(NaN);
219
+ } else if (i === firstValidIndex) {
220
+ result.push(emaValue);
202
221
  } else {
203
- ema3 = (source[i] - ema3) * multiplier + ema3;
204
- result.push(ema3);
222
+ const val = source[i];
223
+ if (val !== void 0 && !isNaN(val)) {
224
+ emaValue = (val - emaValue) * multiplier + emaValue;
225
+ }
226
+ result.push(emaValue);
205
227
  }
206
228
  }
207
229
  return result;
@@ -254,17 +276,18 @@ function bb(series, length2, mult2) {
254
276
  }
255
277
  function stdev(source, length2) {
256
278
  const result = [];
257
- const avg4 = sma(source, length2);
279
+ const len = Math.floor(length2);
280
+ const avg4 = sma(source, len);
258
281
  for (let i = 0; i < source.length; i++) {
259
- if (i < length2 - 1) {
282
+ if (i < len - 1) {
260
283
  result.push(NaN);
261
284
  } else {
262
285
  let sumSquares = 0;
263
- for (let j = 0; j < length2; j++) {
286
+ for (let j = 0; j < len; j++) {
264
287
  const diff2 = source[i - j] - avg4[i];
265
288
  sumSquares += diff2 * diff2;
266
289
  }
267
- result.push(Math.sqrt(sumSquares / length2));
290
+ result.push(Math.sqrt(sumSquares / len));
268
291
  }
269
292
  }
270
293
  return result;
@@ -393,17 +416,34 @@ function supertrend(factor, atrPeriod, high, low, close, wicks = false) {
393
416
  }
394
417
  function rma(source, length2) {
395
418
  const result = [];
396
- const alpha = 1 / length2;
397
- let rmaValue = 0;
398
- for (let i = 0; i < Math.min(length2, source.length); i++) {
399
- rmaValue += source[i];
419
+ const len = Math.floor(length2);
420
+ const alpha = 1 / len;
421
+ let firstValidIndex = -1;
422
+ let validCount = 0;
423
+ let initSum = 0;
424
+ for (let i = 0; i < source.length; i++) {
425
+ const val = source[i];
426
+ if (val !== void 0 && !isNaN(val)) {
427
+ initSum += val;
428
+ validCount++;
429
+ if (validCount === len) {
430
+ firstValidIndex = i;
431
+ break;
432
+ }
433
+ }
400
434
  }
401
- rmaValue = rmaValue / Math.min(length2, source.length);
435
+ let rmaValue = validCount > 0 ? initSum / validCount : NaN;
436
+ let rmaInitialized = firstValidIndex >= 0;
402
437
  for (let i = 0; i < source.length; i++) {
403
- if (i === 0) {
438
+ if (!rmaInitialized || i < firstValidIndex) {
439
+ result.push(NaN);
440
+ } else if (i === firstValidIndex) {
404
441
  result.push(rmaValue);
405
442
  } else {
406
- rmaValue = alpha * source[i] + (1 - alpha) * rmaValue;
443
+ const val = source[i];
444
+ if (val !== void 0 && !isNaN(val)) {
445
+ rmaValue = alpha * val + (1 - alpha) * rmaValue;
446
+ }
407
447
  result.push(rmaValue);
408
448
  }
409
449
  }
@@ -411,14 +451,15 @@ function rma(source, length2) {
411
451
  }
412
452
  function wma(source, length2) {
413
453
  const result = [];
454
+ const len = Math.floor(length2);
414
455
  for (let i = 0; i < source.length; i++) {
415
- if (i < length2 - 1) {
456
+ if (i < len - 1) {
416
457
  result.push(NaN);
417
458
  } else {
418
459
  let sum4 = 0;
419
460
  let weightSum = 0;
420
- for (let j = 0; j < length2; j++) {
421
- const weight = length2 - j;
461
+ for (let j = 0; j < len; j++) {
462
+ const weight = len - j;
422
463
  sum4 += source[i - j] * weight;
423
464
  weightSum += weight;
424
465
  }
@@ -658,12 +699,13 @@ function vwma(source, length2, volume) {
658
699
  }
659
700
  function linreg(source, length2, offset = 0) {
660
701
  const result = [];
702
+ const len = Math.floor(length2);
661
703
  for (let i = 0; i < source.length; i++) {
662
- if (i < length2 - 1) {
704
+ if (i < len - 1) {
663
705
  result.push(NaN);
664
706
  } else {
665
707
  let hasNaN = false;
666
- for (let j = 0; j < length2; j++) {
708
+ for (let j = 0; j < len; j++) {
667
709
  if (isNaN(source[i - j])) {
668
710
  hasNaN = true;
669
711
  break;
@@ -676,17 +718,17 @@ function linreg(source, length2, offset = 0) {
676
718
  let sumY = 0;
677
719
  let sumXY = 0;
678
720
  let sumX2 = 0;
679
- for (let j = 0; j < length2; j++) {
721
+ for (let j = 0; j < len; j++) {
680
722
  const x2 = j;
681
- const y = source[i - (length2 - 1 - j)];
723
+ const y = source[i - (len - 1 - j)];
682
724
  sumX += x2;
683
725
  sumY += y;
684
726
  sumXY += x2 * y;
685
727
  sumX2 += x2 * x2;
686
728
  }
687
- const slope = (length2 * sumXY - sumX * sumY) / (length2 * sumX2 - sumX * sumX);
688
- const intercept = (sumY - slope * sumX) / length2;
689
- const x = length2 - 1 - offset;
729
+ const slope = (len * sumXY - sumX * sumY) / (len * sumX2 - sumX * sumX);
730
+ const intercept = (sumY - slope * sumX) / len;
731
+ const x = len - 1 - offset;
690
732
  result.push(intercept + slope * x);
691
733
  }
692
734
  }
@@ -775,8 +817,8 @@ function cci(source, length2) {
775
817
  if (isNaN(smaValues[i]) || isNaN(devValues[i]) || devValues[i] === 0) {
776
818
  result.push(NaN);
777
819
  } else {
778
- const cci2 = (source[i] - smaValues[i]) / (0.015 * devValues[i]);
779
- result.push(cci2);
820
+ const cci3 = (source[i] - smaValues[i]) / (0.015 * devValues[i]);
821
+ result.push(cci3);
780
822
  }
781
823
  }
782
824
  return result;
@@ -1237,9 +1279,9 @@ function vwap(source, volume) {
1237
1279
  }
1238
1280
  return result;
1239
1281
  }
1240
- function alma(source, length2 = 9, offset = 0.85, sigma = 6) {
1282
+ function alma(source, length2 = 9, offset = 0.85, sigma = 6, floor2 = false) {
1241
1283
  const result = [];
1242
- const m = Math.floor(offset * (length2 - 1));
1284
+ const m = floor2 ? Math.floor(offset * (length2 - 1)) : offset * (length2 - 1);
1243
1285
  const s = length2 / sigma;
1244
1286
  const weights = [];
1245
1287
  let weightSum = 0;
@@ -2241,6 +2283,38 @@ var Series = class _Series {
2241
2283
  });
2242
2284
  }
2243
2285
  // ============================================
2286
+ // Conditional Selection
2287
+ // ============================================
2288
+ /**
2289
+ * Bar-by-bar conditional selection (ternary operator for Series)
2290
+ * Uses this Series as the condition (truthy = nonzero, falsy = zero/NaN)
2291
+ *
2292
+ * @param trueValue - Value or Series to use when condition is truthy
2293
+ * @param falseValue - Value or Series to use when condition is falsy
2294
+ * @returns New Series with bar-by-bar selected values
2295
+ *
2296
+ * @example
2297
+ * ```typescript
2298
+ * // PineScript: result = condition ? trueVal : falseVal
2299
+ * const result = condition.iff(trueVal, falseVal);
2300
+ *
2301
+ * // Example: RSI formula uses ternary for edge cases
2302
+ * // rsi = down == 0 ? 100 : up == 0 ? 0 : formula
2303
+ * const rsi = down.eq(0).iff(100, up.eq(0).iff(0, formula));
2304
+ * ```
2305
+ */
2306
+ iff(trueValue, falseValue) {
2307
+ return new _Series(this.dataSource, (bar, i, data) => {
2308
+ const condition = this.extractor(bar, i, data);
2309
+ const isTruthy = condition !== 0 && !Number.isNaN(condition);
2310
+ if (isTruthy) {
2311
+ return typeof trueValue === "number" ? trueValue : trueValue.extractor(bar, i, data);
2312
+ } else {
2313
+ return typeof falseValue === "number" ? falseValue : falseValue.extractor(bar, i, data);
2314
+ }
2315
+ });
2316
+ }
2317
+ // ============================================
2244
2318
  // Offset/History
2245
2319
  // ============================================
2246
2320
  /**
@@ -3138,6 +3212,7 @@ __export(str_exports, {
3138
3212
  lower: () => lower,
3139
3213
  match: () => match,
3140
3214
  pos: () => pos,
3215
+ repeat: () => repeat,
3141
3216
  replace: () => replace,
3142
3217
  replace_all: () => replace_all,
3143
3218
  split: () => split,
@@ -3223,6 +3298,13 @@ function trimRight(str) {
3223
3298
  function match(source, regex) {
3224
3299
  return new RegExp(regex).test(source);
3225
3300
  }
3301
+ function repeat(source, count, separator = "") {
3302
+ if (source == null)
3303
+ return null;
3304
+ if (count <= 0)
3305
+ return "";
3306
+ return Array(count).fill(source).join(separator);
3307
+ }
3226
3308
  function format_time(time, format2) {
3227
3309
  const date = new Date(time);
3228
3310
  const monthNames = [
@@ -5166,6 +5248,7 @@ __export(ta_series_exports, {
5166
5248
  alma: () => alma2,
5167
5249
  atr: () => atr2,
5168
5250
  bb: () => bb2,
5251
+ cci: () => cci2,
5169
5252
  change: () => change2,
5170
5253
  cross: () => cross2,
5171
5254
  crossover: () => crossover2,
@@ -5183,8 +5266,10 @@ __export(ta_series_exports, {
5183
5266
  rma: () => rma2,
5184
5267
  roc: () => roc2,
5185
5268
  rsi: () => rsi2,
5269
+ sar: () => sar2,
5186
5270
  sma: () => sma2,
5187
5271
  stdev: () => stdev3,
5272
+ stoch: () => stoch2,
5188
5273
  supertrend: () => supertrend2,
5189
5274
  ta: () => ta,
5190
5275
  tr: () => tr2,
@@ -5254,11 +5339,19 @@ function atr2(bars, length2) {
5254
5339
  const result = atr(length2, high, low, close);
5255
5340
  return Series.fromArray(bars, result);
5256
5341
  }
5257
- function tr2(bars) {
5342
+ function tr2(bars, handle_na = false) {
5258
5343
  const high = bars.map((b2) => b2.high);
5259
5344
  const low = bars.map((b2) => b2.low);
5260
5345
  const close = bars.map((b2) => b2.close);
5261
- const result = tr(false, high, low, close);
5346
+ const result = tr(handle_na, high, low, close);
5347
+ return Series.fromArray(bars, result);
5348
+ }
5349
+ function stoch2(source, high, low, length2) {
5350
+ const bars = source.bars;
5351
+ const sourceValues = source.toArray();
5352
+ const highValues = high.toArray();
5353
+ const lowValues = low.toArray();
5354
+ const result = stoch(sourceValues, highValues, lowValues, length2);
5262
5355
  return Series.fromArray(bars, result);
5263
5356
  }
5264
5357
  function crossover2(source1, source2) {
@@ -5385,10 +5478,10 @@ function linreg2(source, length2, offset = 0) {
5385
5478
  const result = linreg(sourceValues, length2, offset);
5386
5479
  return Series.fromArray(bars, result);
5387
5480
  }
5388
- function alma2(source, length2 = 9, offset = 0.85, sigma = 6) {
5481
+ function alma2(source, length2 = 9, offset = 0.85, sigma = 6, floor2 = false) {
5389
5482
  const bars = source.bars;
5390
5483
  const sourceValues = source.toArray();
5391
- const result = alma(sourceValues, length2, offset, sigma);
5484
+ const result = alma(sourceValues, length2, offset, sigma, floor2);
5392
5485
  return Series.fromArray(bars, result);
5393
5486
  }
5394
5487
  function zigzag2(bars, deviation = 5, depth = 10, backstep = 3) {
@@ -5408,6 +5501,19 @@ function zigzag2(bars, deviation = 5, depth = 10, backstep = 3) {
5408
5501
  Series.fromArray(bars, pivotVals.map((b2) => b2 ? 1 : 0))
5409
5502
  ];
5410
5503
  }
5504
+ function cci2(source, length2) {
5505
+ const bars = source.bars;
5506
+ const sourceValues = source.toArray();
5507
+ const result = cci(sourceValues, length2);
5508
+ return Series.fromArray(bars, result);
5509
+ }
5510
+ function sar2(bars, start = 0.02, inc = 0.02, max5 = 0.2) {
5511
+ const high = bars.map((b2) => b2.high);
5512
+ const low = bars.map((b2) => b2.low);
5513
+ const close = bars.map((b2) => b2.close);
5514
+ const result = sar(start, inc, max5, high, low, close);
5515
+ return Series.fromArray(bars, result);
5516
+ }
5411
5517
  var ta = {
5412
5518
  sma: sma2,
5413
5519
  ema: ema2,
@@ -5420,6 +5526,7 @@ var ta = {
5420
5526
  stdev: stdev3,
5421
5527
  atr: atr2,
5422
5528
  tr: tr2,
5529
+ stoch: stoch2,
5423
5530
  crossover: crossover2,
5424
5531
  crossunder: crossunder2,
5425
5532
  cross: cross2,
@@ -5436,10 +5543,18 @@ var ta = {
5436
5543
  ichimoku: ichimoku2,
5437
5544
  linreg: linreg2,
5438
5545
  alma: alma2,
5439
- zigzag: zigzag2
5546
+ zigzag: zigzag2,
5547
+ cci: cci2,
5548
+ sar: sar2
5440
5549
  };
5441
5550
 
5442
5551
  // src/utils/index.ts
5552
+ function isNA(value) {
5553
+ return value === null || value === void 0 || Number.isNaN(value);
5554
+ }
5555
+ function nz(value, defaultValue = 0) {
5556
+ return isNA(value) ? defaultValue : value;
5557
+ }
5443
5558
  function ohlcFromBars(bars) {
5444
5559
  return {
5445
5560
  open: bars.map((b2) => b2.open),
@@ -5460,6 +5575,229 @@ function getLow(ohlc) {
5460
5575
  function getOpen(ohlc) {
5461
5576
  return ohlc.open;
5462
5577
  }
5578
+ function getSourceSeries(bars, source = "close") {
5579
+ const open = new Series(bars, (bar) => bar.open);
5580
+ const high = new Series(bars, (bar) => bar.high);
5581
+ const low = new Series(bars, (bar) => bar.low);
5582
+ const close = new Series(bars, (bar) => bar.close);
5583
+ switch (source) {
5584
+ case "open":
5585
+ return open;
5586
+ case "high":
5587
+ return high;
5588
+ case "low":
5589
+ return low;
5590
+ case "close":
5591
+ return close;
5592
+ case "hl2":
5593
+ return high.add(low).div(2);
5594
+ case "hlc3":
5595
+ return high.add(low).add(close).div(3);
5596
+ case "ohlc4":
5597
+ return open.add(high).add(low).add(close).div(4);
5598
+ case "hlcc4":
5599
+ return high.add(low).add(close).add(close).div(4);
5600
+ default:
5601
+ return close;
5602
+ }
5603
+ }
5604
+
5605
+ // src/lib/zigzag/zigzag.ts
5606
+ var defaultSettings = {
5607
+ devThreshold: 5,
5608
+ depth: 10,
5609
+ lineColor: "#2962FF",
5610
+ extendLast: true,
5611
+ displayReversalPrice: true,
5612
+ displayCumulativeVolume: true,
5613
+ displayReversalPriceChange: true,
5614
+ differencePriceMode: "Absolute",
5615
+ allowZigZagOnOneBar: true
5616
+ };
5617
+ var ZigZag = class {
5618
+ settings;
5619
+ pivots = [];
5620
+ sumVol = 0;
5621
+ highBuffer = [];
5622
+ lowBuffer = [];
5623
+ timeBuffer = [];
5624
+ barCount = 0;
5625
+ constructor(settings) {
5626
+ this.settings = { ...defaultSettings, ...settings };
5627
+ }
5628
+ /**
5629
+ * Process a single bar, detecting pivots.
5630
+ * Must be called sequentially for each bar.
5631
+ * @returns true if a new pivot was detected or updated
5632
+ */
5633
+ update(bar, barIndex) {
5634
+ this.highBuffer.push(bar.high);
5635
+ this.lowBuffer.push(bar.low);
5636
+ this.timeBuffer.push(bar.time);
5637
+ this.barCount++;
5638
+ const depth = Math.max(2, Math.floor(this.settings.depth / 2));
5639
+ this.sumVol += bar.volume ?? 0;
5640
+ if (this.barCount < depth * 2 + 1)
5641
+ return false;
5642
+ let somethingChanged = this.tryFindPivot(true, depth, barIndex);
5643
+ somethingChanged = this.tryFindPivot(
5644
+ false,
5645
+ depth,
5646
+ barIndex,
5647
+ this.settings.allowZigZagOnOneBar || !somethingChanged
5648
+ ) || somethingChanged;
5649
+ return somethingChanged;
5650
+ }
5651
+ /**
5652
+ * Get the last confirmed pivot
5653
+ */
5654
+ lastPivot() {
5655
+ if (this.pivots.length === 0)
5656
+ return null;
5657
+ const last2 = this.pivots[this.pivots.length - 1];
5658
+ return last2 !== void 0 ? last2 : null;
5659
+ }
5660
+ /**
5661
+ * Get extension line to current bar (if extendLast enabled)
5662
+ */
5663
+ getExtension(currentBar, barIndex) {
5664
+ if (!this.settings.extendLast)
5665
+ return null;
5666
+ const last2 = this.lastPivot();
5667
+ if (!last2)
5668
+ return null;
5669
+ const isHigh = !last2.isHigh;
5670
+ const price = isHigh ? currentBar.high : currentBar.low;
5671
+ return {
5672
+ isHigh,
5673
+ volume: this.sumVol,
5674
+ start: last2.end,
5675
+ end: { time: currentBar.time, barIndex, price }
5676
+ };
5677
+ }
5678
+ // ============ Private Methods ============
5679
+ tryFindPivot(isHigh, depth, currentBarIndex, registerPivot = true) {
5680
+ const point = this.findPivotPoint(isHigh, depth, currentBarIndex);
5681
+ if (!point || !registerPivot)
5682
+ return false;
5683
+ return this.newPivotPointFound(isHigh, point);
5684
+ }
5685
+ /**
5686
+ * Check if a bar from `depth` bars back is a pivot point.
5687
+ * A pivot high has prices below it on both sides.
5688
+ * A pivot low has prices above it on both sides.
5689
+ */
5690
+ findPivotPoint(isHigh, depth, currentBarIndex) {
5691
+ const buffer = isHigh ? this.highBuffer : this.lowBuffer;
5692
+ const pivotBufferIdx = buffer.length - 1 - depth;
5693
+ if (pivotBufferIdx < depth)
5694
+ return null;
5695
+ const pivotPrice = buffer[pivotBufferIdx];
5696
+ if (pivotPrice === void 0)
5697
+ return null;
5698
+ for (let i = pivotBufferIdx + 1; i < buffer.length; i++) {
5699
+ const price = buffer[i];
5700
+ if (price === void 0)
5701
+ return null;
5702
+ if (isHigh) {
5703
+ if (price > pivotPrice)
5704
+ return null;
5705
+ } else {
5706
+ if (price < pivotPrice)
5707
+ return null;
5708
+ }
5709
+ }
5710
+ for (let i = pivotBufferIdx - depth; i < pivotBufferIdx; i++) {
5711
+ const price = buffer[i];
5712
+ if (price === void 0)
5713
+ return null;
5714
+ if (isHigh) {
5715
+ if (price >= pivotPrice)
5716
+ return null;
5717
+ } else {
5718
+ if (price <= pivotPrice)
5719
+ return null;
5720
+ }
5721
+ }
5722
+ const pivotBarIndex = currentBarIndex - depth;
5723
+ const pivotTime = this.timeBuffer[pivotBufferIdx];
5724
+ if (pivotTime === void 0)
5725
+ return null;
5726
+ return {
5727
+ time: pivotTime,
5728
+ barIndex: pivotBarIndex,
5729
+ price: pivotPrice
5730
+ };
5731
+ }
5732
+ /**
5733
+ * Calculate percentage deviation from base price to new price
5734
+ */
5735
+ calcDev(basePrice, price) {
5736
+ return 100 * (price - basePrice) / Math.abs(basePrice);
5737
+ }
5738
+ /**
5739
+ * Handle a newly detected pivot point.
5740
+ * Either updates existing pivot (if same direction) or adds new pivot (if direction changed).
5741
+ */
5742
+ newPivotPointFound(isHigh, point) {
5743
+ const last2 = this.lastPivot();
5744
+ if (!last2) {
5745
+ this.pivots.push({
5746
+ isHigh,
5747
+ volume: this.sumVol,
5748
+ start: point,
5749
+ end: point
5750
+ });
5751
+ this.sumVol = 0;
5752
+ return true;
5753
+ }
5754
+ if (last2.isHigh === isHigh) {
5755
+ const isMoreExtreme = isHigh ? point.price > last2.end.price : point.price < last2.end.price;
5756
+ if (isMoreExtreme) {
5757
+ last2.end = point;
5758
+ last2.volume += this.sumVol;
5759
+ this.sumVol = 0;
5760
+ return true;
5761
+ }
5762
+ } else {
5763
+ const dev2 = this.calcDev(last2.end.price, point.price);
5764
+ const threshold = this.settings.devThreshold;
5765
+ const meetsThreshold = last2.isHigh ? dev2 <= -threshold : dev2 >= threshold;
5766
+ if (meetsThreshold) {
5767
+ this.pivots.push({
5768
+ isHigh,
5769
+ volume: this.sumVol,
5770
+ start: last2.end,
5771
+ end: point
5772
+ });
5773
+ this.sumVol = 0;
5774
+ return true;
5775
+ }
5776
+ }
5777
+ return false;
5778
+ }
5779
+ };
5780
+ function calculateZigZag(bars, settings) {
5781
+ if (bars.length === 0) {
5782
+ return { pivots: [], extension: null };
5783
+ }
5784
+ const zz = new ZigZag(settings);
5785
+ for (let i = 0; i < bars.length; i++) {
5786
+ const bar = bars[i];
5787
+ if (bar !== void 0) {
5788
+ zz.update(bar, i);
5789
+ }
5790
+ }
5791
+ const lastBar = bars[bars.length - 1];
5792
+ if (lastBar === void 0) {
5793
+ return { pivots: zz.pivots, extension: null };
5794
+ }
5795
+ const extension = zz.getExtension(lastBar, bars.length - 1);
5796
+ return {
5797
+ pivots: zz.pivots,
5798
+ extension
5799
+ };
5800
+ }
5463
5801
 
5464
5802
  // src/indicator.ts
5465
5803
  function indicator(metadata, setup) {
@@ -5579,7 +5917,7 @@ var input = {
5579
5917
  defaultValue,
5580
5918
  value: defaultValue,
5581
5919
  title: options.title,
5582
- options: ["open", "high", "low", "close", "hl2", "hlc3", "ohlc4"]
5920
+ options: ["open", "high", "low", "close", "hl2", "hlc3", "ohlc4", "hlcc4"]
5583
5921
  };
5584
5922
  },
5585
5923
  /**
@@ -6175,3 +6513,5 @@ var info = {
6175
6513
  indicator: ["indicator", "input", "plotHelper", "createPlot"]
6176
6514
  }
6177
6515
  };
6516
+ function alertcondition(_condition, _title, _message) {
6517
+ }