oakscriptjs 0.1.6 → 0.1.7
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/README.md +30 -240
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +357 -40
- package/dist/index.mjs +357 -40
- package/dist/input.d.ts +1 -1
- package/dist/input.d.ts.map +1 -1
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/zigzag/index.d.ts +2 -0
- package/dist/lib/zigzag/index.d.ts.map +1 -0
- package/dist/lib/zigzag/zigzag.d.ts +47 -0
- package/dist/lib/zigzag/zigzag.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/series.d.ts +1 -0
- package/dist/runtime/series.d.ts.map +1 -1
- package/dist/runtime/types.d.ts +26 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/ta/index.d.ts +1 -1
- package/dist/ta/index.d.ts.map +1 -1
- package/dist/ta-series.d.ts +8 -2
- package/dist/ta-series.d.ts.map +1 -1
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +24 -24
package/dist/index.mjs
CHANGED
|
@@ -5,7 +5,6 @@ var __export = (target, all) => {
|
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
// src/types/index.ts
|
|
8
|
-
var na = null;
|
|
9
8
|
var xloc = {
|
|
10
9
|
/** X-coordinates are bar indices */
|
|
11
10
|
bar_index: "bar_index",
|
|
@@ -80,27 +79,29 @@ __export(ta_exports, {
|
|
|
80
79
|
});
|
|
81
80
|
function sma(source, length2) {
|
|
82
81
|
const result = [];
|
|
82
|
+
const len = Math.floor(length2);
|
|
83
83
|
for (let i = 0; i < source.length; i++) {
|
|
84
|
-
if (i <
|
|
84
|
+
if (i < len - 1) {
|
|
85
85
|
result.push(NaN);
|
|
86
86
|
} else {
|
|
87
87
|
let sum4 = 0;
|
|
88
|
-
for (let j = 0; j <
|
|
88
|
+
for (let j = 0; j < len; j++) {
|
|
89
89
|
sum4 += source[i - j];
|
|
90
90
|
}
|
|
91
|
-
result.push(sum4 /
|
|
91
|
+
result.push(sum4 / len);
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
return result;
|
|
95
95
|
}
|
|
96
96
|
function ema(source, length2) {
|
|
97
97
|
const result = [];
|
|
98
|
-
const
|
|
98
|
+
const len = Math.floor(length2);
|
|
99
|
+
const multiplier = 2 / (len + 1);
|
|
99
100
|
let ema3 = 0;
|
|
100
|
-
for (let i = 0; i < Math.min(
|
|
101
|
+
for (let i = 0; i < Math.min(len, source.length); i++) {
|
|
101
102
|
ema3 += source[i];
|
|
102
103
|
}
|
|
103
|
-
ema3 = ema3 / Math.min(
|
|
104
|
+
ema3 = ema3 / Math.min(len, source.length);
|
|
104
105
|
for (let i = 0; i < source.length; i++) {
|
|
105
106
|
if (i === 0) {
|
|
106
107
|
result.push(source[i]);
|
|
@@ -160,17 +161,18 @@ function bb(series, length2, mult2) {
|
|
|
160
161
|
}
|
|
161
162
|
function stdev(source, length2) {
|
|
162
163
|
const result = [];
|
|
163
|
-
const
|
|
164
|
+
const len = Math.floor(length2);
|
|
165
|
+
const avg4 = sma(source, len);
|
|
164
166
|
for (let i = 0; i < source.length; i++) {
|
|
165
|
-
if (i <
|
|
167
|
+
if (i < len - 1) {
|
|
166
168
|
result.push(NaN);
|
|
167
169
|
} else {
|
|
168
170
|
let sumSquares = 0;
|
|
169
|
-
for (let j = 0; j <
|
|
171
|
+
for (let j = 0; j < len; j++) {
|
|
170
172
|
const diff2 = source[i - j] - avg4[i];
|
|
171
173
|
sumSquares += diff2 * diff2;
|
|
172
174
|
}
|
|
173
|
-
result.push(Math.sqrt(sumSquares /
|
|
175
|
+
result.push(Math.sqrt(sumSquares / len));
|
|
174
176
|
}
|
|
175
177
|
}
|
|
176
178
|
return result;
|
|
@@ -299,17 +301,34 @@ function supertrend(factor, atrPeriod, high, low, close, wicks = false) {
|
|
|
299
301
|
}
|
|
300
302
|
function rma(source, length2) {
|
|
301
303
|
const result = [];
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
304
|
+
const len = Math.floor(length2);
|
|
305
|
+
const alpha = 1 / len;
|
|
306
|
+
let firstValidIndex = -1;
|
|
307
|
+
let validCount = 0;
|
|
308
|
+
let initSum = 0;
|
|
309
|
+
for (let i = 0; i < source.length; i++) {
|
|
310
|
+
const val = source[i];
|
|
311
|
+
if (val !== void 0 && !isNaN(val)) {
|
|
312
|
+
initSum += val;
|
|
313
|
+
validCount++;
|
|
314
|
+
if (validCount === len) {
|
|
315
|
+
firstValidIndex = i;
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
306
319
|
}
|
|
307
|
-
rmaValue =
|
|
320
|
+
let rmaValue = validCount > 0 ? initSum / validCount : NaN;
|
|
321
|
+
let rmaInitialized = firstValidIndex >= 0;
|
|
308
322
|
for (let i = 0; i < source.length; i++) {
|
|
309
|
-
if (i
|
|
323
|
+
if (!rmaInitialized || i < firstValidIndex) {
|
|
324
|
+
result.push(NaN);
|
|
325
|
+
} else if (i === firstValidIndex) {
|
|
310
326
|
result.push(rmaValue);
|
|
311
327
|
} else {
|
|
312
|
-
|
|
328
|
+
const val = source[i];
|
|
329
|
+
if (val !== void 0 && !isNaN(val)) {
|
|
330
|
+
rmaValue = alpha * val + (1 - alpha) * rmaValue;
|
|
331
|
+
}
|
|
313
332
|
result.push(rmaValue);
|
|
314
333
|
}
|
|
315
334
|
}
|
|
@@ -317,14 +336,15 @@ function rma(source, length2) {
|
|
|
317
336
|
}
|
|
318
337
|
function wma(source, length2) {
|
|
319
338
|
const result = [];
|
|
339
|
+
const len = Math.floor(length2);
|
|
320
340
|
for (let i = 0; i < source.length; i++) {
|
|
321
|
-
if (i <
|
|
341
|
+
if (i < len - 1) {
|
|
322
342
|
result.push(NaN);
|
|
323
343
|
} else {
|
|
324
344
|
let sum4 = 0;
|
|
325
345
|
let weightSum = 0;
|
|
326
|
-
for (let j = 0; j <
|
|
327
|
-
const weight =
|
|
346
|
+
for (let j = 0; j < len; j++) {
|
|
347
|
+
const weight = len - j;
|
|
328
348
|
sum4 += source[i - j] * weight;
|
|
329
349
|
weightSum += weight;
|
|
330
350
|
}
|
|
@@ -564,12 +584,13 @@ function vwma(source, length2, volume) {
|
|
|
564
584
|
}
|
|
565
585
|
function linreg(source, length2, offset = 0) {
|
|
566
586
|
const result = [];
|
|
587
|
+
const len = Math.floor(length2);
|
|
567
588
|
for (let i = 0; i < source.length; i++) {
|
|
568
|
-
if (i <
|
|
589
|
+
if (i < len - 1) {
|
|
569
590
|
result.push(NaN);
|
|
570
591
|
} else {
|
|
571
592
|
let hasNaN = false;
|
|
572
|
-
for (let j = 0; j <
|
|
593
|
+
for (let j = 0; j < len; j++) {
|
|
573
594
|
if (isNaN(source[i - j])) {
|
|
574
595
|
hasNaN = true;
|
|
575
596
|
break;
|
|
@@ -582,17 +603,17 @@ function linreg(source, length2, offset = 0) {
|
|
|
582
603
|
let sumY = 0;
|
|
583
604
|
let sumXY = 0;
|
|
584
605
|
let sumX2 = 0;
|
|
585
|
-
for (let j = 0; j <
|
|
606
|
+
for (let j = 0; j < len; j++) {
|
|
586
607
|
const x2 = j;
|
|
587
|
-
const y = source[i - (
|
|
608
|
+
const y = source[i - (len - 1 - j)];
|
|
588
609
|
sumX += x2;
|
|
589
610
|
sumY += y;
|
|
590
611
|
sumXY += x2 * y;
|
|
591
612
|
sumX2 += x2 * x2;
|
|
592
613
|
}
|
|
593
|
-
const slope = (
|
|
594
|
-
const intercept = (sumY - slope * sumX) /
|
|
595
|
-
const x =
|
|
614
|
+
const slope = (len * sumXY - sumX * sumY) / (len * sumX2 - sumX * sumX);
|
|
615
|
+
const intercept = (sumY - slope * sumX) / len;
|
|
616
|
+
const x = len - 1 - offset;
|
|
596
617
|
result.push(intercept + slope * x);
|
|
597
618
|
}
|
|
598
619
|
}
|
|
@@ -681,8 +702,8 @@ function cci(source, length2) {
|
|
|
681
702
|
if (isNaN(smaValues[i]) || isNaN(devValues[i]) || devValues[i] === 0) {
|
|
682
703
|
result.push(NaN);
|
|
683
704
|
} else {
|
|
684
|
-
const
|
|
685
|
-
result.push(
|
|
705
|
+
const cci3 = (source[i] - smaValues[i]) / (0.015 * devValues[i]);
|
|
706
|
+
result.push(cci3);
|
|
686
707
|
}
|
|
687
708
|
}
|
|
688
709
|
return result;
|
|
@@ -1143,9 +1164,9 @@ function vwap(source, volume) {
|
|
|
1143
1164
|
}
|
|
1144
1165
|
return result;
|
|
1145
1166
|
}
|
|
1146
|
-
function alma(source, length2 = 9, offset = 0.85, sigma = 6) {
|
|
1167
|
+
function alma(source, length2 = 9, offset = 0.85, sigma = 6, floor2 = false) {
|
|
1147
1168
|
const result = [];
|
|
1148
|
-
const m = Math.floor(offset * (length2 - 1));
|
|
1169
|
+
const m = floor2 ? Math.floor(offset * (length2 - 1)) : offset * (length2 - 1);
|
|
1149
1170
|
const s = length2 / sigma;
|
|
1150
1171
|
const weights = [];
|
|
1151
1172
|
let weightSum = 0;
|
|
@@ -2147,6 +2168,38 @@ var Series = class _Series {
|
|
|
2147
2168
|
});
|
|
2148
2169
|
}
|
|
2149
2170
|
// ============================================
|
|
2171
|
+
// Conditional Selection
|
|
2172
|
+
// ============================================
|
|
2173
|
+
/**
|
|
2174
|
+
* Bar-by-bar conditional selection (ternary operator for Series)
|
|
2175
|
+
* Uses this Series as the condition (truthy = nonzero, falsy = zero/NaN)
|
|
2176
|
+
*
|
|
2177
|
+
* @param trueValue - Value or Series to use when condition is truthy
|
|
2178
|
+
* @param falseValue - Value or Series to use when condition is falsy
|
|
2179
|
+
* @returns New Series with bar-by-bar selected values
|
|
2180
|
+
*
|
|
2181
|
+
* @example
|
|
2182
|
+
* ```typescript
|
|
2183
|
+
* // PineScript: result = condition ? trueVal : falseVal
|
|
2184
|
+
* const result = condition.iff(trueVal, falseVal);
|
|
2185
|
+
*
|
|
2186
|
+
* // Example: RSI formula uses ternary for edge cases
|
|
2187
|
+
* // rsi = down == 0 ? 100 : up == 0 ? 0 : formula
|
|
2188
|
+
* const rsi = down.eq(0).iff(100, up.eq(0).iff(0, formula));
|
|
2189
|
+
* ```
|
|
2190
|
+
*/
|
|
2191
|
+
iff(trueValue, falseValue) {
|
|
2192
|
+
return new _Series(this.dataSource, (bar, i, data) => {
|
|
2193
|
+
const condition = this.extractor(bar, i, data);
|
|
2194
|
+
const isTruthy = condition !== 0 && !Number.isNaN(condition);
|
|
2195
|
+
if (isTruthy) {
|
|
2196
|
+
return typeof trueValue === "number" ? trueValue : trueValue.extractor(bar, i, data);
|
|
2197
|
+
} else {
|
|
2198
|
+
return typeof falseValue === "number" ? falseValue : falseValue.extractor(bar, i, data);
|
|
2199
|
+
}
|
|
2200
|
+
});
|
|
2201
|
+
}
|
|
2202
|
+
// ============================================
|
|
2150
2203
|
// Offset/History
|
|
2151
2204
|
// ============================================
|
|
2152
2205
|
/**
|
|
@@ -5072,6 +5125,7 @@ __export(ta_series_exports, {
|
|
|
5072
5125
|
alma: () => alma2,
|
|
5073
5126
|
atr: () => atr2,
|
|
5074
5127
|
bb: () => bb2,
|
|
5128
|
+
cci: () => cci2,
|
|
5075
5129
|
change: () => change2,
|
|
5076
5130
|
cross: () => cross2,
|
|
5077
5131
|
crossover: () => crossover2,
|
|
@@ -5089,8 +5143,10 @@ __export(ta_series_exports, {
|
|
|
5089
5143
|
rma: () => rma2,
|
|
5090
5144
|
roc: () => roc2,
|
|
5091
5145
|
rsi: () => rsi2,
|
|
5146
|
+
sar: () => sar2,
|
|
5092
5147
|
sma: () => sma2,
|
|
5093
5148
|
stdev: () => stdev3,
|
|
5149
|
+
stoch: () => stoch2,
|
|
5094
5150
|
supertrend: () => supertrend2,
|
|
5095
5151
|
ta: () => ta,
|
|
5096
5152
|
tr: () => tr2,
|
|
@@ -5160,11 +5216,19 @@ function atr2(bars, length2) {
|
|
|
5160
5216
|
const result = atr(length2, high, low, close);
|
|
5161
5217
|
return Series.fromArray(bars, result);
|
|
5162
5218
|
}
|
|
5163
|
-
function tr2(bars) {
|
|
5219
|
+
function tr2(bars, handle_na = false) {
|
|
5164
5220
|
const high = bars.map((b2) => b2.high);
|
|
5165
5221
|
const low = bars.map((b2) => b2.low);
|
|
5166
5222
|
const close = bars.map((b2) => b2.close);
|
|
5167
|
-
const result = tr(
|
|
5223
|
+
const result = tr(handle_na, high, low, close);
|
|
5224
|
+
return Series.fromArray(bars, result);
|
|
5225
|
+
}
|
|
5226
|
+
function stoch2(source, high, low, length2) {
|
|
5227
|
+
const bars = source.bars;
|
|
5228
|
+
const sourceValues = source.toArray();
|
|
5229
|
+
const highValues = high.toArray();
|
|
5230
|
+
const lowValues = low.toArray();
|
|
5231
|
+
const result = stoch(sourceValues, highValues, lowValues, length2);
|
|
5168
5232
|
return Series.fromArray(bars, result);
|
|
5169
5233
|
}
|
|
5170
5234
|
function crossover2(source1, source2) {
|
|
@@ -5291,10 +5355,10 @@ function linreg2(source, length2, offset = 0) {
|
|
|
5291
5355
|
const result = linreg(sourceValues, length2, offset);
|
|
5292
5356
|
return Series.fromArray(bars, result);
|
|
5293
5357
|
}
|
|
5294
|
-
function alma2(source, length2 = 9, offset = 0.85, sigma = 6) {
|
|
5358
|
+
function alma2(source, length2 = 9, offset = 0.85, sigma = 6, floor2 = false) {
|
|
5295
5359
|
const bars = source.bars;
|
|
5296
5360
|
const sourceValues = source.toArray();
|
|
5297
|
-
const result = alma(sourceValues, length2, offset, sigma);
|
|
5361
|
+
const result = alma(sourceValues, length2, offset, sigma, floor2);
|
|
5298
5362
|
return Series.fromArray(bars, result);
|
|
5299
5363
|
}
|
|
5300
5364
|
function zigzag2(bars, deviation = 5, depth = 10, backstep = 3) {
|
|
@@ -5314,6 +5378,19 @@ function zigzag2(bars, deviation = 5, depth = 10, backstep = 3) {
|
|
|
5314
5378
|
Series.fromArray(bars, pivotVals.map((b2) => b2 ? 1 : 0))
|
|
5315
5379
|
];
|
|
5316
5380
|
}
|
|
5381
|
+
function cci2(source, length2) {
|
|
5382
|
+
const bars = source.bars;
|
|
5383
|
+
const sourceValues = source.toArray();
|
|
5384
|
+
const result = cci(sourceValues, length2);
|
|
5385
|
+
return Series.fromArray(bars, result);
|
|
5386
|
+
}
|
|
5387
|
+
function sar2(bars, start = 0.02, inc = 0.02, max5 = 0.2) {
|
|
5388
|
+
const high = bars.map((b2) => b2.high);
|
|
5389
|
+
const low = bars.map((b2) => b2.low);
|
|
5390
|
+
const close = bars.map((b2) => b2.close);
|
|
5391
|
+
const result = sar(start, inc, max5, high, low, close);
|
|
5392
|
+
return Series.fromArray(bars, result);
|
|
5393
|
+
}
|
|
5317
5394
|
var ta = {
|
|
5318
5395
|
sma: sma2,
|
|
5319
5396
|
ema: ema2,
|
|
@@ -5326,6 +5403,7 @@ var ta = {
|
|
|
5326
5403
|
stdev: stdev3,
|
|
5327
5404
|
atr: atr2,
|
|
5328
5405
|
tr: tr2,
|
|
5406
|
+
stoch: stoch2,
|
|
5329
5407
|
crossover: crossover2,
|
|
5330
5408
|
crossunder: crossunder2,
|
|
5331
5409
|
cross: cross2,
|
|
@@ -5342,10 +5420,18 @@ var ta = {
|
|
|
5342
5420
|
ichimoku: ichimoku2,
|
|
5343
5421
|
linreg: linreg2,
|
|
5344
5422
|
alma: alma2,
|
|
5345
|
-
zigzag: zigzag2
|
|
5423
|
+
zigzag: zigzag2,
|
|
5424
|
+
cci: cci2,
|
|
5425
|
+
sar: sar2
|
|
5346
5426
|
};
|
|
5347
5427
|
|
|
5348
5428
|
// src/utils/index.ts
|
|
5429
|
+
function isNA(value) {
|
|
5430
|
+
return value === null || value === void 0 || Number.isNaN(value);
|
|
5431
|
+
}
|
|
5432
|
+
function nz(value, defaultValue = 0) {
|
|
5433
|
+
return isNA(value) ? defaultValue : value;
|
|
5434
|
+
}
|
|
5349
5435
|
function ohlcFromBars(bars) {
|
|
5350
5436
|
return {
|
|
5351
5437
|
open: bars.map((b2) => b2.open),
|
|
@@ -5366,6 +5452,229 @@ function getLow(ohlc) {
|
|
|
5366
5452
|
function getOpen(ohlc) {
|
|
5367
5453
|
return ohlc.open;
|
|
5368
5454
|
}
|
|
5455
|
+
function getSourceSeries(bars, source = "close") {
|
|
5456
|
+
const open = new Series(bars, (bar) => bar.open);
|
|
5457
|
+
const high = new Series(bars, (bar) => bar.high);
|
|
5458
|
+
const low = new Series(bars, (bar) => bar.low);
|
|
5459
|
+
const close = new Series(bars, (bar) => bar.close);
|
|
5460
|
+
switch (source) {
|
|
5461
|
+
case "open":
|
|
5462
|
+
return open;
|
|
5463
|
+
case "high":
|
|
5464
|
+
return high;
|
|
5465
|
+
case "low":
|
|
5466
|
+
return low;
|
|
5467
|
+
case "close":
|
|
5468
|
+
return close;
|
|
5469
|
+
case "hl2":
|
|
5470
|
+
return high.add(low).div(2);
|
|
5471
|
+
case "hlc3":
|
|
5472
|
+
return high.add(low).add(close).div(3);
|
|
5473
|
+
case "ohlc4":
|
|
5474
|
+
return open.add(high).add(low).add(close).div(4);
|
|
5475
|
+
case "hlcc4":
|
|
5476
|
+
return high.add(low).add(close).add(close).div(4);
|
|
5477
|
+
default:
|
|
5478
|
+
return close;
|
|
5479
|
+
}
|
|
5480
|
+
}
|
|
5481
|
+
|
|
5482
|
+
// src/lib/zigzag/zigzag.ts
|
|
5483
|
+
var defaultSettings = {
|
|
5484
|
+
devThreshold: 5,
|
|
5485
|
+
depth: 10,
|
|
5486
|
+
lineColor: "#2962FF",
|
|
5487
|
+
extendLast: true,
|
|
5488
|
+
displayReversalPrice: true,
|
|
5489
|
+
displayCumulativeVolume: true,
|
|
5490
|
+
displayReversalPriceChange: true,
|
|
5491
|
+
differencePriceMode: "Absolute",
|
|
5492
|
+
allowZigZagOnOneBar: true
|
|
5493
|
+
};
|
|
5494
|
+
var ZigZag = class {
|
|
5495
|
+
settings;
|
|
5496
|
+
pivots = [];
|
|
5497
|
+
sumVol = 0;
|
|
5498
|
+
highBuffer = [];
|
|
5499
|
+
lowBuffer = [];
|
|
5500
|
+
timeBuffer = [];
|
|
5501
|
+
barCount = 0;
|
|
5502
|
+
constructor(settings) {
|
|
5503
|
+
this.settings = { ...defaultSettings, ...settings };
|
|
5504
|
+
}
|
|
5505
|
+
/**
|
|
5506
|
+
* Process a single bar, detecting pivots.
|
|
5507
|
+
* Must be called sequentially for each bar.
|
|
5508
|
+
* @returns true if a new pivot was detected or updated
|
|
5509
|
+
*/
|
|
5510
|
+
update(bar, barIndex) {
|
|
5511
|
+
this.highBuffer.push(bar.high);
|
|
5512
|
+
this.lowBuffer.push(bar.low);
|
|
5513
|
+
this.timeBuffer.push(bar.time);
|
|
5514
|
+
this.barCount++;
|
|
5515
|
+
const depth = Math.max(2, Math.floor(this.settings.depth / 2));
|
|
5516
|
+
this.sumVol += bar.volume ?? 0;
|
|
5517
|
+
if (this.barCount < depth * 2 + 1)
|
|
5518
|
+
return false;
|
|
5519
|
+
let somethingChanged = this.tryFindPivot(true, depth, barIndex);
|
|
5520
|
+
somethingChanged = this.tryFindPivot(
|
|
5521
|
+
false,
|
|
5522
|
+
depth,
|
|
5523
|
+
barIndex,
|
|
5524
|
+
this.settings.allowZigZagOnOneBar || !somethingChanged
|
|
5525
|
+
) || somethingChanged;
|
|
5526
|
+
return somethingChanged;
|
|
5527
|
+
}
|
|
5528
|
+
/**
|
|
5529
|
+
* Get the last confirmed pivot
|
|
5530
|
+
*/
|
|
5531
|
+
lastPivot() {
|
|
5532
|
+
if (this.pivots.length === 0)
|
|
5533
|
+
return null;
|
|
5534
|
+
const last2 = this.pivots[this.pivots.length - 1];
|
|
5535
|
+
return last2 !== void 0 ? last2 : null;
|
|
5536
|
+
}
|
|
5537
|
+
/**
|
|
5538
|
+
* Get extension line to current bar (if extendLast enabled)
|
|
5539
|
+
*/
|
|
5540
|
+
getExtension(currentBar, barIndex) {
|
|
5541
|
+
if (!this.settings.extendLast)
|
|
5542
|
+
return null;
|
|
5543
|
+
const last2 = this.lastPivot();
|
|
5544
|
+
if (!last2)
|
|
5545
|
+
return null;
|
|
5546
|
+
const isHigh = !last2.isHigh;
|
|
5547
|
+
const price = isHigh ? currentBar.high : currentBar.low;
|
|
5548
|
+
return {
|
|
5549
|
+
isHigh,
|
|
5550
|
+
volume: this.sumVol,
|
|
5551
|
+
start: last2.end,
|
|
5552
|
+
end: { time: currentBar.time, barIndex, price }
|
|
5553
|
+
};
|
|
5554
|
+
}
|
|
5555
|
+
// ============ Private Methods ============
|
|
5556
|
+
tryFindPivot(isHigh, depth, currentBarIndex, registerPivot = true) {
|
|
5557
|
+
const point = this.findPivotPoint(isHigh, depth, currentBarIndex);
|
|
5558
|
+
if (!point || !registerPivot)
|
|
5559
|
+
return false;
|
|
5560
|
+
return this.newPivotPointFound(isHigh, point);
|
|
5561
|
+
}
|
|
5562
|
+
/**
|
|
5563
|
+
* Check if a bar from `depth` bars back is a pivot point.
|
|
5564
|
+
* A pivot high has prices below it on both sides.
|
|
5565
|
+
* A pivot low has prices above it on both sides.
|
|
5566
|
+
*/
|
|
5567
|
+
findPivotPoint(isHigh, depth, currentBarIndex) {
|
|
5568
|
+
const buffer = isHigh ? this.highBuffer : this.lowBuffer;
|
|
5569
|
+
const pivotBufferIdx = buffer.length - 1 - depth;
|
|
5570
|
+
if (pivotBufferIdx < depth)
|
|
5571
|
+
return null;
|
|
5572
|
+
const pivotPrice = buffer[pivotBufferIdx];
|
|
5573
|
+
if (pivotPrice === void 0)
|
|
5574
|
+
return null;
|
|
5575
|
+
for (let i = pivotBufferIdx + 1; i < buffer.length; i++) {
|
|
5576
|
+
const price = buffer[i];
|
|
5577
|
+
if (price === void 0)
|
|
5578
|
+
return null;
|
|
5579
|
+
if (isHigh) {
|
|
5580
|
+
if (price > pivotPrice)
|
|
5581
|
+
return null;
|
|
5582
|
+
} else {
|
|
5583
|
+
if (price < pivotPrice)
|
|
5584
|
+
return null;
|
|
5585
|
+
}
|
|
5586
|
+
}
|
|
5587
|
+
for (let i = pivotBufferIdx - depth; i < pivotBufferIdx; i++) {
|
|
5588
|
+
const price = buffer[i];
|
|
5589
|
+
if (price === void 0)
|
|
5590
|
+
return null;
|
|
5591
|
+
if (isHigh) {
|
|
5592
|
+
if (price >= pivotPrice)
|
|
5593
|
+
return null;
|
|
5594
|
+
} else {
|
|
5595
|
+
if (price <= pivotPrice)
|
|
5596
|
+
return null;
|
|
5597
|
+
}
|
|
5598
|
+
}
|
|
5599
|
+
const pivotBarIndex = currentBarIndex - depth;
|
|
5600
|
+
const pivotTime = this.timeBuffer[pivotBufferIdx];
|
|
5601
|
+
if (pivotTime === void 0)
|
|
5602
|
+
return null;
|
|
5603
|
+
return {
|
|
5604
|
+
time: pivotTime,
|
|
5605
|
+
barIndex: pivotBarIndex,
|
|
5606
|
+
price: pivotPrice
|
|
5607
|
+
};
|
|
5608
|
+
}
|
|
5609
|
+
/**
|
|
5610
|
+
* Calculate percentage deviation from base price to new price
|
|
5611
|
+
*/
|
|
5612
|
+
calcDev(basePrice, price) {
|
|
5613
|
+
return 100 * (price - basePrice) / Math.abs(basePrice);
|
|
5614
|
+
}
|
|
5615
|
+
/**
|
|
5616
|
+
* Handle a newly detected pivot point.
|
|
5617
|
+
* Either updates existing pivot (if same direction) or adds new pivot (if direction changed).
|
|
5618
|
+
*/
|
|
5619
|
+
newPivotPointFound(isHigh, point) {
|
|
5620
|
+
const last2 = this.lastPivot();
|
|
5621
|
+
if (!last2) {
|
|
5622
|
+
this.pivots.push({
|
|
5623
|
+
isHigh,
|
|
5624
|
+
volume: this.sumVol,
|
|
5625
|
+
start: point,
|
|
5626
|
+
end: point
|
|
5627
|
+
});
|
|
5628
|
+
this.sumVol = 0;
|
|
5629
|
+
return true;
|
|
5630
|
+
}
|
|
5631
|
+
if (last2.isHigh === isHigh) {
|
|
5632
|
+
const isMoreExtreme = isHigh ? point.price > last2.end.price : point.price < last2.end.price;
|
|
5633
|
+
if (isMoreExtreme) {
|
|
5634
|
+
last2.end = point;
|
|
5635
|
+
last2.volume += this.sumVol;
|
|
5636
|
+
this.sumVol = 0;
|
|
5637
|
+
return true;
|
|
5638
|
+
}
|
|
5639
|
+
} else {
|
|
5640
|
+
const dev2 = this.calcDev(last2.end.price, point.price);
|
|
5641
|
+
const threshold = this.settings.devThreshold;
|
|
5642
|
+
const meetsThreshold = last2.isHigh ? dev2 <= -threshold : dev2 >= threshold;
|
|
5643
|
+
if (meetsThreshold) {
|
|
5644
|
+
this.pivots.push({
|
|
5645
|
+
isHigh,
|
|
5646
|
+
volume: this.sumVol,
|
|
5647
|
+
start: last2.end,
|
|
5648
|
+
end: point
|
|
5649
|
+
});
|
|
5650
|
+
this.sumVol = 0;
|
|
5651
|
+
return true;
|
|
5652
|
+
}
|
|
5653
|
+
}
|
|
5654
|
+
return false;
|
|
5655
|
+
}
|
|
5656
|
+
};
|
|
5657
|
+
function calculateZigZag(bars, settings) {
|
|
5658
|
+
if (bars.length === 0) {
|
|
5659
|
+
return { pivots: [], extension: null };
|
|
5660
|
+
}
|
|
5661
|
+
const zz = new ZigZag(settings);
|
|
5662
|
+
for (let i = 0; i < bars.length; i++) {
|
|
5663
|
+
const bar = bars[i];
|
|
5664
|
+
if (bar !== void 0) {
|
|
5665
|
+
zz.update(bar, i);
|
|
5666
|
+
}
|
|
5667
|
+
}
|
|
5668
|
+
const lastBar = bars[bars.length - 1];
|
|
5669
|
+
if (lastBar === void 0) {
|
|
5670
|
+
return { pivots: zz.pivots, extension: null };
|
|
5671
|
+
}
|
|
5672
|
+
const extension = zz.getExtension(lastBar, bars.length - 1);
|
|
5673
|
+
return {
|
|
5674
|
+
pivots: zz.pivots,
|
|
5675
|
+
extension
|
|
5676
|
+
};
|
|
5677
|
+
}
|
|
5369
5678
|
|
|
5370
5679
|
// src/indicator.ts
|
|
5371
5680
|
function indicator(metadata, setup) {
|
|
@@ -5485,7 +5794,7 @@ var input = {
|
|
|
5485
5794
|
defaultValue,
|
|
5486
5795
|
value: defaultValue,
|
|
5487
5796
|
title: options.title,
|
|
5488
|
-
options: ["open", "high", "low", "close", "hl2", "hlc3", "ohlc4"]
|
|
5797
|
+
options: ["open", "high", "low", "close", "hl2", "hlc3", "ohlc4", "hlcc4"]
|
|
5489
5798
|
};
|
|
5490
5799
|
},
|
|
5491
5800
|
/**
|
|
@@ -6081,18 +6390,23 @@ var info = {
|
|
|
6081
6390
|
indicator: ["indicator", "input", "plotHelper", "createPlot"]
|
|
6082
6391
|
}
|
|
6083
6392
|
};
|
|
6393
|
+
function alertcondition(_condition, _title, _message) {
|
|
6394
|
+
}
|
|
6084
6395
|
export {
|
|
6085
6396
|
BarData,
|
|
6086
6397
|
LightweightChartsAdapter,
|
|
6087
6398
|
Series,
|
|
6088
6399
|
SimpleInputAdapter,
|
|
6089
6400
|
VERSION,
|
|
6401
|
+
ZigZag,
|
|
6090
6402
|
abs,
|
|
6403
|
+
alertcondition,
|
|
6091
6404
|
array_exports as array,
|
|
6092
6405
|
atr2 as atr,
|
|
6093
6406
|
avg,
|
|
6094
6407
|
bb2 as bb,
|
|
6095
6408
|
box_exports as box,
|
|
6409
|
+
calculateZigZag,
|
|
6096
6410
|
ceil,
|
|
6097
6411
|
change2 as change,
|
|
6098
6412
|
chartpoint_exports as chartPoint,
|
|
@@ -6113,6 +6427,7 @@ export {
|
|
|
6113
6427
|
getHigh,
|
|
6114
6428
|
getLow,
|
|
6115
6429
|
getOpen,
|
|
6430
|
+
getSourceSeries,
|
|
6116
6431
|
hline,
|
|
6117
6432
|
indicator,
|
|
6118
6433
|
info,
|
|
@@ -6131,8 +6446,9 @@ export {
|
|
|
6131
6446
|
matrix_exports as matrix,
|
|
6132
6447
|
max2 as max,
|
|
6133
6448
|
min2 as min,
|
|
6134
|
-
na,
|
|
6449
|
+
isNA as na,
|
|
6135
6450
|
new_color2 as new_color,
|
|
6451
|
+
nz,
|
|
6136
6452
|
ohlcFromBars,
|
|
6137
6453
|
plot2 as plot,
|
|
6138
6454
|
plot as plotHelper,
|
|
@@ -6156,5 +6472,6 @@ export {
|
|
|
6156
6472
|
time_exports as time,
|
|
6157
6473
|
tr2 as tr,
|
|
6158
6474
|
vwap2 as vwap,
|
|
6159
|
-
xloc
|
|
6475
|
+
xloc,
|
|
6476
|
+
defaultSettings as zigZagDefaults
|
|
6160
6477
|
};
|
package/dist/input.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ export interface StringInputOptions {
|
|
|
30
30
|
title?: string;
|
|
31
31
|
options?: string[];
|
|
32
32
|
}
|
|
33
|
-
export type SourceType = 'open' | 'high' | 'low' | 'close' | 'hl2' | 'hlc3' | 'ohlc4';
|
|
33
|
+
export type SourceType = 'open' | 'high' | 'low' | 'close' | 'hl2' | 'hlc3' | 'ohlc4' | 'hlcc4';
|
|
34
34
|
export declare const input: {
|
|
35
35
|
int(defaultValue: number, options?: IntInputOptions): InputValue<number>;
|
|
36
36
|
float(defaultValue: number, options?: FloatInputOptions): InputValue<number>;
|
package/dist/input.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,UAAU,CAAC,CAAC;IAE3B,IAAI,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IAErD,YAAY,EAAE,CAAC,CAAC;IAEhB,KAAK,EAAE,CAAC,CAAC;IAET,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAKD,MAAM,WAAW,eAAe;IAE9B,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,MAAM,WAAW,iBAAiB;IAEhC,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,MAAM,WAAW,kBAAkB;IAEjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,MAAM,WAAW,gBAAgB;IAE/B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,MAAM,WAAW,kBAAkB;IAEjC,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAKD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,UAAU,CAAC,CAAC;IAE3B,IAAI,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IAErD,YAAY,EAAE,CAAC,CAAC;IAEhB,KAAK,EAAE,CAAC,CAAC;IAET,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAKD,MAAM,WAAW,eAAe;IAE9B,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,MAAM,WAAW,iBAAiB;IAEhC,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,MAAM,WAAW,kBAAkB;IAEjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,MAAM,WAAW,gBAAgB;IAE/B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,MAAM,WAAW,kBAAkB;IAEjC,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAKD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAKhG,eAAO,MAAM,KAAK;sBAaE,MAAM,YAAW,eAAe,GAAQ,UAAU,CAAC,MAAM,CAAC;wBAwBxD,MAAM,YAAW,iBAAiB,GAAQ,UAAU,CAAC,MAAM,CAAC;0BAwB3D,UAAU,YAAqB,kBAAkB,GAAQ,UAAU,CAAC,UAAU,CAAC;uBAsBjF,OAAO,YAAW,gBAAgB,GAAQ,UAAU,CAAC,OAAO,CAAC;yBAqB3D,MAAM,YAAW,kBAAkB,GAAQ,UAAU,CAAC,MAAM,CAAC;CASnF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAOA,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/zigzag/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,MAAM,EACN,eAAe,EACf,eAAe,IAAI,cAAc,EACjC,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,YAAY,GAClB,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Bar } from '../../types';
|
|
2
|
+
export interface ZigZagSettings {
|
|
3
|
+
devThreshold: number;
|
|
4
|
+
depth: number;
|
|
5
|
+
lineColor: string;
|
|
6
|
+
extendLast: boolean;
|
|
7
|
+
displayReversalPrice: boolean;
|
|
8
|
+
displayCumulativeVolume: boolean;
|
|
9
|
+
displayReversalPriceChange: boolean;
|
|
10
|
+
differencePriceMode: 'Absolute' | 'Percent';
|
|
11
|
+
allowZigZagOnOneBar: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface ZigZagPoint {
|
|
14
|
+
time: number;
|
|
15
|
+
barIndex: number;
|
|
16
|
+
price: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ZigZagPivot {
|
|
19
|
+
isHigh: boolean;
|
|
20
|
+
volume: number;
|
|
21
|
+
start: ZigZagPoint;
|
|
22
|
+
end: ZigZagPoint;
|
|
23
|
+
}
|
|
24
|
+
export interface ZigZagResult {
|
|
25
|
+
pivots: ZigZagPivot[];
|
|
26
|
+
extension: ZigZagPivot | null;
|
|
27
|
+
}
|
|
28
|
+
export declare const defaultSettings: ZigZagSettings;
|
|
29
|
+
export declare class ZigZag {
|
|
30
|
+
settings: ZigZagSettings;
|
|
31
|
+
pivots: ZigZagPivot[];
|
|
32
|
+
sumVol: number;
|
|
33
|
+
private highBuffer;
|
|
34
|
+
private lowBuffer;
|
|
35
|
+
private timeBuffer;
|
|
36
|
+
private barCount;
|
|
37
|
+
constructor(settings?: Partial<ZigZagSettings>);
|
|
38
|
+
update(bar: Bar, barIndex: number): boolean;
|
|
39
|
+
lastPivot(): ZigZagPivot | null;
|
|
40
|
+
getExtension(currentBar: Bar, barIndex: number): ZigZagPivot | null;
|
|
41
|
+
private tryFindPivot;
|
|
42
|
+
private findPivotPoint;
|
|
43
|
+
private calcDev;
|
|
44
|
+
private newPivotPointFound;
|
|
45
|
+
}
|
|
46
|
+
export declare function calculateZigZag(bars: Bar[], settings?: Partial<ZigZagSettings>): ZigZagResult;
|
|
47
|
+
//# sourceMappingURL=zigzag.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zigzag.d.ts","sourceRoot":"","sources":["../../../src/lib/zigzag/zigzag.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAIvC,MAAM,WAAW,cAAc;IAE7B,YAAY,EAAE,MAAM,CAAC;IAErB,KAAK,EAAE,MAAM,CAAC;IAEd,SAAS,EAAE,MAAM,CAAC;IAElB,UAAU,EAAE,OAAO,CAAC;IAEpB,oBAAoB,EAAE,OAAO,CAAC;IAE9B,uBAAuB,EAAE,OAAO,CAAC;IAEjC,0BAA0B,EAAE,OAAO,CAAC;IAEpC,mBAAmB,EAAE,UAAU,GAAG,SAAS,CAAC;IAE5C,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAE1B,IAAI,EAAE,MAAM,CAAC;IAEb,QAAQ,EAAE,MAAM,CAAC;IAEjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAE1B,MAAM,EAAE,OAAO,CAAC;IAEhB,MAAM,EAAE,MAAM,CAAC;IAEf,KAAK,EAAE,WAAW,CAAC;IAEnB,GAAG,EAAE,WAAW,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAE3B,MAAM,EAAE,WAAW,EAAE,CAAC;IAEtB,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;CAC/B;AAID,eAAO,MAAM,eAAe,EAAE,cAU7B,CAAC;AAIF,qBAAa,MAAM;IACjB,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,EAAE,WAAW,EAAE,CAAM;IAC3B,MAAM,EAAE,MAAM,CAAK;IAEnB,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,QAAQ,CAAa;gBAEjB,QAAQ,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC;IAS9C,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IA2B3C,SAAS,IAAI,WAAW,GAAG,IAAI;IAS/B,YAAY,CAAC,UAAU,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAoBnE,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,cAAc;IAsDtB,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,kBAAkB;CAsD3B;AAMD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,GAAG,EAAE,EACX,QAAQ,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GACjC,YAAY,CAwBd"}
|