oakscriptjs 0.5.0 → 0.6.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.
- package/README.md +42 -8
- package/dist/array/index.d.ts +7 -7
- package/dist/array/index.d.ts.map +1 -1
- package/dist/box/index.d.ts +11 -3
- package/dist/box/index.d.ts.map +1 -1
- package/dist/color/index.d.ts +15 -15
- package/dist/color/index.d.ts.map +1 -1
- package/dist/compare/index.d.ts +8 -0
- package/dist/compare/index.d.ts.map +1 -0
- package/dist/drawing/registry.d.ts +19 -0
- package/dist/drawing/registry.d.ts.map +1 -0
- package/dist/index.cjs +1740 -608
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +1740 -608
- package/dist/input.d.ts +7 -1
- package/dist/input.d.ts.map +1 -1
- package/dist/label/index.d.ts +12 -4
- package/dist/label/index.d.ts.map +1 -1
- package/dist/line/index.d.ts +11 -3
- package/dist/line/index.d.ts.map +1 -1
- package/dist/linefill/index.d.ts +3 -1
- package/dist/linefill/index.d.ts.map +1 -1
- package/dist/map/index.d.ts +14 -0
- package/dist/map/index.d.ts.map +1 -0
- package/dist/polyline/index.d.ts +1 -0
- package/dist/polyline/index.d.ts.map +1 -1
- package/dist/runtime/adapters/SimpleInputAdapter.d.ts.map +1 -1
- package/dist/runtime/index.cjs +40 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.mjs +40 -1
- package/dist/runtime/inputs.d.ts +3 -0
- package/dist/runtime/inputs.d.ts.map +1 -1
- package/dist/runtime/series.d.ts.map +1 -1
- package/dist/runtime/types.d.ts +1 -1
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/script/index.cjs +3097 -635
- package/dist/script/index.d.ts +293 -27
- package/dist/script/index.d.ts.map +1 -1
- package/dist/script/index.mjs +3097 -635
- package/dist/security/resample.d.ts +13 -0
- package/dist/security/resample.d.ts.map +1 -0
- package/dist/session/bars.d.ts +34 -0
- package/dist/session/bars.d.ts.map +1 -0
- package/dist/session/calendar.d.ts +31 -0
- package/dist/session/calendar.d.ts.map +1 -0
- package/dist/str/dateformat.d.ts +2 -0
- package/dist/str/dateformat.d.ts.map +1 -0
- package/dist/str/index.d.ts +1 -1
- package/dist/str/index.d.ts.map +1 -1
- package/dist/str/messageformat.d.ts +2 -0
- package/dist/str/messageformat.d.ts.map +1 -0
- package/dist/str/numberformat.d.ts +3 -0
- package/dist/str/numberformat.d.ts.map +1 -0
- package/dist/ta/index.d.ts +14 -5
- package/dist/ta/index.d.ts.map +1 -1
- package/dist/ta-series.d.ts +23 -5
- package/dist/ta-series.d.ts.map +1 -1
- package/dist/text/index.d.ts +4 -0
- package/dist/text/index.d.ts.map +1 -0
- package/dist/time/datestring.d.ts +2 -0
- package/dist/time/datestring.d.ts.map +1 -0
- package/dist/time/index.d.ts +11 -0
- package/dist/time/index.d.ts.map +1 -1
- package/dist/time/session.d.ts +2 -0
- package/dist/time/session.d.ts.map +1 -0
- package/dist/time/timezone.d.ts +13 -0
- package/dist/time/timezone.d.ts.map +1 -0
- package/dist/timeframe/index.d.ts +17 -0
- package/dist/timeframe/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/metadata.d.ts +1 -1
- package/dist/types/metadata.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/script/index.cjs
CHANGED
|
@@ -3,9 +3,9 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target,
|
|
7
|
-
for (var name in
|
|
8
|
-
__defProp(target, name, { get:
|
|
6
|
+
var __export = (target, all7) => {
|
|
7
|
+
for (var name in all7)
|
|
8
|
+
__defProp(target, name, { get: all7[name], enumerable: true });
|
|
9
9
|
};
|
|
10
10
|
var __copyProps = (to, from, except, desc) => {
|
|
11
11
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
@@ -24,21 +24,35 @@ __export(index_exports, {
|
|
|
24
24
|
Series: () => Series,
|
|
25
25
|
alertcondition: () => alertcondition,
|
|
26
26
|
barcolor: () => barcolor,
|
|
27
|
+
barmerge: () => barmerge,
|
|
27
28
|
bgcolor: () => bgcolor,
|
|
29
|
+
box: () => box,
|
|
30
|
+
chart: () => chart,
|
|
28
31
|
close: () => close,
|
|
29
32
|
color: () => color,
|
|
33
|
+
compare: () => compare_exports,
|
|
34
|
+
dayofmonth: () => dayofmonth2,
|
|
35
|
+
dayofweek: () => dayofweek2,
|
|
30
36
|
eachBar: () => eachBar,
|
|
31
37
|
executeScript: () => executeScript,
|
|
32
38
|
fill: () => fill,
|
|
39
|
+
fixnan: () => fixnan2,
|
|
33
40
|
high: () => high,
|
|
34
41
|
hl2: () => hl2,
|
|
35
42
|
hlc3: () => hlc3,
|
|
36
43
|
hlcc4: () => hlcc4,
|
|
37
44
|
hline: () => hline,
|
|
45
|
+
hour: () => hour2,
|
|
46
|
+
inSession: () => inSession3,
|
|
38
47
|
indicator: () => indicator,
|
|
39
48
|
input: () => input,
|
|
49
|
+
label: () => label,
|
|
50
|
+
line: () => line,
|
|
51
|
+
linefill: () => linefill,
|
|
40
52
|
low: () => low,
|
|
41
53
|
math: () => math_exports,
|
|
54
|
+
minute: () => minute2,
|
|
55
|
+
month: () => month2,
|
|
42
56
|
na: () => isNA,
|
|
43
57
|
nz: () => nz,
|
|
44
58
|
ohlc4: () => ohlc4,
|
|
@@ -46,12 +60,59 @@ __export(index_exports, {
|
|
|
46
60
|
plot: () => plot,
|
|
47
61
|
plotchar: () => plotchar,
|
|
48
62
|
plotshape: () => plotshape,
|
|
63
|
+
polyline: () => polyline,
|
|
64
|
+
request: () => request,
|
|
65
|
+
second: () => second2,
|
|
49
66
|
seriesOf: () => seriesOf,
|
|
67
|
+
session: () => session,
|
|
68
|
+
str: () => str,
|
|
69
|
+
syminfo: () => syminfo,
|
|
50
70
|
ta: () => ta2,
|
|
51
|
-
|
|
71
|
+
text: () => text,
|
|
72
|
+
ticker: () => ticker,
|
|
73
|
+
time: () => time,
|
|
74
|
+
time_close: () => time_close,
|
|
75
|
+
time_tradingday: () => time_tradingday,
|
|
76
|
+
timeframe: () => timeframe,
|
|
77
|
+
timestamp: () => timestamp2,
|
|
78
|
+
volume: () => volume,
|
|
79
|
+
weekofyear: () => weekofyear2,
|
|
80
|
+
year: () => year2
|
|
52
81
|
});
|
|
53
82
|
module.exports = __toCommonJS(index_exports);
|
|
54
83
|
|
|
84
|
+
// src/compare/index.ts
|
|
85
|
+
var compare_exports = {};
|
|
86
|
+
__export(compare_exports, {
|
|
87
|
+
EPSILON: () => EPSILON,
|
|
88
|
+
eq: () => eq,
|
|
89
|
+
ge: () => ge,
|
|
90
|
+
gt: () => gt,
|
|
91
|
+
le: () => le,
|
|
92
|
+
lt: () => lt,
|
|
93
|
+
ne: () => ne
|
|
94
|
+
});
|
|
95
|
+
var EPSILON = 1e-10;
|
|
96
|
+
var valid = (a, b2) => !Number.isNaN(a) && !Number.isNaN(b2);
|
|
97
|
+
function eq(a, b2) {
|
|
98
|
+
return valid(a, b2) && Math.abs(a - b2) <= EPSILON;
|
|
99
|
+
}
|
|
100
|
+
function ne(a, b2) {
|
|
101
|
+
return valid(a, b2) && Math.abs(a - b2) > EPSILON;
|
|
102
|
+
}
|
|
103
|
+
function lt(a, b2) {
|
|
104
|
+
return valid(a, b2) && b2 - a > EPSILON;
|
|
105
|
+
}
|
|
106
|
+
function le(a, b2) {
|
|
107
|
+
return valid(a, b2) && a - b2 <= EPSILON;
|
|
108
|
+
}
|
|
109
|
+
function gt(a, b2) {
|
|
110
|
+
return valid(a, b2) && a - b2 > EPSILON;
|
|
111
|
+
}
|
|
112
|
+
function ge(a, b2) {
|
|
113
|
+
return valid(a, b2) && b2 - a <= EPSILON;
|
|
114
|
+
}
|
|
115
|
+
|
|
55
116
|
// src/runtime/series.ts
|
|
56
117
|
var BarData = class _BarData {
|
|
57
118
|
_bars;
|
|
@@ -194,8 +255,8 @@ var Series = class _Series {
|
|
|
194
255
|
* @param field - Field to extract ('open', 'high', 'low', 'close', 'volume')
|
|
195
256
|
* @returns Series with extracted field values
|
|
196
257
|
*/
|
|
197
|
-
static fromBars(bars2,
|
|
198
|
-
return new _Series(bars2, (bar) => bar[
|
|
258
|
+
static fromBars(bars2, field2) {
|
|
259
|
+
return new _Series(bars2, (bar) => bar[field2] ?? NaN);
|
|
199
260
|
}
|
|
200
261
|
/**
|
|
201
262
|
* Create a constant series (same value for all bars)
|
|
@@ -300,7 +361,7 @@ var Series = class _Series {
|
|
|
300
361
|
});
|
|
301
362
|
}
|
|
302
363
|
// ============================================
|
|
303
|
-
// Comparison Operations
|
|
364
|
+
// Comparison Operations (PineScript operators: tolerance 1e-10, false with na; see src/compare)
|
|
304
365
|
// ============================================
|
|
305
366
|
/**
|
|
306
367
|
* Greater than comparison
|
|
@@ -311,7 +372,7 @@ var Series = class _Series {
|
|
|
311
372
|
return new _Series(this.dataSource, (bar, i, data) => {
|
|
312
373
|
const a = this.extractor(bar, i, data);
|
|
313
374
|
const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
|
|
314
|
-
return a
|
|
375
|
+
return gt(a, b2) ? 1 : 0;
|
|
315
376
|
});
|
|
316
377
|
}
|
|
317
378
|
/**
|
|
@@ -323,7 +384,7 @@ var Series = class _Series {
|
|
|
323
384
|
return new _Series(this.dataSource, (bar, i, data) => {
|
|
324
385
|
const a = this.extractor(bar, i, data);
|
|
325
386
|
const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
|
|
326
|
-
return a
|
|
387
|
+
return ge(a, b2) ? 1 : 0;
|
|
327
388
|
});
|
|
328
389
|
}
|
|
329
390
|
/**
|
|
@@ -335,7 +396,7 @@ var Series = class _Series {
|
|
|
335
396
|
return new _Series(this.dataSource, (bar, i, data) => {
|
|
336
397
|
const a = this.extractor(bar, i, data);
|
|
337
398
|
const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
|
|
338
|
-
return a
|
|
399
|
+
return lt(a, b2) ? 1 : 0;
|
|
339
400
|
});
|
|
340
401
|
}
|
|
341
402
|
/**
|
|
@@ -347,7 +408,7 @@ var Series = class _Series {
|
|
|
347
408
|
return new _Series(this.dataSource, (bar, i, data) => {
|
|
348
409
|
const a = this.extractor(bar, i, data);
|
|
349
410
|
const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
|
|
350
|
-
return a
|
|
411
|
+
return le(a, b2) ? 1 : 0;
|
|
351
412
|
});
|
|
352
413
|
}
|
|
353
414
|
/**
|
|
@@ -359,7 +420,7 @@ var Series = class _Series {
|
|
|
359
420
|
return new _Series(this.dataSource, (bar, i, data) => {
|
|
360
421
|
const a = this.extractor(bar, i, data);
|
|
361
422
|
const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
|
|
362
|
-
return a
|
|
423
|
+
return eq(a, b2) ? 1 : 0;
|
|
363
424
|
});
|
|
364
425
|
}
|
|
365
426
|
/**
|
|
@@ -371,7 +432,7 @@ var Series = class _Series {
|
|
|
371
432
|
return new _Series(this.dataSource, (bar, i, data) => {
|
|
372
433
|
const a = this.extractor(bar, i, data);
|
|
373
434
|
const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
|
|
374
|
-
return a
|
|
435
|
+
return ne(a, b2) ? 1 : 0;
|
|
375
436
|
});
|
|
376
437
|
}
|
|
377
438
|
// ============================================
|
|
@@ -569,6 +630,7 @@ var Series = class _Series {
|
|
|
569
630
|
// src/ta-series.ts
|
|
570
631
|
var ta_series_exports = {};
|
|
571
632
|
__export(ta_series_exports, {
|
|
633
|
+
accdist: () => accdist2,
|
|
572
634
|
alma: () => alma2,
|
|
573
635
|
atr: () => atr2,
|
|
574
636
|
barssince: () => barssince2,
|
|
@@ -591,6 +653,7 @@ __export(ta_series_exports, {
|
|
|
591
653
|
highestbars: () => highestbars2,
|
|
592
654
|
hma: () => hma2,
|
|
593
655
|
ichimoku: () => ichimoku2,
|
|
656
|
+
iii: () => iii2,
|
|
594
657
|
kc: () => kc2,
|
|
595
658
|
kcw: () => kcw2,
|
|
596
659
|
linreg: () => linreg2,
|
|
@@ -603,11 +666,15 @@ __export(ta_series_exports, {
|
|
|
603
666
|
min: () => min2,
|
|
604
667
|
mode: () => mode2,
|
|
605
668
|
mom: () => mom2,
|
|
669
|
+
nvi: () => nvi2,
|
|
670
|
+
obv: () => obv2,
|
|
606
671
|
percentile_linear_interpolation: () => percentile_linear_interpolation2,
|
|
607
672
|
percentile_nearest_rank: () => percentile_nearest_rank2,
|
|
608
673
|
percentrank: () => percentrank2,
|
|
609
674
|
pivothigh: () => pivothigh2,
|
|
610
675
|
pivotlow: () => pivotlow2,
|
|
676
|
+
pvi: () => pvi2,
|
|
677
|
+
pvt: () => pvt2,
|
|
611
678
|
range: () => range2,
|
|
612
679
|
rci: () => rci2,
|
|
613
680
|
rising: () => rising2,
|
|
@@ -626,16 +693,19 @@ __export(ta_series_exports, {
|
|
|
626
693
|
valuewhen: () => valuewhen2,
|
|
627
694
|
variance: () => variance2,
|
|
628
695
|
vwap: () => vwap2,
|
|
696
|
+
vwapBands: () => vwapBands,
|
|
629
697
|
vwma: () => vwma2,
|
|
698
|
+
wad: () => wad2,
|
|
630
699
|
wma: () => wma2,
|
|
631
700
|
wpr: () => wpr2,
|
|
701
|
+
wvad: () => wvad2,
|
|
632
702
|
zigzag: () => zigzag2
|
|
633
703
|
});
|
|
634
704
|
|
|
635
705
|
// src/ta/index.ts
|
|
636
|
-
function sma(source,
|
|
706
|
+
function sma(source, length2) {
|
|
637
707
|
const result = [];
|
|
638
|
-
const len = Math.floor(
|
|
708
|
+
const len = Math.floor(length2);
|
|
639
709
|
for (let i = 0; i < source.length; i++) {
|
|
640
710
|
if (i < len - 1) {
|
|
641
711
|
result.push(NaN);
|
|
@@ -649,9 +719,9 @@ function sma(source, length) {
|
|
|
649
719
|
}
|
|
650
720
|
return result;
|
|
651
721
|
}
|
|
652
|
-
function ema(source,
|
|
722
|
+
function ema(source, length2) {
|
|
653
723
|
const result = [];
|
|
654
|
-
const len = Math.floor(
|
|
724
|
+
const len = Math.floor(length2);
|
|
655
725
|
const multiplier = 2 / (len + 1);
|
|
656
726
|
let firstValidIndex = -1;
|
|
657
727
|
let validCount = 0;
|
|
@@ -684,16 +754,16 @@ function ema(source, length) {
|
|
|
684
754
|
}
|
|
685
755
|
return result;
|
|
686
756
|
}
|
|
687
|
-
function rsi(source,
|
|
757
|
+
function rsi(source, length2) {
|
|
688
758
|
const result = [];
|
|
689
759
|
const changes = [];
|
|
690
760
|
for (let i = 1; i < source.length; i++) {
|
|
691
761
|
changes.push(source[i] - source[i - 1]);
|
|
692
762
|
}
|
|
693
|
-
const gains = changes.map((c) => c > 0 ? c : 0);
|
|
694
|
-
const losses = changes.map((c) => c < 0 ? -c : 0);
|
|
695
|
-
const avgGains = rma(gains,
|
|
696
|
-
const avgLosses = rma(losses,
|
|
763
|
+
const gains = changes.map((c) => Number.isNaN(c) ? NaN : c > 0 ? c : 0);
|
|
764
|
+
const losses = changes.map((c) => Number.isNaN(c) ? NaN : c < 0 ? -c : 0);
|
|
765
|
+
const avgGains = rma(gains, length2);
|
|
766
|
+
const avgLosses = rma(losses, length2);
|
|
697
767
|
result.push(NaN);
|
|
698
768
|
for (let i = 0; i < avgGains.length; i++) {
|
|
699
769
|
if (avgLosses[i] === 0) {
|
|
@@ -719,34 +789,53 @@ function macd(source, fastLength, slowLength, signalLength) {
|
|
|
719
789
|
}
|
|
720
790
|
return [macdLine, signalLine, histogram];
|
|
721
791
|
}
|
|
722
|
-
function bb(series,
|
|
723
|
-
const basis = sma(series,
|
|
724
|
-
const dev3 = stdev(series,
|
|
725
|
-
const
|
|
726
|
-
const
|
|
792
|
+
function bb(series, length2, mult) {
|
|
793
|
+
const basis = sma(series, length2);
|
|
794
|
+
const dev3 = stdev(series, length2);
|
|
795
|
+
const upper2 = [];
|
|
796
|
+
const lower2 = [];
|
|
727
797
|
for (let i = 0; i < series.length; i++) {
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
}
|
|
731
|
-
return [basis,
|
|
798
|
+
upper2.push(basis[i] + mult * dev3[i]);
|
|
799
|
+
lower2.push(basis[i] - mult * dev3[i]);
|
|
800
|
+
}
|
|
801
|
+
return [basis, upper2, lower2];
|
|
802
|
+
}
|
|
803
|
+
function stdev(source, length2, biased = true) {
|
|
804
|
+
const len = Math.floor(length2);
|
|
805
|
+
return source.map((_, i) => {
|
|
806
|
+
const values = lastValues(source, i, len);
|
|
807
|
+
if (!values) return NaN;
|
|
808
|
+
const mean = values.reduce((a, b2) => a + b2, 0) / len;
|
|
809
|
+
const squares = values.reduce((a, b2) => a + (b2 - mean) * (b2 - mean), 0);
|
|
810
|
+
return Math.sqrt(squares / (biased ? len : len - 1));
|
|
811
|
+
});
|
|
732
812
|
}
|
|
733
|
-
function
|
|
734
|
-
const
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
813
|
+
function lastValues(source, i, length2) {
|
|
814
|
+
const values = [];
|
|
815
|
+
for (let j = i; j >= 0 && values.length < length2; j--) {
|
|
816
|
+
const x = source[j];
|
|
817
|
+
if (!Number.isNaN(x)) values.push(x);
|
|
818
|
+
}
|
|
819
|
+
return values.length === length2 ? values : null;
|
|
820
|
+
}
|
|
821
|
+
function windowUntilNa(source, i, length2) {
|
|
822
|
+
const values = [];
|
|
823
|
+
for (let j = 0; j < length2 && i - j >= 0; j++) {
|
|
824
|
+
const x = source[i - j];
|
|
825
|
+
if (Number.isNaN(x)) break;
|
|
826
|
+
values.push([x, -j]);
|
|
827
|
+
}
|
|
828
|
+
return values;
|
|
829
|
+
}
|
|
830
|
+
function extremeOffset(source, length2, isHigher) {
|
|
831
|
+
return source.map((_, i) => {
|
|
832
|
+
if (i < length2 - 1) return NaN;
|
|
833
|
+
const w = windowUntilNa(source, i, length2);
|
|
834
|
+
if (w.length === 0) return 0;
|
|
835
|
+
let best = w[0];
|
|
836
|
+
for (const item of w) if (isHigher(item[0], best[0])) best = item;
|
|
837
|
+
return best[1];
|
|
838
|
+
});
|
|
750
839
|
}
|
|
751
840
|
function crossover(series1, series2) {
|
|
752
841
|
const result = [];
|
|
@@ -770,13 +859,13 @@ function crossunder(series1, series2) {
|
|
|
770
859
|
}
|
|
771
860
|
return result;
|
|
772
861
|
}
|
|
773
|
-
function change(source,
|
|
862
|
+
function change(source, length2 = 1) {
|
|
774
863
|
const result = [];
|
|
775
864
|
for (let i = 0; i < source.length; i++) {
|
|
776
|
-
if (i <
|
|
865
|
+
if (i < length2) {
|
|
777
866
|
result.push(NaN);
|
|
778
867
|
} else {
|
|
779
|
-
result.push(source[i] - source[i -
|
|
868
|
+
result.push(source[i] - source[i - length2]);
|
|
780
869
|
}
|
|
781
870
|
}
|
|
782
871
|
return result;
|
|
@@ -811,14 +900,14 @@ function tr(handle_na = false, high2, low2, close2) {
|
|
|
811
900
|
}
|
|
812
901
|
return result;
|
|
813
902
|
}
|
|
814
|
-
function atr(
|
|
903
|
+
function atr(length2, high2, low2, close2) {
|
|
815
904
|
if (!high2 || !low2 || !close2) {
|
|
816
905
|
throw new Error(
|
|
817
906
|
"ta.atr() requires high, low, and close series. Either pass them explicitly or use createContext({ chart: { high, low, close } }) for implicit data."
|
|
818
907
|
);
|
|
819
908
|
}
|
|
820
909
|
const trueRange = tr(false, high2, low2, close2);
|
|
821
|
-
return rma(trueRange,
|
|
910
|
+
return rma(trueRange, length2);
|
|
822
911
|
}
|
|
823
912
|
function supertrend(factor, atrPeriod, high2, low2, close2, wicks = false) {
|
|
824
913
|
if (!high2 || !low2 || !close2) {
|
|
@@ -870,9 +959,9 @@ function supertrend(factor, atrPeriod, high2, low2, close2, wicks = false) {
|
|
|
870
959
|
}
|
|
871
960
|
return [supertrendValues, directions];
|
|
872
961
|
}
|
|
873
|
-
function rma(source,
|
|
962
|
+
function rma(source, length2) {
|
|
874
963
|
const result = [];
|
|
875
|
-
const len = Math.floor(
|
|
964
|
+
const len = Math.floor(length2);
|
|
876
965
|
const alpha = 1 / len;
|
|
877
966
|
let firstValidIndex = -1;
|
|
878
967
|
let validCount = 0;
|
|
@@ -899,15 +988,17 @@ function rma(source, length) {
|
|
|
899
988
|
const val = source[i];
|
|
900
989
|
if (val !== void 0 && !isNaN(val)) {
|
|
901
990
|
rmaValue = alpha * val + (1 - alpha) * rmaValue;
|
|
991
|
+
result.push(rmaValue);
|
|
992
|
+
} else {
|
|
993
|
+
result.push(NaN);
|
|
902
994
|
}
|
|
903
|
-
result.push(rmaValue);
|
|
904
995
|
}
|
|
905
996
|
}
|
|
906
997
|
return result;
|
|
907
998
|
}
|
|
908
|
-
function wma(source,
|
|
999
|
+
function wma(source, length2) {
|
|
909
1000
|
const result = [];
|
|
910
|
-
const len = Math.floor(
|
|
1001
|
+
const len = Math.floor(length2);
|
|
911
1002
|
for (let i = 0; i < source.length; i++) {
|
|
912
1003
|
if (i < len - 1) {
|
|
913
1004
|
result.push(NaN);
|
|
@@ -924,48 +1015,27 @@ function wma(source, length) {
|
|
|
924
1015
|
}
|
|
925
1016
|
return result;
|
|
926
1017
|
}
|
|
927
|
-
function highest(source,
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
let max4 = -Infinity;
|
|
934
|
-
for (let j = 0; j < length; j++) {
|
|
935
|
-
if (!isNaN(source[i - j])) {
|
|
936
|
-
max4 = Math.max(max4, source[i - j]);
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
result.push(max4 === -Infinity ? NaN : max4);
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
return result;
|
|
1018
|
+
function highest(source, length2) {
|
|
1019
|
+
return source.map((_, i) => {
|
|
1020
|
+
if (i < length2 - 1) return NaN;
|
|
1021
|
+
const w = windowUntilNa(source, i, length2);
|
|
1022
|
+
return w.length ? Math.max(...w.map((x) => x[0])) : NaN;
|
|
1023
|
+
});
|
|
943
1024
|
}
|
|
944
|
-
function lowest(source,
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
let min4 = Infinity;
|
|
951
|
-
for (let j = 0; j < length; j++) {
|
|
952
|
-
if (!isNaN(source[i - j])) {
|
|
953
|
-
min4 = Math.min(min4, source[i - j]);
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
result.push(min4 === Infinity ? NaN : min4);
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
return result;
|
|
1025
|
+
function lowest(source, length2) {
|
|
1026
|
+
return source.map((_, i) => {
|
|
1027
|
+
if (i < length2 - 1) return NaN;
|
|
1028
|
+
const w = windowUntilNa(source, i, length2);
|
|
1029
|
+
return w.length ? Math.min(...w.map((x) => x[0])) : NaN;
|
|
1030
|
+
});
|
|
960
1031
|
}
|
|
961
1032
|
function cum(source) {
|
|
962
|
-
const result = [];
|
|
963
1033
|
let sum2 = 0;
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1034
|
+
return source.map((v) => {
|
|
1035
|
+
if (Number.isNaN(v)) return NaN;
|
|
1036
|
+
sum2 += v;
|
|
1037
|
+
return sum2;
|
|
1038
|
+
});
|
|
969
1039
|
}
|
|
970
1040
|
function cross(source1, source2) {
|
|
971
1041
|
const result = [];
|
|
@@ -980,14 +1050,14 @@ function cross(source1, source2) {
|
|
|
980
1050
|
}
|
|
981
1051
|
return result;
|
|
982
1052
|
}
|
|
983
|
-
function rising(source,
|
|
1053
|
+
function rising(source, length2) {
|
|
984
1054
|
const result = [];
|
|
985
1055
|
for (let i = 0; i < source.length; i++) {
|
|
986
|
-
if (i <
|
|
1056
|
+
if (i < length2) {
|
|
987
1057
|
result.push(false);
|
|
988
1058
|
} else {
|
|
989
1059
|
let isRising = true;
|
|
990
|
-
for (let j = 1; j <=
|
|
1060
|
+
for (let j = 1; j <= length2; j++) {
|
|
991
1061
|
if (source[i - j + 1] <= source[i - j]) {
|
|
992
1062
|
isRising = false;
|
|
993
1063
|
break;
|
|
@@ -998,14 +1068,14 @@ function rising(source, length) {
|
|
|
998
1068
|
}
|
|
999
1069
|
return result;
|
|
1000
1070
|
}
|
|
1001
|
-
function falling(source,
|
|
1071
|
+
function falling(source, length2) {
|
|
1002
1072
|
const result = [];
|
|
1003
1073
|
for (let i = 0; i < source.length; i++) {
|
|
1004
|
-
if (i <
|
|
1074
|
+
if (i < length2) {
|
|
1005
1075
|
result.push(false);
|
|
1006
1076
|
} else {
|
|
1007
1077
|
let isFalling = true;
|
|
1008
|
-
for (let j = 1; j <=
|
|
1078
|
+
for (let j = 1; j <= length2; j++) {
|
|
1009
1079
|
if (source[i - j + 1] >= source[i - j]) {
|
|
1010
1080
|
isFalling = false;
|
|
1011
1081
|
break;
|
|
@@ -1016,13 +1086,13 @@ function falling(source, length) {
|
|
|
1016
1086
|
}
|
|
1017
1087
|
return result;
|
|
1018
1088
|
}
|
|
1019
|
-
function roc(source,
|
|
1089
|
+
function roc(source, length2) {
|
|
1020
1090
|
const result = [];
|
|
1021
1091
|
for (let i = 0; i < source.length; i++) {
|
|
1022
|
-
if (i <
|
|
1092
|
+
if (i < length2) {
|
|
1023
1093
|
result.push(NaN);
|
|
1024
1094
|
} else {
|
|
1025
|
-
const oldValue = source[i -
|
|
1095
|
+
const oldValue = source[i - length2];
|
|
1026
1096
|
if (oldValue === 0 || isNaN(oldValue) || isNaN(source[i])) {
|
|
1027
1097
|
result.push(NaN);
|
|
1028
1098
|
} else {
|
|
@@ -1033,49 +1103,49 @@ function roc(source, length) {
|
|
|
1033
1103
|
}
|
|
1034
1104
|
return result;
|
|
1035
1105
|
}
|
|
1036
|
-
function mom(source,
|
|
1106
|
+
function mom(source, length2) {
|
|
1037
1107
|
const result = [];
|
|
1038
1108
|
for (let i = 0; i < source.length; i++) {
|
|
1039
|
-
if (i <
|
|
1109
|
+
if (i < length2) {
|
|
1040
1110
|
result.push(NaN);
|
|
1041
1111
|
} else {
|
|
1042
|
-
if (isNaN(source[i]) || isNaN(source[i -
|
|
1112
|
+
if (isNaN(source[i]) || isNaN(source[i - length2])) {
|
|
1043
1113
|
result.push(NaN);
|
|
1044
1114
|
} else {
|
|
1045
|
-
result.push(source[i] - source[i -
|
|
1115
|
+
result.push(source[i] - source[i - length2]);
|
|
1046
1116
|
}
|
|
1047
1117
|
}
|
|
1048
1118
|
}
|
|
1049
1119
|
return result;
|
|
1050
1120
|
}
|
|
1051
|
-
function dev(source,
|
|
1121
|
+
function dev(source, length2) {
|
|
1052
1122
|
const result = [];
|
|
1053
|
-
const meanValues = sma(source,
|
|
1123
|
+
const meanValues = sma(source, length2);
|
|
1054
1124
|
for (let i = 0; i < source.length; i++) {
|
|
1055
|
-
if (i <
|
|
1125
|
+
if (i < length2 - 1 || isNaN(meanValues[i])) {
|
|
1056
1126
|
result.push(NaN);
|
|
1057
1127
|
} else {
|
|
1058
1128
|
let sum2 = 0;
|
|
1059
|
-
for (let j = 0; j <
|
|
1129
|
+
for (let j = 0; j < length2; j++) {
|
|
1060
1130
|
if (!isNaN(source[i - j])) {
|
|
1061
1131
|
sum2 += Math.abs(source[i - j] - meanValues[i]);
|
|
1062
1132
|
}
|
|
1063
1133
|
}
|
|
1064
|
-
result.push(sum2 /
|
|
1134
|
+
result.push(sum2 / length2);
|
|
1065
1135
|
}
|
|
1066
1136
|
}
|
|
1067
1137
|
return result;
|
|
1068
1138
|
}
|
|
1069
|
-
function variance(source,
|
|
1139
|
+
function variance(source, length2, biased = true) {
|
|
1070
1140
|
const result = [];
|
|
1071
|
-
const meanValues = sma(source,
|
|
1141
|
+
const meanValues = sma(source, length2);
|
|
1072
1142
|
for (let i = 0; i < source.length; i++) {
|
|
1073
|
-
if (i <
|
|
1143
|
+
if (i < length2 - 1 || isNaN(meanValues[i])) {
|
|
1074
1144
|
result.push(NaN);
|
|
1075
1145
|
} else {
|
|
1076
1146
|
let sumSquares = 0;
|
|
1077
1147
|
let count = 0;
|
|
1078
|
-
for (let j = 0; j <
|
|
1148
|
+
for (let j = 0; j < length2; j++) {
|
|
1079
1149
|
if (!isNaN(source[i - j])) {
|
|
1080
1150
|
const diff = source[i - j] - meanValues[i];
|
|
1081
1151
|
sumSquares += diff * diff;
|
|
@@ -1088,14 +1158,14 @@ function variance(source, length, biased = true) {
|
|
|
1088
1158
|
}
|
|
1089
1159
|
return result;
|
|
1090
1160
|
}
|
|
1091
|
-
function median(source,
|
|
1161
|
+
function median(source, length2) {
|
|
1092
1162
|
const result = [];
|
|
1093
1163
|
for (let i = 0; i < source.length; i++) {
|
|
1094
|
-
if (i <
|
|
1164
|
+
if (i < length2 - 1) {
|
|
1095
1165
|
result.push(NaN);
|
|
1096
1166
|
} else {
|
|
1097
1167
|
const values = [];
|
|
1098
|
-
for (let j = 0; j <
|
|
1168
|
+
for (let j = 0; j < length2; j++) {
|
|
1099
1169
|
if (!isNaN(source[i - j])) {
|
|
1100
1170
|
values.push(source[i - j]);
|
|
1101
1171
|
}
|
|
@@ -1131,7 +1201,7 @@ function swma(source) {
|
|
|
1131
1201
|
}
|
|
1132
1202
|
return result;
|
|
1133
1203
|
}
|
|
1134
|
-
function vwma(source,
|
|
1204
|
+
function vwma(source, length2, volume2) {
|
|
1135
1205
|
if (!volume2) {
|
|
1136
1206
|
throw new Error(
|
|
1137
1207
|
"ta.vwma() requires volume series. Either pass it explicitly or use createContext({ chart: { ..., volume } }) for implicit data."
|
|
@@ -1141,8 +1211,8 @@ function vwma(source, length, volume2) {
|
|
|
1141
1211
|
for (let i = 0; i < source.length; i++) {
|
|
1142
1212
|
sourceTimesVolume.push(source[i] * volume2[i]);
|
|
1143
1213
|
}
|
|
1144
|
-
const numerator = sma(sourceTimesVolume,
|
|
1145
|
-
const denominator = sma(volume2,
|
|
1214
|
+
const numerator = sma(sourceTimesVolume, length2);
|
|
1215
|
+
const denominator = sma(volume2, length2);
|
|
1146
1216
|
const result = [];
|
|
1147
1217
|
for (let i = 0; i < source.length; i++) {
|
|
1148
1218
|
if (denominator[i] === 0 || isNaN(denominator[i])) {
|
|
@@ -1153,9 +1223,9 @@ function vwma(source, length, volume2) {
|
|
|
1153
1223
|
}
|
|
1154
1224
|
return result;
|
|
1155
1225
|
}
|
|
1156
|
-
function linreg(source,
|
|
1226
|
+
function linreg(source, length2, offset = 0) {
|
|
1157
1227
|
const result = [];
|
|
1158
|
-
const len = Math.floor(
|
|
1228
|
+
const len = Math.floor(length2);
|
|
1159
1229
|
for (let i = 0; i < source.length; i++) {
|
|
1160
1230
|
if (i < len - 1) {
|
|
1161
1231
|
result.push(NaN);
|
|
@@ -1191,14 +1261,14 @@ function linreg(source, length, offset = 0) {
|
|
|
1191
1261
|
}
|
|
1192
1262
|
return result;
|
|
1193
1263
|
}
|
|
1194
|
-
function correlation(source1, source2,
|
|
1264
|
+
function correlation(source1, source2, length2) {
|
|
1195
1265
|
const result = [];
|
|
1196
1266
|
for (let i = 0; i < source1.length; i++) {
|
|
1197
|
-
if (i <
|
|
1267
|
+
if (i < length2 - 1) {
|
|
1198
1268
|
result.push(NaN);
|
|
1199
1269
|
} else {
|
|
1200
1270
|
const pairs = [];
|
|
1201
|
-
for (let j = 0; j <
|
|
1271
|
+
for (let j = 0; j < length2; j++) {
|
|
1202
1272
|
if (!isNaN(source1[i - j]) && !isNaN(source2[i - j])) {
|
|
1203
1273
|
pairs.push([source1[i - j], source2[i - j]]);
|
|
1204
1274
|
}
|
|
@@ -1235,10 +1305,10 @@ function correlation(source1, source2, length) {
|
|
|
1235
1305
|
}
|
|
1236
1306
|
return result;
|
|
1237
1307
|
}
|
|
1238
|
-
function percentrank(source,
|
|
1308
|
+
function percentrank(source, length2) {
|
|
1239
1309
|
const result = [];
|
|
1240
1310
|
for (let i = 0; i < source.length; i++) {
|
|
1241
|
-
if (i <
|
|
1311
|
+
if (i < length2) {
|
|
1242
1312
|
result.push(NaN);
|
|
1243
1313
|
} else {
|
|
1244
1314
|
if (isNaN(source[i])) {
|
|
@@ -1246,7 +1316,7 @@ function percentrank(source, length) {
|
|
|
1246
1316
|
continue;
|
|
1247
1317
|
}
|
|
1248
1318
|
let hasNaN = false;
|
|
1249
|
-
for (let j = 1; j <=
|
|
1319
|
+
for (let j = 1; j <= length2; j++) {
|
|
1250
1320
|
if (isNaN(source[i - j])) {
|
|
1251
1321
|
hasNaN = true;
|
|
1252
1322
|
break;
|
|
@@ -1257,21 +1327,21 @@ function percentrank(source, length) {
|
|
|
1257
1327
|
} else {
|
|
1258
1328
|
const currentValue = source[i];
|
|
1259
1329
|
let countLessOrEqual = 0;
|
|
1260
|
-
for (let j = 1; j <=
|
|
1330
|
+
for (let j = 1; j <= length2; j++) {
|
|
1261
1331
|
if (source[i - j] <= currentValue) {
|
|
1262
1332
|
countLessOrEqual++;
|
|
1263
1333
|
}
|
|
1264
1334
|
}
|
|
1265
|
-
result.push(countLessOrEqual /
|
|
1335
|
+
result.push(countLessOrEqual / length2 * 100);
|
|
1266
1336
|
}
|
|
1267
1337
|
}
|
|
1268
1338
|
}
|
|
1269
1339
|
return result;
|
|
1270
1340
|
}
|
|
1271
|
-
function cci(source,
|
|
1341
|
+
function cci(source, length2) {
|
|
1272
1342
|
const result = [];
|
|
1273
|
-
const smaValues = sma(source,
|
|
1274
|
-
const devValues = dev(source,
|
|
1343
|
+
const smaValues = sma(source, length2);
|
|
1344
|
+
const devValues = dev(source, length2);
|
|
1275
1345
|
for (let i = 0; i < source.length; i++) {
|
|
1276
1346
|
if (isNaN(smaValues[i]) || isNaN(devValues[i]) || devValues[i] === 0) {
|
|
1277
1347
|
result.push(NaN);
|
|
@@ -1282,10 +1352,10 @@ function cci(source, length) {
|
|
|
1282
1352
|
}
|
|
1283
1353
|
return result;
|
|
1284
1354
|
}
|
|
1285
|
-
function stoch(source, high2, low2,
|
|
1355
|
+
function stoch(source, high2, low2, length2) {
|
|
1286
1356
|
const result = [];
|
|
1287
|
-
const lowestValues = lowest(low2,
|
|
1288
|
-
const highestValues = highest(high2,
|
|
1357
|
+
const lowestValues = lowest(low2, length2);
|
|
1358
|
+
const highestValues = highest(high2, length2);
|
|
1289
1359
|
for (let i = 0; i < source.length; i++) {
|
|
1290
1360
|
if (isNaN(lowestValues[i]) || isNaN(highestValues[i])) {
|
|
1291
1361
|
result.push(NaN);
|
|
@@ -1301,7 +1371,7 @@ function stoch(source, high2, low2, length) {
|
|
|
1301
1371
|
}
|
|
1302
1372
|
return result;
|
|
1303
1373
|
}
|
|
1304
|
-
function mfi(source,
|
|
1374
|
+
function mfi(source, length2, volume2) {
|
|
1305
1375
|
if (!volume2) {
|
|
1306
1376
|
throw new Error(
|
|
1307
1377
|
"ta.mfi() requires volume series. Either pass it explicitly or use createContext({ chart: { ..., volume } }) for implicit data."
|
|
@@ -1330,12 +1400,12 @@ function mfi(source, length, volume2) {
|
|
|
1330
1400
|
}
|
|
1331
1401
|
}
|
|
1332
1402
|
for (let i = 0; i < source.length; i++) {
|
|
1333
|
-
if (i <
|
|
1403
|
+
if (i < length2) {
|
|
1334
1404
|
result.push(NaN);
|
|
1335
1405
|
} else {
|
|
1336
1406
|
let posSum = 0;
|
|
1337
1407
|
let negSum = 0;
|
|
1338
|
-
for (let j = 0; j <
|
|
1408
|
+
for (let j = 0; j < length2; j++) {
|
|
1339
1409
|
posSum += positiveFlow[i - j];
|
|
1340
1410
|
negSum += negativeFlow[i - j];
|
|
1341
1411
|
}
|
|
@@ -1350,11 +1420,11 @@ function mfi(source, length, volume2) {
|
|
|
1350
1420
|
}
|
|
1351
1421
|
return result;
|
|
1352
1422
|
}
|
|
1353
|
-
function hma(source,
|
|
1354
|
-
const halfLength = Math.floor(
|
|
1355
|
-
const sqrtLength = Math.floor(Math.sqrt(
|
|
1423
|
+
function hma(source, length2) {
|
|
1424
|
+
const halfLength = Math.floor(length2 / 2);
|
|
1425
|
+
const sqrtLength = Math.floor(Math.sqrt(length2));
|
|
1356
1426
|
const wmaHalf = wma(source, halfLength);
|
|
1357
|
-
const wmaFull = wma(source,
|
|
1427
|
+
const wmaFull = wma(source, length2);
|
|
1358
1428
|
const diff = [];
|
|
1359
1429
|
for (let i = 0; i < source.length; i++) {
|
|
1360
1430
|
diff.push(2 * wmaHalf[i] - wmaFull[i]);
|
|
@@ -1438,89 +1508,44 @@ function sar(start, inc, max4, high2, low2, close2) {
|
|
|
1438
1508
|
}
|
|
1439
1509
|
return result;
|
|
1440
1510
|
}
|
|
1511
|
+
function pivot(source, leftbars, rightbars, isHigh) {
|
|
1512
|
+
const beatsLeft = isHigh ? (x, v) => x > v : (x, v) => x < v;
|
|
1513
|
+
const beatsRight = isHigh ? (x, v) => x >= v : (x, v) => x <= v;
|
|
1514
|
+
return source.map((_, i) => {
|
|
1515
|
+
const center = i - rightbars;
|
|
1516
|
+
if (center - leftbars < 0) return NaN;
|
|
1517
|
+
const v = source[center];
|
|
1518
|
+
if (Number.isNaN(v)) return NaN;
|
|
1519
|
+
for (let j = 1; j <= leftbars; j++) {
|
|
1520
|
+
const x = source[center - j];
|
|
1521
|
+
if (Number.isNaN(x)) break;
|
|
1522
|
+
if (beatsLeft(x, v)) return NaN;
|
|
1523
|
+
}
|
|
1524
|
+
for (let j = 1; j <= rightbars; j++) {
|
|
1525
|
+
const x = source[center + j];
|
|
1526
|
+
if (Number.isNaN(x)) break;
|
|
1527
|
+
if (beatsRight(x, v)) return NaN;
|
|
1528
|
+
}
|
|
1529
|
+
return v;
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1441
1532
|
function pivothigh(sourceOrLeftbars, leftbarsOrRightbars, rightbars, high2) {
|
|
1442
|
-
let source;
|
|
1443
|
-
let leftbars;
|
|
1444
|
-
let right;
|
|
1445
1533
|
if (rightbars === void 0) {
|
|
1446
1534
|
if (!high2) {
|
|
1447
1535
|
throw new Error("ta.pivothigh() requires high series when using two-parameter version.");
|
|
1448
1536
|
}
|
|
1449
|
-
|
|
1450
|
-
leftbars = sourceOrLeftbars;
|
|
1451
|
-
right = leftbarsOrRightbars;
|
|
1452
|
-
} else {
|
|
1453
|
-
source = sourceOrLeftbars;
|
|
1454
|
-
leftbars = leftbarsOrRightbars;
|
|
1455
|
-
right = rightbars;
|
|
1456
|
-
}
|
|
1457
|
-
const result = [];
|
|
1458
|
-
for (let i = 0; i < source.length; i++) {
|
|
1459
|
-
if (i < leftbars || i + right >= source.length) {
|
|
1460
|
-
result.push(NaN);
|
|
1461
|
-
continue;
|
|
1462
|
-
}
|
|
1463
|
-
const centerValue = source[i];
|
|
1464
|
-
let isPivot = true;
|
|
1465
|
-
for (let j = 1; j <= leftbars; j++) {
|
|
1466
|
-
if (source[i - j] >= centerValue) {
|
|
1467
|
-
isPivot = false;
|
|
1468
|
-
break;
|
|
1469
|
-
}
|
|
1470
|
-
}
|
|
1471
|
-
if (isPivot) {
|
|
1472
|
-
for (let j = 1; j <= right; j++) {
|
|
1473
|
-
if (source[i + j] >= centerValue) {
|
|
1474
|
-
isPivot = false;
|
|
1475
|
-
break;
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
|
-
}
|
|
1479
|
-
result.push(isPivot ? centerValue : NaN);
|
|
1537
|
+
return pivot(high2, sourceOrLeftbars, leftbarsOrRightbars, true);
|
|
1480
1538
|
}
|
|
1481
|
-
return
|
|
1539
|
+
return pivot(sourceOrLeftbars, leftbarsOrRightbars, rightbars, true);
|
|
1482
1540
|
}
|
|
1483
1541
|
function pivotlow(sourceOrLeftbars, leftbarsOrRightbars, rightbars, low2) {
|
|
1484
|
-
let source;
|
|
1485
|
-
let leftbars;
|
|
1486
|
-
let right;
|
|
1487
1542
|
if (rightbars === void 0) {
|
|
1488
1543
|
if (!low2) {
|
|
1489
1544
|
throw new Error("ta.pivotlow() requires low series when using two-parameter version.");
|
|
1490
1545
|
}
|
|
1491
|
-
|
|
1492
|
-
leftbars = sourceOrLeftbars;
|
|
1493
|
-
right = leftbarsOrRightbars;
|
|
1494
|
-
} else {
|
|
1495
|
-
source = sourceOrLeftbars;
|
|
1496
|
-
leftbars = leftbarsOrRightbars;
|
|
1497
|
-
right = rightbars;
|
|
1498
|
-
}
|
|
1499
|
-
const result = [];
|
|
1500
|
-
for (let i = 0; i < source.length; i++) {
|
|
1501
|
-
if (i < leftbars || i + right >= source.length) {
|
|
1502
|
-
result.push(NaN);
|
|
1503
|
-
continue;
|
|
1504
|
-
}
|
|
1505
|
-
const centerValue = source[i];
|
|
1506
|
-
let isPivot = true;
|
|
1507
|
-
for (let j = 1; j <= leftbars; j++) {
|
|
1508
|
-
if (source[i - j] <= centerValue) {
|
|
1509
|
-
isPivot = false;
|
|
1510
|
-
break;
|
|
1511
|
-
}
|
|
1512
|
-
}
|
|
1513
|
-
if (isPivot) {
|
|
1514
|
-
for (let j = 1; j <= right; j++) {
|
|
1515
|
-
if (source[i + j] <= centerValue) {
|
|
1516
|
-
isPivot = false;
|
|
1517
|
-
break;
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
result.push(isPivot ? centerValue : NaN);
|
|
1546
|
+
return pivot(low2, sourceOrLeftbars, leftbarsOrRightbars, false);
|
|
1522
1547
|
}
|
|
1523
|
-
return
|
|
1548
|
+
return pivot(sourceOrLeftbars, leftbarsOrRightbars, rightbars, false);
|
|
1524
1549
|
}
|
|
1525
1550
|
function barssince(condition) {
|
|
1526
1551
|
const result = [];
|
|
@@ -1625,16 +1650,16 @@ function tsi(source, shortLength, longLength) {
|
|
|
1625
1650
|
}
|
|
1626
1651
|
return result;
|
|
1627
1652
|
}
|
|
1628
|
-
function cmo(source,
|
|
1653
|
+
function cmo(source, length2) {
|
|
1629
1654
|
const result = [];
|
|
1630
1655
|
for (let i = 0; i < source.length; i++) {
|
|
1631
|
-
if (i <
|
|
1656
|
+
if (i < length2) {
|
|
1632
1657
|
result.push(NaN);
|
|
1633
1658
|
continue;
|
|
1634
1659
|
}
|
|
1635
1660
|
let sumGains = 0;
|
|
1636
1661
|
let sumLosses = 0;
|
|
1637
|
-
for (let j = 0; j <
|
|
1662
|
+
for (let j = 0; j < length2; j++) {
|
|
1638
1663
|
const change3 = source[i - j] - source[i - j - 1];
|
|
1639
1664
|
if (change3 > 0) {
|
|
1640
1665
|
sumGains += change3;
|
|
@@ -1652,8 +1677,8 @@ function cmo(source, length) {
|
|
|
1652
1677
|
}
|
|
1653
1678
|
return result;
|
|
1654
1679
|
}
|
|
1655
|
-
function kc(source,
|
|
1656
|
-
const middle = ema(source,
|
|
1680
|
+
function kc(source, length2, mult, useTrueRange = true, high2, low2, close2) {
|
|
1681
|
+
const middle = ema(source, length2);
|
|
1657
1682
|
let range3;
|
|
1658
1683
|
if (useTrueRange) {
|
|
1659
1684
|
if (!high2 || !low2 || !close2) {
|
|
@@ -1669,38 +1694,38 @@ function kc(source, length, mult, useTrueRange = true, high2, low2, close2) {
|
|
|
1669
1694
|
range3.push(high2[i] - low2[i]);
|
|
1670
1695
|
}
|
|
1671
1696
|
}
|
|
1672
|
-
const rangeEma = ema(range3,
|
|
1673
|
-
const
|
|
1674
|
-
const
|
|
1697
|
+
const rangeEma = ema(range3, length2);
|
|
1698
|
+
const upper2 = [];
|
|
1699
|
+
const lower2 = [];
|
|
1675
1700
|
for (let i = 0; i < middle.length; i++) {
|
|
1676
|
-
|
|
1677
|
-
|
|
1701
|
+
upper2.push(middle[i] + rangeEma[i] * mult);
|
|
1702
|
+
lower2.push(middle[i] - rangeEma[i] * mult);
|
|
1678
1703
|
}
|
|
1679
|
-
return [middle,
|
|
1704
|
+
return [middle, upper2, lower2];
|
|
1680
1705
|
}
|
|
1681
|
-
function bbw(source,
|
|
1682
|
-
const [basis,
|
|
1706
|
+
function bbw(source, length2, mult) {
|
|
1707
|
+
const [basis, upper2, lower2] = bb(source, length2, mult);
|
|
1683
1708
|
const result = [];
|
|
1684
1709
|
for (let i = 0; i < source.length; i++) {
|
|
1685
1710
|
if (basis[i] === 0) {
|
|
1686
1711
|
result.push(NaN);
|
|
1687
1712
|
} else {
|
|
1688
|
-
const width = (
|
|
1713
|
+
const width = (upper2[i] - lower2[i]) / basis[i] * 100;
|
|
1689
1714
|
result.push(width);
|
|
1690
1715
|
}
|
|
1691
1716
|
}
|
|
1692
1717
|
return result;
|
|
1693
1718
|
}
|
|
1694
|
-
function wpr(high2, low2, close2,
|
|
1719
|
+
function wpr(high2, low2, close2, length2 = 14) {
|
|
1695
1720
|
const result = [];
|
|
1696
1721
|
for (let i = 0; i < close2.length; i++) {
|
|
1697
|
-
if (i <
|
|
1722
|
+
if (i < length2 - 1) {
|
|
1698
1723
|
result.push(NaN);
|
|
1699
1724
|
continue;
|
|
1700
1725
|
}
|
|
1701
|
-
let highestHigh = high2[i -
|
|
1702
|
-
let lowestLow = low2[i -
|
|
1703
|
-
for (let j = i -
|
|
1726
|
+
let highestHigh = high2[i - length2 + 1];
|
|
1727
|
+
let lowestLow = low2[i - length2 + 1];
|
|
1728
|
+
for (let j = i - length2 + 2; j <= i; j++) {
|
|
1704
1729
|
if (high2[j] > highestHigh) highestHigh = high2[j];
|
|
1705
1730
|
if (low2[j] < lowestLow) lowestLow = low2[j];
|
|
1706
1731
|
}
|
|
@@ -1714,181 +1739,138 @@ function wpr(high2, low2, close2, length = 14) {
|
|
|
1714
1739
|
}
|
|
1715
1740
|
return result;
|
|
1716
1741
|
}
|
|
1717
|
-
function vwap(source, volume2) {
|
|
1742
|
+
function vwap(source, volume2, anchor, stdev_mult) {
|
|
1718
1743
|
if (source.length !== volume2.length) {
|
|
1719
1744
|
throw new Error("ta.vwap: source and volume must have the same length");
|
|
1720
1745
|
}
|
|
1721
|
-
const
|
|
1722
|
-
|
|
1723
|
-
|
|
1746
|
+
const mid = [];
|
|
1747
|
+
const upper2 = [];
|
|
1748
|
+
const lower2 = [];
|
|
1749
|
+
let sumPV = 0;
|
|
1750
|
+
let sumV = 0;
|
|
1751
|
+
let sumPPV = 0;
|
|
1724
1752
|
for (let i = 0; i < source.length; i++) {
|
|
1725
|
-
if (
|
|
1726
|
-
|
|
1727
|
-
|
|
1753
|
+
if (anchor && anchor[i]) {
|
|
1754
|
+
sumPV = 0;
|
|
1755
|
+
sumV = 0;
|
|
1756
|
+
sumPPV = 0;
|
|
1728
1757
|
}
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
if (
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1758
|
+
const s = source[i];
|
|
1759
|
+
const v = volume2[i];
|
|
1760
|
+
if (!Number.isNaN(s) && !Number.isNaN(v)) {
|
|
1761
|
+
sumPV += s * v;
|
|
1762
|
+
sumV += v;
|
|
1763
|
+
sumPPV += s * s * v;
|
|
1764
|
+
}
|
|
1765
|
+
const m = sumV === 0 ? NaN : sumPV / sumV;
|
|
1766
|
+
mid.push(m);
|
|
1767
|
+
if (stdev_mult !== void 0) {
|
|
1768
|
+
const sd = Math.sqrt(Math.max(0, sumPPV / sumV - m * m));
|
|
1769
|
+
upper2.push(m + stdev_mult * sd);
|
|
1770
|
+
lower2.push(m - stdev_mult * sd);
|
|
1735
1771
|
}
|
|
1736
1772
|
}
|
|
1737
|
-
return
|
|
1773
|
+
return stdev_mult === void 0 ? mid : [mid, upper2, lower2];
|
|
1738
1774
|
}
|
|
1739
|
-
function alma(source,
|
|
1775
|
+
function alma(source, length2 = 9, offset = 0.85, sigma = 6, floor2 = false) {
|
|
1740
1776
|
const result = [];
|
|
1741
|
-
const m = floor2 ? Math.floor(offset * (
|
|
1742
|
-
const s =
|
|
1777
|
+
const m = floor2 ? Math.floor(offset * (length2 - 1)) : offset * (length2 - 1);
|
|
1778
|
+
const s = length2 / sigma;
|
|
1743
1779
|
const weights = [];
|
|
1744
1780
|
let weightSum = 0;
|
|
1745
|
-
for (let i = 0; i <
|
|
1781
|
+
for (let i = 0; i < length2; i++) {
|
|
1746
1782
|
const weight = Math.exp(-1 * Math.pow(i - m, 2) / (2 * Math.pow(s, 2)));
|
|
1747
1783
|
weights.push(weight);
|
|
1748
1784
|
weightSum += weight;
|
|
1749
1785
|
}
|
|
1750
|
-
for (let i = 0; i <
|
|
1786
|
+
for (let i = 0; i < length2; i++) {
|
|
1751
1787
|
weights[i] /= weightSum;
|
|
1752
1788
|
}
|
|
1753
1789
|
for (let i = 0; i < source.length; i++) {
|
|
1754
|
-
if (i <
|
|
1790
|
+
if (i < length2 - 1) {
|
|
1755
1791
|
result.push(NaN);
|
|
1756
1792
|
continue;
|
|
1757
1793
|
}
|
|
1758
1794
|
let almaValue = 0;
|
|
1759
|
-
for (let j = 0; j <
|
|
1760
|
-
almaValue += source[i -
|
|
1795
|
+
for (let j = 0; j < length2; j++) {
|
|
1796
|
+
almaValue += source[i - length2 + 1 + j] * weights[j];
|
|
1761
1797
|
}
|
|
1762
1798
|
result.push(almaValue);
|
|
1763
1799
|
}
|
|
1764
1800
|
return result;
|
|
1765
1801
|
}
|
|
1766
|
-
function kcw(source,
|
|
1767
|
-
const [basis,
|
|
1802
|
+
function kcw(source, length2 = 20, mult = 2, useTrueRange = true, high2, low2, close2) {
|
|
1803
|
+
const [basis, upper2, lower2] = kc(source, length2, mult, useTrueRange, high2, low2, close2);
|
|
1768
1804
|
const result = [];
|
|
1769
1805
|
for (let i = 0; i < source.length; i++) {
|
|
1770
1806
|
if (isNaN(basis[i]) || basis[i] === 0) {
|
|
1771
1807
|
result.push(NaN);
|
|
1772
1808
|
} else {
|
|
1773
|
-
const width = (
|
|
1809
|
+
const width = (upper2[i] - lower2[i]) / basis[i] * 100;
|
|
1774
1810
|
result.push(width);
|
|
1775
1811
|
}
|
|
1776
1812
|
}
|
|
1777
1813
|
return result;
|
|
1778
1814
|
}
|
|
1779
|
-
function range(
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
for (let i = 0; i < high2.length; i++) {
|
|
1785
|
-
if (isNaN(high2[i]) || isNaN(low2[i])) {
|
|
1786
|
-
result.push(NaN);
|
|
1787
|
-
} else {
|
|
1788
|
-
result.push(high2[i] - low2[i]);
|
|
1789
|
-
}
|
|
1790
|
-
}
|
|
1791
|
-
return result;
|
|
1815
|
+
function range(source, length2) {
|
|
1816
|
+
return source.map((_, i) => {
|
|
1817
|
+
const values = lastValues(source, i, length2);
|
|
1818
|
+
return values ? Math.max(...values) - Math.min(...values) : NaN;
|
|
1819
|
+
});
|
|
1792
1820
|
}
|
|
1793
|
-
function highestbars(source,
|
|
1794
|
-
|
|
1795
|
-
for (let i = 0; i < source.length; i++) {
|
|
1796
|
-
if (i < length - 1) {
|
|
1797
|
-
result.push(NaN);
|
|
1798
|
-
continue;
|
|
1799
|
-
}
|
|
1800
|
-
let highestValue = source[i - length + 1];
|
|
1801
|
-
let highestOffset = length - 1;
|
|
1802
|
-
for (let j = i - length + 2; j <= i; j++) {
|
|
1803
|
-
if (source[j] > highestValue) {
|
|
1804
|
-
highestValue = source[j];
|
|
1805
|
-
highestOffset = i - j;
|
|
1806
|
-
}
|
|
1807
|
-
}
|
|
1808
|
-
result.push(highestOffset);
|
|
1809
|
-
}
|
|
1810
|
-
return result;
|
|
1821
|
+
function highestbars(source, length2) {
|
|
1822
|
+
return extremeOffset(source, length2, (a, b2) => a >= b2);
|
|
1811
1823
|
}
|
|
1812
|
-
function lowestbars(source,
|
|
1813
|
-
|
|
1814
|
-
for (let i = 0; i < source.length; i++) {
|
|
1815
|
-
if (i < length - 1) {
|
|
1816
|
-
result.push(NaN);
|
|
1817
|
-
continue;
|
|
1818
|
-
}
|
|
1819
|
-
let lowestValue = source[i - length + 1];
|
|
1820
|
-
let lowestOffset = length - 1;
|
|
1821
|
-
for (let j = i - length + 2; j <= i; j++) {
|
|
1822
|
-
if (source[j] < lowestValue) {
|
|
1823
|
-
lowestValue = source[j];
|
|
1824
|
-
lowestOffset = i - j;
|
|
1825
|
-
}
|
|
1826
|
-
}
|
|
1827
|
-
result.push(lowestOffset);
|
|
1828
|
-
}
|
|
1829
|
-
return result;
|
|
1824
|
+
function lowestbars(source, length2) {
|
|
1825
|
+
return extremeOffset(source, length2, (a, b2) => a <= b2);
|
|
1830
1826
|
}
|
|
1831
|
-
function max(
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
if (isNaN(source1[i]) || isNaN(source2[i])) {
|
|
1838
|
-
result.push(NaN);
|
|
1839
|
-
} else {
|
|
1840
|
-
result.push(Math.max(source1[i], source2[i]));
|
|
1841
|
-
}
|
|
1842
|
-
}
|
|
1843
|
-
return result;
|
|
1827
|
+
function max(source) {
|
|
1828
|
+
let best = NaN;
|
|
1829
|
+
return source.map((x) => {
|
|
1830
|
+
if (!Number.isNaN(x) && !(x <= best)) best = x;
|
|
1831
|
+
return best;
|
|
1832
|
+
});
|
|
1844
1833
|
}
|
|
1845
|
-
function min(
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
if (isNaN(source1[i]) || isNaN(source2[i])) {
|
|
1852
|
-
result.push(NaN);
|
|
1853
|
-
} else {
|
|
1854
|
-
result.push(Math.min(source1[i], source2[i]));
|
|
1855
|
-
}
|
|
1856
|
-
}
|
|
1857
|
-
return result;
|
|
1834
|
+
function min(source) {
|
|
1835
|
+
let best = NaN;
|
|
1836
|
+
return source.map((x) => {
|
|
1837
|
+
if (!Number.isNaN(x) && !(x >= best)) best = x;
|
|
1838
|
+
return best;
|
|
1839
|
+
});
|
|
1858
1840
|
}
|
|
1859
|
-
function cog(source,
|
|
1841
|
+
function cog(source, length2 = 10) {
|
|
1860
1842
|
const result = [];
|
|
1861
1843
|
for (let i = 0; i < source.length; i++) {
|
|
1862
|
-
if (i <
|
|
1844
|
+
if (i < length2 - 1) {
|
|
1863
1845
|
result.push(NaN);
|
|
1864
1846
|
continue;
|
|
1865
1847
|
}
|
|
1866
1848
|
let numerator = 0;
|
|
1867
1849
|
let denominator = 0;
|
|
1868
|
-
for (let j = 0; j <
|
|
1850
|
+
for (let j = 0; j < length2; j++) {
|
|
1869
1851
|
const weight = j + 1;
|
|
1870
|
-
const price = source[i -
|
|
1852
|
+
const price = source[i - length2 + 1 + j];
|
|
1871
1853
|
numerator += weight * price;
|
|
1872
1854
|
denominator += price;
|
|
1873
1855
|
}
|
|
1874
1856
|
if (denominator === 0) {
|
|
1875
1857
|
result.push(NaN);
|
|
1876
1858
|
} else {
|
|
1877
|
-
const cog3 = -1 * (numerator / denominator) + (
|
|
1859
|
+
const cog3 = -1 * (numerator / denominator) + (length2 + 1) / 2;
|
|
1878
1860
|
result.push(cog3);
|
|
1879
1861
|
}
|
|
1880
1862
|
}
|
|
1881
1863
|
return result;
|
|
1882
1864
|
}
|
|
1883
|
-
function mode(source,
|
|
1865
|
+
function mode(source, length2) {
|
|
1884
1866
|
const result = [];
|
|
1885
1867
|
for (let i = 0; i < source.length; i++) {
|
|
1886
|
-
if (i <
|
|
1868
|
+
if (i < length2 - 1) {
|
|
1887
1869
|
result.push(NaN);
|
|
1888
1870
|
continue;
|
|
1889
1871
|
}
|
|
1890
1872
|
const values = [];
|
|
1891
|
-
for (let j = 0; j <
|
|
1873
|
+
for (let j = 0; j < length2; j++) {
|
|
1892
1874
|
const value = source[i - j];
|
|
1893
1875
|
if (!isNaN(value)) {
|
|
1894
1876
|
values.push(value);
|
|
@@ -1918,15 +1900,15 @@ function mode(source, length) {
|
|
|
1918
1900
|
}
|
|
1919
1901
|
return result;
|
|
1920
1902
|
}
|
|
1921
|
-
function percentile_linear_interpolation(source,
|
|
1903
|
+
function percentile_linear_interpolation(source, length2, percentage) {
|
|
1922
1904
|
const result = [];
|
|
1923
1905
|
for (let i = 0; i < source.length; i++) {
|
|
1924
|
-
if (i <
|
|
1906
|
+
if (i < length2 - 1) {
|
|
1925
1907
|
result.push(NaN);
|
|
1926
1908
|
continue;
|
|
1927
1909
|
}
|
|
1928
1910
|
const values = [];
|
|
1929
|
-
for (let j = 0; j <
|
|
1911
|
+
for (let j = 0; j < length2; j++) {
|
|
1930
1912
|
const value = source[i - j];
|
|
1931
1913
|
values.push(value);
|
|
1932
1914
|
}
|
|
@@ -1948,15 +1930,15 @@ function percentile_linear_interpolation(source, length, percentage) {
|
|
|
1948
1930
|
}
|
|
1949
1931
|
return result;
|
|
1950
1932
|
}
|
|
1951
|
-
function percentile_nearest_rank(source,
|
|
1933
|
+
function percentile_nearest_rank(source, length2, percentage) {
|
|
1952
1934
|
const result = [];
|
|
1953
1935
|
for (let i = 0; i < source.length; i++) {
|
|
1954
|
-
if (i <
|
|
1936
|
+
if (i < length2 - 1) {
|
|
1955
1937
|
result.push(NaN);
|
|
1956
1938
|
continue;
|
|
1957
1939
|
}
|
|
1958
1940
|
const values = [];
|
|
1959
|
-
for (let j = 0; j <
|
|
1941
|
+
for (let j = 0; j < length2; j++) {
|
|
1960
1942
|
const value = source[i - j];
|
|
1961
1943
|
if (!isNaN(value)) {
|
|
1962
1944
|
values.push(value);
|
|
@@ -1977,16 +1959,16 @@ function percentile_nearest_rank(source, length, percentage) {
|
|
|
1977
1959
|
}
|
|
1978
1960
|
return result;
|
|
1979
1961
|
}
|
|
1980
|
-
function rci(source,
|
|
1962
|
+
function rci(source, length2) {
|
|
1981
1963
|
const result = [];
|
|
1982
1964
|
for (let i = 0; i < source.length; i++) {
|
|
1983
|
-
if (i <
|
|
1965
|
+
if (i < length2 - 1) {
|
|
1984
1966
|
result.push(NaN);
|
|
1985
1967
|
continue;
|
|
1986
1968
|
}
|
|
1987
1969
|
const values = [];
|
|
1988
|
-
for (let j = 0; j <
|
|
1989
|
-
values.push(source[i -
|
|
1970
|
+
for (let j = 0; j < length2; j++) {
|
|
1971
|
+
values.push(source[i - length2 + 1 + j]);
|
|
1990
1972
|
}
|
|
1991
1973
|
if (values.some((v) => isNaN(v))) {
|
|
1992
1974
|
result.push(NaN);
|
|
@@ -1994,7 +1976,7 @@ function rci(source, length) {
|
|
|
1994
1976
|
}
|
|
1995
1977
|
const indexed = values.map((value, index) => ({ value, index }));
|
|
1996
1978
|
const sorted = [...indexed].sort((a, b2) => a.value - b2.value);
|
|
1997
|
-
const ranks = new Array(
|
|
1979
|
+
const ranks = new Array(length2).fill(0);
|
|
1998
1980
|
let currentRank = 1;
|
|
1999
1981
|
for (let j = 0; j < sorted.length; j++) {
|
|
2000
1982
|
let tieCount = 1;
|
|
@@ -2009,12 +1991,12 @@ function rci(source, length) {
|
|
|
2009
1991
|
currentRank += tieCount;
|
|
2010
1992
|
}
|
|
2011
1993
|
let sumSquaredDiff = 0;
|
|
2012
|
-
for (let j = 0; j <
|
|
1994
|
+
for (let j = 0; j < length2; j++) {
|
|
2013
1995
|
const timeRank = j + 1;
|
|
2014
1996
|
const diff = ranks[j] - timeRank;
|
|
2015
1997
|
sumSquaredDiff += diff * diff;
|
|
2016
1998
|
}
|
|
2017
|
-
const n =
|
|
1999
|
+
const n = length2;
|
|
2018
2000
|
const base = (n * n * n - n) / 12;
|
|
2019
2001
|
let tieCorrection = 0;
|
|
2020
2002
|
for (let j = 0; j < sorted.length; ) {
|
|
@@ -2040,11 +2022,11 @@ function rci(source, length) {
|
|
|
2040
2022
|
return result;
|
|
2041
2023
|
}
|
|
2042
2024
|
function ichimoku(conversionPeriods, basePeriods, laggingSpan2Periods, displacement, high2, low2, close2) {
|
|
2043
|
-
const
|
|
2025
|
+
const length2 = high2.length;
|
|
2044
2026
|
const highestConversion = highest(high2, conversionPeriods);
|
|
2045
2027
|
const lowestConversion = lowest(low2, conversionPeriods);
|
|
2046
2028
|
const tenkanSen = [];
|
|
2047
|
-
for (let i = 0; i <
|
|
2029
|
+
for (let i = 0; i < length2; i++) {
|
|
2048
2030
|
if (isNaN(highestConversion[i]) || isNaN(lowestConversion[i])) {
|
|
2049
2031
|
tenkanSen.push(NaN);
|
|
2050
2032
|
} else {
|
|
@@ -2054,7 +2036,7 @@ function ichimoku(conversionPeriods, basePeriods, laggingSpan2Periods, displacem
|
|
|
2054
2036
|
const highestBase = highest(high2, basePeriods);
|
|
2055
2037
|
const lowestBase = lowest(low2, basePeriods);
|
|
2056
2038
|
const kijunSen = [];
|
|
2057
|
-
for (let i = 0; i <
|
|
2039
|
+
for (let i = 0; i < length2; i++) {
|
|
2058
2040
|
if (isNaN(highestBase[i]) || isNaN(lowestBase[i])) {
|
|
2059
2041
|
kijunSen.push(NaN);
|
|
2060
2042
|
} else {
|
|
@@ -2062,7 +2044,7 @@ function ichimoku(conversionPeriods, basePeriods, laggingSpan2Periods, displacem
|
|
|
2062
2044
|
}
|
|
2063
2045
|
}
|
|
2064
2046
|
const senkouSpanA = [];
|
|
2065
|
-
for (let i = 0; i <
|
|
2047
|
+
for (let i = 0; i < length2; i++) {
|
|
2066
2048
|
const sourceIndex = i - displacement;
|
|
2067
2049
|
if (sourceIndex < 0 || isNaN(tenkanSen[sourceIndex]) || isNaN(kijunSen[sourceIndex])) {
|
|
2068
2050
|
senkouSpanA.push(NaN);
|
|
@@ -2073,7 +2055,7 @@ function ichimoku(conversionPeriods, basePeriods, laggingSpan2Periods, displacem
|
|
|
2073
2055
|
const highestLagging = highest(high2, laggingSpan2Periods);
|
|
2074
2056
|
const lowestLagging = lowest(low2, laggingSpan2Periods);
|
|
2075
2057
|
const senkouSpanB = [];
|
|
2076
|
-
for (let i = 0; i <
|
|
2058
|
+
for (let i = 0; i < length2; i++) {
|
|
2077
2059
|
const sourceIndex = i - displacement;
|
|
2078
2060
|
if (sourceIndex < 0 || isNaN(highestLagging[sourceIndex]) || isNaN(lowestLagging[sourceIndex])) {
|
|
2079
2061
|
senkouSpanB.push(NaN);
|
|
@@ -2082,9 +2064,9 @@ function ichimoku(conversionPeriods, basePeriods, laggingSpan2Periods, displacem
|
|
|
2082
2064
|
}
|
|
2083
2065
|
}
|
|
2084
2066
|
const chikouSpan = [];
|
|
2085
|
-
for (let i = 0; i <
|
|
2067
|
+
for (let i = 0; i < length2; i++) {
|
|
2086
2068
|
const sourceIndex = i + displacement;
|
|
2087
|
-
if (sourceIndex >=
|
|
2069
|
+
if (sourceIndex >= length2 || isNaN(close2[sourceIndex])) {
|
|
2088
2070
|
chikouSpan.push(NaN);
|
|
2089
2071
|
} else {
|
|
2090
2072
|
chikouSpan.push(close2[sourceIndex]);
|
|
@@ -2106,13 +2088,13 @@ function zigzag(deviation = 5, depth = 10, backstep = 3, source, high2, low2) {
|
|
|
2106
2088
|
"ta.zigzag() requires either source series or high/low series. Either pass them explicitly or use createContext({ chart: { high, low, close } }) for implicit data."
|
|
2107
2089
|
);
|
|
2108
2090
|
}
|
|
2109
|
-
const
|
|
2110
|
-
if (lowSource.length !==
|
|
2091
|
+
const length2 = highSource.length;
|
|
2092
|
+
if (lowSource.length !== length2) {
|
|
2111
2093
|
throw new Error("ta.zigzag: high and low must have the same length");
|
|
2112
2094
|
}
|
|
2113
|
-
const zigzagValues = new Array(
|
|
2114
|
-
const directions = new Array(
|
|
2115
|
-
const isPivot = new Array(
|
|
2095
|
+
const zigzagValues = new Array(length2).fill(NaN);
|
|
2096
|
+
const directions = new Array(length2).fill(0);
|
|
2097
|
+
const isPivot = new Array(length2).fill(false);
|
|
2116
2098
|
const getDeviation = (price1, price2) => {
|
|
2117
2099
|
if (Math.abs(price1) < 1e-10 || isNaN(price1) || isNaN(price2)) return 0;
|
|
2118
2100
|
return Math.abs((price2 - price1) / price1) * 100;
|
|
@@ -2126,7 +2108,7 @@ function zigzag(deviation = 5, depth = 10, backstep = 3, source, high2, low2) {
|
|
|
2126
2108
|
let initialLowest = Infinity;
|
|
2127
2109
|
let initialHighIndex = -1;
|
|
2128
2110
|
let initialLowIndex = -1;
|
|
2129
|
-
for (let i = 0; i < Math.min(depth,
|
|
2111
|
+
for (let i = 0; i < Math.min(depth, length2); i++) {
|
|
2130
2112
|
if (!isNaN(highSource[i]) && highSource[i] > initialHighest) {
|
|
2131
2113
|
initialHighest = highSource[i];
|
|
2132
2114
|
initialHighIndex = i;
|
|
@@ -2149,7 +2131,7 @@ function zigzag(deviation = 5, depth = 10, backstep = 3, source, high2, low2) {
|
|
|
2149
2131
|
} else {
|
|
2150
2132
|
startIndex = depth;
|
|
2151
2133
|
}
|
|
2152
|
-
for (let i = Math.max(startIndex, depth); i <
|
|
2134
|
+
for (let i = Math.max(startIndex, depth); i < length2; i++) {
|
|
2153
2135
|
const currentHigh = highSource[i];
|
|
2154
2136
|
const currentLow = lowSource[i];
|
|
2155
2137
|
if (isNaN(currentHigh) || isNaN(currentLow)) {
|
|
@@ -2227,53 +2209,116 @@ function zigzag(deviation = 5, depth = 10, backstep = 3, source, high2, low2) {
|
|
|
2227
2209
|
if (potentialPivot) {
|
|
2228
2210
|
confirmedPivots.push(potentialPivot);
|
|
2229
2211
|
}
|
|
2230
|
-
for (const
|
|
2231
|
-
zigzagValues[
|
|
2232
|
-
isPivot[
|
|
2212
|
+
for (const pivot2 of confirmedPivots) {
|
|
2213
|
+
zigzagValues[pivot2.index] = pivot2.price;
|
|
2214
|
+
isPivot[pivot2.index] = true;
|
|
2233
2215
|
}
|
|
2234
2216
|
let currentDir = 0;
|
|
2235
2217
|
let pivotIdx = 0;
|
|
2236
2218
|
const numConfirmed = lastPotentialWasAdded ? confirmedPivots.length - 1 : confirmedPivots.length;
|
|
2237
|
-
for (let i = 0; i <
|
|
2219
|
+
for (let i = 0; i < length2; i++) {
|
|
2238
2220
|
while (pivotIdx < numConfirmed && confirmedPivots[pivotIdx].index <= i) {
|
|
2239
|
-
const
|
|
2240
|
-
currentDir =
|
|
2221
|
+
const pivot2 = confirmedPivots[pivotIdx];
|
|
2222
|
+
currentDir = pivot2.type === "low" ? 1 : -1;
|
|
2241
2223
|
pivotIdx++;
|
|
2242
2224
|
}
|
|
2243
2225
|
directions[i] = currentDir;
|
|
2244
2226
|
}
|
|
2245
2227
|
return [zigzagValues, directions, isPivot];
|
|
2246
2228
|
}
|
|
2229
|
+
function obv(close2, volume2) {
|
|
2230
|
+
return cum(close2.map((c, i) => i === 0 ? NaN : Math.sign(c - close2[i - 1]) * volume2[i]));
|
|
2231
|
+
}
|
|
2232
|
+
function pvt(close2, volume2) {
|
|
2233
|
+
return cum(
|
|
2234
|
+
close2.map((c, i) => i === 0 ? NaN : (c - close2[i - 1]) / close2[i - 1] * volume2[i])
|
|
2235
|
+
);
|
|
2236
|
+
}
|
|
2237
|
+
function accdist(high2, low2, close2, volume2) {
|
|
2238
|
+
return cum(
|
|
2239
|
+
close2.map((c, i) => {
|
|
2240
|
+
const h = high2[i];
|
|
2241
|
+
const l = low2[i];
|
|
2242
|
+
return h === l ? 0 : (2 * c - l - h) / (h - l) * volume2[i];
|
|
2243
|
+
})
|
|
2244
|
+
);
|
|
2245
|
+
}
|
|
2246
|
+
function iii(high2, low2, close2, volume2) {
|
|
2247
|
+
return close2.map((c, i) => {
|
|
2248
|
+
const range3 = high2[i] - low2[i];
|
|
2249
|
+
return range3 === 0 ? NaN : (2 * c - high2[i] - low2[i]) / range3 * volume2[i];
|
|
2250
|
+
});
|
|
2251
|
+
}
|
|
2252
|
+
function wvad(open2, high2, low2, close2, volume2) {
|
|
2253
|
+
return close2.map((c, i) => {
|
|
2254
|
+
const range3 = high2[i] - low2[i];
|
|
2255
|
+
return range3 === 0 ? NaN : (c - open2[i]) / range3 * volume2[i];
|
|
2256
|
+
});
|
|
2257
|
+
}
|
|
2258
|
+
function wad(high2, low2, close2) {
|
|
2259
|
+
return cum(
|
|
2260
|
+
close2.map((c, i) => {
|
|
2261
|
+
const prev = i === 0 ? NaN : close2[i - 1];
|
|
2262
|
+
const mom3 = c - prev;
|
|
2263
|
+
if (mom3 > 0) return c - Math.min(low2[i], prev);
|
|
2264
|
+
if (mom3 < 0) return c - Math.max(high2[i], prev);
|
|
2265
|
+
return 0;
|
|
2266
|
+
})
|
|
2267
|
+
);
|
|
2268
|
+
}
|
|
2269
|
+
function volumeIndex(close2, volume2, use) {
|
|
2270
|
+
const result = [];
|
|
2271
|
+
let prevIndex = NaN;
|
|
2272
|
+
for (let i = 0; i < close2.length; i++) {
|
|
2273
|
+
const prev = !prevIndex ? 1 : prevIndex;
|
|
2274
|
+
const c = close2[i];
|
|
2275
|
+
const prevC = i === 0 ? NaN : close2[i - 1];
|
|
2276
|
+
let value = prev;
|
|
2277
|
+
if (c && prevC) {
|
|
2278
|
+
const prevV = i === 0 || Number.isNaN(volume2[i - 1]) ? 0 : volume2[i - 1];
|
|
2279
|
+
if (use(volume2[i], prevV)) value = prev + (c - prevC) / prevC * prev;
|
|
2280
|
+
}
|
|
2281
|
+
result.push(value);
|
|
2282
|
+
prevIndex = value;
|
|
2283
|
+
}
|
|
2284
|
+
return result;
|
|
2285
|
+
}
|
|
2286
|
+
function nvi(close2, volume2) {
|
|
2287
|
+
return volumeIndex(close2, volume2, (v, prevV) => v < prevV);
|
|
2288
|
+
}
|
|
2289
|
+
function pvi(close2, volume2) {
|
|
2290
|
+
return volumeIndex(close2, volume2, (v, prevV) => v > prevV);
|
|
2291
|
+
}
|
|
2247
2292
|
|
|
2248
2293
|
// src/ta-series.ts
|
|
2249
|
-
function sma2(source,
|
|
2294
|
+
function sma2(source, length2) {
|
|
2250
2295
|
const bars2 = source.bars;
|
|
2251
2296
|
const sourceValues = source.toArray();
|
|
2252
|
-
const result = sma(sourceValues,
|
|
2297
|
+
const result = sma(sourceValues, length2);
|
|
2253
2298
|
return Series.fromArray(bars2, result);
|
|
2254
2299
|
}
|
|
2255
|
-
function ema2(source,
|
|
2300
|
+
function ema2(source, length2) {
|
|
2256
2301
|
const bars2 = source.bars;
|
|
2257
2302
|
const sourceValues = source.toArray();
|
|
2258
|
-
const result = ema(sourceValues,
|
|
2303
|
+
const result = ema(sourceValues, length2);
|
|
2259
2304
|
return Series.fromArray(bars2, result);
|
|
2260
2305
|
}
|
|
2261
|
-
function wma2(source,
|
|
2306
|
+
function wma2(source, length2) {
|
|
2262
2307
|
const bars2 = source.bars;
|
|
2263
2308
|
const sourceValues = source.toArray();
|
|
2264
|
-
const result = wma(sourceValues,
|
|
2309
|
+
const result = wma(sourceValues, length2);
|
|
2265
2310
|
return Series.fromArray(bars2, result);
|
|
2266
2311
|
}
|
|
2267
|
-
function rma2(source,
|
|
2312
|
+
function rma2(source, length2) {
|
|
2268
2313
|
const bars2 = source.bars;
|
|
2269
2314
|
const sourceValues = source.toArray();
|
|
2270
|
-
const result = rma(sourceValues,
|
|
2315
|
+
const result = rma(sourceValues, length2);
|
|
2271
2316
|
return Series.fromArray(bars2, result);
|
|
2272
2317
|
}
|
|
2273
|
-
function rsi2(source,
|
|
2318
|
+
function rsi2(source, length2) {
|
|
2274
2319
|
const bars2 = source.bars;
|
|
2275
2320
|
const sourceValues = source.toArray();
|
|
2276
|
-
const result = rsi(sourceValues,
|
|
2321
|
+
const result = rsi(sourceValues, length2);
|
|
2277
2322
|
return Series.fromArray(bars2, result);
|
|
2278
2323
|
}
|
|
2279
2324
|
function macd2(source, fastLength, slowLength, signalLength) {
|
|
@@ -2285,26 +2330,24 @@ function macd2(source, fastLength, slowLength, signalLength) {
|
|
|
2285
2330
|
const histSeries = Series.fromArray(bars2, histVals);
|
|
2286
2331
|
return [macdSeries, signalSeries, histSeries];
|
|
2287
2332
|
}
|
|
2288
|
-
function bb2(source,
|
|
2333
|
+
function bb2(source, length2, mult) {
|
|
2289
2334
|
const bars2 = source.bars;
|
|
2290
2335
|
const sourceValues = source.toArray();
|
|
2291
|
-
const [upperVals, basisVals, lowerVals] = bb(sourceValues,
|
|
2336
|
+
const [upperVals, basisVals, lowerVals] = bb(sourceValues, length2, mult);
|
|
2292
2337
|
const upperSeries = Series.fromArray(bars2, upperVals);
|
|
2293
2338
|
const basisSeries = Series.fromArray(bars2, basisVals);
|
|
2294
2339
|
const lowerSeries = Series.fromArray(bars2, lowerVals);
|
|
2295
2340
|
return [upperSeries, basisSeries, lowerSeries];
|
|
2296
2341
|
}
|
|
2297
|
-
function stdev2(source,
|
|
2342
|
+
function stdev2(source, length2, biased = true) {
|
|
2298
2343
|
const bars2 = source.bars;
|
|
2299
|
-
|
|
2300
|
-
const result = stdev(sourceValues, length);
|
|
2301
|
-
return Series.fromArray(bars2, result);
|
|
2344
|
+
return Series.fromArray(bars2, stdev(source.toArray(), length2, biased));
|
|
2302
2345
|
}
|
|
2303
|
-
function atr2(bars2,
|
|
2346
|
+
function atr2(bars2, length2) {
|
|
2304
2347
|
const high2 = bars2.map((b2) => b2.high);
|
|
2305
2348
|
const low2 = bars2.map((b2) => b2.low);
|
|
2306
2349
|
const close2 = bars2.map((b2) => b2.close);
|
|
2307
|
-
const result = atr(
|
|
2350
|
+
const result = atr(length2, high2, low2, close2);
|
|
2308
2351
|
return Series.fromArray(bars2, result);
|
|
2309
2352
|
}
|
|
2310
2353
|
function tr2(bars2, handle_na = false) {
|
|
@@ -2314,12 +2357,46 @@ function tr2(bars2, handle_na = false) {
|
|
|
2314
2357
|
const result = tr(handle_na, high2, low2, close2);
|
|
2315
2358
|
return Series.fromArray(bars2, result);
|
|
2316
2359
|
}
|
|
2317
|
-
|
|
2360
|
+
var col = (bars2, f) => bars2.map((b2) => b2[f] ?? NaN);
|
|
2361
|
+
function obv2(bars2) {
|
|
2362
|
+
return Series.fromArray(bars2, obv(col(bars2, "close"), col(bars2, "volume")));
|
|
2363
|
+
}
|
|
2364
|
+
function pvt2(bars2) {
|
|
2365
|
+
return Series.fromArray(bars2, pvt(col(bars2, "close"), col(bars2, "volume")));
|
|
2366
|
+
}
|
|
2367
|
+
function accdist2(bars2) {
|
|
2368
|
+
return Series.fromArray(
|
|
2369
|
+
bars2,
|
|
2370
|
+
accdist(col(bars2, "high"), col(bars2, "low"), col(bars2, "close"), col(bars2, "volume"))
|
|
2371
|
+
);
|
|
2372
|
+
}
|
|
2373
|
+
function nvi2(bars2) {
|
|
2374
|
+
return Series.fromArray(bars2, nvi(col(bars2, "close"), col(bars2, "volume")));
|
|
2375
|
+
}
|
|
2376
|
+
function pvi2(bars2) {
|
|
2377
|
+
return Series.fromArray(bars2, pvi(col(bars2, "close"), col(bars2, "volume")));
|
|
2378
|
+
}
|
|
2379
|
+
function iii2(bars2) {
|
|
2380
|
+
return Series.fromArray(
|
|
2381
|
+
bars2,
|
|
2382
|
+
iii(col(bars2, "high"), col(bars2, "low"), col(bars2, "close"), col(bars2, "volume"))
|
|
2383
|
+
);
|
|
2384
|
+
}
|
|
2385
|
+
function wad2(bars2) {
|
|
2386
|
+
return Series.fromArray(bars2, wad(col(bars2, "high"), col(bars2, "low"), col(bars2, "close")));
|
|
2387
|
+
}
|
|
2388
|
+
function wvad2(bars2) {
|
|
2389
|
+
return Series.fromArray(
|
|
2390
|
+
bars2,
|
|
2391
|
+
wvad(col(bars2, "open"), col(bars2, "high"), col(bars2, "low"), col(bars2, "close"), col(bars2, "volume"))
|
|
2392
|
+
);
|
|
2393
|
+
}
|
|
2394
|
+
function stoch2(source, high2, low2, length2) {
|
|
2318
2395
|
const bars2 = source.bars;
|
|
2319
2396
|
const sourceValues = source.toArray();
|
|
2320
2397
|
const highValues = high2.toArray();
|
|
2321
2398
|
const lowValues = low2.toArray();
|
|
2322
|
-
const result = stoch(sourceValues, highValues, lowValues,
|
|
2399
|
+
const result = stoch(sourceValues, highValues, lowValues, length2);
|
|
2323
2400
|
return Series.fromArray(bars2, result);
|
|
2324
2401
|
}
|
|
2325
2402
|
function crossover2(source1, source2) {
|
|
@@ -2346,47 +2423,47 @@ function cross2(source1, source2) {
|
|
|
2346
2423
|
const numResult = result.map((b2) => b2 ? 1 : 0);
|
|
2347
2424
|
return Series.fromArray(bars2, numResult);
|
|
2348
2425
|
}
|
|
2349
|
-
function change2(source,
|
|
2426
|
+
function change2(source, length2 = 1) {
|
|
2350
2427
|
const bars2 = source.bars;
|
|
2351
2428
|
const sourceValues = source.toArray();
|
|
2352
|
-
const result = change(sourceValues,
|
|
2429
|
+
const result = change(sourceValues, length2);
|
|
2353
2430
|
return Series.fromArray(bars2, result);
|
|
2354
2431
|
}
|
|
2355
|
-
function mom2(source,
|
|
2432
|
+
function mom2(source, length2) {
|
|
2356
2433
|
const bars2 = source.bars;
|
|
2357
2434
|
const sourceValues = source.toArray();
|
|
2358
|
-
const result = mom(sourceValues,
|
|
2435
|
+
const result = mom(sourceValues, length2);
|
|
2359
2436
|
return Series.fromArray(bars2, result);
|
|
2360
2437
|
}
|
|
2361
|
-
function roc2(source,
|
|
2438
|
+
function roc2(source, length2) {
|
|
2362
2439
|
const bars2 = source.bars;
|
|
2363
2440
|
const sourceValues = source.toArray();
|
|
2364
|
-
const result = roc(sourceValues,
|
|
2441
|
+
const result = roc(sourceValues, length2);
|
|
2365
2442
|
return Series.fromArray(bars2, result);
|
|
2366
2443
|
}
|
|
2367
|
-
function highest2(source,
|
|
2444
|
+
function highest2(source, length2) {
|
|
2368
2445
|
const bars2 = source.bars;
|
|
2369
2446
|
const sourceValues = source.toArray();
|
|
2370
|
-
const result = highest(sourceValues,
|
|
2447
|
+
const result = highest(sourceValues, length2);
|
|
2371
2448
|
return Series.fromArray(bars2, result);
|
|
2372
2449
|
}
|
|
2373
|
-
function lowest2(source,
|
|
2450
|
+
function lowest2(source, length2) {
|
|
2374
2451
|
const bars2 = source.bars;
|
|
2375
2452
|
const sourceValues = source.toArray();
|
|
2376
|
-
const result = lowest(sourceValues,
|
|
2453
|
+
const result = lowest(sourceValues, length2);
|
|
2377
2454
|
return Series.fromArray(bars2, result);
|
|
2378
2455
|
}
|
|
2379
|
-
function rising2(source,
|
|
2456
|
+
function rising2(source, length2) {
|
|
2380
2457
|
const bars2 = source.bars;
|
|
2381
2458
|
const sourceValues = source.toArray();
|
|
2382
|
-
const result = rising(sourceValues,
|
|
2459
|
+
const result = rising(sourceValues, length2);
|
|
2383
2460
|
const numResult = result.map((b2) => b2 ? 1 : 0);
|
|
2384
2461
|
return Series.fromArray(bars2, numResult);
|
|
2385
2462
|
}
|
|
2386
|
-
function falling2(source,
|
|
2463
|
+
function falling2(source, length2) {
|
|
2387
2464
|
const bars2 = source.bars;
|
|
2388
2465
|
const sourceValues = source.toArray();
|
|
2389
|
-
const result = falling(sourceValues,
|
|
2466
|
+
const result = falling(sourceValues, length2);
|
|
2390
2467
|
const numResult = result.map((b2) => b2 ? 1 : 0);
|
|
2391
2468
|
return Series.fromArray(bars2, numResult);
|
|
2392
2469
|
}
|
|
@@ -2405,12 +2482,14 @@ function supertrend2(bars2, factor, atrLength) {
|
|
|
2405
2482
|
const dirSeries = Series.fromArray(bars2, dirVals);
|
|
2406
2483
|
return [trendSeries, dirSeries];
|
|
2407
2484
|
}
|
|
2408
|
-
function vwap2(source, volume2) {
|
|
2485
|
+
function vwap2(source, volume2, anchor) {
|
|
2409
2486
|
const bars2 = source.bars;
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2487
|
+
return Series.fromArray(bars2, vwap(source.toArray(), volume2.toArray(), anchor?.toArray()));
|
|
2488
|
+
}
|
|
2489
|
+
function vwapBands(source, volume2, anchor, stdev_mult) {
|
|
2490
|
+
const bars2 = source.bars;
|
|
2491
|
+
const [m, u, l] = vwap(source.toArray(), volume2.toArray(), anchor?.toArray(), stdev_mult);
|
|
2492
|
+
return [Series.fromArray(bars2, m), Series.fromArray(bars2, u), Series.fromArray(bars2, l)];
|
|
2414
2493
|
}
|
|
2415
2494
|
function ichimoku2(bars2, conversionPeriods, basePeriods, laggingSpan2Periods, displacement) {
|
|
2416
2495
|
const high2 = bars2.map((b2) => b2.high);
|
|
@@ -2433,23 +2512,23 @@ function ichimoku2(bars2, conversionPeriods, basePeriods, laggingSpan2Periods, d
|
|
|
2433
2512
|
Series.fromArray(bars2, chikou)
|
|
2434
2513
|
];
|
|
2435
2514
|
}
|
|
2436
|
-
function vwma2(source,
|
|
2515
|
+
function vwma2(source, length2, volume2) {
|
|
2437
2516
|
const bars2 = source.bars;
|
|
2438
2517
|
const sourceValues = source.toArray();
|
|
2439
2518
|
const volumeValues = volume2.toArray();
|
|
2440
|
-
const result = vwma(sourceValues,
|
|
2519
|
+
const result = vwma(sourceValues, length2, volumeValues);
|
|
2441
2520
|
return Series.fromArray(bars2, result);
|
|
2442
2521
|
}
|
|
2443
|
-
function linreg2(source,
|
|
2522
|
+
function linreg2(source, length2, offset = 0) {
|
|
2444
2523
|
const bars2 = source.bars;
|
|
2445
2524
|
const sourceValues = source.toArray();
|
|
2446
|
-
const result = linreg(sourceValues,
|
|
2525
|
+
const result = linreg(sourceValues, length2, offset);
|
|
2447
2526
|
return Series.fromArray(bars2, result);
|
|
2448
2527
|
}
|
|
2449
|
-
function alma2(source,
|
|
2528
|
+
function alma2(source, length2 = 9, offset = 0.85, sigma = 6, floor2 = false) {
|
|
2450
2529
|
const bars2 = source.bars;
|
|
2451
2530
|
const sourceValues = source.toArray();
|
|
2452
|
-
const result = alma(sourceValues,
|
|
2531
|
+
const result = alma(sourceValues, length2, offset, sigma, floor2);
|
|
2453
2532
|
return Series.fromArray(bars2, result);
|
|
2454
2533
|
}
|
|
2455
2534
|
function zigzag2(bars2, deviation = 5, depth = 10, backstep = 3) {
|
|
@@ -2469,10 +2548,10 @@ function zigzag2(bars2, deviation = 5, depth = 10, backstep = 3) {
|
|
|
2469
2548
|
Series.fromArray(bars2, pivotVals.map((b2) => b2 ? 1 : 0))
|
|
2470
2549
|
];
|
|
2471
2550
|
}
|
|
2472
|
-
function cci2(source,
|
|
2551
|
+
function cci2(source, length2) {
|
|
2473
2552
|
const bars2 = source.bars;
|
|
2474
2553
|
const sourceValues = source.toArray();
|
|
2475
|
-
const result = cci(sourceValues,
|
|
2554
|
+
const result = cci(sourceValues, length2);
|
|
2476
2555
|
return Series.fromArray(bars2, result);
|
|
2477
2556
|
}
|
|
2478
2557
|
function sar2(bars2, start = 0.02, inc = 0.02, max4 = 0.2) {
|
|
@@ -2482,19 +2561,19 @@ function sar2(bars2, start = 0.02, inc = 0.02, max4 = 0.2) {
|
|
|
2482
2561
|
const result = sar(start, inc, max4, high2, low2, close2);
|
|
2483
2562
|
return Series.fromArray(bars2, result);
|
|
2484
2563
|
}
|
|
2485
|
-
function dev2(source,
|
|
2564
|
+
function dev2(source, length2) {
|
|
2486
2565
|
const bars2 = source.bars;
|
|
2487
|
-
const result = dev(source.toArray(),
|
|
2566
|
+
const result = dev(source.toArray(), length2);
|
|
2488
2567
|
return Series.fromArray(bars2, result);
|
|
2489
2568
|
}
|
|
2490
|
-
function variance2(source,
|
|
2569
|
+
function variance2(source, length2, biased = true) {
|
|
2491
2570
|
const bars2 = source.bars;
|
|
2492
|
-
const result = variance(source.toArray(),
|
|
2571
|
+
const result = variance(source.toArray(), length2, biased);
|
|
2493
2572
|
return Series.fromArray(bars2, result);
|
|
2494
2573
|
}
|
|
2495
|
-
function median2(source,
|
|
2574
|
+
function median2(source, length2) {
|
|
2496
2575
|
const bars2 = source.bars;
|
|
2497
|
-
const result = median(source.toArray(),
|
|
2576
|
+
const result = median(source.toArray(), length2);
|
|
2498
2577
|
return Series.fromArray(bars2, result);
|
|
2499
2578
|
}
|
|
2500
2579
|
function swma2(source) {
|
|
@@ -2502,24 +2581,24 @@ function swma2(source) {
|
|
|
2502
2581
|
const result = swma(source.toArray());
|
|
2503
2582
|
return Series.fromArray(bars2, result);
|
|
2504
2583
|
}
|
|
2505
|
-
function correlation2(source1, source2,
|
|
2584
|
+
function correlation2(source1, source2, length2) {
|
|
2506
2585
|
const bars2 = source1.bars;
|
|
2507
|
-
const result = correlation(source1.toArray(), source2.toArray(),
|
|
2586
|
+
const result = correlation(source1.toArray(), source2.toArray(), length2);
|
|
2508
2587
|
return Series.fromArray(bars2, result);
|
|
2509
2588
|
}
|
|
2510
|
-
function percentrank2(source,
|
|
2589
|
+
function percentrank2(source, length2) {
|
|
2511
2590
|
const bars2 = source.bars;
|
|
2512
|
-
const result = percentrank(source.toArray(),
|
|
2591
|
+
const result = percentrank(source.toArray(), length2);
|
|
2513
2592
|
return Series.fromArray(bars2, result);
|
|
2514
2593
|
}
|
|
2515
|
-
function mfi2(source,
|
|
2594
|
+
function mfi2(source, length2, volume2) {
|
|
2516
2595
|
const bars2 = source.bars;
|
|
2517
|
-
const result = mfi(source.toArray(),
|
|
2596
|
+
const result = mfi(source.toArray(), length2, volume2.toArray());
|
|
2518
2597
|
return Series.fromArray(bars2, result);
|
|
2519
2598
|
}
|
|
2520
|
-
function hma2(source,
|
|
2599
|
+
function hma2(source, length2) {
|
|
2521
2600
|
const bars2 = source.bars;
|
|
2522
|
-
const result = hma(source.toArray(),
|
|
2601
|
+
const result = hma(source.toArray(), length2);
|
|
2523
2602
|
return Series.fromArray(bars2, result);
|
|
2524
2603
|
}
|
|
2525
2604
|
function pivothigh2(source, leftbars, rightbars) {
|
|
@@ -2560,89 +2639,86 @@ function tsi2(source, shortLength, longLength) {
|
|
|
2560
2639
|
const result = tsi(source.toArray(), shortLength, longLength);
|
|
2561
2640
|
return Series.fromArray(bars2, result);
|
|
2562
2641
|
}
|
|
2563
|
-
function cmo2(source,
|
|
2642
|
+
function cmo2(source, length2) {
|
|
2564
2643
|
const bars2 = source.bars;
|
|
2565
|
-
const result = cmo(source.toArray(),
|
|
2644
|
+
const result = cmo(source.toArray(), length2);
|
|
2566
2645
|
return Series.fromArray(bars2, result);
|
|
2567
2646
|
}
|
|
2568
|
-
function kc2(bars2, source,
|
|
2647
|
+
function kc2(bars2, source, length2, mult, useTrueRange = true) {
|
|
2569
2648
|
const high2 = bars2.map((b2) => b2.high);
|
|
2570
2649
|
const low2 = bars2.map((b2) => b2.low);
|
|
2571
2650
|
const close2 = bars2.map((b2) => b2.close);
|
|
2572
|
-
const [middle,
|
|
2651
|
+
const [middle, upper2, lower2] = kc(source.toArray(), length2, mult, useTrueRange, high2, low2, close2);
|
|
2573
2652
|
return [
|
|
2574
2653
|
Series.fromArray(bars2, middle),
|
|
2575
|
-
Series.fromArray(bars2,
|
|
2576
|
-
Series.fromArray(bars2,
|
|
2654
|
+
Series.fromArray(bars2, upper2),
|
|
2655
|
+
Series.fromArray(bars2, lower2)
|
|
2577
2656
|
];
|
|
2578
2657
|
}
|
|
2579
|
-
function bbw2(source,
|
|
2658
|
+
function bbw2(source, length2, mult) {
|
|
2580
2659
|
const bars2 = source.bars;
|
|
2581
|
-
const result = bbw(source.toArray(),
|
|
2660
|
+
const result = bbw(source.toArray(), length2, mult);
|
|
2582
2661
|
return Series.fromArray(bars2, result);
|
|
2583
2662
|
}
|
|
2584
|
-
function wpr2(bars2,
|
|
2663
|
+
function wpr2(bars2, length2 = 14) {
|
|
2585
2664
|
const high2 = bars2.map((b2) => b2.high);
|
|
2586
2665
|
const low2 = bars2.map((b2) => b2.low);
|
|
2587
2666
|
const close2 = bars2.map((b2) => b2.close);
|
|
2588
|
-
const result = wpr(high2, low2, close2,
|
|
2667
|
+
const result = wpr(high2, low2, close2, length2);
|
|
2589
2668
|
return Series.fromArray(bars2, result);
|
|
2590
2669
|
}
|
|
2591
|
-
function kcw2(bars2, source,
|
|
2670
|
+
function kcw2(bars2, source, length2 = 20, mult = 2, useTrueRange = true) {
|
|
2592
2671
|
const high2 = bars2.map((b2) => b2.high);
|
|
2593
2672
|
const low2 = bars2.map((b2) => b2.low);
|
|
2594
2673
|
const close2 = bars2.map((b2) => b2.close);
|
|
2595
|
-
const result = kcw(source.toArray(),
|
|
2674
|
+
const result = kcw(source.toArray(), length2, mult, useTrueRange, high2, low2, close2);
|
|
2596
2675
|
return Series.fromArray(bars2, result);
|
|
2597
2676
|
}
|
|
2598
|
-
function range2(
|
|
2599
|
-
const bars2 =
|
|
2600
|
-
|
|
2601
|
-
return Series.fromArray(bars2, result);
|
|
2677
|
+
function range2(source, length2) {
|
|
2678
|
+
const bars2 = source.bars;
|
|
2679
|
+
return Series.fromArray(bars2, range(source.toArray(), length2));
|
|
2602
2680
|
}
|
|
2603
|
-
function highestbars2(source,
|
|
2681
|
+
function highestbars2(source, length2) {
|
|
2604
2682
|
const bars2 = source.bars;
|
|
2605
|
-
const result = highestbars(source.toArray(),
|
|
2683
|
+
const result = highestbars(source.toArray(), length2);
|
|
2606
2684
|
return Series.fromArray(bars2, result);
|
|
2607
2685
|
}
|
|
2608
|
-
function lowestbars2(source,
|
|
2686
|
+
function lowestbars2(source, length2) {
|
|
2609
2687
|
const bars2 = source.bars;
|
|
2610
|
-
const result = lowestbars(source.toArray(),
|
|
2688
|
+
const result = lowestbars(source.toArray(), length2);
|
|
2611
2689
|
return Series.fromArray(bars2, result);
|
|
2612
2690
|
}
|
|
2613
|
-
function max2(
|
|
2614
|
-
const bars2 =
|
|
2615
|
-
|
|
2616
|
-
return Series.fromArray(bars2, result);
|
|
2691
|
+
function max2(source) {
|
|
2692
|
+
const bars2 = source.bars;
|
|
2693
|
+
return Series.fromArray(bars2, max(source.toArray()));
|
|
2617
2694
|
}
|
|
2618
|
-
function min2(
|
|
2619
|
-
const bars2 =
|
|
2620
|
-
|
|
2621
|
-
return Series.fromArray(bars2, result);
|
|
2695
|
+
function min2(source) {
|
|
2696
|
+
const bars2 = source.bars;
|
|
2697
|
+
return Series.fromArray(bars2, min(source.toArray()));
|
|
2622
2698
|
}
|
|
2623
|
-
function cog2(source,
|
|
2699
|
+
function cog2(source, length2 = 10) {
|
|
2624
2700
|
const bars2 = source.bars;
|
|
2625
|
-
const result = cog(source.toArray(),
|
|
2701
|
+
const result = cog(source.toArray(), length2);
|
|
2626
2702
|
return Series.fromArray(bars2, result);
|
|
2627
2703
|
}
|
|
2628
|
-
function mode2(source,
|
|
2704
|
+
function mode2(source, length2) {
|
|
2629
2705
|
const bars2 = source.bars;
|
|
2630
|
-
const result = mode(source.toArray(),
|
|
2706
|
+
const result = mode(source.toArray(), length2);
|
|
2631
2707
|
return Series.fromArray(bars2, result);
|
|
2632
2708
|
}
|
|
2633
|
-
function percentile_linear_interpolation2(source,
|
|
2709
|
+
function percentile_linear_interpolation2(source, length2, percentage) {
|
|
2634
2710
|
const bars2 = source.bars;
|
|
2635
|
-
const result = percentile_linear_interpolation(source.toArray(),
|
|
2711
|
+
const result = percentile_linear_interpolation(source.toArray(), length2, percentage);
|
|
2636
2712
|
return Series.fromArray(bars2, result);
|
|
2637
2713
|
}
|
|
2638
|
-
function percentile_nearest_rank2(source,
|
|
2714
|
+
function percentile_nearest_rank2(source, length2, percentage) {
|
|
2639
2715
|
const bars2 = source.bars;
|
|
2640
|
-
const result = percentile_nearest_rank(source.toArray(),
|
|
2716
|
+
const result = percentile_nearest_rank(source.toArray(), length2, percentage);
|
|
2641
2717
|
return Series.fromArray(bars2, result);
|
|
2642
2718
|
}
|
|
2643
|
-
function rci2(source,
|
|
2719
|
+
function rci2(source, length2) {
|
|
2644
2720
|
const bars2 = source.bars;
|
|
2645
|
-
const result = rci(source.toArray(),
|
|
2721
|
+
const result = rci(source.toArray(), length2);
|
|
2646
2722
|
return Series.fromArray(bars2, result);
|
|
2647
2723
|
}
|
|
2648
2724
|
var ta = {
|
|
@@ -2701,6 +2777,15 @@ var ta = {
|
|
|
2701
2777
|
lowestbars: lowestbars2,
|
|
2702
2778
|
max: max2,
|
|
2703
2779
|
min: min2,
|
|
2780
|
+
vwapBands,
|
|
2781
|
+
obv: obv2,
|
|
2782
|
+
pvt: pvt2,
|
|
2783
|
+
accdist: accdist2,
|
|
2784
|
+
nvi: nvi2,
|
|
2785
|
+
pvi: pvi2,
|
|
2786
|
+
iii: iii2,
|
|
2787
|
+
wad: wad2,
|
|
2788
|
+
wvad: wvad2,
|
|
2704
2789
|
cog: cog2,
|
|
2705
2790
|
mode: mode2,
|
|
2706
2791
|
percentile_linear_interpolation: percentile_linear_interpolation2,
|
|
@@ -2773,52 +2858,59 @@ function t(clr) {
|
|
|
2773
2858
|
}
|
|
2774
2859
|
function parseColor(clr) {
|
|
2775
2860
|
if (typeof clr === "string") {
|
|
2776
|
-
const
|
|
2777
|
-
if (
|
|
2861
|
+
const hex = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(clr.trim());
|
|
2862
|
+
if (hex) {
|
|
2863
|
+
let digits = hex[1];
|
|
2864
|
+
if (digits.length <= 4) digits = [...digits].map((c) => c + c).join("");
|
|
2865
|
+
const byte = (k) => parseInt(digits.slice(k, k + 2), 16);
|
|
2866
|
+
return { r: byte(0), g: byte(2), b: byte(4), t: digits.length === 8 ? (1 - byte(6) / 255) * 100 : 0 };
|
|
2867
|
+
}
|
|
2868
|
+
const match2 = clr.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
|
|
2869
|
+
if (match2) {
|
|
2778
2870
|
return {
|
|
2779
|
-
r: parseInt(
|
|
2780
|
-
g: parseInt(
|
|
2781
|
-
b: parseInt(
|
|
2782
|
-
t:
|
|
2871
|
+
r: parseInt(match2[1]),
|
|
2872
|
+
g: parseInt(match2[2]),
|
|
2873
|
+
b: parseInt(match2[3]),
|
|
2874
|
+
t: match2[4] ? (1 - parseFloat(match2[4])) * 100 : 0
|
|
2783
2875
|
};
|
|
2784
2876
|
}
|
|
2785
2877
|
}
|
|
2786
2878
|
return { r: 0, g: 0, b: 0, t: 0 };
|
|
2787
2879
|
}
|
|
2788
|
-
var aqua = "#
|
|
2789
|
-
var black = "#
|
|
2790
|
-
var blue = "#
|
|
2791
|
-
var fuchsia = "#
|
|
2792
|
-
var gray = "#
|
|
2793
|
-
var green = "#
|
|
2794
|
-
var lime = "#
|
|
2795
|
-
var maroon = "#
|
|
2796
|
-
var navy = "#
|
|
2880
|
+
var aqua = "#00BCD4";
|
|
2881
|
+
var black = "#363A45";
|
|
2882
|
+
var blue = "#2962FF";
|
|
2883
|
+
var fuchsia = "#E040FB";
|
|
2884
|
+
var gray = "#787B86";
|
|
2885
|
+
var green = "#4CAF50";
|
|
2886
|
+
var lime = "#00E676";
|
|
2887
|
+
var maroon = "#880E4F";
|
|
2888
|
+
var navy = "#311B92";
|
|
2797
2889
|
var olive = "#808000";
|
|
2798
|
-
var orange = "#
|
|
2799
|
-
var purple = "#
|
|
2800
|
-
var red = "#
|
|
2801
|
-
var silver = "#
|
|
2802
|
-
var teal = "#
|
|
2890
|
+
var orange = "#FF9800";
|
|
2891
|
+
var purple = "#9C27B0";
|
|
2892
|
+
var red = "#F23645";
|
|
2893
|
+
var silver = "#B2B5BE";
|
|
2894
|
+
var teal = "#089981";
|
|
2803
2895
|
var white = "#FFFFFF";
|
|
2804
|
-
var yellow = "#
|
|
2896
|
+
var yellow = "#FDD835";
|
|
2805
2897
|
function from_gradient(value, bottom_value, top_value, bottom_color, top_color) {
|
|
2806
|
-
const parseColor2 = (
|
|
2807
|
-
if (typeof
|
|
2808
|
-
if (
|
|
2809
|
-
const hex =
|
|
2898
|
+
const parseColor2 = (col2) => {
|
|
2899
|
+
if (typeof col2 === "string") {
|
|
2900
|
+
if (col2.startsWith("#")) {
|
|
2901
|
+
const hex = col2.slice(1);
|
|
2810
2902
|
const r4 = parseInt(hex.slice(0, 2), 16);
|
|
2811
2903
|
const g4 = parseInt(hex.slice(2, 4), 16);
|
|
2812
2904
|
const b4 = parseInt(hex.slice(4, 6), 16);
|
|
2813
2905
|
return [r4, g4, b4, 1];
|
|
2814
2906
|
}
|
|
2815
|
-
const
|
|
2816
|
-
if (
|
|
2907
|
+
const match2 = col2.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
|
|
2908
|
+
if (match2) {
|
|
2817
2909
|
return [
|
|
2818
|
-
parseInt(
|
|
2819
|
-
parseInt(
|
|
2820
|
-
parseInt(
|
|
2821
|
-
|
|
2910
|
+
parseInt(match2[1]),
|
|
2911
|
+
parseInt(match2[2]),
|
|
2912
|
+
parseInt(match2[3]),
|
|
2913
|
+
match2[4] ? parseFloat(match2[4]) : 1
|
|
2822
2914
|
];
|
|
2823
2915
|
}
|
|
2824
2916
|
}
|
|
@@ -2844,81 +2936,2065 @@ function from_gradient(value, bottom_value, top_value, bottom_color, top_color)
|
|
|
2844
2936
|
return `rgba(${r3}, ${g3}, ${b3}, ${a})`;
|
|
2845
2937
|
}
|
|
2846
2938
|
|
|
2939
|
+
// src/drawing/registry.ts
|
|
2940
|
+
var DEFAULT_MAX_COUNT = 50;
|
|
2941
|
+
var SLACK = 5;
|
|
2942
|
+
var live = { line: [], label: [], box: [], polyline: [], linefill: [] };
|
|
2943
|
+
var limits = {
|
|
2944
|
+
line: DEFAULT_MAX_COUNT,
|
|
2945
|
+
label: DEFAULT_MAX_COUNT,
|
|
2946
|
+
box: DEFAULT_MAX_COUNT,
|
|
2947
|
+
polyline: DEFAULT_MAX_COUNT
|
|
2948
|
+
};
|
|
2949
|
+
var deleted = /* @__PURE__ */ new WeakSet();
|
|
2950
|
+
var COORDINATES = {
|
|
2951
|
+
line: ["x1", "y1", "x2", "y2"],
|
|
2952
|
+
label: ["x", "y"],
|
|
2953
|
+
box: ["left", "top", "right", "bottom"],
|
|
2954
|
+
polyline: [],
|
|
2955
|
+
linefill: []
|
|
2956
|
+
};
|
|
2957
|
+
function markDeleted(kind, obj, explicit) {
|
|
2958
|
+
deleted.add(obj);
|
|
2959
|
+
for (const field2 of COORDINATES[kind]) obj[field2] = NaN;
|
|
2960
|
+
if (kind === "line" && explicit) {
|
|
2961
|
+
for (const fill2 of live.linefill.filter((f) => f.line1 === obj || f.line2 === obj)) remove("linefill", fill2);
|
|
2962
|
+
}
|
|
2963
|
+
}
|
|
2964
|
+
function register(kind, obj) {
|
|
2965
|
+
const list = live[kind];
|
|
2966
|
+
list.push(obj);
|
|
2967
|
+
const max4 = limits[kind === "linefill" ? "line" : kind];
|
|
2968
|
+
if (list.length > max4 + SLACK) {
|
|
2969
|
+
for (const old of list.splice(0, list.length - max4)) markDeleted(kind, old, false);
|
|
2970
|
+
}
|
|
2971
|
+
return obj;
|
|
2972
|
+
}
|
|
2973
|
+
function remove(kind, obj) {
|
|
2974
|
+
const list = live[kind];
|
|
2975
|
+
const index = list.indexOf(obj);
|
|
2976
|
+
if (index !== -1) list.splice(index, 1);
|
|
2977
|
+
if (!deleted.has(obj)) markDeleted(kind, obj, true);
|
|
2978
|
+
}
|
|
2979
|
+
function isDeleted(obj) {
|
|
2980
|
+
return typeof obj === "object" && obj !== null && deleted.has(obj);
|
|
2981
|
+
}
|
|
2982
|
+
function all(kind) {
|
|
2983
|
+
return [...live[kind]];
|
|
2984
|
+
}
|
|
2985
|
+
function resetDrawings(newLimits = {}) {
|
|
2986
|
+
for (const kind of Object.keys(live)) live[kind].length = 0;
|
|
2987
|
+
limits = {
|
|
2988
|
+
line: newLimits.line ?? DEFAULT_MAX_COUNT,
|
|
2989
|
+
label: newLimits.label ?? DEFAULT_MAX_COUNT,
|
|
2990
|
+
box: newLimits.box ?? DEFAULT_MAX_COUNT,
|
|
2991
|
+
polyline: newLimits.polyline ?? DEFAULT_MAX_COUNT
|
|
2992
|
+
};
|
|
2993
|
+
}
|
|
2994
|
+
function setDrawingLimits(newLimits) {
|
|
2995
|
+
limits = { ...limits, ...Object.fromEntries(Object.entries(newLimits).filter(([, v]) => v !== void 0)) };
|
|
2996
|
+
}
|
|
2997
|
+
|
|
2847
2998
|
// src/utils/index.ts
|
|
2848
2999
|
function isNA(value) {
|
|
2849
|
-
return value === null || value === void 0 || Number.isNaN(value);
|
|
3000
|
+
return value === null || value === void 0 || Number.isNaN(value) || isDeleted(value);
|
|
2850
3001
|
}
|
|
2851
3002
|
function nz(value, defaultValue = 0) {
|
|
2852
3003
|
return isNA(value) ? defaultValue : value;
|
|
2853
3004
|
}
|
|
3005
|
+
function fixnan(source) {
|
|
3006
|
+
let last;
|
|
3007
|
+
let seen = false;
|
|
3008
|
+
return source.map((v) => {
|
|
3009
|
+
if (!isNA(v)) {
|
|
3010
|
+
last = v;
|
|
3011
|
+
seen = true;
|
|
3012
|
+
return v;
|
|
3013
|
+
}
|
|
3014
|
+
return seen ? last : v;
|
|
3015
|
+
});
|
|
3016
|
+
}
|
|
2854
3017
|
|
|
2855
|
-
// src/
|
|
2856
|
-
var
|
|
2857
|
-
__export(
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
sum: () => sum,
|
|
2883
|
-
tan: () => tan,
|
|
2884
|
-
todegrees: () => todegrees,
|
|
2885
|
-
toradians: () => toradians
|
|
3018
|
+
// src/line/index.ts
|
|
3019
|
+
var line_exports = {};
|
|
3020
|
+
__export(line_exports, {
|
|
3021
|
+
all: () => all2,
|
|
3022
|
+
copy: () => copy,
|
|
3023
|
+
delete: () => delete_line,
|
|
3024
|
+
delete_line: () => delete_line,
|
|
3025
|
+
get_price: () => get_price,
|
|
3026
|
+
get_x1: () => get_x1,
|
|
3027
|
+
get_x2: () => get_x2,
|
|
3028
|
+
get_y1: () => get_y1,
|
|
3029
|
+
get_y2: () => get_y2,
|
|
3030
|
+
new: () => new_line,
|
|
3031
|
+
new_line: () => new_line,
|
|
3032
|
+
set_color: () => set_color,
|
|
3033
|
+
set_extend: () => set_extend,
|
|
3034
|
+
set_first_point: () => set_first_point,
|
|
3035
|
+
set_second_point: () => set_second_point,
|
|
3036
|
+
set_style: () => set_style,
|
|
3037
|
+
set_width: () => set_width,
|
|
3038
|
+
set_x1: () => set_x1,
|
|
3039
|
+
set_x2: () => set_x2,
|
|
3040
|
+
set_xloc: () => set_xloc,
|
|
3041
|
+
set_xy1: () => set_xy1,
|
|
3042
|
+
set_xy2: () => set_xy2,
|
|
3043
|
+
set_y1: () => set_y1,
|
|
3044
|
+
set_y2: () => set_y2
|
|
2886
3045
|
});
|
|
2887
|
-
function
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
const
|
|
2891
|
-
const
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
3046
|
+
function new_line(...args) {
|
|
3047
|
+
let x1, y1, x2, y2, rest;
|
|
3048
|
+
if (typeof args[0] === "object" && args[0] !== null) {
|
|
3049
|
+
const [p1, p2, ...others] = args;
|
|
3050
|
+
const xloc2 = others[0] ?? "bar_index";
|
|
3051
|
+
[x1, y1, x2, y2, rest] = [pointX(p1, xloc2), p1.price, pointX(p2, xloc2), p2.price, others];
|
|
3052
|
+
} else {
|
|
3053
|
+
[x1, y1, x2, y2] = args;
|
|
3054
|
+
rest = args.slice(4);
|
|
3055
|
+
}
|
|
3056
|
+
const [xloc, extend, lineColor, style, width, force_overlay] = rest;
|
|
3057
|
+
return register("line", {
|
|
3058
|
+
x1,
|
|
3059
|
+
y1,
|
|
3060
|
+
x2,
|
|
3061
|
+
y2,
|
|
3062
|
+
xloc: xloc ?? "bar_index",
|
|
3063
|
+
extend: extend ?? "none",
|
|
3064
|
+
color: lineColor,
|
|
3065
|
+
style: style || "solid",
|
|
3066
|
+
width: width || 1,
|
|
3067
|
+
force_overlay: force_overlay ?? false
|
|
3068
|
+
});
|
|
2900
3069
|
}
|
|
2901
|
-
function
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
3070
|
+
function get_price(id, x) {
|
|
3071
|
+
const { x1, y1, x2, y2, extend, xloc } = id;
|
|
3072
|
+
if (xloc === "bar_time") {
|
|
3073
|
+
throw new Error("line.get_price() only works with xloc.bar_index lines, not xloc.bar_time");
|
|
3074
|
+
}
|
|
3075
|
+
if (x2 === x1) {
|
|
3076
|
+
return NaN;
|
|
3077
|
+
}
|
|
3078
|
+
const slope = (y2 - y1) / (x2 - x1);
|
|
3079
|
+
const price = y1 + slope * (x - x1);
|
|
3080
|
+
if (extend === "none") {
|
|
3081
|
+
if (x < Math.min(x1, x2) || x > Math.max(x1, x2)) {
|
|
3082
|
+
return NaN;
|
|
3083
|
+
}
|
|
3084
|
+
} else if (extend === "left") {
|
|
3085
|
+
if (x > Math.max(x1, x2)) {
|
|
3086
|
+
return NaN;
|
|
3087
|
+
}
|
|
3088
|
+
} else if (extend === "right") {
|
|
3089
|
+
if (x < Math.min(x1, x2)) {
|
|
3090
|
+
return NaN;
|
|
2910
3091
|
}
|
|
2911
|
-
return Series.fromArray(bars2, result);
|
|
2912
3092
|
}
|
|
2913
|
-
return
|
|
3093
|
+
return price;
|
|
2914
3094
|
}
|
|
2915
|
-
function
|
|
2916
|
-
|
|
3095
|
+
function get_x1(id) {
|
|
3096
|
+
return id.x1;
|
|
3097
|
+
}
|
|
3098
|
+
function get_x2(id) {
|
|
3099
|
+
return id.x2;
|
|
3100
|
+
}
|
|
3101
|
+
function get_y1(id) {
|
|
3102
|
+
return id.y1;
|
|
3103
|
+
}
|
|
3104
|
+
function get_y2(id) {
|
|
3105
|
+
return id.y2;
|
|
3106
|
+
}
|
|
3107
|
+
function copy(id) {
|
|
3108
|
+
return register("line", { ...id });
|
|
3109
|
+
}
|
|
3110
|
+
function set_x1(id, x) {
|
|
3111
|
+
if (isDeleted(id)) return id;
|
|
3112
|
+
id.x1 = x;
|
|
3113
|
+
return id;
|
|
3114
|
+
}
|
|
3115
|
+
function set_x2(id, x) {
|
|
3116
|
+
if (isDeleted(id)) return id;
|
|
3117
|
+
id.x2 = x;
|
|
3118
|
+
return id;
|
|
3119
|
+
}
|
|
3120
|
+
function set_y1(id, y) {
|
|
3121
|
+
if (isDeleted(id)) return id;
|
|
3122
|
+
id.y1 = y;
|
|
3123
|
+
return id;
|
|
3124
|
+
}
|
|
3125
|
+
function set_y2(id, y) {
|
|
3126
|
+
if (isDeleted(id)) return id;
|
|
3127
|
+
id.y2 = y;
|
|
3128
|
+
return id;
|
|
3129
|
+
}
|
|
3130
|
+
function set_xy1(id, x, y) {
|
|
3131
|
+
if (isDeleted(id)) return id;
|
|
3132
|
+
id.x1 = x;
|
|
3133
|
+
id.y1 = y;
|
|
3134
|
+
return id;
|
|
3135
|
+
}
|
|
3136
|
+
function set_xy2(id, x, y) {
|
|
3137
|
+
if (isDeleted(id)) return id;
|
|
3138
|
+
id.x2 = x;
|
|
3139
|
+
id.y2 = y;
|
|
3140
|
+
return id;
|
|
3141
|
+
}
|
|
3142
|
+
function set_xloc(id, x1, x2, xloc) {
|
|
3143
|
+
if (isDeleted(id)) return id;
|
|
3144
|
+
id.x1 = x1;
|
|
3145
|
+
id.x2 = x2;
|
|
3146
|
+
id.xloc = xloc;
|
|
3147
|
+
return id;
|
|
3148
|
+
}
|
|
3149
|
+
function set_extend(id, extend) {
|
|
3150
|
+
if (isDeleted(id)) return id;
|
|
3151
|
+
id.extend = extend;
|
|
3152
|
+
return id;
|
|
3153
|
+
}
|
|
3154
|
+
function set_color(id, lineColor) {
|
|
3155
|
+
if (isDeleted(id)) return id;
|
|
3156
|
+
id.color = lineColor;
|
|
3157
|
+
return id;
|
|
3158
|
+
}
|
|
3159
|
+
function set_style(id, style) {
|
|
3160
|
+
if (isDeleted(id)) return id;
|
|
3161
|
+
id.style = style;
|
|
3162
|
+
return id;
|
|
3163
|
+
}
|
|
3164
|
+
function set_width(id, width) {
|
|
3165
|
+
if (isDeleted(id)) return id;
|
|
3166
|
+
id.width = width;
|
|
3167
|
+
return id;
|
|
3168
|
+
}
|
|
3169
|
+
function delete_line(id) {
|
|
3170
|
+
remove("line", id);
|
|
3171
|
+
}
|
|
3172
|
+
function pointX(point, xloc) {
|
|
3173
|
+
const x = xloc === "bar_time" ? point.time : point.index;
|
|
3174
|
+
return x ?? NaN;
|
|
3175
|
+
}
|
|
3176
|
+
function all2() {
|
|
3177
|
+
return all("line");
|
|
3178
|
+
}
|
|
3179
|
+
function set_first_point(id, point) {
|
|
3180
|
+
if (isDeleted(id)) return id;
|
|
3181
|
+
id.x1 = pointX(point, id.xloc);
|
|
3182
|
+
id.y1 = point.price;
|
|
3183
|
+
return id;
|
|
3184
|
+
}
|
|
3185
|
+
function set_second_point(id, point) {
|
|
3186
|
+
if (isDeleted(id)) return id;
|
|
3187
|
+
id.x2 = pointX(point, id.xloc);
|
|
3188
|
+
id.y2 = point.price;
|
|
3189
|
+
return id;
|
|
3190
|
+
}
|
|
3191
|
+
|
|
3192
|
+
// src/label/index.ts
|
|
3193
|
+
var label_exports = {};
|
|
3194
|
+
__export(label_exports, {
|
|
3195
|
+
all: () => all3,
|
|
3196
|
+
copy: () => copy2,
|
|
3197
|
+
delete: () => delete_label,
|
|
3198
|
+
delete_label: () => delete_label,
|
|
3199
|
+
get_text: () => get_text,
|
|
3200
|
+
get_x: () => get_x,
|
|
3201
|
+
get_y: () => get_y,
|
|
3202
|
+
new: () => new_label,
|
|
3203
|
+
new_label: () => new_label,
|
|
3204
|
+
set_color: () => set_color2,
|
|
3205
|
+
set_point: () => set_point,
|
|
3206
|
+
set_size: () => set_size,
|
|
3207
|
+
set_style: () => set_style2,
|
|
3208
|
+
set_text: () => set_text,
|
|
3209
|
+
set_text_font_family: () => set_text_font_family,
|
|
3210
|
+
set_text_formatting: () => set_text_formatting,
|
|
3211
|
+
set_textalign: () => set_textalign,
|
|
3212
|
+
set_textcolor: () => set_textcolor,
|
|
3213
|
+
set_tooltip: () => set_tooltip,
|
|
3214
|
+
set_x: () => set_x,
|
|
3215
|
+
set_xloc: () => set_xloc2,
|
|
3216
|
+
set_xy: () => set_xy,
|
|
3217
|
+
set_y: () => set_y,
|
|
3218
|
+
set_yloc: () => set_yloc
|
|
3219
|
+
});
|
|
3220
|
+
function new_label(...args) {
|
|
3221
|
+
let x, y, rest;
|
|
3222
|
+
if (typeof args[0] === "object" && args[0] !== null) {
|
|
3223
|
+
const point = args[0];
|
|
3224
|
+
rest = args.slice(1);
|
|
3225
|
+
x = pointX2(point, rest[1] ?? "bar_index");
|
|
3226
|
+
y = point.price;
|
|
3227
|
+
} else {
|
|
3228
|
+
[x, y] = args;
|
|
3229
|
+
rest = args.slice(2);
|
|
3230
|
+
}
|
|
3231
|
+
const [
|
|
3232
|
+
text2,
|
|
3233
|
+
xloc,
|
|
3234
|
+
yloc,
|
|
3235
|
+
labelColor,
|
|
3236
|
+
style,
|
|
3237
|
+
textcolor,
|
|
3238
|
+
size,
|
|
3239
|
+
textalign,
|
|
3240
|
+
tooltip,
|
|
3241
|
+
text_font_family,
|
|
3242
|
+
force_overlay,
|
|
3243
|
+
text_formatting
|
|
3244
|
+
] = rest;
|
|
3245
|
+
return register("label", {
|
|
3246
|
+
x,
|
|
3247
|
+
y,
|
|
3248
|
+
xloc: xloc ?? "bar_index",
|
|
3249
|
+
yloc: yloc ?? "price",
|
|
3250
|
+
text: text2,
|
|
3251
|
+
tooltip,
|
|
3252
|
+
color: labelColor,
|
|
3253
|
+
style,
|
|
3254
|
+
textcolor,
|
|
3255
|
+
size,
|
|
3256
|
+
textalign,
|
|
3257
|
+
text_font_family,
|
|
3258
|
+
force_overlay: force_overlay ?? false,
|
|
3259
|
+
text_formatting
|
|
3260
|
+
});
|
|
3261
|
+
}
|
|
3262
|
+
function get_x(id) {
|
|
3263
|
+
return id.x;
|
|
3264
|
+
}
|
|
3265
|
+
function get_y(id) {
|
|
3266
|
+
return id.y;
|
|
3267
|
+
}
|
|
3268
|
+
function get_text(id) {
|
|
3269
|
+
return id.text;
|
|
3270
|
+
}
|
|
3271
|
+
function copy2(id) {
|
|
3272
|
+
return register("label", { ...id });
|
|
3273
|
+
}
|
|
3274
|
+
function set_x(id, x) {
|
|
3275
|
+
if (isDeleted(id)) return id;
|
|
3276
|
+
id.x = x;
|
|
3277
|
+
return id;
|
|
3278
|
+
}
|
|
3279
|
+
function set_y(id, y) {
|
|
3280
|
+
if (isDeleted(id)) return id;
|
|
3281
|
+
id.y = y;
|
|
3282
|
+
return id;
|
|
3283
|
+
}
|
|
3284
|
+
function set_xy(id, x, y) {
|
|
3285
|
+
if (isDeleted(id)) return id;
|
|
3286
|
+
id.x = x;
|
|
3287
|
+
id.y = y;
|
|
3288
|
+
return id;
|
|
3289
|
+
}
|
|
3290
|
+
function set_xloc2(id, x, xloc) {
|
|
3291
|
+
if (isDeleted(id)) return id;
|
|
3292
|
+
id.x = x;
|
|
3293
|
+
id.xloc = xloc;
|
|
3294
|
+
return id;
|
|
3295
|
+
}
|
|
3296
|
+
function set_yloc(id, yloc) {
|
|
3297
|
+
if (isDeleted(id)) return id;
|
|
3298
|
+
id.yloc = yloc;
|
|
3299
|
+
return id;
|
|
3300
|
+
}
|
|
3301
|
+
function set_text(id, text2) {
|
|
3302
|
+
if (isDeleted(id)) return id;
|
|
3303
|
+
id.text = text2;
|
|
3304
|
+
return id;
|
|
3305
|
+
}
|
|
3306
|
+
function set_tooltip(id, tooltip) {
|
|
3307
|
+
if (isDeleted(id)) return id;
|
|
3308
|
+
id.tooltip = tooltip;
|
|
3309
|
+
return id;
|
|
3310
|
+
}
|
|
3311
|
+
function set_color2(id, labelColor) {
|
|
3312
|
+
if (isDeleted(id)) return id;
|
|
3313
|
+
id.color = labelColor;
|
|
3314
|
+
return id;
|
|
3315
|
+
}
|
|
3316
|
+
function set_textcolor(id, textColor) {
|
|
3317
|
+
if (isDeleted(id)) return id;
|
|
3318
|
+
id.textcolor = textColor;
|
|
3319
|
+
return id;
|
|
3320
|
+
}
|
|
3321
|
+
function set_style2(id, style) {
|
|
3322
|
+
if (isDeleted(id)) return id;
|
|
3323
|
+
id.style = style;
|
|
3324
|
+
return id;
|
|
3325
|
+
}
|
|
3326
|
+
function set_size(id, size) {
|
|
3327
|
+
if (isDeleted(id)) return id;
|
|
3328
|
+
id.size = size;
|
|
3329
|
+
return id;
|
|
3330
|
+
}
|
|
3331
|
+
function set_textalign(id, align) {
|
|
3332
|
+
if (isDeleted(id)) return id;
|
|
3333
|
+
id.textalign = align;
|
|
3334
|
+
return id;
|
|
3335
|
+
}
|
|
3336
|
+
function set_text_font_family(id, font) {
|
|
3337
|
+
if (isDeleted(id)) return id;
|
|
3338
|
+
id.text_font_family = font;
|
|
3339
|
+
return id;
|
|
3340
|
+
}
|
|
3341
|
+
function delete_label(id) {
|
|
3342
|
+
remove("label", id);
|
|
3343
|
+
}
|
|
3344
|
+
function pointX2(point, xloc) {
|
|
3345
|
+
const x = xloc === "bar_time" ? point.time : point.index;
|
|
3346
|
+
return x ?? NaN;
|
|
3347
|
+
}
|
|
3348
|
+
function all3() {
|
|
3349
|
+
return all("label");
|
|
3350
|
+
}
|
|
3351
|
+
function set_point(id, point) {
|
|
3352
|
+
if (isDeleted(id)) return id;
|
|
3353
|
+
id.x = pointX2(point, id.xloc);
|
|
3354
|
+
id.y = point.price;
|
|
3355
|
+
return id;
|
|
3356
|
+
}
|
|
3357
|
+
function set_text_formatting(id, formatting) {
|
|
3358
|
+
if (isDeleted(id)) return id;
|
|
3359
|
+
id.text_formatting = formatting;
|
|
3360
|
+
return id;
|
|
3361
|
+
}
|
|
3362
|
+
|
|
3363
|
+
// src/box/index.ts
|
|
3364
|
+
var box_exports = {};
|
|
3365
|
+
__export(box_exports, {
|
|
3366
|
+
all: () => all4,
|
|
3367
|
+
copy: () => copy3,
|
|
3368
|
+
delete: () => delete_box,
|
|
3369
|
+
delete_box: () => delete_box,
|
|
3370
|
+
get_bottom: () => get_bottom,
|
|
3371
|
+
get_left: () => get_left,
|
|
3372
|
+
get_right: () => get_right,
|
|
3373
|
+
get_top: () => get_top,
|
|
3374
|
+
new: () => new_box,
|
|
3375
|
+
new_box: () => new_box,
|
|
3376
|
+
set_bgcolor: () => set_bgcolor,
|
|
3377
|
+
set_border_color: () => set_border_color,
|
|
3378
|
+
set_border_style: () => set_border_style,
|
|
3379
|
+
set_border_width: () => set_border_width,
|
|
3380
|
+
set_bottom: () => set_bottom,
|
|
3381
|
+
set_bottom_right_point: () => set_bottom_right_point,
|
|
3382
|
+
set_extend: () => set_extend2,
|
|
3383
|
+
set_left: () => set_left,
|
|
3384
|
+
set_lefttop: () => set_lefttop,
|
|
3385
|
+
set_right: () => set_right,
|
|
3386
|
+
set_rightbottom: () => set_rightbottom,
|
|
3387
|
+
set_text: () => set_text2,
|
|
3388
|
+
set_text_color: () => set_text_color,
|
|
3389
|
+
set_text_font_family: () => set_text_font_family2,
|
|
3390
|
+
set_text_formatting: () => set_text_formatting2,
|
|
3391
|
+
set_text_halign: () => set_text_halign,
|
|
3392
|
+
set_text_size: () => set_text_size,
|
|
3393
|
+
set_text_valign: () => set_text_valign,
|
|
3394
|
+
set_text_wrap: () => set_text_wrap,
|
|
3395
|
+
set_top: () => set_top,
|
|
3396
|
+
set_top_left_point: () => set_top_left_point,
|
|
3397
|
+
set_xloc: () => set_xloc3
|
|
3398
|
+
});
|
|
3399
|
+
function new_box(...args) {
|
|
3400
|
+
let left, top, right, bottom, rest;
|
|
3401
|
+
if (typeof args[0] === "object" && args[0] !== null) {
|
|
3402
|
+
const [tl, br, ...others] = args;
|
|
3403
|
+
const xloc2 = others[4] ?? "bar_index";
|
|
3404
|
+
[left, top, right, bottom, rest] = [pointX3(tl, xloc2), tl.price, pointX3(br, xloc2), br.price, others];
|
|
3405
|
+
} else {
|
|
3406
|
+
[left, top, right, bottom] = args;
|
|
3407
|
+
rest = args.slice(4);
|
|
3408
|
+
}
|
|
3409
|
+
const [
|
|
3410
|
+
border_color,
|
|
3411
|
+
border_width,
|
|
3412
|
+
border_style,
|
|
3413
|
+
extend,
|
|
3414
|
+
xloc,
|
|
3415
|
+
bgcolor2,
|
|
3416
|
+
text2,
|
|
3417
|
+
text_size,
|
|
3418
|
+
text_color,
|
|
3419
|
+
text_halign,
|
|
3420
|
+
text_valign,
|
|
3421
|
+
text_wrap,
|
|
3422
|
+
text_font_family,
|
|
3423
|
+
force_overlay,
|
|
3424
|
+
text_formatting
|
|
3425
|
+
] = rest;
|
|
3426
|
+
return register("box", {
|
|
3427
|
+
left,
|
|
3428
|
+
top,
|
|
3429
|
+
right,
|
|
3430
|
+
bottom,
|
|
3431
|
+
xloc: xloc ?? "bar_index",
|
|
3432
|
+
extend: extend ?? "none",
|
|
3433
|
+
border_color,
|
|
3434
|
+
border_width: border_width || 1,
|
|
3435
|
+
border_style: border_style || "solid",
|
|
3436
|
+
bgcolor: bgcolor2,
|
|
3437
|
+
text: text2,
|
|
3438
|
+
text_size,
|
|
3439
|
+
text_color,
|
|
3440
|
+
text_halign,
|
|
3441
|
+
text_valign,
|
|
3442
|
+
text_wrap,
|
|
3443
|
+
text_font_family,
|
|
3444
|
+
force_overlay: force_overlay ?? false,
|
|
3445
|
+
text_formatting
|
|
3446
|
+
});
|
|
3447
|
+
}
|
|
3448
|
+
function get_left(id) {
|
|
3449
|
+
return id.left;
|
|
3450
|
+
}
|
|
3451
|
+
function get_right(id) {
|
|
3452
|
+
return id.right;
|
|
3453
|
+
}
|
|
3454
|
+
function get_top(id) {
|
|
3455
|
+
return id.top;
|
|
3456
|
+
}
|
|
3457
|
+
function get_bottom(id) {
|
|
3458
|
+
return id.bottom;
|
|
3459
|
+
}
|
|
3460
|
+
function copy3(id) {
|
|
3461
|
+
return register("box", { ...id });
|
|
3462
|
+
}
|
|
3463
|
+
function set_left(id, left) {
|
|
3464
|
+
if (isDeleted(id)) return id;
|
|
3465
|
+
id.left = left;
|
|
3466
|
+
return id;
|
|
3467
|
+
}
|
|
3468
|
+
function set_right(id, right) {
|
|
3469
|
+
if (isDeleted(id)) return id;
|
|
3470
|
+
id.right = right;
|
|
3471
|
+
return id;
|
|
3472
|
+
}
|
|
3473
|
+
function set_top(id, top) {
|
|
3474
|
+
if (isDeleted(id)) return id;
|
|
3475
|
+
id.top = top;
|
|
3476
|
+
return id;
|
|
3477
|
+
}
|
|
3478
|
+
function set_bottom(id, bottom) {
|
|
3479
|
+
if (isDeleted(id)) return id;
|
|
3480
|
+
id.bottom = bottom;
|
|
3481
|
+
return id;
|
|
3482
|
+
}
|
|
3483
|
+
function set_lefttop(id, left, top) {
|
|
3484
|
+
if (isDeleted(id)) return id;
|
|
3485
|
+
id.left = left;
|
|
3486
|
+
id.top = top;
|
|
3487
|
+
return id;
|
|
3488
|
+
}
|
|
3489
|
+
function set_rightbottom(id, right, bottom) {
|
|
3490
|
+
if (isDeleted(id)) return id;
|
|
3491
|
+
id.right = right;
|
|
3492
|
+
id.bottom = bottom;
|
|
3493
|
+
return id;
|
|
3494
|
+
}
|
|
3495
|
+
function set_xloc3(id, left, right, xloc) {
|
|
3496
|
+
if (isDeleted(id)) return id;
|
|
3497
|
+
id.left = left;
|
|
3498
|
+
id.right = right;
|
|
3499
|
+
id.xloc = xloc;
|
|
3500
|
+
return id;
|
|
3501
|
+
}
|
|
3502
|
+
function set_extend2(id, extend) {
|
|
3503
|
+
if (isDeleted(id)) return id;
|
|
3504
|
+
id.extend = extend;
|
|
3505
|
+
return id;
|
|
3506
|
+
}
|
|
3507
|
+
function set_border_color(id, borderColor) {
|
|
3508
|
+
if (isDeleted(id)) return id;
|
|
3509
|
+
id.border_color = borderColor;
|
|
3510
|
+
return id;
|
|
3511
|
+
}
|
|
3512
|
+
function set_border_width(id, width) {
|
|
3513
|
+
if (isDeleted(id)) return id;
|
|
3514
|
+
id.border_width = width;
|
|
3515
|
+
return id;
|
|
3516
|
+
}
|
|
3517
|
+
function set_border_style(id, style) {
|
|
3518
|
+
if (isDeleted(id)) return id;
|
|
3519
|
+
id.border_style = style;
|
|
3520
|
+
return id;
|
|
3521
|
+
}
|
|
3522
|
+
function set_bgcolor(id, bgColor) {
|
|
3523
|
+
if (isDeleted(id)) return id;
|
|
3524
|
+
id.bgcolor = bgColor;
|
|
3525
|
+
return id;
|
|
3526
|
+
}
|
|
3527
|
+
function set_text2(id, text2) {
|
|
3528
|
+
if (isDeleted(id)) return id;
|
|
3529
|
+
id.text = text2;
|
|
3530
|
+
return id;
|
|
3531
|
+
}
|
|
3532
|
+
function set_text_color(id, textColor) {
|
|
3533
|
+
if (isDeleted(id)) return id;
|
|
3534
|
+
id.text_color = textColor;
|
|
3535
|
+
return id;
|
|
3536
|
+
}
|
|
3537
|
+
function set_text_size(id, size) {
|
|
3538
|
+
if (isDeleted(id)) return id;
|
|
3539
|
+
id.text_size = size;
|
|
3540
|
+
return id;
|
|
3541
|
+
}
|
|
3542
|
+
function set_text_halign(id, align) {
|
|
3543
|
+
if (isDeleted(id)) return id;
|
|
3544
|
+
id.text_halign = align;
|
|
3545
|
+
return id;
|
|
3546
|
+
}
|
|
3547
|
+
function set_text_valign(id, align) {
|
|
3548
|
+
if (isDeleted(id)) return id;
|
|
3549
|
+
id.text_valign = align;
|
|
3550
|
+
return id;
|
|
3551
|
+
}
|
|
3552
|
+
function set_text_wrap(id, wrap) {
|
|
3553
|
+
if (isDeleted(id)) return id;
|
|
3554
|
+
id.text_wrap = wrap;
|
|
3555
|
+
return id;
|
|
3556
|
+
}
|
|
3557
|
+
function set_text_font_family2(id, font) {
|
|
3558
|
+
if (isDeleted(id)) return id;
|
|
3559
|
+
id.text_font_family = font;
|
|
3560
|
+
return id;
|
|
3561
|
+
}
|
|
3562
|
+
function delete_box(id) {
|
|
3563
|
+
remove("box", id);
|
|
3564
|
+
}
|
|
3565
|
+
function pointX3(point, xloc) {
|
|
3566
|
+
const x = xloc === "bar_time" ? point.time : point.index;
|
|
3567
|
+
return x ?? NaN;
|
|
3568
|
+
}
|
|
3569
|
+
function all4() {
|
|
3570
|
+
return all("box");
|
|
3571
|
+
}
|
|
3572
|
+
function set_top_left_point(id, point) {
|
|
3573
|
+
if (isDeleted(id)) return id;
|
|
3574
|
+
id.left = pointX3(point, id.xloc);
|
|
3575
|
+
id.top = point.price;
|
|
3576
|
+
return id;
|
|
3577
|
+
}
|
|
3578
|
+
function set_bottom_right_point(id, point) {
|
|
3579
|
+
if (isDeleted(id)) return id;
|
|
3580
|
+
id.right = pointX3(point, id.xloc);
|
|
3581
|
+
id.bottom = point.price;
|
|
3582
|
+
return id;
|
|
3583
|
+
}
|
|
3584
|
+
function set_text_formatting2(id, formatting) {
|
|
3585
|
+
if (isDeleted(id)) return id;
|
|
3586
|
+
id.text_formatting = formatting;
|
|
3587
|
+
return id;
|
|
3588
|
+
}
|
|
3589
|
+
|
|
3590
|
+
// src/linefill/index.ts
|
|
3591
|
+
var linefill_exports = {};
|
|
3592
|
+
__export(linefill_exports, {
|
|
3593
|
+
all: () => all5,
|
|
3594
|
+
delete: () => delete_linefill,
|
|
3595
|
+
delete_linefill: () => delete_linefill,
|
|
3596
|
+
get_line1: () => get_line1,
|
|
3597
|
+
get_line2: () => get_line2,
|
|
3598
|
+
new: () => new_linefill,
|
|
3599
|
+
new_linefill: () => new_linefill,
|
|
3600
|
+
set_color: () => set_color3
|
|
3601
|
+
});
|
|
3602
|
+
function new_linefill(line1, line2, fillColor) {
|
|
3603
|
+
return register("linefill", {
|
|
3604
|
+
line1,
|
|
3605
|
+
line2,
|
|
3606
|
+
color: fillColor
|
|
3607
|
+
});
|
|
3608
|
+
}
|
|
3609
|
+
function get_line1(id) {
|
|
3610
|
+
return id.line1;
|
|
3611
|
+
}
|
|
3612
|
+
function get_line2(id) {
|
|
3613
|
+
return id.line2;
|
|
3614
|
+
}
|
|
3615
|
+
function set_color3(id, fillColor) {
|
|
3616
|
+
if (isDeleted(id)) return id;
|
|
3617
|
+
id.color = fillColor;
|
|
3618
|
+
return id;
|
|
3619
|
+
}
|
|
3620
|
+
function delete_linefill(id) {
|
|
3621
|
+
remove("linefill", id);
|
|
3622
|
+
}
|
|
3623
|
+
function all5() {
|
|
3624
|
+
return all("linefill");
|
|
3625
|
+
}
|
|
3626
|
+
|
|
3627
|
+
// src/polyline/index.ts
|
|
3628
|
+
var polyline_exports = {};
|
|
3629
|
+
__export(polyline_exports, {
|
|
3630
|
+
all: () => all6,
|
|
3631
|
+
clear_all: () => clear_all,
|
|
3632
|
+
delete: () => delete_polyline,
|
|
3633
|
+
delete_polyline: () => delete_polyline,
|
|
3634
|
+
get_all: () => get_all,
|
|
3635
|
+
new: () => new_polyline,
|
|
3636
|
+
new_polyline: () => new_polyline,
|
|
3637
|
+
reset_id_counter: () => reset_id_counter
|
|
3638
|
+
});
|
|
3639
|
+
var polylineIdCounter = 0;
|
|
3640
|
+
function generateId() {
|
|
3641
|
+
return `polyline_${++polylineIdCounter}`;
|
|
3642
|
+
}
|
|
3643
|
+
function new_polyline(points, curved = false, closed = false, xloc = "bar_index", line_color = "#2196F3", fill_color = null, line_style = "solid", line_width = 1, force_overlay = false) {
|
|
3644
|
+
if (curved) {
|
|
3645
|
+
console.warn(
|
|
3646
|
+
"polyline.new(): curved polylines are not yet supported. Using straight-line connections."
|
|
3647
|
+
);
|
|
3648
|
+
}
|
|
3649
|
+
if (line_width < 1) {
|
|
3650
|
+
console.warn("polyline.new(): line_width must be at least 1. Using 1.");
|
|
3651
|
+
line_width = 1;
|
|
3652
|
+
}
|
|
3653
|
+
const polyline2 = {
|
|
3654
|
+
id: generateId(),
|
|
3655
|
+
points: [...points],
|
|
3656
|
+
// Create a copy of the points array
|
|
3657
|
+
curved,
|
|
3658
|
+
closed,
|
|
3659
|
+
xloc,
|
|
3660
|
+
line_color,
|
|
3661
|
+
fill_color,
|
|
3662
|
+
line_style,
|
|
3663
|
+
line_width,
|
|
3664
|
+
force_overlay
|
|
3665
|
+
};
|
|
3666
|
+
return register("polyline", polyline2);
|
|
3667
|
+
}
|
|
3668
|
+
function delete_polyline(id) {
|
|
3669
|
+
remove("polyline", id);
|
|
3670
|
+
}
|
|
3671
|
+
function get_all() {
|
|
3672
|
+
return all("polyline");
|
|
3673
|
+
}
|
|
3674
|
+
function all6() {
|
|
3675
|
+
return all("polyline");
|
|
3676
|
+
}
|
|
3677
|
+
function clear_all() {
|
|
3678
|
+
for (const p of all("polyline")) remove("polyline", p);
|
|
3679
|
+
}
|
|
3680
|
+
function reset_id_counter() {
|
|
3681
|
+
polylineIdCounter = 0;
|
|
3682
|
+
}
|
|
3683
|
+
|
|
3684
|
+
// src/chartpoint/index.ts
|
|
3685
|
+
var chartpoint_exports = {};
|
|
3686
|
+
__export(chartpoint_exports, {
|
|
3687
|
+
copy: () => copy4,
|
|
3688
|
+
from_index: () => from_index,
|
|
3689
|
+
from_time: () => from_time,
|
|
3690
|
+
new: () => new_point,
|
|
3691
|
+
new_point: () => new_point
|
|
3692
|
+
});
|
|
3693
|
+
function new_point(time2, index, price) {
|
|
3694
|
+
return {
|
|
3695
|
+
time: time2,
|
|
3696
|
+
index,
|
|
3697
|
+
price
|
|
3698
|
+
};
|
|
3699
|
+
}
|
|
3700
|
+
function from_time(time2, price) {
|
|
3701
|
+
return {
|
|
3702
|
+
time: time2,
|
|
3703
|
+
index: null,
|
|
3704
|
+
price
|
|
3705
|
+
};
|
|
3706
|
+
}
|
|
3707
|
+
function from_index(index, price) {
|
|
3708
|
+
return {
|
|
3709
|
+
time: null,
|
|
3710
|
+
index,
|
|
3711
|
+
price
|
|
3712
|
+
};
|
|
3713
|
+
}
|
|
3714
|
+
function copy4(point) {
|
|
3715
|
+
return {
|
|
3716
|
+
time: point.time,
|
|
3717
|
+
index: point.index,
|
|
3718
|
+
price: point.price
|
|
3719
|
+
};
|
|
3720
|
+
}
|
|
3721
|
+
|
|
3722
|
+
// src/text/index.ts
|
|
3723
|
+
var text_exports = {};
|
|
3724
|
+
__export(text_exports, {
|
|
3725
|
+
format_bold: () => format_bold,
|
|
3726
|
+
format_italic: () => format_italic,
|
|
3727
|
+
format_none: () => format_none
|
|
3728
|
+
});
|
|
3729
|
+
var format_none = 0;
|
|
3730
|
+
var format_bold = 1;
|
|
3731
|
+
var format_italic = 2;
|
|
3732
|
+
|
|
3733
|
+
// src/timeframe/index.ts
|
|
3734
|
+
var timeframe_exports = {};
|
|
3735
|
+
__export(timeframe_exports, {
|
|
3736
|
+
from_seconds: () => from_seconds,
|
|
3737
|
+
in_seconds: () => in_seconds,
|
|
3738
|
+
info: () => info
|
|
3739
|
+
});
|
|
3740
|
+
var SECONDS_PER_MINUTE = 60;
|
|
3741
|
+
var SECONDS_PER_DAY = 86400;
|
|
3742
|
+
var SECONDS_PER_WEEK = 604800;
|
|
3743
|
+
var SECONDS_PER_MONTH = 2628003;
|
|
3744
|
+
var SECONDS_365_DAYS = 365 * SECONDS_PER_DAY;
|
|
3745
|
+
var UNIT_SECONDS = {
|
|
3746
|
+
S: 1,
|
|
3747
|
+
"": SECONDS_PER_MINUTE,
|
|
3748
|
+
D: SECONDS_PER_DAY,
|
|
3749
|
+
W: SECONDS_PER_WEEK,
|
|
3750
|
+
M: SECONDS_PER_MONTH
|
|
3751
|
+
};
|
|
3752
|
+
var SECOND_TIMEFRAMES = [1, 5, 10, 15, 30];
|
|
3753
|
+
function in_seconds(timeframe2) {
|
|
3754
|
+
const text2 = timeframe2.trim();
|
|
3755
|
+
if (text2 === "") {
|
|
3756
|
+
throw new RangeError("timeframe.in_seconds() needs a timeframe: the chart timeframe is not known here");
|
|
3757
|
+
}
|
|
3758
|
+
const before = /^(\d*)([SDWMT]?)$/.exec(text2);
|
|
3759
|
+
const after = before ? null : /^([SDWMT])(\d+)$/.exec(text2);
|
|
3760
|
+
if (!before && !after) throw new RangeError(`Invalid timeframe "${timeframe2}"`);
|
|
3761
|
+
const [digits, unit] = before ? [before[1], before[2]] : [after[2], after[1]];
|
|
3762
|
+
if (unit === "T") return NaN;
|
|
3763
|
+
const multiplier = digits === "" ? 1 : Number(digits);
|
|
3764
|
+
return multiplier * UNIT_SECONDS[unit];
|
|
3765
|
+
}
|
|
3766
|
+
function from_seconds(seconds) {
|
|
3767
|
+
if (Number.isNaN(seconds)) throw new RangeError("timeframe.from_seconds() needs a number of seconds");
|
|
3768
|
+
if (seconds >= SECONDS_365_DAYS) return "12M";
|
|
3769
|
+
if (seconds > 0) {
|
|
3770
|
+
if (seconds % SECONDS_PER_MONTH === 0) return `${seconds / SECONDS_PER_MONTH}M`;
|
|
3771
|
+
if (seconds % SECONDS_PER_WEEK === 0) return `${seconds / SECONDS_PER_WEEK}W`;
|
|
3772
|
+
if (seconds % SECONDS_PER_DAY === 0) return `${seconds / SECONDS_PER_DAY}D`;
|
|
3773
|
+
if (seconds % SECONDS_PER_MINUTE === 0 && seconds < SECONDS_PER_DAY) return `${seconds / SECONDS_PER_MINUTE}`;
|
|
3774
|
+
}
|
|
3775
|
+
const second3 = SECOND_TIMEFRAMES.find((m) => seconds <= m);
|
|
3776
|
+
if (second3 !== void 0) return `${second3}S`;
|
|
3777
|
+
if (seconds < SECONDS_PER_DAY) return `${Math.ceil(seconds / SECONDS_PER_MINUTE)}`;
|
|
3778
|
+
return `${Math.ceil(seconds / SECONDS_PER_DAY)}D`;
|
|
3779
|
+
}
|
|
3780
|
+
function info(timeframe2) {
|
|
3781
|
+
const text2 = timeframe2.trim();
|
|
3782
|
+
const m = /^(\d*)([SDWMT]?)$/.exec(text2);
|
|
3783
|
+
if (!m || text2 === "") throw new RangeError(`Invalid timeframe "${timeframe2}"`);
|
|
3784
|
+
const unit = m[2];
|
|
3785
|
+
const multiplier = m[1] === "" ? 1 : Number(m[1]);
|
|
3786
|
+
return {
|
|
3787
|
+
period: unit === "" ? String(multiplier) : `${multiplier}${unit}`,
|
|
3788
|
+
multiplier,
|
|
3789
|
+
isintraday: unit === "" || unit === "S" || unit === "T",
|
|
3790
|
+
isdaily: unit === "D",
|
|
3791
|
+
isweekly: unit === "W",
|
|
3792
|
+
ismonthly: unit === "M",
|
|
3793
|
+
isminutes: unit === "",
|
|
3794
|
+
isseconds: unit === "S",
|
|
3795
|
+
isticks: unit === "T",
|
|
3796
|
+
isdwm: unit === "D" || unit === "W" || unit === "M"
|
|
3797
|
+
};
|
|
3798
|
+
}
|
|
3799
|
+
|
|
3800
|
+
// src/time/timezone.ts
|
|
3801
|
+
var MS_PER_SECOND = 1e3;
|
|
3802
|
+
var MS_PER_DAY = 864e5;
|
|
3803
|
+
var MAX_OFFSET_SECONDS = 18 * 3600;
|
|
3804
|
+
var OFFSET_NOTATION = /^(?:UTC|GMT)(?:([+-])(\d{1,2})(?::?(\d{2})(?::?(\d{2}))?)?)?$/;
|
|
3805
|
+
var REJECTED_NAMES = /* @__PURE__ */ new Set(["EST", "MST", "HST"]);
|
|
3806
|
+
var canonicalNames;
|
|
3807
|
+
function hasTimeZoneCase(name) {
|
|
3808
|
+
if (name.split("/").some((segment) => !/^[A-Z]/.test(segment))) return false;
|
|
3809
|
+
canonicalNames ??= new Map(Intl.supportedValuesOf("timeZone").map((n) => [n.toLowerCase(), n]));
|
|
3810
|
+
const canonical = canonicalNames.get(name.toLowerCase());
|
|
3811
|
+
return canonical === void 0 || canonical === name;
|
|
3812
|
+
}
|
|
3813
|
+
var zones = /* @__PURE__ */ new Map();
|
|
3814
|
+
function resolveZone(timezone) {
|
|
3815
|
+
let zone = zones.get(timezone);
|
|
3816
|
+
if (zone) return zone;
|
|
3817
|
+
const invalid = () => new RangeError(
|
|
3818
|
+
`Invalid time zone "${timezone}": use UTC/GMT offset notation ("UTC-5", "GMT+0530") or an IANA name ("America/New_York")`
|
|
3819
|
+
);
|
|
3820
|
+
const m = OFFSET_NOTATION.exec(timezone);
|
|
3821
|
+
if (m) {
|
|
3822
|
+
const [, sign2, h = "0", mi = "0", s] = m;
|
|
3823
|
+
const minutes = Number(mi);
|
|
3824
|
+
const seconds = s === void 0 ? 0 : Number(s);
|
|
3825
|
+
if (minutes > 59 || seconds > 59 || s !== void 0 && h.length !== 2) throw invalid();
|
|
3826
|
+
const offsetSeconds = Number(h) * 3600 + minutes * 60 + seconds;
|
|
3827
|
+
if (offsetSeconds > MAX_OFFSET_SECONDS) throw invalid();
|
|
3828
|
+
zone = { kind: "fixed", offsetMs: (sign2 === "-" ? -offsetSeconds : offsetSeconds) * MS_PER_SECOND };
|
|
3829
|
+
} else {
|
|
3830
|
+
if (REJECTED_NAMES.has(timezone) || !hasTimeZoneCase(timezone)) throw invalid();
|
|
3831
|
+
let format2;
|
|
3832
|
+
try {
|
|
3833
|
+
format2 = new Intl.DateTimeFormat("en-US", {
|
|
3834
|
+
timeZone: timezone,
|
|
3835
|
+
hourCycle: "h23",
|
|
3836
|
+
year: "numeric",
|
|
3837
|
+
month: "numeric",
|
|
3838
|
+
day: "numeric",
|
|
3839
|
+
hour: "numeric",
|
|
3840
|
+
minute: "numeric",
|
|
3841
|
+
second: "numeric"
|
|
3842
|
+
});
|
|
3843
|
+
} catch {
|
|
3844
|
+
throw invalid();
|
|
3845
|
+
}
|
|
3846
|
+
zone = { kind: "iana", format: format2 };
|
|
3847
|
+
}
|
|
3848
|
+
zones.set(timezone, zone);
|
|
3849
|
+
return zone;
|
|
3850
|
+
}
|
|
3851
|
+
function offsetAt(zone, time2) {
|
|
3852
|
+
if (zone.kind === "fixed") return zone.offsetMs;
|
|
3853
|
+
const wholeSecond = Math.floor(time2 / 1e3) * 1e3;
|
|
3854
|
+
const f = {};
|
|
3855
|
+
for (const part of zone.format.formatToParts(wholeSecond)) {
|
|
3856
|
+
if (part.type !== "literal") f[part.type] = Number(part.value);
|
|
3857
|
+
}
|
|
3858
|
+
const local = Date.UTC(f.year, f.month - 1, f.day, f.hour, f.minute, f.second);
|
|
3859
|
+
return local - wholeSecond;
|
|
3860
|
+
}
|
|
3861
|
+
function zoneOffset(time2, timezone) {
|
|
3862
|
+
return offsetAt(resolveZone(timezone), time2);
|
|
3863
|
+
}
|
|
3864
|
+
function zonedFields(time2, timezone) {
|
|
3865
|
+
const local = new Date(time2 + offsetAt(resolveZone(timezone), time2));
|
|
3866
|
+
return {
|
|
3867
|
+
year: local.getUTCFullYear(),
|
|
3868
|
+
month: local.getUTCMonth() + 1,
|
|
3869
|
+
day: local.getUTCDate(),
|
|
3870
|
+
hour: local.getUTCHours(),
|
|
3871
|
+
minute: local.getUTCMinutes(),
|
|
3872
|
+
second: local.getUTCSeconds(),
|
|
3873
|
+
dayOfWeek: local.getUTCDay() + 1
|
|
3874
|
+
};
|
|
3875
|
+
}
|
|
3876
|
+
function zonedToUnix(timezone, year3, month3, day, hour3 = 0, minute3 = 0, second3 = 0) {
|
|
3877
|
+
const zone = resolveZone(timezone);
|
|
3878
|
+
const local = Date.UTC(year3, month3 - 1, day, hour3, minute3, second3);
|
|
3879
|
+
if (zone.kind === "fixed") return local - zone.offsetMs;
|
|
3880
|
+
const before = offsetAt(zone, local - MS_PER_DAY);
|
|
3881
|
+
const after = offsetAt(zone, local + MS_PER_DAY);
|
|
3882
|
+
const candidates = [local - before, local - after].filter((t2) => local - offsetAt(zone, t2) === t2);
|
|
3883
|
+
if (candidates.length) return Math.max(...candidates);
|
|
3884
|
+
return local - before;
|
|
3885
|
+
}
|
|
3886
|
+
|
|
3887
|
+
// src/time/datestring.ts
|
|
3888
|
+
var MONTHS = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"];
|
|
3889
|
+
var FULL_MONTHS = [
|
|
3890
|
+
"january",
|
|
3891
|
+
"february",
|
|
3892
|
+
"march",
|
|
3893
|
+
"april",
|
|
3894
|
+
"may",
|
|
3895
|
+
"june",
|
|
3896
|
+
"july",
|
|
3897
|
+
"august",
|
|
3898
|
+
"september",
|
|
3899
|
+
"october",
|
|
3900
|
+
"november",
|
|
3901
|
+
"december"
|
|
3902
|
+
];
|
|
3903
|
+
var ZONE_NAMES = {
|
|
3904
|
+
ut: 0,
|
|
3905
|
+
utc: 0,
|
|
3906
|
+
gmt: 0,
|
|
3907
|
+
est: -5,
|
|
3908
|
+
edt: -4,
|
|
3909
|
+
cst: -6,
|
|
3910
|
+
cdt: -5,
|
|
3911
|
+
mst: -7,
|
|
3912
|
+
mdt: -6,
|
|
3913
|
+
pst: -8,
|
|
3914
|
+
pdt: -7
|
|
3915
|
+
};
|
|
3916
|
+
var TIME = String.raw`(\d{1,2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3})\d*)?)?`;
|
|
3917
|
+
var ZONE = String.raw`(ut|utc|gmt|[ecmp][sd]t|(?:utc|gmt)?\s*[+-]\d{1,2}(?::?\d{2})?)`;
|
|
3918
|
+
var NUMERIC_ZONE = String.raw`([+-]\d{2}(?::?\d{2})?)`;
|
|
3919
|
+
var DATE = String.raw`(\d{4})([-/])(\d{1,2})\2(\d{1,2})`;
|
|
3920
|
+
var WEEKDAY = String.raw`(?:[a-z]{3,9},?\s+)?`;
|
|
3921
|
+
var ISO_T = new RegExp(String.raw`^${DATE}t${TIME}\s*${NUMERIC_ZONE}?$`, "i");
|
|
3922
|
+
var ISO = new RegExp(String.raw`^${DATE}(?:\s+${TIME})?\s*${ZONE}?$`, "i");
|
|
3923
|
+
var DAY_FIRST = new RegExp(String.raw`^${WEEKDAY}(\d{1,2})(?:\s+|-)([a-z]+)\.?,?(?:\s+|-)(\d{4})(?:,?\s+${TIME})?\s*${ZONE}?$`, "i");
|
|
3924
|
+
var MONTH_FIRST = new RegExp(String.raw`^${WEEKDAY}([a-z]+)\.?\s+(\d{1,2}),?\s+(\d{4})(?:,?\s+${TIME})?\s*${ZONE}?$`, "i");
|
|
3925
|
+
function monthNumber(name) {
|
|
3926
|
+
const lower2 = name.toLowerCase();
|
|
3927
|
+
const i = FULL_MONTHS.findIndex((full, k) => lower2.startsWith(MONTHS[k]) && full.startsWith(lower2));
|
|
3928
|
+
return i + 1;
|
|
3929
|
+
}
|
|
3930
|
+
function zoneMinutes(zone) {
|
|
3931
|
+
if (!zone) return 0;
|
|
3932
|
+
const lower2 = zone.toLowerCase().replace(/\s+/g, "");
|
|
3933
|
+
const named = ZONE_NAMES[lower2];
|
|
3934
|
+
if (named !== void 0) return named * 60;
|
|
3935
|
+
const m = /^(?:utc|gmt)?([+-])(\d{1,2})(?::?(\d{2}))?$/.exec(lower2);
|
|
3936
|
+
if (!m) return NaN;
|
|
3937
|
+
const minutes = Number(m[2]) * 60 + (m[3] ? Number(m[3]) : 0);
|
|
3938
|
+
return m[1] === "-" ? -minutes : minutes;
|
|
3939
|
+
}
|
|
3940
|
+
function parseDateString(dateString) {
|
|
3941
|
+
const text2 = dateString.trim();
|
|
3942
|
+
let year3, month3, day;
|
|
3943
|
+
let rest;
|
|
3944
|
+
let m;
|
|
3945
|
+
if (m = ISO_T.exec(text2) ?? ISO.exec(text2)) {
|
|
3946
|
+
[year3, month3, day] = [m[1], Number(m[3]), m[4]];
|
|
3947
|
+
rest = m.slice(5);
|
|
3948
|
+
} else if (m = DAY_FIRST.exec(text2)) {
|
|
3949
|
+
[day, month3, year3] = [m[1], monthNumber(m[2]), m[3]];
|
|
3950
|
+
rest = m.slice(4);
|
|
3951
|
+
} else if (m = MONTH_FIRST.exec(text2)) {
|
|
3952
|
+
[month3, day, year3] = [monthNumber(m[1]), m[2], m[3]];
|
|
3953
|
+
rest = m.slice(4);
|
|
3954
|
+
} else {
|
|
3955
|
+
throw new SyntaxError(`Invalid date string "${dateString}": use RFC 2822 or ISO 8601 ("20 Feb 2020", "2020-02-20T14:48:00")`);
|
|
3956
|
+
}
|
|
3957
|
+
const [hour3 = "0", minute3 = "0", second3 = "0", millis = "0", zone] = rest;
|
|
3958
|
+
const d = Number(day);
|
|
3959
|
+
const h = Number(hour3);
|
|
3960
|
+
const mi = Number(minute3);
|
|
3961
|
+
const s = Number(second3);
|
|
3962
|
+
const offset = zoneMinutes(zone);
|
|
3963
|
+
const endOfDay = h === 24 && mi === 0 && s === 0 && Number(millis) === 0;
|
|
3964
|
+
if (month3 < 1 || month3 > 12 || d < 1 || d > 31 || h > 23 && !endOfDay || mi > 59 || s > 59 || Number.isNaN(offset)) {
|
|
3965
|
+
throw new SyntaxError(`Invalid date string "${dateString}": a field is out of range`);
|
|
3966
|
+
}
|
|
3967
|
+
const ms = Number(millis.padEnd(3, "0"));
|
|
3968
|
+
return Date.UTC(Number(year3), month3 - 1, d, h, mi, s, ms) - offset * 6e4;
|
|
3969
|
+
}
|
|
3970
|
+
|
|
3971
|
+
// src/time/session.ts
|
|
3972
|
+
var PERIOD = /^(\d{2})(\d{2})-(\d{2})(\d{2})$/;
|
|
3973
|
+
var sessions = /* @__PURE__ */ new Map();
|
|
3974
|
+
function parseSession(session2) {
|
|
3975
|
+
let parsed = sessions.get(session2);
|
|
3976
|
+
if (parsed) return parsed;
|
|
3977
|
+
const invalid = () => new SyntaxError(`Invalid session "${session2}": expected "HHmm-HHmm[,HHmm-HHmm...][:days]"`);
|
|
3978
|
+
const text2 = session2.trim() === "24x7" ? "0000-0000" : session2.replace(/\s+/g, "");
|
|
3979
|
+
const [periodText = "", dayText, extra] = text2.split(":");
|
|
3980
|
+
if (extra !== void 0 || periodText === "") throw invalid();
|
|
3981
|
+
const periods = periodText.split(",").map((p) => {
|
|
3982
|
+
const m = PERIOD.exec(p);
|
|
3983
|
+
if (!m) throw invalid();
|
|
3984
|
+
const [h1, m1, h2, m2] = [m[1], m[2], m[3], m[4]].map(Number);
|
|
3985
|
+
if (h1 > 23 || h2 > 23 || m1 > 59 || m2 > 59) throw invalid();
|
|
3986
|
+
return { start: h1 * 60 + m1, end: h2 * 60 + m2 };
|
|
3987
|
+
});
|
|
3988
|
+
const dayDigits = dayText ?? (periods.length > 1 ? "23456" : "1234567");
|
|
3989
|
+
if (!/^[1-7]+$/.test(dayDigits)) throw invalid();
|
|
3990
|
+
const days = new Array(8).fill(false);
|
|
3991
|
+
for (const d of dayDigits) days[Number(d)] = true;
|
|
3992
|
+
parsed = { periods, days };
|
|
3993
|
+
sessions.set(session2, parsed);
|
|
3994
|
+
return parsed;
|
|
3995
|
+
}
|
|
3996
|
+
function inSession(time2, session2, timezone) {
|
|
3997
|
+
if (Number.isNaN(time2)) return false;
|
|
3998
|
+
const { periods, days } = parseSession(session2);
|
|
3999
|
+
const f = zonedFields(time2, timezone);
|
|
4000
|
+
const minute3 = f.hour * 60 + f.minute;
|
|
4001
|
+
const nextDay = f.dayOfWeek % 7 + 1;
|
|
4002
|
+
for (const { start, end } of periods) {
|
|
4003
|
+
if (start < end || start === 0 && end === 0) {
|
|
4004
|
+
if (minute3 >= start && (minute3 < end || end === 0) && days[f.dayOfWeek]) return true;
|
|
4005
|
+
} else {
|
|
4006
|
+
if (minute3 >= start && days[nextDay]) return true;
|
|
4007
|
+
if (minute3 < end && days[f.dayOfWeek]) return true;
|
|
4008
|
+
}
|
|
4009
|
+
}
|
|
4010
|
+
return false;
|
|
4011
|
+
}
|
|
4012
|
+
|
|
4013
|
+
// src/time/index.ts
|
|
4014
|
+
function timestamp(first, ...rest) {
|
|
4015
|
+
if (typeof first === "string") {
|
|
4016
|
+
if (rest.length === 0) return parseDateString(first);
|
|
4017
|
+
const [year3, month4, day2, hour4, minute4, second4] = rest;
|
|
4018
|
+
return zonedToUnix(first, year3, month4, day2, hour4 ?? 0, minute4 ?? 0, second4 ?? 0);
|
|
4019
|
+
}
|
|
4020
|
+
const [month3, day, hour3, minute3, second3] = rest;
|
|
4021
|
+
return new Date(first, month3 - 1, day, hour3 || 0, minute3 || 0, second3 || 0).getTime();
|
|
4022
|
+
}
|
|
4023
|
+
function field(time2, timezone, pick) {
|
|
4024
|
+
return Number.isNaN(time2) ? NaN : pick(zonedFields(time2, timezone));
|
|
4025
|
+
}
|
|
4026
|
+
function year(time2, timezone) {
|
|
4027
|
+
return field(time2, timezone, (f) => f.year);
|
|
4028
|
+
}
|
|
4029
|
+
function month(time2, timezone) {
|
|
4030
|
+
return field(time2, timezone, (f) => f.month);
|
|
4031
|
+
}
|
|
4032
|
+
function dayofmonth(time2, timezone) {
|
|
4033
|
+
return field(time2, timezone, (f) => f.day);
|
|
4034
|
+
}
|
|
4035
|
+
function dayofweek(time2, timezone) {
|
|
4036
|
+
return field(time2, timezone, (f) => f.dayOfWeek);
|
|
4037
|
+
}
|
|
4038
|
+
function weekofyear(time2, timezone) {
|
|
4039
|
+
return field(time2, timezone, (f) => {
|
|
4040
|
+
const date = Date.UTC(f.year, f.month - 1, f.day);
|
|
4041
|
+
const mondayBased = (f.dayOfWeek + 5) % 7;
|
|
4042
|
+
const thursday = new Date(date + (3 - mondayBased) * 864e5);
|
|
4043
|
+
const yearStart = Date.UTC(thursday.getUTCFullYear(), 0, 1);
|
|
4044
|
+
return 1 + Math.floor((thursday.getTime() - yearStart) / (7 * 864e5));
|
|
4045
|
+
});
|
|
4046
|
+
}
|
|
4047
|
+
function hour(time2, timezone) {
|
|
4048
|
+
return field(time2, timezone, (f) => f.hour);
|
|
4049
|
+
}
|
|
4050
|
+
function minute(time2, timezone) {
|
|
4051
|
+
return field(time2, timezone, (f) => f.minute);
|
|
4052
|
+
}
|
|
4053
|
+
function second(time2, timezone) {
|
|
4054
|
+
return field(time2, timezone, (f) => f.second);
|
|
4055
|
+
}
|
|
4056
|
+
function inSession2(time2, session2, timezone) {
|
|
4057
|
+
return inSession(time2, session2, timezone);
|
|
4058
|
+
}
|
|
4059
|
+
|
|
4060
|
+
// src/str/index.ts
|
|
4061
|
+
var str_exports = {};
|
|
4062
|
+
__export(str_exports, {
|
|
4063
|
+
charAt: () => charAt,
|
|
4064
|
+
concat: () => concat,
|
|
4065
|
+
contains: () => contains,
|
|
4066
|
+
endswith: () => endswith,
|
|
4067
|
+
format: () => format,
|
|
4068
|
+
format_time: () => format_time,
|
|
4069
|
+
length: () => length,
|
|
4070
|
+
lower: () => lower,
|
|
4071
|
+
match: () => match,
|
|
4072
|
+
pos: () => pos,
|
|
4073
|
+
repeat: () => repeat,
|
|
4074
|
+
replace: () => replace,
|
|
4075
|
+
replace_all: () => replace_all,
|
|
4076
|
+
split: () => split,
|
|
4077
|
+
startswith: () => startswith,
|
|
4078
|
+
substring: () => substring,
|
|
4079
|
+
tonumber: () => tonumber,
|
|
4080
|
+
tostring: () => tostring,
|
|
4081
|
+
trim: () => trim,
|
|
4082
|
+
trimLeft: () => trimLeft,
|
|
4083
|
+
trimRight: () => trimRight,
|
|
4084
|
+
upper: () => upper
|
|
4085
|
+
});
|
|
4086
|
+
|
|
4087
|
+
// src/str/numberformat.ts
|
|
4088
|
+
var patterns = /* @__PURE__ */ new Map();
|
|
4089
|
+
function parsePattern(pattern) {
|
|
4090
|
+
const cached = patterns.get(pattern);
|
|
4091
|
+
if (cached) return cached;
|
|
4092
|
+
let prefix = "";
|
|
4093
|
+
let suffix = "";
|
|
4094
|
+
let number2 = "";
|
|
4095
|
+
let percent = false;
|
|
4096
|
+
let phase = "prefix";
|
|
4097
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
4098
|
+
const ch = pattern[i];
|
|
4099
|
+
let literal;
|
|
4100
|
+
if (ch === "'") {
|
|
4101
|
+
const end = pattern.indexOf("'", i + 1);
|
|
4102
|
+
if (end === i + 1) {
|
|
4103
|
+
literal = "'";
|
|
4104
|
+
i = end;
|
|
4105
|
+
} else {
|
|
4106
|
+
literal = pattern.slice(i + 1, end === -1 ? void 0 : end);
|
|
4107
|
+
i = end === -1 ? pattern.length : end;
|
|
4108
|
+
}
|
|
4109
|
+
} else if (phase !== "suffix" && ("#0,.".includes(ch) || phase === "number" && ch === "E")) {
|
|
4110
|
+
phase = "number";
|
|
4111
|
+
number2 += ch;
|
|
4112
|
+
continue;
|
|
4113
|
+
} else {
|
|
4114
|
+
if (ch === "%") percent = true;
|
|
4115
|
+
literal = ch;
|
|
4116
|
+
}
|
|
4117
|
+
if (phase === "number") phase = "suffix";
|
|
4118
|
+
if (phase === "prefix") prefix += literal;
|
|
4119
|
+
else suffix += literal;
|
|
4120
|
+
}
|
|
4121
|
+
const [mantissa = "", exp2] = number2.split("E");
|
|
4122
|
+
const [intPart = "", fracPart = ""] = mantissa.split(".");
|
|
4123
|
+
const lastComma = intPart.lastIndexOf(",");
|
|
4124
|
+
const parsed = {
|
|
4125
|
+
prefix,
|
|
4126
|
+
suffix,
|
|
4127
|
+
// as in Java, a pattern with a decimal point and no '0' at all ("#.##") shows one integer digit
|
|
4128
|
+
minInt: !mantissa.includes("0") && mantissa.includes(".") ? 1 : [...intPart].filter((c) => c === "0").length,
|
|
4129
|
+
minFrac: [...fracPart].filter((c) => c === "0").length,
|
|
4130
|
+
maxFrac: [...fracPart].filter((c) => c === "0" || c === "#").length,
|
|
4131
|
+
grouping: lastComma === -1 ? 0 : intPart.length - lastComma - 1,
|
|
4132
|
+
percent,
|
|
4133
|
+
exponent: exp2 === void 0 ? null : exp2.length,
|
|
4134
|
+
hasDigits: /[0#]/.test(mantissa)
|
|
4135
|
+
};
|
|
4136
|
+
patterns.set(pattern, parsed);
|
|
4137
|
+
return parsed;
|
|
4138
|
+
}
|
|
4139
|
+
function shortestDigits(x) {
|
|
4140
|
+
const m = /^(\d+)(?:\.(\d+))?(?:e([+-]\d+))?$/.exec(String(Math.abs(x)));
|
|
4141
|
+
const all7 = m[1] + (m[2] ?? "");
|
|
4142
|
+
let intLen = m[1].length + Number(m[3] ?? 0);
|
|
4143
|
+
const lead = all7.length - all7.replace(/^0+/, "").length;
|
|
4144
|
+
intLen -= lead;
|
|
4145
|
+
const digits = all7.slice(lead).replace(/0+$/, "");
|
|
4146
|
+
return { digits, intLen: digits ? intLen : 0 };
|
|
4147
|
+
}
|
|
4148
|
+
function exactDigits(x) {
|
|
4149
|
+
const abs2 = Math.abs(x);
|
|
4150
|
+
if (abs2 === 0) return { digits: "", intLen: 0 };
|
|
4151
|
+
const view = new DataView(new ArrayBuffer(8));
|
|
4152
|
+
view.setFloat64(0, abs2);
|
|
4153
|
+
const bits = view.getBigUint64(0);
|
|
4154
|
+
const expBits = Number(bits >> 52n & 0x7ffn);
|
|
4155
|
+
let mant = bits & 0xfffffffffffffn;
|
|
4156
|
+
const e2 = expBits === 0 ? -1074 : expBits - 1075;
|
|
4157
|
+
if (expBits !== 0) mant |= 1n << 52n;
|
|
4158
|
+
let str2;
|
|
4159
|
+
let fracDigits;
|
|
4160
|
+
if (e2 >= 0) {
|
|
4161
|
+
str2 = (mant << BigInt(e2)).toString();
|
|
4162
|
+
fracDigits = 0;
|
|
4163
|
+
} else {
|
|
4164
|
+
str2 = (mant * 5n ** BigInt(-e2)).toString();
|
|
4165
|
+
fracDigits = -e2;
|
|
4166
|
+
}
|
|
4167
|
+
const intLen = str2.length - fracDigits;
|
|
4168
|
+
const lead = str2.length - str2.replace(/^0+/, "").length;
|
|
4169
|
+
const digits = str2.slice(lead).replace(/0+$/, "");
|
|
4170
|
+
return { digits, intLen: intLen - lead };
|
|
4171
|
+
}
|
|
4172
|
+
function roundDigits(d, frac, mode3) {
|
|
4173
|
+
const keep = d.intLen + frac;
|
|
4174
|
+
if (keep >= d.digits.length) return d;
|
|
4175
|
+
if (keep < 0) return { digits: "", intLen: 0 };
|
|
4176
|
+
const first = d.digits.charCodeAt(keep) - 48;
|
|
4177
|
+
let up;
|
|
4178
|
+
if (mode3 === "halfUpShortest") up = first >= 5;
|
|
4179
|
+
else if (first !== 5) up = first > 5;
|
|
4180
|
+
else if (d.digits.length > keep + 1) up = true;
|
|
4181
|
+
else up = keep > 0 && (d.digits.charCodeAt(keep - 1) - 48) % 2 === 1;
|
|
4182
|
+
let kept = d.digits.slice(0, keep);
|
|
4183
|
+
let intLen = d.intLen;
|
|
4184
|
+
if (up) {
|
|
4185
|
+
const n = (BigInt(kept || "0") + 1n).toString();
|
|
4186
|
+
if (n.length > kept.length) intLen += 1;
|
|
4187
|
+
kept = n;
|
|
4188
|
+
}
|
|
4189
|
+
kept = kept.replace(/0+$/, "");
|
|
4190
|
+
return { digits: kept, intLen: kept ? intLen : 0 };
|
|
4191
|
+
}
|
|
4192
|
+
function group(int, size) {
|
|
4193
|
+
if (!size || int.length <= size) return int;
|
|
4194
|
+
const parts = [];
|
|
4195
|
+
for (let end = int.length; end > 0; end -= size) parts.unshift(int.slice(Math.max(0, end - size), end));
|
|
4196
|
+
return parts.join(",");
|
|
4197
|
+
}
|
|
4198
|
+
function layout(d, p) {
|
|
4199
|
+
let int = d.intLen > 0 ? d.digits.slice(0, d.intLen).padEnd(d.intLen, "0") : "";
|
|
4200
|
+
int = int.replace(/^0+/, "").padStart(p.minInt, "0");
|
|
4201
|
+
let frac = d.intLen < 0 ? "0".repeat(-d.intLen) + d.digits : d.digits.slice(Math.max(0, d.intLen));
|
|
4202
|
+
frac = frac.slice(0, p.maxFrac).replace(/0+$/, "").padEnd(p.minFrac, "0");
|
|
4203
|
+
if (!int && !frac) int = "0";
|
|
4204
|
+
return group(int, p.grouping) + (frac ? "." + frac : "");
|
|
4205
|
+
}
|
|
4206
|
+
function formatNumber(value, pattern, mode3) {
|
|
4207
|
+
if (Number.isNaN(value)) return "NaN";
|
|
4208
|
+
const p = parsePattern(pattern);
|
|
4209
|
+
if (!Number.isFinite(value)) return (value < 0 ? "-" : "") + p.prefix + "\u221E" + p.suffix;
|
|
4210
|
+
const x = p.percent ? value * 100 : value;
|
|
4211
|
+
const toDigits = mode3 === "halfUpShortest" ? shortestDigits : exactDigits;
|
|
4212
|
+
let body;
|
|
4213
|
+
let isZero;
|
|
4214
|
+
if (p.exponent !== null) {
|
|
4215
|
+
const rounded = roundDigits(toDigits(x), p.maxFrac, mode3);
|
|
4216
|
+
const intDigits = Math.max(p.minInt, 1);
|
|
4217
|
+
isZero = rounded.digits === "";
|
|
4218
|
+
let exponent = isZero ? 0 : rounded.intLen - intDigits;
|
|
4219
|
+
let mant = roundDigits({ digits: rounded.digits, intLen: isZero ? 0 : intDigits }, p.maxFrac, mode3);
|
|
4220
|
+
if (mant.intLen > intDigits) {
|
|
4221
|
+
exponent += 1;
|
|
4222
|
+
mant = { digits: mant.digits, intLen: intDigits };
|
|
4223
|
+
}
|
|
4224
|
+
const e2 = String(Math.abs(exponent)).padStart(p.exponent, "0");
|
|
4225
|
+
body = layout(mant, p) + "E" + (exponent < 0 ? "-" : "") + e2;
|
|
4226
|
+
} else {
|
|
4227
|
+
const rounded = roundDigits(toDigits(x), p.hasDigits ? p.maxFrac : 0, mode3);
|
|
4228
|
+
isZero = rounded.digits === "";
|
|
4229
|
+
body = p.hasDigits ? layout(rounded, p) : layout(rounded, { ...p, minInt: 0, maxFrac: 0, minFrac: 0 });
|
|
4230
|
+
}
|
|
4231
|
+
const negative = x < 0 && (!isZero || !p.hasDigits);
|
|
4232
|
+
return (negative ? "-" : "") + p.prefix + body + p.suffix;
|
|
4233
|
+
}
|
|
4234
|
+
|
|
4235
|
+
// src/str/dateformat.ts
|
|
4236
|
+
var MONTHS2 = [
|
|
4237
|
+
"January",
|
|
4238
|
+
"February",
|
|
4239
|
+
"March",
|
|
4240
|
+
"April",
|
|
4241
|
+
"May",
|
|
4242
|
+
"June",
|
|
4243
|
+
"July",
|
|
4244
|
+
"August",
|
|
4245
|
+
"September",
|
|
4246
|
+
"October",
|
|
4247
|
+
"November",
|
|
4248
|
+
"December"
|
|
4249
|
+
];
|
|
4250
|
+
var DAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
4251
|
+
var pad = (n, width) => String(n).padStart(width, "0");
|
|
4252
|
+
function zoneName(time2, timezone, offsetMs) {
|
|
4253
|
+
if (timezone === "Etc/UTC") return "UTC";
|
|
4254
|
+
if (/^(UTC|GMT)/.test(timezone)) {
|
|
4255
|
+
if (offsetMs === 0) return "GMT";
|
|
4256
|
+
const minutes = Math.abs(offsetMs) / 6e4;
|
|
4257
|
+
return `GMT${offsetMs < 0 ? "-" : "+"}${pad(Math.floor(minutes / 60), 2)}:${pad(minutes % 60, 2)}`;
|
|
4258
|
+
}
|
|
4259
|
+
const part = new Intl.DateTimeFormat("en-US", { timeZone: timezone, timeZoneName: "short" }).formatToParts(time2).find((p) => p.type === "timeZoneName");
|
|
4260
|
+
return part?.value ?? timezone;
|
|
4261
|
+
}
|
|
4262
|
+
function weekOfYear(year3, month3, day) {
|
|
4263
|
+
const date = Date.UTC(year3, month3 - 1, day);
|
|
4264
|
+
const dow = new Date(date).getUTCDay();
|
|
4265
|
+
const weekStart2 = date - dow * 864e5;
|
|
4266
|
+
if (weekStart2 + 6 * 864e5 >= Date.UTC(year3 + 1, 0, 1)) return 1;
|
|
4267
|
+
const jan1 = Date.UTC(year3, 0, 1);
|
|
4268
|
+
const jan1Dow = new Date(jan1).getUTCDay();
|
|
4269
|
+
return Math.floor((date - jan1 + jan1Dow * 864e5) / (7 * 864e5)) + 1;
|
|
4270
|
+
}
|
|
4271
|
+
function formatDate(time2, pattern, timezone) {
|
|
4272
|
+
if (Number.isNaN(time2)) return "NaN";
|
|
4273
|
+
const f = zonedFields(time2, timezone);
|
|
4274
|
+
const offset = zoneOffset(time2, timezone);
|
|
4275
|
+
const ms = (time2 % 1e3 + 1e3) % 1e3;
|
|
4276
|
+
const dayOfYear = (Date.UTC(f.year, f.month - 1, f.day) - Date.UTC(f.year, 0, 1)) / 864e5 + 1;
|
|
4277
|
+
let out = "";
|
|
4278
|
+
for (let i = 0; i < pattern.length; ) {
|
|
4279
|
+
const ch = pattern[i];
|
|
4280
|
+
if (ch === "'") {
|
|
4281
|
+
const end = pattern.indexOf("'", i + 1);
|
|
4282
|
+
if (end === i + 1) {
|
|
4283
|
+
out += "'";
|
|
4284
|
+
i += 2;
|
|
4285
|
+
} else {
|
|
4286
|
+
out += pattern.slice(i + 1, end === -1 ? void 0 : end);
|
|
4287
|
+
i = end === -1 ? pattern.length : end + 1;
|
|
4288
|
+
}
|
|
4289
|
+
continue;
|
|
4290
|
+
}
|
|
4291
|
+
if (!/[A-Za-z]/.test(ch)) {
|
|
4292
|
+
out += ch;
|
|
4293
|
+
i++;
|
|
4294
|
+
continue;
|
|
4295
|
+
}
|
|
4296
|
+
let n = 1;
|
|
4297
|
+
while (pattern[i + n] === ch) n++;
|
|
4298
|
+
i += n;
|
|
4299
|
+
const hour12 = f.hour % 12;
|
|
4300
|
+
switch (ch) {
|
|
4301
|
+
case "y":
|
|
4302
|
+
out += n === 2 ? pad(f.year % 100, 2) : pad(f.year, n);
|
|
4303
|
+
break;
|
|
4304
|
+
case "M":
|
|
4305
|
+
out += n >= 4 ? MONTHS2[f.month - 1] : n === 3 ? MONTHS2[f.month - 1].slice(0, 3) : pad(f.month, n);
|
|
4306
|
+
break;
|
|
4307
|
+
case "d":
|
|
4308
|
+
out += pad(f.day, n);
|
|
4309
|
+
break;
|
|
4310
|
+
case "E":
|
|
4311
|
+
out += n >= 4 ? DAYS[f.dayOfWeek - 1] : DAYS[f.dayOfWeek - 1].slice(0, 3);
|
|
4312
|
+
break;
|
|
4313
|
+
case "u":
|
|
4314
|
+
out += pad(f.dayOfWeek === 1 ? 7 : f.dayOfWeek - 1, n);
|
|
4315
|
+
break;
|
|
4316
|
+
case "D":
|
|
4317
|
+
out += pad(dayOfYear, n);
|
|
4318
|
+
break;
|
|
4319
|
+
case "w":
|
|
4320
|
+
out += pad(weekOfYear(f.year, f.month, f.day), n);
|
|
4321
|
+
break;
|
|
4322
|
+
case "H":
|
|
4323
|
+
out += pad(f.hour, n);
|
|
4324
|
+
break;
|
|
4325
|
+
case "k":
|
|
4326
|
+
out += pad(f.hour === 0 ? 24 : f.hour, n);
|
|
4327
|
+
break;
|
|
4328
|
+
case "K":
|
|
4329
|
+
out += pad(hour12, n);
|
|
4330
|
+
break;
|
|
4331
|
+
case "h":
|
|
4332
|
+
out += pad(hour12 === 0 ? 12 : hour12, n);
|
|
4333
|
+
break;
|
|
4334
|
+
case "a":
|
|
4335
|
+
out += f.hour < 12 ? "AM" : "PM";
|
|
4336
|
+
break;
|
|
4337
|
+
case "m":
|
|
4338
|
+
out += pad(f.minute, n);
|
|
4339
|
+
break;
|
|
4340
|
+
case "s":
|
|
4341
|
+
out += pad(f.second, n);
|
|
4342
|
+
break;
|
|
4343
|
+
case "S":
|
|
4344
|
+
out += pad(ms, n);
|
|
4345
|
+
break;
|
|
4346
|
+
case "Z": {
|
|
4347
|
+
const minutes = Math.abs(offset) / 6e4;
|
|
4348
|
+
out += (offset < 0 ? "-" : "+") + pad(Math.floor(minutes / 60), 2) + pad(minutes % 60, 2);
|
|
4349
|
+
break;
|
|
4350
|
+
}
|
|
4351
|
+
case "z":
|
|
4352
|
+
out += zoneName(time2, timezone, offset);
|
|
4353
|
+
break;
|
|
4354
|
+
default:
|
|
4355
|
+
throw new SyntaxError(`Unsupported date pattern letter "${ch}" in "${pattern}"`);
|
|
4356
|
+
}
|
|
4357
|
+
}
|
|
4358
|
+
return out;
|
|
4359
|
+
}
|
|
4360
|
+
|
|
4361
|
+
// src/str/messageformat.ts
|
|
4362
|
+
var DATE_STYLES = {
|
|
4363
|
+
short: "M/d/yy",
|
|
4364
|
+
medium: "MMM d, yyyy",
|
|
4365
|
+
long: "MMMM d, yyyy",
|
|
4366
|
+
full: "EEEE, MMMM d, yyyy"
|
|
4367
|
+
};
|
|
4368
|
+
var TIME_STYLES = {
|
|
4369
|
+
short: "h:mm\u202Fa",
|
|
4370
|
+
medium: "h:mm:ss\u202Fa",
|
|
4371
|
+
long: "h:mm:ss\u202Fa z",
|
|
4372
|
+
full: "h:mm:ss\u202Fa z"
|
|
4373
|
+
};
|
|
4374
|
+
function number(value, pattern) {
|
|
4375
|
+
return typeof value === "number" ? formatNumber(value, pattern, "halfEvenExact") : String(value);
|
|
4376
|
+
}
|
|
4377
|
+
function choice(value, spec) {
|
|
4378
|
+
const options = spec.split("|").map((part) => {
|
|
4379
|
+
const m = /^\s*(-?[\d.]+|-?∞)\s*([#<≤])(.*)$/.exec(part);
|
|
4380
|
+
if (!m) throw new SyntaxError(`Invalid choice format "${spec}"`);
|
|
4381
|
+
const limit = m[1].includes("\u221E") ? m[1].startsWith("-") ? -Infinity : Infinity : Number(m[1]);
|
|
4382
|
+
return { limit: m[2] === "<" ? limit + Number.EPSILON * Math.max(1, Math.abs(limit)) : limit, text: m[3] };
|
|
4383
|
+
});
|
|
4384
|
+
let chosen = options[0];
|
|
4385
|
+
for (const o of options) if (value >= o.limit) chosen = o;
|
|
4386
|
+
return chosen.text;
|
|
4387
|
+
}
|
|
4388
|
+
function formatArgument(value, type, style, timezone) {
|
|
4389
|
+
if (value === void 0) return "";
|
|
4390
|
+
if (!type) return typeof value === "number" ? number(value, "#,##0.###") : String(value);
|
|
4391
|
+
switch (type.trim()) {
|
|
4392
|
+
case "number": {
|
|
4393
|
+
const s = style?.trim();
|
|
4394
|
+
if (!s) return number(value, "#,##0.###");
|
|
4395
|
+
if (s === "integer") return number(value, "#,##0");
|
|
4396
|
+
if (s === "percent") return number(value, "#,##0%");
|
|
4397
|
+
if (s === "currency") return number(value, "'$'#,##0.00");
|
|
4398
|
+
return number(value, style);
|
|
4399
|
+
}
|
|
4400
|
+
case "date":
|
|
4401
|
+
case "time": {
|
|
4402
|
+
const styles = type.trim() === "date" ? DATE_STYLES : TIME_STYLES;
|
|
4403
|
+
const s = style?.trim() ?? "medium";
|
|
4404
|
+
return formatDate(Number(value), styles[s] ?? style, typeof timezone === "function" ? timezone() : timezone);
|
|
4405
|
+
}
|
|
4406
|
+
case "choice":
|
|
4407
|
+
return choice(Number(value), style ?? "");
|
|
4408
|
+
default:
|
|
4409
|
+
throw new SyntaxError(`Unknown format type "${type}"`);
|
|
4410
|
+
}
|
|
4411
|
+
}
|
|
4412
|
+
function formatMessage(pattern, args, timezone) {
|
|
4413
|
+
let out = "";
|
|
4414
|
+
for (let i = 0; i < pattern.length; ) {
|
|
4415
|
+
const ch = pattern[i];
|
|
4416
|
+
if (ch === "'") {
|
|
4417
|
+
if (pattern[i + 1] === "'") {
|
|
4418
|
+
out += "'";
|
|
4419
|
+
i += 2;
|
|
4420
|
+
continue;
|
|
4421
|
+
}
|
|
4422
|
+
const end = pattern.indexOf("'", i + 1);
|
|
4423
|
+
out += pattern.slice(i + 1, end === -1 ? void 0 : end);
|
|
4424
|
+
i = end === -1 ? pattern.length : end + 1;
|
|
4425
|
+
continue;
|
|
4426
|
+
}
|
|
4427
|
+
if (ch !== "{") {
|
|
4428
|
+
out += ch;
|
|
4429
|
+
i++;
|
|
4430
|
+
continue;
|
|
4431
|
+
}
|
|
4432
|
+
let depth = 1;
|
|
4433
|
+
let j = i + 1;
|
|
4434
|
+
let inQuote = false;
|
|
4435
|
+
for (; j < pattern.length && depth > 0; j++) {
|
|
4436
|
+
const c = pattern[j];
|
|
4437
|
+
if (c === "'") inQuote = !inQuote;
|
|
4438
|
+
else if (!inQuote && c === "{") depth++;
|
|
4439
|
+
else if (!inQuote && c === "}") depth--;
|
|
4440
|
+
}
|
|
4441
|
+
const inner = pattern.slice(i + 1, j - 1);
|
|
4442
|
+
const [index = "", type, ...rest] = inner.split(",");
|
|
4443
|
+
const style = rest.length ? rest.join(",") : void 0;
|
|
4444
|
+
const n = Number(index.trim());
|
|
4445
|
+
out += n < args.length ? formatArgument(args[n], type, style, timezone) : `{${inner}}`;
|
|
4446
|
+
i = j;
|
|
4447
|
+
}
|
|
4448
|
+
return out;
|
|
4449
|
+
}
|
|
4450
|
+
|
|
4451
|
+
// src/str/index.ts
|
|
4452
|
+
function length(str2) {
|
|
4453
|
+
return str2.length;
|
|
4454
|
+
}
|
|
4455
|
+
function tostring(value, format2) {
|
|
4456
|
+
if (typeof value !== "number") return String(value);
|
|
4457
|
+
if (!Number.isFinite(value)) return String(value);
|
|
4458
|
+
if (format2 === void 0 || format2 === "") {
|
|
4459
|
+
if (Math.abs(value) >= 1e21 && Number.isFinite(value)) {
|
|
4460
|
+
return String(value).replace("e+", "E").replace(/\.0+E/, "E");
|
|
4461
|
+
}
|
|
4462
|
+
return formatNumber(value, "#.##########", "halfUpShortest");
|
|
4463
|
+
}
|
|
4464
|
+
switch (format2) {
|
|
4465
|
+
case "percent":
|
|
4466
|
+
return formatNumber(value, "0.00", "halfUpShortest") + "%";
|
|
4467
|
+
case "volume": {
|
|
4468
|
+
const abs2 = Math.abs(value);
|
|
4469
|
+
for (const [size, unit] of [[1e12, "T"], [1e9, "B"], [1e6, "M"], [1e3, "K"]]) {
|
|
4470
|
+
if (abs2 >= size) return formatNumber(value / size, "#.###", "halfUpShortest") + unit;
|
|
4471
|
+
}
|
|
4472
|
+
return formatNumber(value, "#", "halfUpShortest");
|
|
4473
|
+
}
|
|
4474
|
+
case "mintick":
|
|
4475
|
+
throw new Error("str.tostring(x, format.mintick) needs the symbol tick size (syminfo.mintick), which is not known here");
|
|
4476
|
+
default:
|
|
4477
|
+
return formatNumber(value, format2, "halfUpShortest");
|
|
4478
|
+
}
|
|
4479
|
+
}
|
|
4480
|
+
function tonumber(str2) {
|
|
4481
|
+
const num = parseFloat(str2);
|
|
4482
|
+
return isNaN(num) ? null : num;
|
|
4483
|
+
}
|
|
4484
|
+
function substring(str2, begin, end) {
|
|
4485
|
+
return str2.substring(begin, end);
|
|
4486
|
+
}
|
|
4487
|
+
function upper(str2) {
|
|
4488
|
+
return str2.toUpperCase();
|
|
4489
|
+
}
|
|
4490
|
+
function lower(str2) {
|
|
4491
|
+
return str2.toLowerCase();
|
|
4492
|
+
}
|
|
4493
|
+
function contains(source, str2) {
|
|
4494
|
+
return source.includes(str2);
|
|
4495
|
+
}
|
|
4496
|
+
function pos(source, str2) {
|
|
4497
|
+
return source.indexOf(str2);
|
|
4498
|
+
}
|
|
4499
|
+
function replace(source, target, replacement, occurrence) {
|
|
4500
|
+
if (occurrence === 0) {
|
|
4501
|
+
return source.replace(target, replacement);
|
|
4502
|
+
} else {
|
|
4503
|
+
return source.replaceAll(target, replacement);
|
|
4504
|
+
}
|
|
4505
|
+
}
|
|
4506
|
+
function replace_all(source, target, replacement) {
|
|
4507
|
+
return source.replaceAll(target, replacement);
|
|
4508
|
+
}
|
|
4509
|
+
function split(str2, separator) {
|
|
4510
|
+
return str2.split(separator);
|
|
4511
|
+
}
|
|
4512
|
+
function concat(...strings) {
|
|
4513
|
+
return strings.join("");
|
|
4514
|
+
}
|
|
4515
|
+
function format(formatStr, ...args) {
|
|
4516
|
+
return formatMessage(formatStr, args, "Etc/UTC");
|
|
4517
|
+
}
|
|
4518
|
+
function startswith(source, str2) {
|
|
4519
|
+
return source.startsWith(str2);
|
|
4520
|
+
}
|
|
4521
|
+
function endswith(source, str2) {
|
|
4522
|
+
return source.endsWith(str2);
|
|
4523
|
+
}
|
|
4524
|
+
function charAt(str2, pos2) {
|
|
4525
|
+
return str2.charAt(pos2);
|
|
4526
|
+
}
|
|
4527
|
+
function trim(str2) {
|
|
4528
|
+
return str2.trim();
|
|
4529
|
+
}
|
|
4530
|
+
function trimLeft(str2) {
|
|
4531
|
+
return str2.trimStart();
|
|
4532
|
+
}
|
|
4533
|
+
function trimRight(str2) {
|
|
4534
|
+
return str2.trimEnd();
|
|
4535
|
+
}
|
|
4536
|
+
function match(source, regex) {
|
|
4537
|
+
return new RegExp(regex).test(source);
|
|
4538
|
+
}
|
|
4539
|
+
function repeat(source, count, separator = "") {
|
|
4540
|
+
if (source == null) return null;
|
|
4541
|
+
if (count <= 0) return "";
|
|
4542
|
+
return Array(count).fill(source).join(separator);
|
|
4543
|
+
}
|
|
4544
|
+
function format_time(time2, format2 = "yyyy-MM-dd'T'HH:mm:ssZ", timezone = "Etc/UTC") {
|
|
4545
|
+
return formatDate(time2, format2, timezone);
|
|
4546
|
+
}
|
|
4547
|
+
|
|
4548
|
+
// src/session/calendar.ts
|
|
4549
|
+
var toDateNum = (y, m, d) => y * 1e4 + m * 100 + d;
|
|
4550
|
+
var utcOf = (date) => Date.UTC(Math.floor(date / 1e4), Math.floor(date / 100) % 100 - 1, date % 100);
|
|
4551
|
+
var fromUtc = (ms) => {
|
|
4552
|
+
const d = new Date(ms);
|
|
4553
|
+
return toDateNum(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate());
|
|
4554
|
+
};
|
|
4555
|
+
var addDays = (date, n) => fromUtc(utcOf(date) + n * 864e5);
|
|
4556
|
+
var weekdayOf = (date) => new Date(utcOf(date)).getUTCDay() + 1;
|
|
4557
|
+
var dateUtcMs = utcOf;
|
|
4558
|
+
function parseTime(token, spec) {
|
|
4559
|
+
const m = /^(\d{2})(\d{2})(?:F(\d+))?$/.exec(token.trim());
|
|
4560
|
+
if (!m) throw new SyntaxError(`Invalid session "${spec}"`);
|
|
4561
|
+
return { minutes: Number(m[1]) * 60 + Number(m[2]), offset: m[3] === void 0 ? void 0 : Number(m[3]) };
|
|
4562
|
+
}
|
|
4563
|
+
function parsePeriods(text2, spec) {
|
|
4564
|
+
if (text2.trim() === "24x7") return [{ start: 0, end: 1440, startOffset: 0, endOffset: 0 }];
|
|
4565
|
+
return text2.split(",").map((p) => {
|
|
4566
|
+
const [a = "", b2 = ""] = p.split("-");
|
|
4567
|
+
const s = parseTime(a, spec);
|
|
4568
|
+
const e2 = parseTime(b2, spec);
|
|
4569
|
+
if (s.minutes === 0 && e2.minutes === 0 && s.offset === void 0 && e2.offset === void 0) {
|
|
4570
|
+
return { start: 0, end: 1440, startOffset: 0, endOffset: 0 };
|
|
4571
|
+
}
|
|
4572
|
+
return {
|
|
4573
|
+
start: s.minutes,
|
|
4574
|
+
end: e2.minutes,
|
|
4575
|
+
startOffset: s.offset ?? (e2.minutes <= s.minutes ? 1 : 0),
|
|
4576
|
+
endOffset: e2.offset ?? 0
|
|
4577
|
+
};
|
|
4578
|
+
});
|
|
4579
|
+
}
|
|
4580
|
+
function parseVersion(text2, from, spec, rule) {
|
|
4581
|
+
const [periodText = "", dayText] = text2.trim().split(":");
|
|
4582
|
+
const periods = parsePeriods(periodText, spec);
|
|
4583
|
+
const allDays = periodText.trim() === "24x7" || rule === "pine" && periods.length === 1;
|
|
4584
|
+
const digits = dayText ?? (allDays ? "1234567" : "23456");
|
|
4585
|
+
if (!/^[1-7]+$/.test(digits)) throw new SyntaxError(`Invalid session days in "${spec}"`);
|
|
4586
|
+
const days = new Array(8).fill(false);
|
|
4587
|
+
for (const d of digits) days[Number(d)] = true;
|
|
4588
|
+
return { from, periods, days };
|
|
4589
|
+
}
|
|
4590
|
+
var TradingCalendar = class {
|
|
4591
|
+
/**
|
|
4592
|
+
* @param timezone - Time zone of the session hours (the exchange time zone)
|
|
4593
|
+
* @param spec - Session information (TradingView format)
|
|
4594
|
+
* @param rule - Days without ":days": 'symbol' (Monday to Friday) or 'pine' (PineScript session strings)
|
|
4595
|
+
*/
|
|
4596
|
+
constructor(timezone, spec, rule = "symbol") {
|
|
4597
|
+
this.timezone = timezone;
|
|
4598
|
+
const [first = "", ...changes] = spec.session.split("#");
|
|
4599
|
+
this.versions = [parseVersion(first, 0, spec.session, rule)];
|
|
4600
|
+
for (const change3 of changes) {
|
|
4601
|
+
const m = /^(\d{8})\/(.+)$/.exec(change3.trim());
|
|
4602
|
+
if (!m) throw new SyntaxError(`Invalid session change in "${spec.session}"`);
|
|
4603
|
+
this.versions.push(parseVersion(m[2], Number(m[1]), spec.session, rule));
|
|
4604
|
+
}
|
|
4605
|
+
for (const part of (spec.corrections ?? "").split(";").filter((p) => p.trim())) {
|
|
4606
|
+
const i = part.lastIndexOf(":");
|
|
4607
|
+
const text2 = part.slice(0, i).trim();
|
|
4608
|
+
const periods = text2 === "dayoff" ? null : parsePeriods(text2, part);
|
|
4609
|
+
for (const date of part.slice(i + 1).split(",")) this.corrections.set(Number(date), periods);
|
|
4610
|
+
}
|
|
4611
|
+
const holidays = Array.isArray(spec.holidays) ? spec.holidays : (spec.holidays ?? "").split(",");
|
|
4612
|
+
this.holidays = new Set(holidays.filter((h) => h.trim()).map(Number));
|
|
4613
|
+
}
|
|
4614
|
+
timezone;
|
|
4615
|
+
versions;
|
|
4616
|
+
corrections = /* @__PURE__ */ new Map();
|
|
4617
|
+
holidays;
|
|
4618
|
+
cache = /* @__PURE__ */ new Map();
|
|
4619
|
+
/** Session periods [start, end) of the trading day `date`; empty when the day has no session. */
|
|
4620
|
+
periods(date) {
|
|
4621
|
+
let out = this.cache.get(date);
|
|
4622
|
+
if (out) return out;
|
|
4623
|
+
let periods = [];
|
|
4624
|
+
const correction = this.corrections.get(date);
|
|
4625
|
+
if (correction !== void 0) {
|
|
4626
|
+
periods = correction ?? [];
|
|
4627
|
+
} else if (!this.holidays.has(date)) {
|
|
4628
|
+
const version = [...this.versions].reverse().find((v) => v.from <= date);
|
|
4629
|
+
if (version.days[weekdayOf(date)]) periods = version.periods;
|
|
4630
|
+
}
|
|
4631
|
+
const y = Math.floor(date / 1e4);
|
|
4632
|
+
const m = Math.floor(date / 100) % 100;
|
|
4633
|
+
const d = date % 100;
|
|
4634
|
+
out = periods.map((p) => [
|
|
4635
|
+
zonedToUnix(this.timezone, y, m, d - p.startOffset, Math.floor(p.start / 60), p.start % 60),
|
|
4636
|
+
zonedToUnix(this.timezone, y, m, d - p.endOffset, Math.floor(p.end / 60), p.end % 60)
|
|
4637
|
+
]);
|
|
4638
|
+
this.cache.set(date, out);
|
|
4639
|
+
return out;
|
|
4640
|
+
}
|
|
4641
|
+
isTradingDay(date) {
|
|
4642
|
+
return this.periods(date).length > 0;
|
|
4643
|
+
}
|
|
4644
|
+
/**
|
|
4645
|
+
* Trading day and period of a time: the period that contains it, else the last period that started
|
|
4646
|
+
* before it. Null when no trading day is found near the time.
|
|
4647
|
+
*/
|
|
4648
|
+
locate(time2) {
|
|
4649
|
+
const f = zonedFields(time2, this.timezone);
|
|
4650
|
+
const local = toDateNum(f.year, f.month, f.day);
|
|
4651
|
+
for (let k = 0; k <= 5; k++) {
|
|
4652
|
+
const date = addDays(local, k);
|
|
4653
|
+
const index = this.periods(date).findIndex(([s, e2]) => s <= time2 && time2 < e2);
|
|
4654
|
+
if (index !== -1) return { date, index, inside: true };
|
|
4655
|
+
}
|
|
4656
|
+
for (let k = 5; k >= -7; k--) {
|
|
4657
|
+
const date = addDays(local, k);
|
|
4658
|
+
const periods = this.periods(date);
|
|
4659
|
+
let index = -1;
|
|
4660
|
+
periods.forEach(([s], i) => {
|
|
4661
|
+
if (s <= time2) index = i;
|
|
4662
|
+
});
|
|
4663
|
+
if (index !== -1) return { date, index, inside: false };
|
|
4664
|
+
}
|
|
4665
|
+
return null;
|
|
4666
|
+
}
|
|
4667
|
+
/** First trading day in [from, to] (dates), or null. */
|
|
4668
|
+
firstTradingDay(from, to) {
|
|
4669
|
+
for (let date = from; date <= to; date = addDays(date, 1)) if (this.isTradingDay(date)) return date;
|
|
4670
|
+
return null;
|
|
4671
|
+
}
|
|
4672
|
+
/** Last trading day in [from, to] (dates), or null. */
|
|
4673
|
+
lastTradingDay(from, to) {
|
|
4674
|
+
for (let date = to; date >= from; date = addDays(date, -1)) if (this.isTradingDay(date)) return date;
|
|
4675
|
+
return null;
|
|
4676
|
+
}
|
|
4677
|
+
};
|
|
4678
|
+
var weekStart = (date) => addDays(date, -((weekdayOf(date) + 5) % 7));
|
|
4679
|
+
var monthStart = (date) => Math.floor(date / 100) * 100 + 1;
|
|
4680
|
+
var monthEnd = (date) => addDays(monthStart(addDays(monthStart(date), 32)), -1);
|
|
4681
|
+
|
|
4682
|
+
// src/session/bars.ts
|
|
4683
|
+
function unitOf(tf) {
|
|
4684
|
+
return { unit: tf.isdaily ? "D" : tf.isweekly ? "W" : "M", n: tf.multiplier };
|
|
4685
|
+
}
|
|
4686
|
+
var yearOf = (date) => Math.floor(date / 1e4);
|
|
4687
|
+
var firstMonday = (year3) => {
|
|
4688
|
+
const jan1 = year3 * 1e4 + 101;
|
|
4689
|
+
const monday = weekStart(jan1);
|
|
4690
|
+
return monday === jan1 ? jan1 : addDays(monday, 7);
|
|
4691
|
+
};
|
|
4692
|
+
var SessionBars = class {
|
|
4693
|
+
constructor(calendar2, chartTimeframe2) {
|
|
4694
|
+
this.calendar = calendar2;
|
|
4695
|
+
this.chart = info(chartTimeframe2);
|
|
4696
|
+
}
|
|
4697
|
+
calendar;
|
|
4698
|
+
chart;
|
|
4699
|
+
yearDays = /* @__PURE__ */ new Map();
|
|
4700
|
+
/** Trading days of a calendar year, in order. */
|
|
4701
|
+
tradingDaysOf(year3) {
|
|
4702
|
+
let days = this.yearDays.get(year3);
|
|
4703
|
+
if (!days) {
|
|
4704
|
+
days = [];
|
|
4705
|
+
for (let date = year3 * 1e4 + 101; yearOf(date) === year3; date = addDays(date, 1)) {
|
|
4706
|
+
if (this.calendar.isTradingDay(date)) days.push(date);
|
|
4707
|
+
}
|
|
4708
|
+
this.yearDays.set(year3, days);
|
|
4709
|
+
}
|
|
4710
|
+
return days;
|
|
4711
|
+
}
|
|
4712
|
+
/**
|
|
4713
|
+
* Dates [from, to] of the `n`-`unit` period that contains `date` (for "D": its first and last trading days).
|
|
4714
|
+
* Periods restart each calendar year.
|
|
4715
|
+
*/
|
|
4716
|
+
periodRange(date, unit, n) {
|
|
4717
|
+
if (unit === "D") {
|
|
4718
|
+
if (n === 1) return [date, date];
|
|
4719
|
+
const days = this.tradingDaysOf(yearOf(date));
|
|
4720
|
+
let k = days.findIndex((d) => d >= date);
|
|
4721
|
+
if (k === -1) return this.periodRange(yearOf(date) * 1e4 + 1e4 + 101, unit, n);
|
|
4722
|
+
k -= k % n;
|
|
4723
|
+
return [days[k], days[Math.min(k + n, days.length) - 1]];
|
|
4724
|
+
}
|
|
4725
|
+
if (unit === "W") {
|
|
4726
|
+
const monday = weekStart(date);
|
|
4727
|
+
const year4 = yearOf(monday);
|
|
4728
|
+
const first = firstMonday(year4);
|
|
4729
|
+
const next = firstMonday(year4 + 1);
|
|
4730
|
+
const k = Math.round((dateUtcMs(monday) - dateUtcMs(first)) / (7 * 864e5));
|
|
4731
|
+
const from = addDays(first, (k - k % n) * 7);
|
|
4732
|
+
const to = addDays(from, n * 7 - 1);
|
|
4733
|
+
return [from, to < next ? to : addDays(next, -1)];
|
|
4734
|
+
}
|
|
4735
|
+
const year3 = yearOf(date);
|
|
4736
|
+
const month3 = Math.floor(date / 100) % 100;
|
|
4737
|
+
const firstMonth = month3 - (month3 - 1) % n;
|
|
4738
|
+
const lastMonth = Math.min(firstMonth + n - 1, 12);
|
|
4739
|
+
return [monthStart(year3 * 1e4 + firstMonth * 100 + 1), monthEnd(year3 * 1e4 + lastMonth * 100 + 1)];
|
|
4740
|
+
}
|
|
4741
|
+
dayStart(date) {
|
|
4742
|
+
return this.calendar.periods(date)[0][0];
|
|
4743
|
+
}
|
|
4744
|
+
dayEnd(date) {
|
|
4745
|
+
const p = this.calendar.periods(date);
|
|
4746
|
+
return p[p.length - 1][1];
|
|
4747
|
+
}
|
|
4748
|
+
/** PineScript `time(tf)` for a bar that opens at `time`; NaN when no trading day is found. */
|
|
4749
|
+
timeOf(time2, timeframe2) {
|
|
4750
|
+
const tf = info(timeframe2);
|
|
4751
|
+
const at = this.calendar.locate(time2);
|
|
4752
|
+
if (!at) return NaN;
|
|
4753
|
+
if (tf.isintraday) {
|
|
4754
|
+
if (this.chart.isdwm) return time2;
|
|
4755
|
+
const [start] = this.calendar.periods(at.date)[at.index];
|
|
4756
|
+
const ms = in_seconds(tf.period) * 1e3;
|
|
4757
|
+
return start + Math.floor((time2 - start) / ms) * ms;
|
|
4758
|
+
}
|
|
4759
|
+
const { unit, n } = unitOf(tf);
|
|
4760
|
+
const [from, to] = this.periodRange(at.date, unit, n);
|
|
4761
|
+
const first = this.calendar.firstTradingDay(from, to);
|
|
4762
|
+
return first === null ? NaN : this.dayStart(first);
|
|
4763
|
+
}
|
|
4764
|
+
/** PineScript `time_close(tf)` for a bar that opens at `time`. */
|
|
4765
|
+
closeOf(time2, timeframe2) {
|
|
4766
|
+
const tf = info(timeframe2);
|
|
4767
|
+
const at = this.calendar.locate(time2);
|
|
4768
|
+
if (!at) return NaN;
|
|
4769
|
+
if (tf.isintraday) {
|
|
4770
|
+
const [, end] = this.calendar.periods(at.date)[at.index];
|
|
4771
|
+
if (this.chart.isdwm) return end;
|
|
4772
|
+
return Math.min(this.timeOf(time2, timeframe2) + in_seconds(tf.period) * 1e3, end);
|
|
4773
|
+
}
|
|
4774
|
+
const { unit, n } = unitOf(tf);
|
|
4775
|
+
const [from, to] = this.periodRange(at.date, unit, n);
|
|
4776
|
+
if (this.chart.isintraday && (unit !== "D" || n > 1)) {
|
|
4777
|
+
const [nextFrom, nextTo] = this.periodRange(addDays(to, 1), unit, n);
|
|
4778
|
+
const first = this.calendar.firstTradingDay(nextFrom, addDays(nextTo, 31));
|
|
4779
|
+
return first === null ? NaN : this.dayStart(first);
|
|
4780
|
+
}
|
|
4781
|
+
const last = this.calendar.lastTradingDay(from, to);
|
|
4782
|
+
return last === null ? NaN : this.dayEnd(last);
|
|
4783
|
+
}
|
|
4784
|
+
/** Trading day of a bar: on D / W / M charts the last trading day of the chart period. */
|
|
4785
|
+
tradingDay(time2) {
|
|
4786
|
+
const at = this.calendar.locate(time2);
|
|
4787
|
+
if (!at) return null;
|
|
4788
|
+
if (this.chart.isdwm) {
|
|
4789
|
+
const { unit, n } = unitOf(this.chart);
|
|
4790
|
+
const [from, to] = this.periodRange(at.date, unit, n);
|
|
4791
|
+
return this.calendar.lastTradingDay(from, to);
|
|
4792
|
+
}
|
|
4793
|
+
return at.date;
|
|
4794
|
+
}
|
|
4795
|
+
/**
|
|
4796
|
+
* End of the `timeframe` period that contains `time`: the intraday close, the session end of the day,
|
|
4797
|
+
* or the session end of the last trading day of the period. Used to know whether the last loaded
|
|
4798
|
+
* bar completes a higher-timeframe period (request.security).
|
|
4799
|
+
*/
|
|
4800
|
+
periodEnd(time2, timeframe2) {
|
|
4801
|
+
const tf = info(timeframe2);
|
|
4802
|
+
const at = this.calendar.locate(time2);
|
|
4803
|
+
if (!at) return NaN;
|
|
4804
|
+
if (tf.isintraday) {
|
|
4805
|
+
const [, end] = this.calendar.periods(at.date)[at.index];
|
|
4806
|
+
return Math.min(this.timeOf(time2, timeframe2) + in_seconds(tf.period) * 1e3, end);
|
|
4807
|
+
}
|
|
4808
|
+
const { unit, n } = unitOf(tf);
|
|
4809
|
+
const [from, to] = this.periodRange(at.date, unit, n);
|
|
4810
|
+
const last = this.calendar.lastTradingDay(from, to);
|
|
4811
|
+
return last === null ? NaN : this.dayEnd(last);
|
|
4812
|
+
}
|
|
4813
|
+
/** PineScript `time_tradingday`: 00:00 UTC of the trading day. */
|
|
4814
|
+
tradingDayTime(time2) {
|
|
4815
|
+
const day = this.tradingDay(time2);
|
|
4816
|
+
return day === null ? NaN : dateUtcMs(day);
|
|
4817
|
+
}
|
|
4818
|
+
/** True when the bar at `time` is inside the session. */
|
|
4819
|
+
inside(time2) {
|
|
4820
|
+
return this.calendar.locate(time2)?.inside ?? false;
|
|
4821
|
+
}
|
|
4822
|
+
/** Session start and end of the trading day of `time`, or null. */
|
|
4823
|
+
dayBounds(time2) {
|
|
4824
|
+
const at = this.calendar.locate(time2);
|
|
4825
|
+
return at ? { date: at.date, start: this.dayStart(at.date), end: this.dayEnd(at.date) } : null;
|
|
4826
|
+
}
|
|
4827
|
+
};
|
|
4828
|
+
function sessionFlags(times, bars2, regular) {
|
|
4829
|
+
const n = times.length;
|
|
4830
|
+
const flag2 = () => new Array(n).fill(false);
|
|
4831
|
+
const out = {
|
|
4832
|
+
isfirstbar: flag2(),
|
|
4833
|
+
islastbar: flag2(),
|
|
4834
|
+
ismarket: flag2(),
|
|
4835
|
+
ispremarket: flag2(),
|
|
4836
|
+
ispostmarket: flag2(),
|
|
4837
|
+
isfirstbar_regular: flag2(),
|
|
4838
|
+
islastbar_regular: flag2()
|
|
4839
|
+
};
|
|
4840
|
+
const chart2 = bars2.chart;
|
|
4841
|
+
let previousPeriod = "";
|
|
4842
|
+
let previousRegular = "";
|
|
4843
|
+
for (let i = 0; i < n; i++) {
|
|
4844
|
+
const t2 = times[i];
|
|
4845
|
+
if (chart2.isdwm) {
|
|
4846
|
+
for (const k of ["isfirstbar", "islastbar", "ismarket", "isfirstbar_regular", "islastbar_regular"]) out[k][i] = true;
|
|
4847
|
+
continue;
|
|
4848
|
+
}
|
|
4849
|
+
const at = bars2.calendar.locate(t2);
|
|
4850
|
+
if (!at) {
|
|
4851
|
+
previousPeriod = previousRegular = "";
|
|
4852
|
+
continue;
|
|
4853
|
+
}
|
|
4854
|
+
const close2 = bars2.closeOf(t2, chart2.period);
|
|
4855
|
+
const [, end] = bars2.calendar.periods(at.date)[at.index];
|
|
4856
|
+
const period = `${at.date}/${at.index}`;
|
|
4857
|
+
out.isfirstbar[i] = period !== previousPeriod;
|
|
4858
|
+
out.islastbar[i] = close2 >= end;
|
|
4859
|
+
const regularPeriods = regular.calendar.periods(at.date);
|
|
4860
|
+
const r2 = regularPeriods.findIndex(([s, e2]) => s <= t2 && t2 < e2);
|
|
4861
|
+
const market = r2 !== -1;
|
|
4862
|
+
out.ismarket[i] = market;
|
|
4863
|
+
if (!market && regularPeriods.length) {
|
|
4864
|
+
out.ispremarket[i] = t2 < regularPeriods[0][0];
|
|
4865
|
+
out.ispostmarket[i] = t2 >= regularPeriods[regularPeriods.length - 1][1];
|
|
4866
|
+
}
|
|
4867
|
+
const regularPeriod = market ? `${at.date}/${r2}` : "";
|
|
4868
|
+
out.isfirstbar_regular[i] = market && regularPeriod !== previousRegular;
|
|
4869
|
+
out.islastbar_regular[i] = market && close2 >= regularPeriods[r2][1];
|
|
4870
|
+
previousPeriod = period;
|
|
4871
|
+
previousRegular = regularPeriod;
|
|
4872
|
+
}
|
|
4873
|
+
return out;
|
|
4874
|
+
}
|
|
4875
|
+
|
|
4876
|
+
// src/security/resample.ts
|
|
4877
|
+
function resample(bars2, periodStart) {
|
|
4878
|
+
const out = [];
|
|
4879
|
+
const group2 = [];
|
|
4880
|
+
bars2.forEach((b2, i) => {
|
|
4881
|
+
const start = periodStart[i];
|
|
4882
|
+
const last = out[out.length - 1];
|
|
4883
|
+
if (!last || last.time !== start) {
|
|
4884
|
+
out.push({ time: start, open: b2.open, high: b2.high, low: b2.low, close: b2.close, volume: b2.volume ?? NaN });
|
|
4885
|
+
} else {
|
|
4886
|
+
last.high = Math.max(last.high, b2.high);
|
|
4887
|
+
last.low = Math.min(last.low, b2.low);
|
|
4888
|
+
last.close = b2.close;
|
|
4889
|
+
last.volume = (last.volume ?? 0) + (b2.volume ?? NaN);
|
|
4890
|
+
}
|
|
4891
|
+
group2.push(out.length - 1);
|
|
4892
|
+
});
|
|
4893
|
+
return { bars: out, group: group2 };
|
|
4894
|
+
}
|
|
4895
|
+
function periodsOf(starts, dayPeriods, reaches) {
|
|
4896
|
+
const n = starts.length;
|
|
4897
|
+
const group2 = [];
|
|
4898
|
+
starts.forEach((s, i) => group2.push(i === 0 ? 0 : group2[i - 1] + (s !== starts[i - 1] ? 1 : 0)));
|
|
4899
|
+
const latest = [];
|
|
4900
|
+
starts.forEach((s, i) => {
|
|
4901
|
+
let done = i === 0 ? -1 : latest[i - 1];
|
|
4902
|
+
if (i > 0 && group2[i] !== group2[i - 1]) done = Math.max(done, group2[i] - 1);
|
|
4903
|
+
const ends = i < n - 1 ? starts[i + 1] !== s || dayPeriods[i + 1] !== dayPeriods[i] : true;
|
|
4904
|
+
if (ends && reaches[i]) done = Math.max(done, group2[i]);
|
|
4905
|
+
latest.push(done);
|
|
4906
|
+
});
|
|
4907
|
+
return { group: group2, latest };
|
|
4908
|
+
}
|
|
4909
|
+
function mapToChart(values, group2, latest, lookahead, gaps) {
|
|
4910
|
+
return group2.map((g2, i) => {
|
|
4911
|
+
if (lookahead) {
|
|
4912
|
+
const first = i === 0 || group2[i - 1] !== g2;
|
|
4913
|
+
return gaps && !first ? NaN : values[g2] ?? NaN;
|
|
4914
|
+
}
|
|
4915
|
+
const done = latest[i];
|
|
4916
|
+
if (done < 0 || gaps && i > 0 && latest[i - 1] === done) return NaN;
|
|
4917
|
+
return values[done] ?? NaN;
|
|
4918
|
+
});
|
|
4919
|
+
}
|
|
4920
|
+
function heikinAshi(bars2) {
|
|
4921
|
+
const out = [];
|
|
4922
|
+
bars2.forEach((b2, i) => {
|
|
4923
|
+
const close2 = (b2.open + b2.high + b2.low + b2.close) / 4;
|
|
4924
|
+
const prev = out[i - 1];
|
|
4925
|
+
const open2 = prev ? (prev.open + prev.close) / 2 : (b2.open + b2.close) / 2;
|
|
4926
|
+
out.push({ time: b2.time, open: open2, high: Math.max(b2.high, open2, close2), low: Math.min(b2.low, open2, close2), close: close2, volume: b2.volume });
|
|
4927
|
+
});
|
|
4928
|
+
return out;
|
|
4929
|
+
}
|
|
4930
|
+
|
|
4931
|
+
// src/math/index.ts
|
|
4932
|
+
var math_exports = {};
|
|
4933
|
+
__export(math_exports, {
|
|
4934
|
+
abs: () => abs,
|
|
4935
|
+
acos: () => acos,
|
|
4936
|
+
asin: () => asin,
|
|
4937
|
+
atan: () => atan,
|
|
4938
|
+
avg: () => avg,
|
|
4939
|
+
ceil: () => ceil,
|
|
4940
|
+
cos: () => cos,
|
|
4941
|
+
e: () => e,
|
|
4942
|
+
exp: () => exp,
|
|
4943
|
+
floor: () => floor,
|
|
4944
|
+
log: () => log,
|
|
4945
|
+
log10: () => log10,
|
|
4946
|
+
max: () => max3,
|
|
4947
|
+
min: () => min3,
|
|
4948
|
+
phi: () => phi,
|
|
4949
|
+
pi: () => pi,
|
|
4950
|
+
pow: () => pow,
|
|
4951
|
+
random: () => random,
|
|
4952
|
+
round: () => round,
|
|
4953
|
+
round_to_mintick: () => round_to_mintick,
|
|
4954
|
+
rphi: () => rphi,
|
|
4955
|
+
sign: () => sign,
|
|
4956
|
+
sin: () => sin,
|
|
4957
|
+
sqrt: () => sqrt,
|
|
4958
|
+
sum: () => sum,
|
|
4959
|
+
tan: () => tan,
|
|
4960
|
+
todegrees: () => todegrees,
|
|
4961
|
+
toradians: () => toradians
|
|
4962
|
+
});
|
|
4963
|
+
function abs(value) {
|
|
4964
|
+
if (value instanceof Series) {
|
|
4965
|
+
const bars2 = value.bars;
|
|
4966
|
+
const valueArray = value.toArray();
|
|
4967
|
+
const length2 = bars2.length;
|
|
4968
|
+
const result = [];
|
|
4969
|
+
for (let i = 0; i < length2; i++) {
|
|
4970
|
+
const v = valueArray[i] ?? NaN;
|
|
4971
|
+
result.push(Math.abs(v));
|
|
4972
|
+
}
|
|
4973
|
+
return Series.fromArray(bars2, result);
|
|
4974
|
+
}
|
|
4975
|
+
return Math.abs(value);
|
|
4976
|
+
}
|
|
4977
|
+
function ceil(value) {
|
|
4978
|
+
if (value instanceof Series) {
|
|
2917
4979
|
const bars2 = value.bars;
|
|
2918
4980
|
const valueArray = value.toArray();
|
|
2919
|
-
const
|
|
4981
|
+
const length2 = bars2.length;
|
|
2920
4982
|
const result = [];
|
|
2921
|
-
for (let i = 0; i <
|
|
4983
|
+
for (let i = 0; i < length2; i++) {
|
|
4984
|
+
const v = valueArray[i] ?? NaN;
|
|
4985
|
+
result.push(Math.ceil(v));
|
|
4986
|
+
}
|
|
4987
|
+
return Series.fromArray(bars2, result);
|
|
4988
|
+
}
|
|
4989
|
+
return Math.ceil(value);
|
|
4990
|
+
}
|
|
4991
|
+
function floor(value) {
|
|
4992
|
+
if (value instanceof Series) {
|
|
4993
|
+
const bars2 = value.bars;
|
|
4994
|
+
const valueArray = value.toArray();
|
|
4995
|
+
const length2 = bars2.length;
|
|
4996
|
+
const result = [];
|
|
4997
|
+
for (let i = 0; i < length2; i++) {
|
|
2922
4998
|
const v = valueArray[i] ?? NaN;
|
|
2923
4999
|
result.push(Math.floor(v));
|
|
2924
5000
|
}
|
|
@@ -2930,16 +5006,16 @@ function round(value, precision) {
|
|
|
2930
5006
|
if (value instanceof Series) {
|
|
2931
5007
|
const bars2 = value.bars;
|
|
2932
5008
|
const valueArray = value.toArray();
|
|
2933
|
-
const
|
|
5009
|
+
const length2 = bars2.length;
|
|
2934
5010
|
const result = [];
|
|
2935
5011
|
if (precision === void 0) {
|
|
2936
|
-
for (let i = 0; i <
|
|
5012
|
+
for (let i = 0; i < length2; i++) {
|
|
2937
5013
|
const v = valueArray[i] ?? NaN;
|
|
2938
5014
|
result.push(Math.round(v));
|
|
2939
5015
|
}
|
|
2940
5016
|
} else {
|
|
2941
5017
|
const multiplier2 = Math.pow(10, precision);
|
|
2942
|
-
for (let i = 0; i <
|
|
5018
|
+
for (let i = 0; i < length2; i++) {
|
|
2943
5019
|
const v = valueArray[i] ?? NaN;
|
|
2944
5020
|
result.push(Math.round(v * multiplier2) / multiplier2);
|
|
2945
5021
|
}
|
|
@@ -2959,12 +5035,12 @@ function max3(...values) {
|
|
|
2959
5035
|
}
|
|
2960
5036
|
const firstSeries = values.find((v) => v instanceof Series);
|
|
2961
5037
|
const bars2 = firstSeries.bars;
|
|
2962
|
-
const
|
|
5038
|
+
const length2 = bars2.length;
|
|
2963
5039
|
const valueArrays = values.map(
|
|
2964
5040
|
(v) => v instanceof Series ? v.toArray() : null
|
|
2965
5041
|
);
|
|
2966
5042
|
const result = [];
|
|
2967
|
-
for (let i = 0; i <
|
|
5043
|
+
for (let i = 0; i < length2; i++) {
|
|
2968
5044
|
const nums = values.map(
|
|
2969
5045
|
(v, idx) => valueArrays[idx] ? valueArrays[idx][i] ?? NaN : v
|
|
2970
5046
|
);
|
|
@@ -2979,12 +5055,12 @@ function min3(...values) {
|
|
|
2979
5055
|
}
|
|
2980
5056
|
const firstSeries = values.find((v) => v instanceof Series);
|
|
2981
5057
|
const bars2 = firstSeries.bars;
|
|
2982
|
-
const
|
|
5058
|
+
const length2 = bars2.length;
|
|
2983
5059
|
const valueArrays = values.map(
|
|
2984
5060
|
(v) => v instanceof Series ? v.toArray() : null
|
|
2985
5061
|
);
|
|
2986
5062
|
const result = [];
|
|
2987
|
-
for (let i = 0; i <
|
|
5063
|
+
for (let i = 0; i < length2; i++) {
|
|
2988
5064
|
const nums = values.map(
|
|
2989
5065
|
(v, idx) => valueArrays[idx] ? valueArrays[idx][i] ?? NaN : v
|
|
2990
5066
|
);
|
|
@@ -2999,12 +5075,12 @@ function avg(...values) {
|
|
|
2999
5075
|
}
|
|
3000
5076
|
const firstSeries = values.find((v) => v instanceof Series);
|
|
3001
5077
|
const bars2 = firstSeries.bars;
|
|
3002
|
-
const
|
|
5078
|
+
const length2 = bars2.length;
|
|
3003
5079
|
const valueArrays = values.map(
|
|
3004
5080
|
(v) => v instanceof Series ? v.toArray() : null
|
|
3005
5081
|
);
|
|
3006
5082
|
const result = [];
|
|
3007
|
-
for (let i = 0; i <
|
|
5083
|
+
for (let i = 0; i < length2; i++) {
|
|
3008
5084
|
const nums = values.map(
|
|
3009
5085
|
(v, idx) => valueArrays[idx] ? valueArrays[idx][i] ?? NaN : v
|
|
3010
5086
|
);
|
|
@@ -3013,15 +5089,15 @@ function avg(...values) {
|
|
|
3013
5089
|
}
|
|
3014
5090
|
return Series.fromArray(bars2, result);
|
|
3015
5091
|
}
|
|
3016
|
-
function sum(source,
|
|
5092
|
+
function sum(source, length2) {
|
|
3017
5093
|
const sourceArray = source instanceof Series ? source.toArray() : source;
|
|
3018
5094
|
const result = [];
|
|
3019
5095
|
for (let i = 0; i < sourceArray.length; i++) {
|
|
3020
|
-
if (i <
|
|
5096
|
+
if (i < length2 - 1) {
|
|
3021
5097
|
result.push(NaN);
|
|
3022
5098
|
} else {
|
|
3023
5099
|
let total = 0;
|
|
3024
|
-
for (let j = 0; j <
|
|
5100
|
+
for (let j = 0; j < length2; j++) {
|
|
3025
5101
|
total += sourceArray[i - j];
|
|
3026
5102
|
}
|
|
3027
5103
|
result.push(total);
|
|
@@ -3036,9 +5112,9 @@ function sqrt(value) {
|
|
|
3036
5112
|
if (value instanceof Series) {
|
|
3037
5113
|
const bars2 = value.bars;
|
|
3038
5114
|
const valueArray = value.toArray();
|
|
3039
|
-
const
|
|
5115
|
+
const length2 = bars2.length;
|
|
3040
5116
|
const result = [];
|
|
3041
|
-
for (let i = 0; i <
|
|
5117
|
+
for (let i = 0; i < length2; i++) {
|
|
3042
5118
|
const v = valueArray[i] ?? NaN;
|
|
3043
5119
|
result.push(Math.sqrt(v));
|
|
3044
5120
|
}
|
|
@@ -3055,9 +5131,9 @@ function pow(base, exponent) {
|
|
|
3055
5131
|
const bars2 = baseIsSeries ? base.bars : exponent.bars;
|
|
3056
5132
|
const baseArray = baseIsSeries ? base.toArray() : null;
|
|
3057
5133
|
const expArray = expIsSeries ? exponent.toArray() : null;
|
|
3058
|
-
const
|
|
5134
|
+
const length2 = bars2.length;
|
|
3059
5135
|
const result = [];
|
|
3060
|
-
for (let i = 0; i <
|
|
5136
|
+
for (let i = 0; i < length2; i++) {
|
|
3061
5137
|
const b2 = baseArray ? baseArray[i] ?? NaN : base;
|
|
3062
5138
|
const e2 = expArray ? expArray[i] ?? NaN : exponent;
|
|
3063
5139
|
result.push(Math.pow(b2, e2));
|
|
@@ -3068,9 +5144,9 @@ function exp(value) {
|
|
|
3068
5144
|
if (value instanceof Series) {
|
|
3069
5145
|
const bars2 = value.bars;
|
|
3070
5146
|
const valueArray = value.toArray();
|
|
3071
|
-
const
|
|
5147
|
+
const length2 = bars2.length;
|
|
3072
5148
|
const result = [];
|
|
3073
|
-
for (let i = 0; i <
|
|
5149
|
+
for (let i = 0; i < length2; i++) {
|
|
3074
5150
|
const v = valueArray[i] ?? NaN;
|
|
3075
5151
|
result.push(Math.exp(v));
|
|
3076
5152
|
}
|
|
@@ -3082,9 +5158,9 @@ function log(value) {
|
|
|
3082
5158
|
if (value instanceof Series) {
|
|
3083
5159
|
const bars2 = value.bars;
|
|
3084
5160
|
const valueArray = value.toArray();
|
|
3085
|
-
const
|
|
5161
|
+
const length2 = bars2.length;
|
|
3086
5162
|
const result = [];
|
|
3087
|
-
for (let i = 0; i <
|
|
5163
|
+
for (let i = 0; i < length2; i++) {
|
|
3088
5164
|
const v = valueArray[i] ?? NaN;
|
|
3089
5165
|
result.push(Math.log(v));
|
|
3090
5166
|
}
|
|
@@ -3096,9 +5172,9 @@ function log10(value) {
|
|
|
3096
5172
|
if (value instanceof Series) {
|
|
3097
5173
|
const bars2 = value.bars;
|
|
3098
5174
|
const valueArray = value.toArray();
|
|
3099
|
-
const
|
|
5175
|
+
const length2 = bars2.length;
|
|
3100
5176
|
const result = [];
|
|
3101
|
-
for (let i = 0; i <
|
|
5177
|
+
for (let i = 0; i < length2; i++) {
|
|
3102
5178
|
const v = valueArray[i] ?? NaN;
|
|
3103
5179
|
result.push(Math.log10(v));
|
|
3104
5180
|
}
|
|
@@ -3110,9 +5186,9 @@ function sin(value) {
|
|
|
3110
5186
|
if (value instanceof Series) {
|
|
3111
5187
|
const bars2 = value.bars;
|
|
3112
5188
|
const valueArray = value.toArray();
|
|
3113
|
-
const
|
|
5189
|
+
const length2 = bars2.length;
|
|
3114
5190
|
const result = [];
|
|
3115
|
-
for (let i = 0; i <
|
|
5191
|
+
for (let i = 0; i < length2; i++) {
|
|
3116
5192
|
const v = valueArray[i] ?? NaN;
|
|
3117
5193
|
result.push(Math.sin(v));
|
|
3118
5194
|
}
|
|
@@ -3124,9 +5200,9 @@ function cos(value) {
|
|
|
3124
5200
|
if (value instanceof Series) {
|
|
3125
5201
|
const bars2 = value.bars;
|
|
3126
5202
|
const valueArray = value.toArray();
|
|
3127
|
-
const
|
|
5203
|
+
const length2 = bars2.length;
|
|
3128
5204
|
const result = [];
|
|
3129
|
-
for (let i = 0; i <
|
|
5205
|
+
for (let i = 0; i < length2; i++) {
|
|
3130
5206
|
const v = valueArray[i] ?? NaN;
|
|
3131
5207
|
result.push(Math.cos(v));
|
|
3132
5208
|
}
|
|
@@ -3138,9 +5214,9 @@ function tan(value) {
|
|
|
3138
5214
|
if (value instanceof Series) {
|
|
3139
5215
|
const bars2 = value.bars;
|
|
3140
5216
|
const valueArray = value.toArray();
|
|
3141
|
-
const
|
|
5217
|
+
const length2 = bars2.length;
|
|
3142
5218
|
const result = [];
|
|
3143
|
-
for (let i = 0; i <
|
|
5219
|
+
for (let i = 0; i < length2; i++) {
|
|
3144
5220
|
const v = valueArray[i] ?? NaN;
|
|
3145
5221
|
result.push(Math.tan(v));
|
|
3146
5222
|
}
|
|
@@ -3152,9 +5228,9 @@ function asin(value) {
|
|
|
3152
5228
|
if (value instanceof Series) {
|
|
3153
5229
|
const bars2 = value.bars;
|
|
3154
5230
|
const valueArray = value.toArray();
|
|
3155
|
-
const
|
|
5231
|
+
const length2 = bars2.length;
|
|
3156
5232
|
const result = [];
|
|
3157
|
-
for (let i = 0; i <
|
|
5233
|
+
for (let i = 0; i < length2; i++) {
|
|
3158
5234
|
const v = valueArray[i] ?? NaN;
|
|
3159
5235
|
result.push(Math.asin(v));
|
|
3160
5236
|
}
|
|
@@ -3166,9 +5242,9 @@ function acos(value) {
|
|
|
3166
5242
|
if (value instanceof Series) {
|
|
3167
5243
|
const bars2 = value.bars;
|
|
3168
5244
|
const valueArray = value.toArray();
|
|
3169
|
-
const
|
|
5245
|
+
const length2 = bars2.length;
|
|
3170
5246
|
const result = [];
|
|
3171
|
-
for (let i = 0; i <
|
|
5247
|
+
for (let i = 0; i < length2; i++) {
|
|
3172
5248
|
const v = valueArray[i] ?? NaN;
|
|
3173
5249
|
result.push(Math.acos(v));
|
|
3174
5250
|
}
|
|
@@ -3180,9 +5256,9 @@ function atan(value) {
|
|
|
3180
5256
|
if (value instanceof Series) {
|
|
3181
5257
|
const bars2 = value.bars;
|
|
3182
5258
|
const valueArray = value.toArray();
|
|
3183
|
-
const
|
|
5259
|
+
const length2 = bars2.length;
|
|
3184
5260
|
const result = [];
|
|
3185
|
-
for (let i = 0; i <
|
|
5261
|
+
for (let i = 0; i < length2; i++) {
|
|
3186
5262
|
const v = valueArray[i] ?? NaN;
|
|
3187
5263
|
result.push(Math.atan(v));
|
|
3188
5264
|
}
|
|
@@ -3194,9 +5270,9 @@ function toradians(degrees) {
|
|
|
3194
5270
|
if (degrees instanceof Series) {
|
|
3195
5271
|
const bars2 = degrees.bars;
|
|
3196
5272
|
const valueArray = degrees.toArray();
|
|
3197
|
-
const
|
|
5273
|
+
const length2 = bars2.length;
|
|
3198
5274
|
const result = [];
|
|
3199
|
-
for (let i = 0; i <
|
|
5275
|
+
for (let i = 0; i < length2; i++) {
|
|
3200
5276
|
const v = valueArray[i] ?? NaN;
|
|
3201
5277
|
result.push(v * (Math.PI / 180));
|
|
3202
5278
|
}
|
|
@@ -3208,9 +5284,9 @@ function todegrees(radians) {
|
|
|
3208
5284
|
if (radians instanceof Series) {
|
|
3209
5285
|
const bars2 = radians.bars;
|
|
3210
5286
|
const valueArray = radians.toArray();
|
|
3211
|
-
const
|
|
5287
|
+
const length2 = bars2.length;
|
|
3212
5288
|
const result = [];
|
|
3213
|
-
for (let i = 0; i <
|
|
5289
|
+
for (let i = 0; i < length2; i++) {
|
|
3214
5290
|
const v = valueArray[i] ?? NaN;
|
|
3215
5291
|
result.push(v * (180 / Math.PI));
|
|
3216
5292
|
}
|
|
@@ -3229,9 +5305,9 @@ function sign(value) {
|
|
|
3229
5305
|
if (value instanceof Series) {
|
|
3230
5306
|
const bars2 = value.bars;
|
|
3231
5307
|
const valueArray = value.toArray();
|
|
3232
|
-
const
|
|
5308
|
+
const length2 = bars2.length;
|
|
3233
5309
|
const result = [];
|
|
3234
|
-
for (let i = 0; i <
|
|
5310
|
+
for (let i = 0; i < length2; i++) {
|
|
3235
5311
|
const v = valueArray[i] ?? NaN;
|
|
3236
5312
|
result.push(v > 0 ? 1 : v < 0 ? -1 : 0);
|
|
3237
5313
|
}
|
|
@@ -3239,11 +5315,11 @@ function sign(value) {
|
|
|
3239
5315
|
}
|
|
3240
5316
|
return value > 0 ? 1 : value < 0 ? -1 : 0;
|
|
3241
5317
|
}
|
|
3242
|
-
function round_to_mintick(
|
|
3243
|
-
if (
|
|
3244
|
-
const bars2 =
|
|
3245
|
-
const valueArray =
|
|
3246
|
-
const
|
|
5318
|
+
function round_to_mintick(number2, mintick) {
|
|
5319
|
+
if (number2 instanceof Series) {
|
|
5320
|
+
const bars2 = number2.bars;
|
|
5321
|
+
const valueArray = number2.toArray();
|
|
5322
|
+
const length2 = bars2.length;
|
|
3247
5323
|
if (mintick === void 0) {
|
|
3248
5324
|
throw new Error(
|
|
3249
5325
|
"math.round_to_mintick() requires mintick value. Either pass it explicitly or use createContext({ syminfo: { mintick } }) for implicit data."
|
|
@@ -3251,11 +5327,11 @@ function round_to_mintick(number, mintick) {
|
|
|
3251
5327
|
}
|
|
3252
5328
|
const result = [];
|
|
3253
5329
|
if (mintick === 0) {
|
|
3254
|
-
for (let i = 0; i <
|
|
5330
|
+
for (let i = 0; i < length2; i++) {
|
|
3255
5331
|
result.push(valueArray[i] ?? NaN);
|
|
3256
5332
|
}
|
|
3257
5333
|
} else {
|
|
3258
|
-
for (let i = 0; i <
|
|
5334
|
+
for (let i = 0; i < length2; i++) {
|
|
3259
5335
|
const v = valueArray[i];
|
|
3260
5336
|
if (v === void 0 || isNaN(v)) {
|
|
3261
5337
|
result.push(NaN);
|
|
@@ -3266,7 +5342,7 @@ function round_to_mintick(number, mintick) {
|
|
|
3266
5342
|
}
|
|
3267
5343
|
return Series.fromArray(bars2, result);
|
|
3268
5344
|
}
|
|
3269
|
-
if (isNaN(
|
|
5345
|
+
if (isNaN(number2)) {
|
|
3270
5346
|
return NaN;
|
|
3271
5347
|
}
|
|
3272
5348
|
if (mintick === void 0) {
|
|
@@ -3275,9 +5351,9 @@ function round_to_mintick(number, mintick) {
|
|
|
3275
5351
|
);
|
|
3276
5352
|
}
|
|
3277
5353
|
if (mintick === 0) {
|
|
3278
|
-
return
|
|
5354
|
+
return number2;
|
|
3279
5355
|
}
|
|
3280
|
-
return Math.round(
|
|
5356
|
+
return Math.round(number2 / mintick) * mintick;
|
|
3281
5357
|
}
|
|
3282
5358
|
var pi = Math.PI;
|
|
3283
5359
|
var e = Math.E;
|
|
@@ -3324,9 +5400,11 @@ function slugId(title, fallback, taken) {
|
|
|
3324
5400
|
taken.add(id);
|
|
3325
5401
|
return id;
|
|
3326
5402
|
}
|
|
3327
|
-
function executeScript(body, barsInput, inputs = {}) {
|
|
5403
|
+
function executeScript(body, barsInput, inputs = {}, chart2 = {}) {
|
|
3328
5404
|
ctxBars.setAll(barsInput);
|
|
5405
|
+
chartCtx = { ...chart2 };
|
|
3329
5406
|
ctx = freshCollector(inputs);
|
|
5407
|
+
resetDrawings();
|
|
3330
5408
|
try {
|
|
3331
5409
|
body();
|
|
3332
5410
|
const c = ctx;
|
|
@@ -3367,6 +5445,12 @@ function indicator(title, options = {}) {
|
|
|
3367
5445
|
c.overlay = options.overlay ?? true;
|
|
3368
5446
|
c.precision = options.precision;
|
|
3369
5447
|
c.format = options.format;
|
|
5448
|
+
setDrawingLimits({
|
|
5449
|
+
line: options.max_lines_count,
|
|
5450
|
+
label: options.max_labels_count,
|
|
5451
|
+
box: options.max_boxes_count,
|
|
5452
|
+
polyline: options.max_polylines_count
|
|
5453
|
+
});
|
|
3370
5454
|
}
|
|
3371
5455
|
function registerInput(config, fallbackId) {
|
|
3372
5456
|
const c = collector();
|
|
@@ -3403,6 +5487,19 @@ var input = {
|
|
|
3403
5487
|
source(defval = "close", title) {
|
|
3404
5488
|
const name = registerInput({ type: "source", defval, title }, "input_source");
|
|
3405
5489
|
return sourceSeries(name);
|
|
5490
|
+
},
|
|
5491
|
+
/** Timeframe string ("60", "1D", "W"). As in PineScript, "" means the chart timeframe. */
|
|
5492
|
+
timeframe(defval, title, opts = {}) {
|
|
5493
|
+
return registerInput({ type: "timeframe", defval, title, options: opts.options }, "input_timeframe");
|
|
5494
|
+
},
|
|
5495
|
+
/** Session string ("0930-1600", "0930-1600:23456"). */
|
|
5496
|
+
session(defval, title, opts = {}) {
|
|
5497
|
+
return registerInput({ type: "session", defval, title, options: opts.options }, "input_session");
|
|
5498
|
+
},
|
|
5499
|
+
/** Date and time as a UNIX time in milliseconds, e.g. `input.time(timestamp('2024-01-01'), 'Start')`. */
|
|
5500
|
+
time(defval, title) {
|
|
5501
|
+
const v = registerInput({ type: "time", defval, title }, "input_time");
|
|
5502
|
+
return typeof v === "number" ? v : defval;
|
|
3406
5503
|
}
|
|
3407
5504
|
};
|
|
3408
5505
|
var open = Series.fromBars(ctxBars, "open");
|
|
@@ -3419,18 +5516,60 @@ function sourceSeries(name) {
|
|
|
3419
5516
|
return SOURCES[name] ?? close;
|
|
3420
5517
|
}
|
|
3421
5518
|
var bars = () => ctxBars.bars;
|
|
5519
|
+
function barsSeries(compute) {
|
|
5520
|
+
let version = -1;
|
|
5521
|
+
let values = [];
|
|
5522
|
+
return new Series(ctxBars, (_bar, i, data) => {
|
|
5523
|
+
if (version !== ctxBars.version) {
|
|
5524
|
+
values = compute(data).toArray();
|
|
5525
|
+
version = ctxBars.version;
|
|
5526
|
+
}
|
|
5527
|
+
return values[i] ?? NaN;
|
|
5528
|
+
});
|
|
5529
|
+
}
|
|
3422
5530
|
var ta2 = {
|
|
3423
5531
|
...ta_series_exports,
|
|
3424
5532
|
tr: (handleNa = false) => tr2(bars(), handleNa),
|
|
3425
|
-
atr: (
|
|
5533
|
+
atr: (length2) => atr2(bars(), length2),
|
|
3426
5534
|
sar: (start, inc, max4) => sar2(bars(), start, inc, max4),
|
|
3427
|
-
wpr: (
|
|
5535
|
+
wpr: (length2) => wpr2(bars(), length2),
|
|
3428
5536
|
supertrend: (factor, atrLength) => supertrend2(bars(), factor, atrLength),
|
|
3429
5537
|
dmi: (diLength, adxSmoothing) => dmi2(bars(), diLength, adxSmoothing),
|
|
3430
|
-
kc: (source,
|
|
3431
|
-
kcw: (source,
|
|
3432
|
-
ichimoku: (conversionPeriods, basePeriods, laggingSpan2Periods, displacement) => ichimoku2(bars(), conversionPeriods, basePeriods, laggingSpan2Periods, displacement)
|
|
5538
|
+
kc: (source, length2, mult, useTrueRange) => kc2(bars(), source, length2, mult, useTrueRange),
|
|
5539
|
+
kcw: (source, length2, mult, useTrueRange) => kcw2(bars(), source, length2, mult, useTrueRange),
|
|
5540
|
+
ichimoku: (conversionPeriods, basePeriods, laggingSpan2Periods, displacement) => ichimoku2(bars(), conversionPeriods, basePeriods, laggingSpan2Periods, displacement),
|
|
5541
|
+
/** `ta.highest(source, length)` or `ta.highest(length)` (source = high). */
|
|
5542
|
+
highest: (sourceOrLength, length2) => typeof sourceOrLength === "number" ? highest2(high, sourceOrLength) : highest2(sourceOrLength, length2),
|
|
5543
|
+
/** `ta.lowest(source, length)` or `ta.lowest(length)` (source = low). */
|
|
5544
|
+
lowest: (sourceOrLength, length2) => typeof sourceOrLength === "number" ? lowest2(low, sourceOrLength) : lowest2(sourceOrLength, length2),
|
|
5545
|
+
/** `ta.highestbars(source, length)` or `ta.highestbars(length)` (source = high); offsets are 0 or negative. */
|
|
5546
|
+
highestbars: (sourceOrLength, length2) => typeof sourceOrLength === "number" ? highestbars2(high, sourceOrLength) : highestbars2(sourceOrLength, length2),
|
|
5547
|
+
/** `ta.lowestbars(source, length)` or `ta.lowestbars(length)` (source = low); offsets are 0 or negative. */
|
|
5548
|
+
lowestbars: (sourceOrLength, length2) => typeof sourceOrLength === "number" ? lowestbars2(low, sourceOrLength) : lowestbars2(sourceOrLength, length2),
|
|
5549
|
+
/** `ta.vwap(source, anchor?, stdev_mult?)` with the chart volume; the default anchor is a new trading
|
|
5550
|
+
* day (`timeframe.change("1D")`), which needs the chart context (timeframe, time zone, session). */
|
|
5551
|
+
vwap: ((source, anchor, stdev_mult) => {
|
|
5552
|
+
const a = anchor ?? changeOf("1D");
|
|
5553
|
+
return stdev_mult === void 0 ? vwap2(source, volume, a) : vwapBands(source, volume, a, stdev_mult);
|
|
5554
|
+
}),
|
|
5555
|
+
/** `ta.pivothigh(source, leftbars, rightbars)` or `ta.pivothigh(leftbars, rightbars)` (source = high).
|
|
5556
|
+
* The value appears `rightbars` bars after the pivot bar, as in PineScript. */
|
|
5557
|
+
pivothigh: (sourceOrLeft, leftOrRight, rightbars) => typeof sourceOrLeft === "number" ? pivothigh2(high, sourceOrLeft, leftOrRight) : pivothigh2(sourceOrLeft, leftOrRight, rightbars),
|
|
5558
|
+
/** `ta.pivotlow(source, leftbars, rightbars)` or `ta.pivotlow(leftbars, rightbars)` (source = low). */
|
|
5559
|
+
pivotlow: (sourceOrLeft, leftOrRight, rightbars) => typeof sourceOrLeft === "number" ? pivotlow2(low, sourceOrLeft, leftOrRight) : pivotlow2(sourceOrLeft, leftOrRight, rightbars),
|
|
5560
|
+
// PineScript variables of the chart bars: `ta.obv`, not `ta.obv()`.
|
|
5561
|
+
obv: barsSeries(obv2),
|
|
5562
|
+
pvt: barsSeries(pvt2),
|
|
5563
|
+
accdist: barsSeries(accdist2),
|
|
5564
|
+
nvi: barsSeries(nvi2),
|
|
5565
|
+
pvi: barsSeries(pvi2),
|
|
5566
|
+
iii: barsSeries(iii2),
|
|
5567
|
+
wad: barsSeries(wad2),
|
|
5568
|
+
wvad: barsSeries(wvad2)
|
|
3433
5569
|
};
|
|
5570
|
+
function fixnan2(source) {
|
|
5571
|
+
return source instanceof Series ? Series.fromArray(ctxBars, fixnan(source.toArray())) : fixnan(source);
|
|
5572
|
+
}
|
|
3434
5573
|
function colorWhen(cond, colorTrue, colorFalse) {
|
|
3435
5574
|
return cond.toArray().map((v) => !isNA(v) && v !== 0 ? colorTrue : colorFalse);
|
|
3436
5575
|
}
|
|
@@ -3442,8 +5581,8 @@ var color = {
|
|
|
3442
5581
|
function plot(series, title, options = {}) {
|
|
3443
5582
|
const c = collector();
|
|
3444
5583
|
const id = `plot${c.plotConfig.length}`;
|
|
3445
|
-
const
|
|
3446
|
-
const staticColor = typeof options.color === "string" ? options.color :
|
|
5584
|
+
const perBar2 = Array.isArray(options.color) ? options.color : void 0;
|
|
5585
|
+
const staticColor = typeof options.color === "string" ? options.color : perBar2?.[perBar2.length - 1] ?? "#2962FF";
|
|
3447
5586
|
c.plotConfig.push({
|
|
3448
5587
|
id,
|
|
3449
5588
|
title: title ?? id,
|
|
@@ -3459,7 +5598,7 @@ function plot(series, title, options = {}) {
|
|
|
3459
5598
|
for (let i = 0; i < b2.length; i++) {
|
|
3460
5599
|
const value = values[i];
|
|
3461
5600
|
if (value === void 0 || Number.isNaN(value)) continue;
|
|
3462
|
-
data.push(
|
|
5601
|
+
data.push(perBar2 ? { time: b2[i].time, value, color: perBar2[i] } : { time: b2[i].time, value });
|
|
3463
5602
|
}
|
|
3464
5603
|
c.plots[id] = data;
|
|
3465
5604
|
return { id, kind: "plot" };
|
|
@@ -3479,7 +5618,7 @@ function hline(price, title, options = {}) {
|
|
|
3479
5618
|
}
|
|
3480
5619
|
function fill(a, b2, options = {}) {
|
|
3481
5620
|
const c = collector();
|
|
3482
|
-
const
|
|
5621
|
+
const perBar2 = Array.isArray(options.color) ? options.color : void 0;
|
|
3483
5622
|
const staticColor = typeof options.color === "string" ? options.color : void 0;
|
|
3484
5623
|
if (a.kind === "hline" && b2.kind === "hline") {
|
|
3485
5624
|
c.fillConfig.push({
|
|
@@ -3487,7 +5626,7 @@ function fill(a, b2, options = {}) {
|
|
|
3487
5626
|
plot1: a.id,
|
|
3488
5627
|
plot2: b2.id,
|
|
3489
5628
|
color: staticColor,
|
|
3490
|
-
colors:
|
|
5629
|
+
colors: perBar2,
|
|
3491
5630
|
title: options.title
|
|
3492
5631
|
});
|
|
3493
5632
|
return;
|
|
@@ -3496,7 +5635,7 @@ function fill(a, b2, options = {}) {
|
|
|
3496
5635
|
plot1: a.id,
|
|
3497
5636
|
plot2: b2.id,
|
|
3498
5637
|
options: { color: staticColor, title: options.title },
|
|
3499
|
-
colors:
|
|
5638
|
+
colors: perBar2
|
|
3500
5639
|
});
|
|
3501
5640
|
}
|
|
3502
5641
|
function emitMarkers(kind, condition, title, options) {
|
|
@@ -3555,11 +5694,11 @@ function emitBarColors(kind, colors, options) {
|
|
|
3555
5694
|
const off = options.offset ?? 0;
|
|
3556
5695
|
const target = kind === "bgcolor" ? c.bgcolors : c.barcolors;
|
|
3557
5696
|
for (let i = 0; i < b2.length; i++) {
|
|
3558
|
-
const
|
|
3559
|
-
if (!
|
|
5697
|
+
const col2 = typeof colors === "string" ? colors : colors[i];
|
|
5698
|
+
if (!col2) continue;
|
|
3560
5699
|
const j = i + off;
|
|
3561
5700
|
if (j < 0 || j >= b2.length) continue;
|
|
3562
|
-
target.push({ time: b2[j].time, color:
|
|
5701
|
+
target.push({ time: b2[j].time, color: col2 });
|
|
3563
5702
|
}
|
|
3564
5703
|
}
|
|
3565
5704
|
function bgcolor(colors, options = {}) {
|
|
@@ -3611,12 +5750,335 @@ function eachBar(fn) {
|
|
|
3611
5750
|
return j >= 0 ? out[j] : NaN;
|
|
3612
5751
|
}
|
|
3613
5752
|
};
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
5753
|
+
try {
|
|
5754
|
+
for (idx = 0; idx < b2.length; idx++) {
|
|
5755
|
+
currentBar = idx;
|
|
5756
|
+
const r2 = fn(ctx2);
|
|
5757
|
+
out[idx] = typeof r2 === "number" ? r2 : typeof r2 === "boolean" ? r2 ? 1 : 0 : NaN;
|
|
5758
|
+
}
|
|
5759
|
+
} finally {
|
|
5760
|
+
currentBar = -1;
|
|
3617
5761
|
}
|
|
3618
5762
|
return Series.fromArray(ctxBars, out);
|
|
3619
5763
|
}
|
|
5764
|
+
var currentBar = -1;
|
|
5765
|
+
var chartCtx = {};
|
|
5766
|
+
function chartTimeframe() {
|
|
5767
|
+
collector();
|
|
5768
|
+
if (!chartCtx.timeframe) {
|
|
5769
|
+
throw new Error("The chart timeframe is not known: pass it as executeScript(body, bars, inputs, { timeframe }).");
|
|
5770
|
+
}
|
|
5771
|
+
return info(chartCtx.timeframe);
|
|
5772
|
+
}
|
|
5773
|
+
function exchangeTimezone() {
|
|
5774
|
+
collector();
|
|
5775
|
+
if (!chartCtx.timezone) {
|
|
5776
|
+
throw new Error("The exchange time zone is not known: pass it as executeScript(body, bars, inputs, { timezone }).");
|
|
5777
|
+
}
|
|
5778
|
+
return chartCtx.timezone;
|
|
5779
|
+
}
|
|
5780
|
+
var timeframe = {
|
|
5781
|
+
...timeframe_exports,
|
|
5782
|
+
get period() {
|
|
5783
|
+
return chartTimeframe().period;
|
|
5784
|
+
},
|
|
5785
|
+
get main_period() {
|
|
5786
|
+
return chartTimeframe().period;
|
|
5787
|
+
},
|
|
5788
|
+
get multiplier() {
|
|
5789
|
+
return chartTimeframe().multiplier;
|
|
5790
|
+
},
|
|
5791
|
+
get isintraday() {
|
|
5792
|
+
return chartTimeframe().isintraday;
|
|
5793
|
+
},
|
|
5794
|
+
get isdaily() {
|
|
5795
|
+
return chartTimeframe().isdaily;
|
|
5796
|
+
},
|
|
5797
|
+
get isweekly() {
|
|
5798
|
+
return chartTimeframe().isweekly;
|
|
5799
|
+
},
|
|
5800
|
+
get ismonthly() {
|
|
5801
|
+
return chartTimeframe().ismonthly;
|
|
5802
|
+
},
|
|
5803
|
+
get isminutes() {
|
|
5804
|
+
return chartTimeframe().isminutes;
|
|
5805
|
+
},
|
|
5806
|
+
get isseconds() {
|
|
5807
|
+
return chartTimeframe().isseconds;
|
|
5808
|
+
},
|
|
5809
|
+
get isticks() {
|
|
5810
|
+
return chartTimeframe().isticks;
|
|
5811
|
+
},
|
|
5812
|
+
get isdwm() {
|
|
5813
|
+
return chartTimeframe().isdwm;
|
|
5814
|
+
},
|
|
5815
|
+
/** PineScript `timeframe.change(tf)`: 1 on bars that open a new `tf` period (0 on the first bar). */
|
|
5816
|
+
change(tf) {
|
|
5817
|
+
return changeOf(tf || chartTimeframe().period);
|
|
5818
|
+
},
|
|
5819
|
+
/** Seconds in `timeframe`; without it (or with "") the chart timeframe, as in PineScript. */
|
|
5820
|
+
in_seconds(tf) {
|
|
5821
|
+
return in_seconds(tf === void 0 || tf === "" ? chartTimeframe().period : tf);
|
|
5822
|
+
}
|
|
5823
|
+
};
|
|
5824
|
+
var syminfo = {
|
|
5825
|
+
get timezone() {
|
|
5826
|
+
return exchangeTimezone();
|
|
5827
|
+
},
|
|
5828
|
+
get tickerid() {
|
|
5829
|
+
collector();
|
|
5830
|
+
if (!chartCtx.tickerid) {
|
|
5831
|
+
throw new Error("The chart symbol is not known: pass it as executeScript(body, bars, inputs, { tickerid }).");
|
|
5832
|
+
}
|
|
5833
|
+
return chartCtx.tickerid;
|
|
5834
|
+
},
|
|
5835
|
+
get session() {
|
|
5836
|
+
collector();
|
|
5837
|
+
return chartCtx.sessionType ?? "regular";
|
|
5838
|
+
}
|
|
5839
|
+
};
|
|
5840
|
+
function calendar(fn) {
|
|
5841
|
+
return ((time2, timezone) => {
|
|
5842
|
+
const tz = timezone ?? exchangeTimezone();
|
|
5843
|
+
return time2 instanceof Series ? Series.fromArray(ctxBars, time2.toArray().map((t2) => fn(t2, tz))) : fn(time2, tz);
|
|
5844
|
+
});
|
|
5845
|
+
}
|
|
5846
|
+
var year2 = calendar(year);
|
|
5847
|
+
var month2 = calendar(month);
|
|
5848
|
+
var weekofyear2 = calendar(weekofyear);
|
|
5849
|
+
var dayofmonth2 = calendar(dayofmonth);
|
|
5850
|
+
var dayofweek2 = calendar(dayofweek);
|
|
5851
|
+
var hour2 = calendar(hour);
|
|
5852
|
+
var minute2 = calendar(minute);
|
|
5853
|
+
var second2 = calendar(second);
|
|
5854
|
+
function timestamp2(first, ...rest) {
|
|
5855
|
+
if (typeof first === "number") {
|
|
5856
|
+
const [m2, d2, h2, mi2, s2] = rest;
|
|
5857
|
+
return timestamp(exchangeTimezone(), first, m2, d2, h2, mi2, s2);
|
|
5858
|
+
}
|
|
5859
|
+
if (rest.length === 0) return timestamp(first);
|
|
5860
|
+
const [y, m, d, h, mi, s] = rest;
|
|
5861
|
+
return timestamp(first, y, m, d, h, mi, s);
|
|
5862
|
+
}
|
|
5863
|
+
function inSession3(time2, session2, timezone) {
|
|
5864
|
+
return inSession2(time2, session2, timezone ?? exchangeTimezone());
|
|
5865
|
+
}
|
|
5866
|
+
var str = {
|
|
5867
|
+
...str_exports,
|
|
5868
|
+
format_time(time2, format2 = "yyyy-MM-dd'T'HH:mm:ssZ", timezone) {
|
|
5869
|
+
return format_time(time2, format2, timezone ?? exchangeTimezone());
|
|
5870
|
+
},
|
|
5871
|
+
format(pattern, ...args) {
|
|
5872
|
+
return formatMessage(pattern, args, exchangeTimezone);
|
|
5873
|
+
}
|
|
5874
|
+
};
|
|
5875
|
+
function barTime(bar) {
|
|
5876
|
+
return bar.time * (chartCtx.timeUnit === "ms" ? 1 : 1e3);
|
|
5877
|
+
}
|
|
5878
|
+
var toSpec = (s) => typeof s === "string" ? { session: s } : s;
|
|
5879
|
+
var sessionCache = null;
|
|
5880
|
+
function sessionBars() {
|
|
5881
|
+
const tz = exchangeTimezone();
|
|
5882
|
+
const tf = chartTimeframe().period;
|
|
5883
|
+
if (!chartCtx.session) {
|
|
5884
|
+
throw new Error("The session is not known: pass it as executeScript(body, bars, inputs, { session }).");
|
|
5885
|
+
}
|
|
5886
|
+
if (sessionCache?.ctx !== chartCtx) {
|
|
5887
|
+
const loaded = toSpec(chartCtx.session);
|
|
5888
|
+
const regular = chartCtx.regularSession ? toSpec(chartCtx.regularSession) : loaded;
|
|
5889
|
+
sessionCache = {
|
|
5890
|
+
ctx: chartCtx,
|
|
5891
|
+
bars: new SessionBars(new TradingCalendar(tz, loaded), tf),
|
|
5892
|
+
regular: new SessionBars(new TradingCalendar(tz, { holidays: loaded.holidays, ...regular }), tf)
|
|
5893
|
+
};
|
|
5894
|
+
}
|
|
5895
|
+
return sessionCache;
|
|
5896
|
+
}
|
|
5897
|
+
function calendarFor(session2, timezone) {
|
|
5898
|
+
const { bars: bars2 } = sessionBars();
|
|
5899
|
+
if (!session2 && !timezone) return { bars: bars2, test: false };
|
|
5900
|
+
const tz = timezone ?? exchangeTimezone();
|
|
5901
|
+
const spec = session2 ? { session: session2 } : { session: toSpec(chartCtx.session).session };
|
|
5902
|
+
return { bars: new SessionBars(new TradingCalendar(tz, spec, session2 ? "pine" : "symbol"), bars2.chart.period), test: true };
|
|
5903
|
+
}
|
|
5904
|
+
function perBar(fn) {
|
|
5905
|
+
const times = ctxBars.bars.map(barTime);
|
|
5906
|
+
return Series.fromArray(ctxBars, times.map((t2, i) => fn(t2, i, times)));
|
|
5907
|
+
}
|
|
5908
|
+
function callableSeries(series, fn) {
|
|
5909
|
+
Object.setPrototypeOf(fn, Series.prototype);
|
|
5910
|
+
Object.assign(fn, series);
|
|
5911
|
+
return fn;
|
|
5912
|
+
}
|
|
5913
|
+
function timeFunction(tf, session2, timezone) {
|
|
5914
|
+
collector();
|
|
5915
|
+
const { bars: bars2, test } = calendarFor(session2, timezone);
|
|
5916
|
+
const timeframeString = tf || chartTimeframe().period;
|
|
5917
|
+
return perBar((t2) => test && !bars2.inside(t2) ? NaN : bars2.timeOf(t2, timeframeString));
|
|
5918
|
+
}
|
|
5919
|
+
function timeCloseFunction(tf, session2, timezone) {
|
|
5920
|
+
collector();
|
|
5921
|
+
const { bars: bars2, test } = calendarFor(session2, timezone);
|
|
5922
|
+
const timeframeString = tf || chartTimeframe().period;
|
|
5923
|
+
return perBar((t2) => test && !bars2.inside(t2) ? NaN : bars2.closeOf(t2, timeframeString));
|
|
5924
|
+
}
|
|
5925
|
+
var time = callableSeries(new Series(ctxBars, (b2) => barTime(b2)), timeFunction);
|
|
5926
|
+
var time_close = callableSeries(
|
|
5927
|
+
new Series(ctxBars, (_b, i) => sessionBars().bars.closeOf(barTime(ctxBars.bars[i]), chartTimeframe().period)),
|
|
5928
|
+
timeCloseFunction
|
|
5929
|
+
);
|
|
5930
|
+
var time_tradingday = new Series(ctxBars, (b2) => sessionBars().bars.tradingDayTime(barTime(b2)));
|
|
5931
|
+
function changeOf(tf) {
|
|
5932
|
+
const { bars: bars2 } = sessionBars();
|
|
5933
|
+
return perBar((t2, i, times) => i > 0 && bars2.timeOf(t2, tf) !== bars2.timeOf(times[i - 1], tf) ? 1 : 0);
|
|
5934
|
+
}
|
|
5935
|
+
function flag(key) {
|
|
5936
|
+
const { bars: bars2, regular } = sessionBars();
|
|
5937
|
+
const values = sessionFlags(ctxBars.bars.map(barTime), bars2, regular)[key];
|
|
5938
|
+
return Series.fromArray(ctxBars, values.map((v) => v ? 1 : 0));
|
|
5939
|
+
}
|
|
5940
|
+
var session = {
|
|
5941
|
+
regular: "regular",
|
|
5942
|
+
extended: "extended",
|
|
5943
|
+
get isfirstbar() {
|
|
5944
|
+
return flag("isfirstbar");
|
|
5945
|
+
},
|
|
5946
|
+
get islastbar() {
|
|
5947
|
+
return flag("islastbar");
|
|
5948
|
+
},
|
|
5949
|
+
get ismarket() {
|
|
5950
|
+
return flag("ismarket");
|
|
5951
|
+
},
|
|
5952
|
+
get ispremarket() {
|
|
5953
|
+
return flag("ispremarket");
|
|
5954
|
+
},
|
|
5955
|
+
get ispostmarket() {
|
|
5956
|
+
return flag("ispostmarket");
|
|
5957
|
+
},
|
|
5958
|
+
get isfirstbar_regular() {
|
|
5959
|
+
return flag("isfirstbar_regular");
|
|
5960
|
+
},
|
|
5961
|
+
get islastbar_regular() {
|
|
5962
|
+
return flag("islastbar_regular");
|
|
5963
|
+
}
|
|
5964
|
+
};
|
|
5965
|
+
var barmerge = {
|
|
5966
|
+
gaps_on: "gaps_on",
|
|
5967
|
+
gaps_off: "gaps_off",
|
|
5968
|
+
lookahead_on: "lookahead_on",
|
|
5969
|
+
lookahead_off: "lookahead_off"
|
|
5970
|
+
};
|
|
5971
|
+
var HEIKIN_ASHI = "heikinashi:";
|
|
5972
|
+
var ticker = {
|
|
5973
|
+
heikinashi(symbol) {
|
|
5974
|
+
return HEIKIN_ASHI + symbol;
|
|
5975
|
+
},
|
|
5976
|
+
standard(symbol) {
|
|
5977
|
+
return symbol.startsWith(HEIKIN_ASHI) ? symbol.slice(HEIKIN_ASHI.length) : symbol;
|
|
5978
|
+
}
|
|
5979
|
+
};
|
|
5980
|
+
function valuesOf(value, length2) {
|
|
5981
|
+
return value instanceof Series ? value.toArray().slice() : new Array(length2).fill(Number(value));
|
|
5982
|
+
}
|
|
5983
|
+
function security(symbol, timeframe2, expression, gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_off) {
|
|
5984
|
+
collector();
|
|
5985
|
+
const heikin = symbol.startsWith(HEIKIN_ASHI);
|
|
5986
|
+
const base = heikin ? symbol.slice(HEIKIN_ASHI.length) : symbol;
|
|
5987
|
+
if (base !== "" && base !== chartCtx.tickerid) {
|
|
5988
|
+
throw new Error(`request.security: "${symbol}" is not the chart symbol; other symbols need external data.`);
|
|
5989
|
+
}
|
|
5990
|
+
const chart2 = chartTimeframe();
|
|
5991
|
+
const tf = info(timeframe2 || chart2.period).period;
|
|
5992
|
+
if (in_seconds(tf) < in_seconds(chart2.period)) {
|
|
5993
|
+
throw new Error(`request.security: timeframe "${tf}" is lower than the chart timeframe "${chart2.period}".`);
|
|
5994
|
+
}
|
|
5995
|
+
const chartBars = ctxBars.bars;
|
|
5996
|
+
const times = chartBars.map(barTime);
|
|
5997
|
+
let htf;
|
|
5998
|
+
let group2;
|
|
5999
|
+
let latest;
|
|
6000
|
+
if (tf === chart2.period) {
|
|
6001
|
+
htf = chartBars;
|
|
6002
|
+
group2 = chartBars.map((_, i) => i);
|
|
6003
|
+
latest = group2;
|
|
6004
|
+
} else {
|
|
6005
|
+
const { bars: loaded, regular } = sessionBars();
|
|
6006
|
+
const calendar2 = info(tf).isdwm ? regular : loaded;
|
|
6007
|
+
const starts = times.map((t2) => calendar2.timeOf(t2, tf));
|
|
6008
|
+
const dayPeriods = times.map((t2, i) => {
|
|
6009
|
+
const at = loaded.calendar.locate(t2);
|
|
6010
|
+
const periods = at ? calendar2.calendar.periods(at.date) : [];
|
|
6011
|
+
return periods.length ? calendar2.timeOf(periods[0][0], tf) : starts[i];
|
|
6012
|
+
});
|
|
6013
|
+
const reaches = times.map((t2) => loaded.closeOf(t2, chart2.period) >= calendar2.periodEnd(t2, tf));
|
|
6014
|
+
({ group: group2, latest } = periodsOf(starts, dayPeriods, reaches));
|
|
6015
|
+
const unit = chartCtx.timeUnit === "ms" ? 1 : 1e3;
|
|
6016
|
+
htf = resample(chartBars, starts.map((s) => s / unit)).bars;
|
|
6017
|
+
}
|
|
6018
|
+
if (heikin) htf = heikinAshi(htf);
|
|
6019
|
+
const savedCtx = chartCtx;
|
|
6020
|
+
let result;
|
|
6021
|
+
let values;
|
|
6022
|
+
ctxBars.setAll(htf);
|
|
6023
|
+
chartCtx = { ...chartCtx, timeframe: tf };
|
|
6024
|
+
try {
|
|
6025
|
+
result = expression();
|
|
6026
|
+
const parts = Array.isArray(result) ? result : [result];
|
|
6027
|
+
values = parts.map((p) => valuesOf(p, htf.length));
|
|
6028
|
+
} finally {
|
|
6029
|
+
ctxBars.setAll(chartBars);
|
|
6030
|
+
chartCtx = savedCtx;
|
|
6031
|
+
}
|
|
6032
|
+
const mapped = values.map(
|
|
6033
|
+
(v) => Series.fromArray(ctxBars, mapToChart(v, group2, latest, lookahead === barmerge.lookahead_on, gaps === barmerge.gaps_on))
|
|
6034
|
+
);
|
|
6035
|
+
return Array.isArray(result) ? mapped : mapped[0];
|
|
6036
|
+
}
|
|
6037
|
+
var request = { security };
|
|
6038
|
+
var line = {
|
|
6039
|
+
...line_exports,
|
|
6040
|
+
get all() {
|
|
6041
|
+
return all2();
|
|
6042
|
+
}
|
|
6043
|
+
};
|
|
6044
|
+
var label = {
|
|
6045
|
+
...label_exports,
|
|
6046
|
+
get all() {
|
|
6047
|
+
return all3();
|
|
6048
|
+
}
|
|
6049
|
+
};
|
|
6050
|
+
var box = {
|
|
6051
|
+
...box_exports,
|
|
6052
|
+
get all() {
|
|
6053
|
+
return all4();
|
|
6054
|
+
}
|
|
6055
|
+
};
|
|
6056
|
+
var linefill = {
|
|
6057
|
+
...linefill_exports,
|
|
6058
|
+
get all() {
|
|
6059
|
+
return all5();
|
|
6060
|
+
}
|
|
6061
|
+
};
|
|
6062
|
+
var polyline = {
|
|
6063
|
+
...polyline_exports,
|
|
6064
|
+
get all() {
|
|
6065
|
+
return all6();
|
|
6066
|
+
}
|
|
6067
|
+
};
|
|
6068
|
+
var text = { ...text_exports };
|
|
6069
|
+
var chart = {
|
|
6070
|
+
point: {
|
|
6071
|
+
...chartpoint_exports,
|
|
6072
|
+
now(price) {
|
|
6073
|
+
collector();
|
|
6074
|
+
if (currentBar < 0) {
|
|
6075
|
+
throw new Error("chart.point.now() needs a current bar: call it inside eachBar().");
|
|
6076
|
+
}
|
|
6077
|
+
const bar = ctxBars.bars[currentBar];
|
|
6078
|
+
return new_point(barTime(bar), currentBar, price ?? bar.close);
|
|
6079
|
+
}
|
|
6080
|
+
}
|
|
6081
|
+
};
|
|
3620
6082
|
function seriesOf(values) {
|
|
3621
6083
|
collector();
|
|
3622
6084
|
return Series.fromArray(ctxBars, values);
|