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.mjs
CHANGED
|
@@ -1,9 +1,41 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
|
-
var __export = (target,
|
|
3
|
-
for (var name in
|
|
4
|
-
__defProp(target, name, { get:
|
|
2
|
+
var __export = (target, all7) => {
|
|
3
|
+
for (var name in all7)
|
|
4
|
+
__defProp(target, name, { get: all7[name], enumerable: true });
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
+
// src/compare/index.ts
|
|
8
|
+
var compare_exports = {};
|
|
9
|
+
__export(compare_exports, {
|
|
10
|
+
EPSILON: () => EPSILON,
|
|
11
|
+
eq: () => eq,
|
|
12
|
+
ge: () => ge,
|
|
13
|
+
gt: () => gt,
|
|
14
|
+
le: () => le,
|
|
15
|
+
lt: () => lt,
|
|
16
|
+
ne: () => ne
|
|
17
|
+
});
|
|
18
|
+
var EPSILON = 1e-10;
|
|
19
|
+
var valid = (a, b2) => !Number.isNaN(a) && !Number.isNaN(b2);
|
|
20
|
+
function eq(a, b2) {
|
|
21
|
+
return valid(a, b2) && Math.abs(a - b2) <= EPSILON;
|
|
22
|
+
}
|
|
23
|
+
function ne(a, b2) {
|
|
24
|
+
return valid(a, b2) && Math.abs(a - b2) > EPSILON;
|
|
25
|
+
}
|
|
26
|
+
function lt(a, b2) {
|
|
27
|
+
return valid(a, b2) && b2 - a > EPSILON;
|
|
28
|
+
}
|
|
29
|
+
function le(a, b2) {
|
|
30
|
+
return valid(a, b2) && a - b2 <= EPSILON;
|
|
31
|
+
}
|
|
32
|
+
function gt(a, b2) {
|
|
33
|
+
return valid(a, b2) && a - b2 > EPSILON;
|
|
34
|
+
}
|
|
35
|
+
function ge(a, b2) {
|
|
36
|
+
return valid(a, b2) && b2 - a <= EPSILON;
|
|
37
|
+
}
|
|
38
|
+
|
|
7
39
|
// src/runtime/series.ts
|
|
8
40
|
var BarData = class _BarData {
|
|
9
41
|
_bars;
|
|
@@ -146,8 +178,8 @@ var Series = class _Series {
|
|
|
146
178
|
* @param field - Field to extract ('open', 'high', 'low', 'close', 'volume')
|
|
147
179
|
* @returns Series with extracted field values
|
|
148
180
|
*/
|
|
149
|
-
static fromBars(bars2,
|
|
150
|
-
return new _Series(bars2, (bar) => bar[
|
|
181
|
+
static fromBars(bars2, field2) {
|
|
182
|
+
return new _Series(bars2, (bar) => bar[field2] ?? NaN);
|
|
151
183
|
}
|
|
152
184
|
/**
|
|
153
185
|
* Create a constant series (same value for all bars)
|
|
@@ -252,7 +284,7 @@ var Series = class _Series {
|
|
|
252
284
|
});
|
|
253
285
|
}
|
|
254
286
|
// ============================================
|
|
255
|
-
// Comparison Operations
|
|
287
|
+
// Comparison Operations (PineScript operators: tolerance 1e-10, false with na; see src/compare)
|
|
256
288
|
// ============================================
|
|
257
289
|
/**
|
|
258
290
|
* Greater than comparison
|
|
@@ -263,7 +295,7 @@ var Series = class _Series {
|
|
|
263
295
|
return new _Series(this.dataSource, (bar, i, data) => {
|
|
264
296
|
const a = this.extractor(bar, i, data);
|
|
265
297
|
const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
|
|
266
|
-
return a
|
|
298
|
+
return gt(a, b2) ? 1 : 0;
|
|
267
299
|
});
|
|
268
300
|
}
|
|
269
301
|
/**
|
|
@@ -275,7 +307,7 @@ var Series = class _Series {
|
|
|
275
307
|
return new _Series(this.dataSource, (bar, i, data) => {
|
|
276
308
|
const a = this.extractor(bar, i, data);
|
|
277
309
|
const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
|
|
278
|
-
return a
|
|
310
|
+
return ge(a, b2) ? 1 : 0;
|
|
279
311
|
});
|
|
280
312
|
}
|
|
281
313
|
/**
|
|
@@ -287,7 +319,7 @@ var Series = class _Series {
|
|
|
287
319
|
return new _Series(this.dataSource, (bar, i, data) => {
|
|
288
320
|
const a = this.extractor(bar, i, data);
|
|
289
321
|
const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
|
|
290
|
-
return a
|
|
322
|
+
return lt(a, b2) ? 1 : 0;
|
|
291
323
|
});
|
|
292
324
|
}
|
|
293
325
|
/**
|
|
@@ -299,7 +331,7 @@ var Series = class _Series {
|
|
|
299
331
|
return new _Series(this.dataSource, (bar, i, data) => {
|
|
300
332
|
const a = this.extractor(bar, i, data);
|
|
301
333
|
const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
|
|
302
|
-
return a
|
|
334
|
+
return le(a, b2) ? 1 : 0;
|
|
303
335
|
});
|
|
304
336
|
}
|
|
305
337
|
/**
|
|
@@ -311,7 +343,7 @@ var Series = class _Series {
|
|
|
311
343
|
return new _Series(this.dataSource, (bar, i, data) => {
|
|
312
344
|
const a = this.extractor(bar, i, data);
|
|
313
345
|
const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
|
|
314
|
-
return a
|
|
346
|
+
return eq(a, b2) ? 1 : 0;
|
|
315
347
|
});
|
|
316
348
|
}
|
|
317
349
|
/**
|
|
@@ -323,7 +355,7 @@ var Series = class _Series {
|
|
|
323
355
|
return new _Series(this.dataSource, (bar, i, data) => {
|
|
324
356
|
const a = this.extractor(bar, i, data);
|
|
325
357
|
const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
|
|
326
|
-
return a
|
|
358
|
+
return ne(a, b2) ? 1 : 0;
|
|
327
359
|
});
|
|
328
360
|
}
|
|
329
361
|
// ============================================
|
|
@@ -521,6 +553,7 @@ var Series = class _Series {
|
|
|
521
553
|
// src/ta-series.ts
|
|
522
554
|
var ta_series_exports = {};
|
|
523
555
|
__export(ta_series_exports, {
|
|
556
|
+
accdist: () => accdist2,
|
|
524
557
|
alma: () => alma2,
|
|
525
558
|
atr: () => atr2,
|
|
526
559
|
barssince: () => barssince2,
|
|
@@ -543,6 +576,7 @@ __export(ta_series_exports, {
|
|
|
543
576
|
highestbars: () => highestbars2,
|
|
544
577
|
hma: () => hma2,
|
|
545
578
|
ichimoku: () => ichimoku2,
|
|
579
|
+
iii: () => iii2,
|
|
546
580
|
kc: () => kc2,
|
|
547
581
|
kcw: () => kcw2,
|
|
548
582
|
linreg: () => linreg2,
|
|
@@ -555,11 +589,15 @@ __export(ta_series_exports, {
|
|
|
555
589
|
min: () => min2,
|
|
556
590
|
mode: () => mode2,
|
|
557
591
|
mom: () => mom2,
|
|
592
|
+
nvi: () => nvi2,
|
|
593
|
+
obv: () => obv2,
|
|
558
594
|
percentile_linear_interpolation: () => percentile_linear_interpolation2,
|
|
559
595
|
percentile_nearest_rank: () => percentile_nearest_rank2,
|
|
560
596
|
percentrank: () => percentrank2,
|
|
561
597
|
pivothigh: () => pivothigh2,
|
|
562
598
|
pivotlow: () => pivotlow2,
|
|
599
|
+
pvi: () => pvi2,
|
|
600
|
+
pvt: () => pvt2,
|
|
563
601
|
range: () => range2,
|
|
564
602
|
rci: () => rci2,
|
|
565
603
|
rising: () => rising2,
|
|
@@ -578,16 +616,19 @@ __export(ta_series_exports, {
|
|
|
578
616
|
valuewhen: () => valuewhen2,
|
|
579
617
|
variance: () => variance2,
|
|
580
618
|
vwap: () => vwap2,
|
|
619
|
+
vwapBands: () => vwapBands,
|
|
581
620
|
vwma: () => vwma2,
|
|
621
|
+
wad: () => wad2,
|
|
582
622
|
wma: () => wma2,
|
|
583
623
|
wpr: () => wpr2,
|
|
624
|
+
wvad: () => wvad2,
|
|
584
625
|
zigzag: () => zigzag2
|
|
585
626
|
});
|
|
586
627
|
|
|
587
628
|
// src/ta/index.ts
|
|
588
|
-
function sma(source,
|
|
629
|
+
function sma(source, length2) {
|
|
589
630
|
const result = [];
|
|
590
|
-
const len = Math.floor(
|
|
631
|
+
const len = Math.floor(length2);
|
|
591
632
|
for (let i = 0; i < source.length; i++) {
|
|
592
633
|
if (i < len - 1) {
|
|
593
634
|
result.push(NaN);
|
|
@@ -601,9 +642,9 @@ function sma(source, length) {
|
|
|
601
642
|
}
|
|
602
643
|
return result;
|
|
603
644
|
}
|
|
604
|
-
function ema(source,
|
|
645
|
+
function ema(source, length2) {
|
|
605
646
|
const result = [];
|
|
606
|
-
const len = Math.floor(
|
|
647
|
+
const len = Math.floor(length2);
|
|
607
648
|
const multiplier = 2 / (len + 1);
|
|
608
649
|
let firstValidIndex = -1;
|
|
609
650
|
let validCount = 0;
|
|
@@ -636,16 +677,16 @@ function ema(source, length) {
|
|
|
636
677
|
}
|
|
637
678
|
return result;
|
|
638
679
|
}
|
|
639
|
-
function rsi(source,
|
|
680
|
+
function rsi(source, length2) {
|
|
640
681
|
const result = [];
|
|
641
682
|
const changes = [];
|
|
642
683
|
for (let i = 1; i < source.length; i++) {
|
|
643
684
|
changes.push(source[i] - source[i - 1]);
|
|
644
685
|
}
|
|
645
|
-
const gains = changes.map((c) => c > 0 ? c : 0);
|
|
646
|
-
const losses = changes.map((c) => c < 0 ? -c : 0);
|
|
647
|
-
const avgGains = rma(gains,
|
|
648
|
-
const avgLosses = rma(losses,
|
|
686
|
+
const gains = changes.map((c) => Number.isNaN(c) ? NaN : c > 0 ? c : 0);
|
|
687
|
+
const losses = changes.map((c) => Number.isNaN(c) ? NaN : c < 0 ? -c : 0);
|
|
688
|
+
const avgGains = rma(gains, length2);
|
|
689
|
+
const avgLosses = rma(losses, length2);
|
|
649
690
|
result.push(NaN);
|
|
650
691
|
for (let i = 0; i < avgGains.length; i++) {
|
|
651
692
|
if (avgLosses[i] === 0) {
|
|
@@ -671,34 +712,53 @@ function macd(source, fastLength, slowLength, signalLength) {
|
|
|
671
712
|
}
|
|
672
713
|
return [macdLine, signalLine, histogram];
|
|
673
714
|
}
|
|
674
|
-
function bb(series,
|
|
675
|
-
const basis = sma(series,
|
|
676
|
-
const dev3 = stdev(series,
|
|
677
|
-
const
|
|
678
|
-
const
|
|
715
|
+
function bb(series, length2, mult) {
|
|
716
|
+
const basis = sma(series, length2);
|
|
717
|
+
const dev3 = stdev(series, length2);
|
|
718
|
+
const upper2 = [];
|
|
719
|
+
const lower2 = [];
|
|
679
720
|
for (let i = 0; i < series.length; i++) {
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
}
|
|
683
|
-
return [basis,
|
|
721
|
+
upper2.push(basis[i] + mult * dev3[i]);
|
|
722
|
+
lower2.push(basis[i] - mult * dev3[i]);
|
|
723
|
+
}
|
|
724
|
+
return [basis, upper2, lower2];
|
|
725
|
+
}
|
|
726
|
+
function stdev(source, length2, biased = true) {
|
|
727
|
+
const len = Math.floor(length2);
|
|
728
|
+
return source.map((_, i) => {
|
|
729
|
+
const values = lastValues(source, i, len);
|
|
730
|
+
if (!values) return NaN;
|
|
731
|
+
const mean = values.reduce((a, b2) => a + b2, 0) / len;
|
|
732
|
+
const squares = values.reduce((a, b2) => a + (b2 - mean) * (b2 - mean), 0);
|
|
733
|
+
return Math.sqrt(squares / (biased ? len : len - 1));
|
|
734
|
+
});
|
|
684
735
|
}
|
|
685
|
-
function
|
|
686
|
-
const
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
736
|
+
function lastValues(source, i, length2) {
|
|
737
|
+
const values = [];
|
|
738
|
+
for (let j = i; j >= 0 && values.length < length2; j--) {
|
|
739
|
+
const x = source[j];
|
|
740
|
+
if (!Number.isNaN(x)) values.push(x);
|
|
741
|
+
}
|
|
742
|
+
return values.length === length2 ? values : null;
|
|
743
|
+
}
|
|
744
|
+
function windowUntilNa(source, i, length2) {
|
|
745
|
+
const values = [];
|
|
746
|
+
for (let j = 0; j < length2 && i - j >= 0; j++) {
|
|
747
|
+
const x = source[i - j];
|
|
748
|
+
if (Number.isNaN(x)) break;
|
|
749
|
+
values.push([x, -j]);
|
|
750
|
+
}
|
|
751
|
+
return values;
|
|
752
|
+
}
|
|
753
|
+
function extremeOffset(source, length2, isHigher) {
|
|
754
|
+
return source.map((_, i) => {
|
|
755
|
+
if (i < length2 - 1) return NaN;
|
|
756
|
+
const w = windowUntilNa(source, i, length2);
|
|
757
|
+
if (w.length === 0) return 0;
|
|
758
|
+
let best = w[0];
|
|
759
|
+
for (const item of w) if (isHigher(item[0], best[0])) best = item;
|
|
760
|
+
return best[1];
|
|
761
|
+
});
|
|
702
762
|
}
|
|
703
763
|
function crossover(series1, series2) {
|
|
704
764
|
const result = [];
|
|
@@ -722,13 +782,13 @@ function crossunder(series1, series2) {
|
|
|
722
782
|
}
|
|
723
783
|
return result;
|
|
724
784
|
}
|
|
725
|
-
function change(source,
|
|
785
|
+
function change(source, length2 = 1) {
|
|
726
786
|
const result = [];
|
|
727
787
|
for (let i = 0; i < source.length; i++) {
|
|
728
|
-
if (i <
|
|
788
|
+
if (i < length2) {
|
|
729
789
|
result.push(NaN);
|
|
730
790
|
} else {
|
|
731
|
-
result.push(source[i] - source[i -
|
|
791
|
+
result.push(source[i] - source[i - length2]);
|
|
732
792
|
}
|
|
733
793
|
}
|
|
734
794
|
return result;
|
|
@@ -763,14 +823,14 @@ function tr(handle_na = false, high2, low2, close2) {
|
|
|
763
823
|
}
|
|
764
824
|
return result;
|
|
765
825
|
}
|
|
766
|
-
function atr(
|
|
826
|
+
function atr(length2, high2, low2, close2) {
|
|
767
827
|
if (!high2 || !low2 || !close2) {
|
|
768
828
|
throw new Error(
|
|
769
829
|
"ta.atr() requires high, low, and close series. Either pass them explicitly or use createContext({ chart: { high, low, close } }) for implicit data."
|
|
770
830
|
);
|
|
771
831
|
}
|
|
772
832
|
const trueRange = tr(false, high2, low2, close2);
|
|
773
|
-
return rma(trueRange,
|
|
833
|
+
return rma(trueRange, length2);
|
|
774
834
|
}
|
|
775
835
|
function supertrend(factor, atrPeriod, high2, low2, close2, wicks = false) {
|
|
776
836
|
if (!high2 || !low2 || !close2) {
|
|
@@ -822,9 +882,9 @@ function supertrend(factor, atrPeriod, high2, low2, close2, wicks = false) {
|
|
|
822
882
|
}
|
|
823
883
|
return [supertrendValues, directions];
|
|
824
884
|
}
|
|
825
|
-
function rma(source,
|
|
885
|
+
function rma(source, length2) {
|
|
826
886
|
const result = [];
|
|
827
|
-
const len = Math.floor(
|
|
887
|
+
const len = Math.floor(length2);
|
|
828
888
|
const alpha = 1 / len;
|
|
829
889
|
let firstValidIndex = -1;
|
|
830
890
|
let validCount = 0;
|
|
@@ -851,15 +911,17 @@ function rma(source, length) {
|
|
|
851
911
|
const val = source[i];
|
|
852
912
|
if (val !== void 0 && !isNaN(val)) {
|
|
853
913
|
rmaValue = alpha * val + (1 - alpha) * rmaValue;
|
|
914
|
+
result.push(rmaValue);
|
|
915
|
+
} else {
|
|
916
|
+
result.push(NaN);
|
|
854
917
|
}
|
|
855
|
-
result.push(rmaValue);
|
|
856
918
|
}
|
|
857
919
|
}
|
|
858
920
|
return result;
|
|
859
921
|
}
|
|
860
|
-
function wma(source,
|
|
922
|
+
function wma(source, length2) {
|
|
861
923
|
const result = [];
|
|
862
|
-
const len = Math.floor(
|
|
924
|
+
const len = Math.floor(length2);
|
|
863
925
|
for (let i = 0; i < source.length; i++) {
|
|
864
926
|
if (i < len - 1) {
|
|
865
927
|
result.push(NaN);
|
|
@@ -876,48 +938,27 @@ function wma(source, length) {
|
|
|
876
938
|
}
|
|
877
939
|
return result;
|
|
878
940
|
}
|
|
879
|
-
function highest(source,
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
let max4 = -Infinity;
|
|
886
|
-
for (let j = 0; j < length; j++) {
|
|
887
|
-
if (!isNaN(source[i - j])) {
|
|
888
|
-
max4 = Math.max(max4, source[i - j]);
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
result.push(max4 === -Infinity ? NaN : max4);
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
return result;
|
|
941
|
+
function highest(source, length2) {
|
|
942
|
+
return source.map((_, i) => {
|
|
943
|
+
if (i < length2 - 1) return NaN;
|
|
944
|
+
const w = windowUntilNa(source, i, length2);
|
|
945
|
+
return w.length ? Math.max(...w.map((x) => x[0])) : NaN;
|
|
946
|
+
});
|
|
895
947
|
}
|
|
896
|
-
function lowest(source,
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
let min4 = Infinity;
|
|
903
|
-
for (let j = 0; j < length; j++) {
|
|
904
|
-
if (!isNaN(source[i - j])) {
|
|
905
|
-
min4 = Math.min(min4, source[i - j]);
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
result.push(min4 === Infinity ? NaN : min4);
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
return result;
|
|
948
|
+
function lowest(source, length2) {
|
|
949
|
+
return source.map((_, i) => {
|
|
950
|
+
if (i < length2 - 1) return NaN;
|
|
951
|
+
const w = windowUntilNa(source, i, length2);
|
|
952
|
+
return w.length ? Math.min(...w.map((x) => x[0])) : NaN;
|
|
953
|
+
});
|
|
912
954
|
}
|
|
913
955
|
function cum(source) {
|
|
914
|
-
const result = [];
|
|
915
956
|
let sum2 = 0;
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
957
|
+
return source.map((v) => {
|
|
958
|
+
if (Number.isNaN(v)) return NaN;
|
|
959
|
+
sum2 += v;
|
|
960
|
+
return sum2;
|
|
961
|
+
});
|
|
921
962
|
}
|
|
922
963
|
function cross(source1, source2) {
|
|
923
964
|
const result = [];
|
|
@@ -932,14 +973,14 @@ function cross(source1, source2) {
|
|
|
932
973
|
}
|
|
933
974
|
return result;
|
|
934
975
|
}
|
|
935
|
-
function rising(source,
|
|
976
|
+
function rising(source, length2) {
|
|
936
977
|
const result = [];
|
|
937
978
|
for (let i = 0; i < source.length; i++) {
|
|
938
|
-
if (i <
|
|
979
|
+
if (i < length2) {
|
|
939
980
|
result.push(false);
|
|
940
981
|
} else {
|
|
941
982
|
let isRising = true;
|
|
942
|
-
for (let j = 1; j <=
|
|
983
|
+
for (let j = 1; j <= length2; j++) {
|
|
943
984
|
if (source[i - j + 1] <= source[i - j]) {
|
|
944
985
|
isRising = false;
|
|
945
986
|
break;
|
|
@@ -950,14 +991,14 @@ function rising(source, length) {
|
|
|
950
991
|
}
|
|
951
992
|
return result;
|
|
952
993
|
}
|
|
953
|
-
function falling(source,
|
|
994
|
+
function falling(source, length2) {
|
|
954
995
|
const result = [];
|
|
955
996
|
for (let i = 0; i < source.length; i++) {
|
|
956
|
-
if (i <
|
|
997
|
+
if (i < length2) {
|
|
957
998
|
result.push(false);
|
|
958
999
|
} else {
|
|
959
1000
|
let isFalling = true;
|
|
960
|
-
for (let j = 1; j <=
|
|
1001
|
+
for (let j = 1; j <= length2; j++) {
|
|
961
1002
|
if (source[i - j + 1] >= source[i - j]) {
|
|
962
1003
|
isFalling = false;
|
|
963
1004
|
break;
|
|
@@ -968,13 +1009,13 @@ function falling(source, length) {
|
|
|
968
1009
|
}
|
|
969
1010
|
return result;
|
|
970
1011
|
}
|
|
971
|
-
function roc(source,
|
|
1012
|
+
function roc(source, length2) {
|
|
972
1013
|
const result = [];
|
|
973
1014
|
for (let i = 0; i < source.length; i++) {
|
|
974
|
-
if (i <
|
|
1015
|
+
if (i < length2) {
|
|
975
1016
|
result.push(NaN);
|
|
976
1017
|
} else {
|
|
977
|
-
const oldValue = source[i -
|
|
1018
|
+
const oldValue = source[i - length2];
|
|
978
1019
|
if (oldValue === 0 || isNaN(oldValue) || isNaN(source[i])) {
|
|
979
1020
|
result.push(NaN);
|
|
980
1021
|
} else {
|
|
@@ -985,49 +1026,49 @@ function roc(source, length) {
|
|
|
985
1026
|
}
|
|
986
1027
|
return result;
|
|
987
1028
|
}
|
|
988
|
-
function mom(source,
|
|
1029
|
+
function mom(source, length2) {
|
|
989
1030
|
const result = [];
|
|
990
1031
|
for (let i = 0; i < source.length; i++) {
|
|
991
|
-
if (i <
|
|
1032
|
+
if (i < length2) {
|
|
992
1033
|
result.push(NaN);
|
|
993
1034
|
} else {
|
|
994
|
-
if (isNaN(source[i]) || isNaN(source[i -
|
|
1035
|
+
if (isNaN(source[i]) || isNaN(source[i - length2])) {
|
|
995
1036
|
result.push(NaN);
|
|
996
1037
|
} else {
|
|
997
|
-
result.push(source[i] - source[i -
|
|
1038
|
+
result.push(source[i] - source[i - length2]);
|
|
998
1039
|
}
|
|
999
1040
|
}
|
|
1000
1041
|
}
|
|
1001
1042
|
return result;
|
|
1002
1043
|
}
|
|
1003
|
-
function dev(source,
|
|
1044
|
+
function dev(source, length2) {
|
|
1004
1045
|
const result = [];
|
|
1005
|
-
const meanValues = sma(source,
|
|
1046
|
+
const meanValues = sma(source, length2);
|
|
1006
1047
|
for (let i = 0; i < source.length; i++) {
|
|
1007
|
-
if (i <
|
|
1048
|
+
if (i < length2 - 1 || isNaN(meanValues[i])) {
|
|
1008
1049
|
result.push(NaN);
|
|
1009
1050
|
} else {
|
|
1010
1051
|
let sum2 = 0;
|
|
1011
|
-
for (let j = 0; j <
|
|
1052
|
+
for (let j = 0; j < length2; j++) {
|
|
1012
1053
|
if (!isNaN(source[i - j])) {
|
|
1013
1054
|
sum2 += Math.abs(source[i - j] - meanValues[i]);
|
|
1014
1055
|
}
|
|
1015
1056
|
}
|
|
1016
|
-
result.push(sum2 /
|
|
1057
|
+
result.push(sum2 / length2);
|
|
1017
1058
|
}
|
|
1018
1059
|
}
|
|
1019
1060
|
return result;
|
|
1020
1061
|
}
|
|
1021
|
-
function variance(source,
|
|
1062
|
+
function variance(source, length2, biased = true) {
|
|
1022
1063
|
const result = [];
|
|
1023
|
-
const meanValues = sma(source,
|
|
1064
|
+
const meanValues = sma(source, length2);
|
|
1024
1065
|
for (let i = 0; i < source.length; i++) {
|
|
1025
|
-
if (i <
|
|
1066
|
+
if (i < length2 - 1 || isNaN(meanValues[i])) {
|
|
1026
1067
|
result.push(NaN);
|
|
1027
1068
|
} else {
|
|
1028
1069
|
let sumSquares = 0;
|
|
1029
1070
|
let count = 0;
|
|
1030
|
-
for (let j = 0; j <
|
|
1071
|
+
for (let j = 0; j < length2; j++) {
|
|
1031
1072
|
if (!isNaN(source[i - j])) {
|
|
1032
1073
|
const diff = source[i - j] - meanValues[i];
|
|
1033
1074
|
sumSquares += diff * diff;
|
|
@@ -1040,14 +1081,14 @@ function variance(source, length, biased = true) {
|
|
|
1040
1081
|
}
|
|
1041
1082
|
return result;
|
|
1042
1083
|
}
|
|
1043
|
-
function median(source,
|
|
1084
|
+
function median(source, length2) {
|
|
1044
1085
|
const result = [];
|
|
1045
1086
|
for (let i = 0; i < source.length; i++) {
|
|
1046
|
-
if (i <
|
|
1087
|
+
if (i < length2 - 1) {
|
|
1047
1088
|
result.push(NaN);
|
|
1048
1089
|
} else {
|
|
1049
1090
|
const values = [];
|
|
1050
|
-
for (let j = 0; j <
|
|
1091
|
+
for (let j = 0; j < length2; j++) {
|
|
1051
1092
|
if (!isNaN(source[i - j])) {
|
|
1052
1093
|
values.push(source[i - j]);
|
|
1053
1094
|
}
|
|
@@ -1083,7 +1124,7 @@ function swma(source) {
|
|
|
1083
1124
|
}
|
|
1084
1125
|
return result;
|
|
1085
1126
|
}
|
|
1086
|
-
function vwma(source,
|
|
1127
|
+
function vwma(source, length2, volume2) {
|
|
1087
1128
|
if (!volume2) {
|
|
1088
1129
|
throw new Error(
|
|
1089
1130
|
"ta.vwma() requires volume series. Either pass it explicitly or use createContext({ chart: { ..., volume } }) for implicit data."
|
|
@@ -1093,8 +1134,8 @@ function vwma(source, length, volume2) {
|
|
|
1093
1134
|
for (let i = 0; i < source.length; i++) {
|
|
1094
1135
|
sourceTimesVolume.push(source[i] * volume2[i]);
|
|
1095
1136
|
}
|
|
1096
|
-
const numerator = sma(sourceTimesVolume,
|
|
1097
|
-
const denominator = sma(volume2,
|
|
1137
|
+
const numerator = sma(sourceTimesVolume, length2);
|
|
1138
|
+
const denominator = sma(volume2, length2);
|
|
1098
1139
|
const result = [];
|
|
1099
1140
|
for (let i = 0; i < source.length; i++) {
|
|
1100
1141
|
if (denominator[i] === 0 || isNaN(denominator[i])) {
|
|
@@ -1105,9 +1146,9 @@ function vwma(source, length, volume2) {
|
|
|
1105
1146
|
}
|
|
1106
1147
|
return result;
|
|
1107
1148
|
}
|
|
1108
|
-
function linreg(source,
|
|
1149
|
+
function linreg(source, length2, offset = 0) {
|
|
1109
1150
|
const result = [];
|
|
1110
|
-
const len = Math.floor(
|
|
1151
|
+
const len = Math.floor(length2);
|
|
1111
1152
|
for (let i = 0; i < source.length; i++) {
|
|
1112
1153
|
if (i < len - 1) {
|
|
1113
1154
|
result.push(NaN);
|
|
@@ -1143,14 +1184,14 @@ function linreg(source, length, offset = 0) {
|
|
|
1143
1184
|
}
|
|
1144
1185
|
return result;
|
|
1145
1186
|
}
|
|
1146
|
-
function correlation(source1, source2,
|
|
1187
|
+
function correlation(source1, source2, length2) {
|
|
1147
1188
|
const result = [];
|
|
1148
1189
|
for (let i = 0; i < source1.length; i++) {
|
|
1149
|
-
if (i <
|
|
1190
|
+
if (i < length2 - 1) {
|
|
1150
1191
|
result.push(NaN);
|
|
1151
1192
|
} else {
|
|
1152
1193
|
const pairs = [];
|
|
1153
|
-
for (let j = 0; j <
|
|
1194
|
+
for (let j = 0; j < length2; j++) {
|
|
1154
1195
|
if (!isNaN(source1[i - j]) && !isNaN(source2[i - j])) {
|
|
1155
1196
|
pairs.push([source1[i - j], source2[i - j]]);
|
|
1156
1197
|
}
|
|
@@ -1187,10 +1228,10 @@ function correlation(source1, source2, length) {
|
|
|
1187
1228
|
}
|
|
1188
1229
|
return result;
|
|
1189
1230
|
}
|
|
1190
|
-
function percentrank(source,
|
|
1231
|
+
function percentrank(source, length2) {
|
|
1191
1232
|
const result = [];
|
|
1192
1233
|
for (let i = 0; i < source.length; i++) {
|
|
1193
|
-
if (i <
|
|
1234
|
+
if (i < length2) {
|
|
1194
1235
|
result.push(NaN);
|
|
1195
1236
|
} else {
|
|
1196
1237
|
if (isNaN(source[i])) {
|
|
@@ -1198,7 +1239,7 @@ function percentrank(source, length) {
|
|
|
1198
1239
|
continue;
|
|
1199
1240
|
}
|
|
1200
1241
|
let hasNaN = false;
|
|
1201
|
-
for (let j = 1; j <=
|
|
1242
|
+
for (let j = 1; j <= length2; j++) {
|
|
1202
1243
|
if (isNaN(source[i - j])) {
|
|
1203
1244
|
hasNaN = true;
|
|
1204
1245
|
break;
|
|
@@ -1209,21 +1250,21 @@ function percentrank(source, length) {
|
|
|
1209
1250
|
} else {
|
|
1210
1251
|
const currentValue = source[i];
|
|
1211
1252
|
let countLessOrEqual = 0;
|
|
1212
|
-
for (let j = 1; j <=
|
|
1253
|
+
for (let j = 1; j <= length2; j++) {
|
|
1213
1254
|
if (source[i - j] <= currentValue) {
|
|
1214
1255
|
countLessOrEqual++;
|
|
1215
1256
|
}
|
|
1216
1257
|
}
|
|
1217
|
-
result.push(countLessOrEqual /
|
|
1258
|
+
result.push(countLessOrEqual / length2 * 100);
|
|
1218
1259
|
}
|
|
1219
1260
|
}
|
|
1220
1261
|
}
|
|
1221
1262
|
return result;
|
|
1222
1263
|
}
|
|
1223
|
-
function cci(source,
|
|
1264
|
+
function cci(source, length2) {
|
|
1224
1265
|
const result = [];
|
|
1225
|
-
const smaValues = sma(source,
|
|
1226
|
-
const devValues = dev(source,
|
|
1266
|
+
const smaValues = sma(source, length2);
|
|
1267
|
+
const devValues = dev(source, length2);
|
|
1227
1268
|
for (let i = 0; i < source.length; i++) {
|
|
1228
1269
|
if (isNaN(smaValues[i]) || isNaN(devValues[i]) || devValues[i] === 0) {
|
|
1229
1270
|
result.push(NaN);
|
|
@@ -1234,10 +1275,10 @@ function cci(source, length) {
|
|
|
1234
1275
|
}
|
|
1235
1276
|
return result;
|
|
1236
1277
|
}
|
|
1237
|
-
function stoch(source, high2, low2,
|
|
1278
|
+
function stoch(source, high2, low2, length2) {
|
|
1238
1279
|
const result = [];
|
|
1239
|
-
const lowestValues = lowest(low2,
|
|
1240
|
-
const highestValues = highest(high2,
|
|
1280
|
+
const lowestValues = lowest(low2, length2);
|
|
1281
|
+
const highestValues = highest(high2, length2);
|
|
1241
1282
|
for (let i = 0; i < source.length; i++) {
|
|
1242
1283
|
if (isNaN(lowestValues[i]) || isNaN(highestValues[i])) {
|
|
1243
1284
|
result.push(NaN);
|
|
@@ -1253,7 +1294,7 @@ function stoch(source, high2, low2, length) {
|
|
|
1253
1294
|
}
|
|
1254
1295
|
return result;
|
|
1255
1296
|
}
|
|
1256
|
-
function mfi(source,
|
|
1297
|
+
function mfi(source, length2, volume2) {
|
|
1257
1298
|
if (!volume2) {
|
|
1258
1299
|
throw new Error(
|
|
1259
1300
|
"ta.mfi() requires volume series. Either pass it explicitly or use createContext({ chart: { ..., volume } }) for implicit data."
|
|
@@ -1282,12 +1323,12 @@ function mfi(source, length, volume2) {
|
|
|
1282
1323
|
}
|
|
1283
1324
|
}
|
|
1284
1325
|
for (let i = 0; i < source.length; i++) {
|
|
1285
|
-
if (i <
|
|
1326
|
+
if (i < length2) {
|
|
1286
1327
|
result.push(NaN);
|
|
1287
1328
|
} else {
|
|
1288
1329
|
let posSum = 0;
|
|
1289
1330
|
let negSum = 0;
|
|
1290
|
-
for (let j = 0; j <
|
|
1331
|
+
for (let j = 0; j < length2; j++) {
|
|
1291
1332
|
posSum += positiveFlow[i - j];
|
|
1292
1333
|
negSum += negativeFlow[i - j];
|
|
1293
1334
|
}
|
|
@@ -1302,11 +1343,11 @@ function mfi(source, length, volume2) {
|
|
|
1302
1343
|
}
|
|
1303
1344
|
return result;
|
|
1304
1345
|
}
|
|
1305
|
-
function hma(source,
|
|
1306
|
-
const halfLength = Math.floor(
|
|
1307
|
-
const sqrtLength = Math.floor(Math.sqrt(
|
|
1346
|
+
function hma(source, length2) {
|
|
1347
|
+
const halfLength = Math.floor(length2 / 2);
|
|
1348
|
+
const sqrtLength = Math.floor(Math.sqrt(length2));
|
|
1308
1349
|
const wmaHalf = wma(source, halfLength);
|
|
1309
|
-
const wmaFull = wma(source,
|
|
1350
|
+
const wmaFull = wma(source, length2);
|
|
1310
1351
|
const diff = [];
|
|
1311
1352
|
for (let i = 0; i < source.length; i++) {
|
|
1312
1353
|
diff.push(2 * wmaHalf[i] - wmaFull[i]);
|
|
@@ -1390,89 +1431,44 @@ function sar(start, inc, max4, high2, low2, close2) {
|
|
|
1390
1431
|
}
|
|
1391
1432
|
return result;
|
|
1392
1433
|
}
|
|
1434
|
+
function pivot(source, leftbars, rightbars, isHigh) {
|
|
1435
|
+
const beatsLeft = isHigh ? (x, v) => x > v : (x, v) => x < v;
|
|
1436
|
+
const beatsRight = isHigh ? (x, v) => x >= v : (x, v) => x <= v;
|
|
1437
|
+
return source.map((_, i) => {
|
|
1438
|
+
const center = i - rightbars;
|
|
1439
|
+
if (center - leftbars < 0) return NaN;
|
|
1440
|
+
const v = source[center];
|
|
1441
|
+
if (Number.isNaN(v)) return NaN;
|
|
1442
|
+
for (let j = 1; j <= leftbars; j++) {
|
|
1443
|
+
const x = source[center - j];
|
|
1444
|
+
if (Number.isNaN(x)) break;
|
|
1445
|
+
if (beatsLeft(x, v)) return NaN;
|
|
1446
|
+
}
|
|
1447
|
+
for (let j = 1; j <= rightbars; j++) {
|
|
1448
|
+
const x = source[center + j];
|
|
1449
|
+
if (Number.isNaN(x)) break;
|
|
1450
|
+
if (beatsRight(x, v)) return NaN;
|
|
1451
|
+
}
|
|
1452
|
+
return v;
|
|
1453
|
+
});
|
|
1454
|
+
}
|
|
1393
1455
|
function pivothigh(sourceOrLeftbars, leftbarsOrRightbars, rightbars, high2) {
|
|
1394
|
-
let source;
|
|
1395
|
-
let leftbars;
|
|
1396
|
-
let right;
|
|
1397
1456
|
if (rightbars === void 0) {
|
|
1398
1457
|
if (!high2) {
|
|
1399
1458
|
throw new Error("ta.pivothigh() requires high series when using two-parameter version.");
|
|
1400
1459
|
}
|
|
1401
|
-
|
|
1402
|
-
leftbars = sourceOrLeftbars;
|
|
1403
|
-
right = leftbarsOrRightbars;
|
|
1404
|
-
} else {
|
|
1405
|
-
source = sourceOrLeftbars;
|
|
1406
|
-
leftbars = leftbarsOrRightbars;
|
|
1407
|
-
right = rightbars;
|
|
1408
|
-
}
|
|
1409
|
-
const result = [];
|
|
1410
|
-
for (let i = 0; i < source.length; i++) {
|
|
1411
|
-
if (i < leftbars || i + right >= source.length) {
|
|
1412
|
-
result.push(NaN);
|
|
1413
|
-
continue;
|
|
1414
|
-
}
|
|
1415
|
-
const centerValue = source[i];
|
|
1416
|
-
let isPivot = true;
|
|
1417
|
-
for (let j = 1; j <= leftbars; j++) {
|
|
1418
|
-
if (source[i - j] >= centerValue) {
|
|
1419
|
-
isPivot = false;
|
|
1420
|
-
break;
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
if (isPivot) {
|
|
1424
|
-
for (let j = 1; j <= right; j++) {
|
|
1425
|
-
if (source[i + j] >= centerValue) {
|
|
1426
|
-
isPivot = false;
|
|
1427
|
-
break;
|
|
1428
|
-
}
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
result.push(isPivot ? centerValue : NaN);
|
|
1460
|
+
return pivot(high2, sourceOrLeftbars, leftbarsOrRightbars, true);
|
|
1432
1461
|
}
|
|
1433
|
-
return
|
|
1462
|
+
return pivot(sourceOrLeftbars, leftbarsOrRightbars, rightbars, true);
|
|
1434
1463
|
}
|
|
1435
1464
|
function pivotlow(sourceOrLeftbars, leftbarsOrRightbars, rightbars, low2) {
|
|
1436
|
-
let source;
|
|
1437
|
-
let leftbars;
|
|
1438
|
-
let right;
|
|
1439
1465
|
if (rightbars === void 0) {
|
|
1440
1466
|
if (!low2) {
|
|
1441
1467
|
throw new Error("ta.pivotlow() requires low series when using two-parameter version.");
|
|
1442
1468
|
}
|
|
1443
|
-
|
|
1444
|
-
leftbars = sourceOrLeftbars;
|
|
1445
|
-
right = leftbarsOrRightbars;
|
|
1446
|
-
} else {
|
|
1447
|
-
source = sourceOrLeftbars;
|
|
1448
|
-
leftbars = leftbarsOrRightbars;
|
|
1449
|
-
right = rightbars;
|
|
1450
|
-
}
|
|
1451
|
-
const result = [];
|
|
1452
|
-
for (let i = 0; i < source.length; i++) {
|
|
1453
|
-
if (i < leftbars || i + right >= source.length) {
|
|
1454
|
-
result.push(NaN);
|
|
1455
|
-
continue;
|
|
1456
|
-
}
|
|
1457
|
-
const centerValue = source[i];
|
|
1458
|
-
let isPivot = true;
|
|
1459
|
-
for (let j = 1; j <= leftbars; j++) {
|
|
1460
|
-
if (source[i - j] <= centerValue) {
|
|
1461
|
-
isPivot = false;
|
|
1462
|
-
break;
|
|
1463
|
-
}
|
|
1464
|
-
}
|
|
1465
|
-
if (isPivot) {
|
|
1466
|
-
for (let j = 1; j <= right; j++) {
|
|
1467
|
-
if (source[i + j] <= centerValue) {
|
|
1468
|
-
isPivot = false;
|
|
1469
|
-
break;
|
|
1470
|
-
}
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
result.push(isPivot ? centerValue : NaN);
|
|
1469
|
+
return pivot(low2, sourceOrLeftbars, leftbarsOrRightbars, false);
|
|
1474
1470
|
}
|
|
1475
|
-
return
|
|
1471
|
+
return pivot(sourceOrLeftbars, leftbarsOrRightbars, rightbars, false);
|
|
1476
1472
|
}
|
|
1477
1473
|
function barssince(condition) {
|
|
1478
1474
|
const result = [];
|
|
@@ -1577,16 +1573,16 @@ function tsi(source, shortLength, longLength) {
|
|
|
1577
1573
|
}
|
|
1578
1574
|
return result;
|
|
1579
1575
|
}
|
|
1580
|
-
function cmo(source,
|
|
1576
|
+
function cmo(source, length2) {
|
|
1581
1577
|
const result = [];
|
|
1582
1578
|
for (let i = 0; i < source.length; i++) {
|
|
1583
|
-
if (i <
|
|
1579
|
+
if (i < length2) {
|
|
1584
1580
|
result.push(NaN);
|
|
1585
1581
|
continue;
|
|
1586
1582
|
}
|
|
1587
1583
|
let sumGains = 0;
|
|
1588
1584
|
let sumLosses = 0;
|
|
1589
|
-
for (let j = 0; j <
|
|
1585
|
+
for (let j = 0; j < length2; j++) {
|
|
1590
1586
|
const change3 = source[i - j] - source[i - j - 1];
|
|
1591
1587
|
if (change3 > 0) {
|
|
1592
1588
|
sumGains += change3;
|
|
@@ -1604,8 +1600,8 @@ function cmo(source, length) {
|
|
|
1604
1600
|
}
|
|
1605
1601
|
return result;
|
|
1606
1602
|
}
|
|
1607
|
-
function kc(source,
|
|
1608
|
-
const middle = ema(source,
|
|
1603
|
+
function kc(source, length2, mult, useTrueRange = true, high2, low2, close2) {
|
|
1604
|
+
const middle = ema(source, length2);
|
|
1609
1605
|
let range3;
|
|
1610
1606
|
if (useTrueRange) {
|
|
1611
1607
|
if (!high2 || !low2 || !close2) {
|
|
@@ -1621,38 +1617,38 @@ function kc(source, length, mult, useTrueRange = true, high2, low2, close2) {
|
|
|
1621
1617
|
range3.push(high2[i] - low2[i]);
|
|
1622
1618
|
}
|
|
1623
1619
|
}
|
|
1624
|
-
const rangeEma = ema(range3,
|
|
1625
|
-
const
|
|
1626
|
-
const
|
|
1620
|
+
const rangeEma = ema(range3, length2);
|
|
1621
|
+
const upper2 = [];
|
|
1622
|
+
const lower2 = [];
|
|
1627
1623
|
for (let i = 0; i < middle.length; i++) {
|
|
1628
|
-
|
|
1629
|
-
|
|
1624
|
+
upper2.push(middle[i] + rangeEma[i] * mult);
|
|
1625
|
+
lower2.push(middle[i] - rangeEma[i] * mult);
|
|
1630
1626
|
}
|
|
1631
|
-
return [middle,
|
|
1627
|
+
return [middle, upper2, lower2];
|
|
1632
1628
|
}
|
|
1633
|
-
function bbw(source,
|
|
1634
|
-
const [basis,
|
|
1629
|
+
function bbw(source, length2, mult) {
|
|
1630
|
+
const [basis, upper2, lower2] = bb(source, length2, mult);
|
|
1635
1631
|
const result = [];
|
|
1636
1632
|
for (let i = 0; i < source.length; i++) {
|
|
1637
1633
|
if (basis[i] === 0) {
|
|
1638
1634
|
result.push(NaN);
|
|
1639
1635
|
} else {
|
|
1640
|
-
const width = (
|
|
1636
|
+
const width = (upper2[i] - lower2[i]) / basis[i] * 100;
|
|
1641
1637
|
result.push(width);
|
|
1642
1638
|
}
|
|
1643
1639
|
}
|
|
1644
1640
|
return result;
|
|
1645
1641
|
}
|
|
1646
|
-
function wpr(high2, low2, close2,
|
|
1642
|
+
function wpr(high2, low2, close2, length2 = 14) {
|
|
1647
1643
|
const result = [];
|
|
1648
1644
|
for (let i = 0; i < close2.length; i++) {
|
|
1649
|
-
if (i <
|
|
1645
|
+
if (i < length2 - 1) {
|
|
1650
1646
|
result.push(NaN);
|
|
1651
1647
|
continue;
|
|
1652
1648
|
}
|
|
1653
|
-
let highestHigh = high2[i -
|
|
1654
|
-
let lowestLow = low2[i -
|
|
1655
|
-
for (let j = i -
|
|
1649
|
+
let highestHigh = high2[i - length2 + 1];
|
|
1650
|
+
let lowestLow = low2[i - length2 + 1];
|
|
1651
|
+
for (let j = i - length2 + 2; j <= i; j++) {
|
|
1656
1652
|
if (high2[j] > highestHigh) highestHigh = high2[j];
|
|
1657
1653
|
if (low2[j] < lowestLow) lowestLow = low2[j];
|
|
1658
1654
|
}
|
|
@@ -1666,181 +1662,138 @@ function wpr(high2, low2, close2, length = 14) {
|
|
|
1666
1662
|
}
|
|
1667
1663
|
return result;
|
|
1668
1664
|
}
|
|
1669
|
-
function vwap(source, volume2) {
|
|
1665
|
+
function vwap(source, volume2, anchor, stdev_mult) {
|
|
1670
1666
|
if (source.length !== volume2.length) {
|
|
1671
1667
|
throw new Error("ta.vwap: source and volume must have the same length");
|
|
1672
1668
|
}
|
|
1673
|
-
const
|
|
1674
|
-
|
|
1675
|
-
|
|
1669
|
+
const mid = [];
|
|
1670
|
+
const upper2 = [];
|
|
1671
|
+
const lower2 = [];
|
|
1672
|
+
let sumPV = 0;
|
|
1673
|
+
let sumV = 0;
|
|
1674
|
+
let sumPPV = 0;
|
|
1676
1675
|
for (let i = 0; i < source.length; i++) {
|
|
1677
|
-
if (
|
|
1678
|
-
|
|
1679
|
-
|
|
1676
|
+
if (anchor && anchor[i]) {
|
|
1677
|
+
sumPV = 0;
|
|
1678
|
+
sumV = 0;
|
|
1679
|
+
sumPPV = 0;
|
|
1680
1680
|
}
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
if (
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1681
|
+
const s = source[i];
|
|
1682
|
+
const v = volume2[i];
|
|
1683
|
+
if (!Number.isNaN(s) && !Number.isNaN(v)) {
|
|
1684
|
+
sumPV += s * v;
|
|
1685
|
+
sumV += v;
|
|
1686
|
+
sumPPV += s * s * v;
|
|
1687
|
+
}
|
|
1688
|
+
const m = sumV === 0 ? NaN : sumPV / sumV;
|
|
1689
|
+
mid.push(m);
|
|
1690
|
+
if (stdev_mult !== void 0) {
|
|
1691
|
+
const sd = Math.sqrt(Math.max(0, sumPPV / sumV - m * m));
|
|
1692
|
+
upper2.push(m + stdev_mult * sd);
|
|
1693
|
+
lower2.push(m - stdev_mult * sd);
|
|
1687
1694
|
}
|
|
1688
1695
|
}
|
|
1689
|
-
return
|
|
1696
|
+
return stdev_mult === void 0 ? mid : [mid, upper2, lower2];
|
|
1690
1697
|
}
|
|
1691
|
-
function alma(source,
|
|
1698
|
+
function alma(source, length2 = 9, offset = 0.85, sigma = 6, floor2 = false) {
|
|
1692
1699
|
const result = [];
|
|
1693
|
-
const m = floor2 ? Math.floor(offset * (
|
|
1694
|
-
const s =
|
|
1700
|
+
const m = floor2 ? Math.floor(offset * (length2 - 1)) : offset * (length2 - 1);
|
|
1701
|
+
const s = length2 / sigma;
|
|
1695
1702
|
const weights = [];
|
|
1696
1703
|
let weightSum = 0;
|
|
1697
|
-
for (let i = 0; i <
|
|
1704
|
+
for (let i = 0; i < length2; i++) {
|
|
1698
1705
|
const weight = Math.exp(-1 * Math.pow(i - m, 2) / (2 * Math.pow(s, 2)));
|
|
1699
1706
|
weights.push(weight);
|
|
1700
1707
|
weightSum += weight;
|
|
1701
1708
|
}
|
|
1702
|
-
for (let i = 0; i <
|
|
1709
|
+
for (let i = 0; i < length2; i++) {
|
|
1703
1710
|
weights[i] /= weightSum;
|
|
1704
1711
|
}
|
|
1705
1712
|
for (let i = 0; i < source.length; i++) {
|
|
1706
|
-
if (i <
|
|
1713
|
+
if (i < length2 - 1) {
|
|
1707
1714
|
result.push(NaN);
|
|
1708
1715
|
continue;
|
|
1709
1716
|
}
|
|
1710
1717
|
let almaValue = 0;
|
|
1711
|
-
for (let j = 0; j <
|
|
1712
|
-
almaValue += source[i -
|
|
1718
|
+
for (let j = 0; j < length2; j++) {
|
|
1719
|
+
almaValue += source[i - length2 + 1 + j] * weights[j];
|
|
1713
1720
|
}
|
|
1714
1721
|
result.push(almaValue);
|
|
1715
1722
|
}
|
|
1716
1723
|
return result;
|
|
1717
1724
|
}
|
|
1718
|
-
function kcw(source,
|
|
1719
|
-
const [basis,
|
|
1725
|
+
function kcw(source, length2 = 20, mult = 2, useTrueRange = true, high2, low2, close2) {
|
|
1726
|
+
const [basis, upper2, lower2] = kc(source, length2, mult, useTrueRange, high2, low2, close2);
|
|
1720
1727
|
const result = [];
|
|
1721
1728
|
for (let i = 0; i < source.length; i++) {
|
|
1722
1729
|
if (isNaN(basis[i]) || basis[i] === 0) {
|
|
1723
1730
|
result.push(NaN);
|
|
1724
1731
|
} else {
|
|
1725
|
-
const width = (
|
|
1732
|
+
const width = (upper2[i] - lower2[i]) / basis[i] * 100;
|
|
1726
1733
|
result.push(width);
|
|
1727
1734
|
}
|
|
1728
1735
|
}
|
|
1729
1736
|
return result;
|
|
1730
1737
|
}
|
|
1731
|
-
function range(
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
for (let i = 0; i < high2.length; i++) {
|
|
1737
|
-
if (isNaN(high2[i]) || isNaN(low2[i])) {
|
|
1738
|
-
result.push(NaN);
|
|
1739
|
-
} else {
|
|
1740
|
-
result.push(high2[i] - low2[i]);
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
return result;
|
|
1738
|
+
function range(source, length2) {
|
|
1739
|
+
return source.map((_, i) => {
|
|
1740
|
+
const values = lastValues(source, i, length2);
|
|
1741
|
+
return values ? Math.max(...values) - Math.min(...values) : NaN;
|
|
1742
|
+
});
|
|
1744
1743
|
}
|
|
1745
|
-
function highestbars(source,
|
|
1746
|
-
|
|
1747
|
-
for (let i = 0; i < source.length; i++) {
|
|
1748
|
-
if (i < length - 1) {
|
|
1749
|
-
result.push(NaN);
|
|
1750
|
-
continue;
|
|
1751
|
-
}
|
|
1752
|
-
let highestValue = source[i - length + 1];
|
|
1753
|
-
let highestOffset = length - 1;
|
|
1754
|
-
for (let j = i - length + 2; j <= i; j++) {
|
|
1755
|
-
if (source[j] > highestValue) {
|
|
1756
|
-
highestValue = source[j];
|
|
1757
|
-
highestOffset = i - j;
|
|
1758
|
-
}
|
|
1759
|
-
}
|
|
1760
|
-
result.push(highestOffset);
|
|
1761
|
-
}
|
|
1762
|
-
return result;
|
|
1744
|
+
function highestbars(source, length2) {
|
|
1745
|
+
return extremeOffset(source, length2, (a, b2) => a >= b2);
|
|
1763
1746
|
}
|
|
1764
|
-
function lowestbars(source,
|
|
1765
|
-
|
|
1766
|
-
for (let i = 0; i < source.length; i++) {
|
|
1767
|
-
if (i < length - 1) {
|
|
1768
|
-
result.push(NaN);
|
|
1769
|
-
continue;
|
|
1770
|
-
}
|
|
1771
|
-
let lowestValue = source[i - length + 1];
|
|
1772
|
-
let lowestOffset = length - 1;
|
|
1773
|
-
for (let j = i - length + 2; j <= i; j++) {
|
|
1774
|
-
if (source[j] < lowestValue) {
|
|
1775
|
-
lowestValue = source[j];
|
|
1776
|
-
lowestOffset = i - j;
|
|
1777
|
-
}
|
|
1778
|
-
}
|
|
1779
|
-
result.push(lowestOffset);
|
|
1780
|
-
}
|
|
1781
|
-
return result;
|
|
1747
|
+
function lowestbars(source, length2) {
|
|
1748
|
+
return extremeOffset(source, length2, (a, b2) => a <= b2);
|
|
1782
1749
|
}
|
|
1783
|
-
function max(
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
if (isNaN(source1[i]) || isNaN(source2[i])) {
|
|
1790
|
-
result.push(NaN);
|
|
1791
|
-
} else {
|
|
1792
|
-
result.push(Math.max(source1[i], source2[i]));
|
|
1793
|
-
}
|
|
1794
|
-
}
|
|
1795
|
-
return result;
|
|
1750
|
+
function max(source) {
|
|
1751
|
+
let best = NaN;
|
|
1752
|
+
return source.map((x) => {
|
|
1753
|
+
if (!Number.isNaN(x) && !(x <= best)) best = x;
|
|
1754
|
+
return best;
|
|
1755
|
+
});
|
|
1796
1756
|
}
|
|
1797
|
-
function min(
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
if (isNaN(source1[i]) || isNaN(source2[i])) {
|
|
1804
|
-
result.push(NaN);
|
|
1805
|
-
} else {
|
|
1806
|
-
result.push(Math.min(source1[i], source2[i]));
|
|
1807
|
-
}
|
|
1808
|
-
}
|
|
1809
|
-
return result;
|
|
1757
|
+
function min(source) {
|
|
1758
|
+
let best = NaN;
|
|
1759
|
+
return source.map((x) => {
|
|
1760
|
+
if (!Number.isNaN(x) && !(x >= best)) best = x;
|
|
1761
|
+
return best;
|
|
1762
|
+
});
|
|
1810
1763
|
}
|
|
1811
|
-
function cog(source,
|
|
1764
|
+
function cog(source, length2 = 10) {
|
|
1812
1765
|
const result = [];
|
|
1813
1766
|
for (let i = 0; i < source.length; i++) {
|
|
1814
|
-
if (i <
|
|
1767
|
+
if (i < length2 - 1) {
|
|
1815
1768
|
result.push(NaN);
|
|
1816
1769
|
continue;
|
|
1817
1770
|
}
|
|
1818
1771
|
let numerator = 0;
|
|
1819
1772
|
let denominator = 0;
|
|
1820
|
-
for (let j = 0; j <
|
|
1773
|
+
for (let j = 0; j < length2; j++) {
|
|
1821
1774
|
const weight = j + 1;
|
|
1822
|
-
const price = source[i -
|
|
1775
|
+
const price = source[i - length2 + 1 + j];
|
|
1823
1776
|
numerator += weight * price;
|
|
1824
1777
|
denominator += price;
|
|
1825
1778
|
}
|
|
1826
1779
|
if (denominator === 0) {
|
|
1827
1780
|
result.push(NaN);
|
|
1828
1781
|
} else {
|
|
1829
|
-
const cog3 = -1 * (numerator / denominator) + (
|
|
1782
|
+
const cog3 = -1 * (numerator / denominator) + (length2 + 1) / 2;
|
|
1830
1783
|
result.push(cog3);
|
|
1831
1784
|
}
|
|
1832
1785
|
}
|
|
1833
1786
|
return result;
|
|
1834
1787
|
}
|
|
1835
|
-
function mode(source,
|
|
1788
|
+
function mode(source, length2) {
|
|
1836
1789
|
const result = [];
|
|
1837
1790
|
for (let i = 0; i < source.length; i++) {
|
|
1838
|
-
if (i <
|
|
1791
|
+
if (i < length2 - 1) {
|
|
1839
1792
|
result.push(NaN);
|
|
1840
1793
|
continue;
|
|
1841
1794
|
}
|
|
1842
1795
|
const values = [];
|
|
1843
|
-
for (let j = 0; j <
|
|
1796
|
+
for (let j = 0; j < length2; j++) {
|
|
1844
1797
|
const value = source[i - j];
|
|
1845
1798
|
if (!isNaN(value)) {
|
|
1846
1799
|
values.push(value);
|
|
@@ -1870,15 +1823,15 @@ function mode(source, length) {
|
|
|
1870
1823
|
}
|
|
1871
1824
|
return result;
|
|
1872
1825
|
}
|
|
1873
|
-
function percentile_linear_interpolation(source,
|
|
1826
|
+
function percentile_linear_interpolation(source, length2, percentage) {
|
|
1874
1827
|
const result = [];
|
|
1875
1828
|
for (let i = 0; i < source.length; i++) {
|
|
1876
|
-
if (i <
|
|
1829
|
+
if (i < length2 - 1) {
|
|
1877
1830
|
result.push(NaN);
|
|
1878
1831
|
continue;
|
|
1879
1832
|
}
|
|
1880
1833
|
const values = [];
|
|
1881
|
-
for (let j = 0; j <
|
|
1834
|
+
for (let j = 0; j < length2; j++) {
|
|
1882
1835
|
const value = source[i - j];
|
|
1883
1836
|
values.push(value);
|
|
1884
1837
|
}
|
|
@@ -1900,15 +1853,15 @@ function percentile_linear_interpolation(source, length, percentage) {
|
|
|
1900
1853
|
}
|
|
1901
1854
|
return result;
|
|
1902
1855
|
}
|
|
1903
|
-
function percentile_nearest_rank(source,
|
|
1856
|
+
function percentile_nearest_rank(source, length2, percentage) {
|
|
1904
1857
|
const result = [];
|
|
1905
1858
|
for (let i = 0; i < source.length; i++) {
|
|
1906
|
-
if (i <
|
|
1859
|
+
if (i < length2 - 1) {
|
|
1907
1860
|
result.push(NaN);
|
|
1908
1861
|
continue;
|
|
1909
1862
|
}
|
|
1910
1863
|
const values = [];
|
|
1911
|
-
for (let j = 0; j <
|
|
1864
|
+
for (let j = 0; j < length2; j++) {
|
|
1912
1865
|
const value = source[i - j];
|
|
1913
1866
|
if (!isNaN(value)) {
|
|
1914
1867
|
values.push(value);
|
|
@@ -1929,16 +1882,16 @@ function percentile_nearest_rank(source, length, percentage) {
|
|
|
1929
1882
|
}
|
|
1930
1883
|
return result;
|
|
1931
1884
|
}
|
|
1932
|
-
function rci(source,
|
|
1885
|
+
function rci(source, length2) {
|
|
1933
1886
|
const result = [];
|
|
1934
1887
|
for (let i = 0; i < source.length; i++) {
|
|
1935
|
-
if (i <
|
|
1888
|
+
if (i < length2 - 1) {
|
|
1936
1889
|
result.push(NaN);
|
|
1937
1890
|
continue;
|
|
1938
1891
|
}
|
|
1939
1892
|
const values = [];
|
|
1940
|
-
for (let j = 0; j <
|
|
1941
|
-
values.push(source[i -
|
|
1893
|
+
for (let j = 0; j < length2; j++) {
|
|
1894
|
+
values.push(source[i - length2 + 1 + j]);
|
|
1942
1895
|
}
|
|
1943
1896
|
if (values.some((v) => isNaN(v))) {
|
|
1944
1897
|
result.push(NaN);
|
|
@@ -1946,7 +1899,7 @@ function rci(source, length) {
|
|
|
1946
1899
|
}
|
|
1947
1900
|
const indexed = values.map((value, index) => ({ value, index }));
|
|
1948
1901
|
const sorted = [...indexed].sort((a, b2) => a.value - b2.value);
|
|
1949
|
-
const ranks = new Array(
|
|
1902
|
+
const ranks = new Array(length2).fill(0);
|
|
1950
1903
|
let currentRank = 1;
|
|
1951
1904
|
for (let j = 0; j < sorted.length; j++) {
|
|
1952
1905
|
let tieCount = 1;
|
|
@@ -1961,12 +1914,12 @@ function rci(source, length) {
|
|
|
1961
1914
|
currentRank += tieCount;
|
|
1962
1915
|
}
|
|
1963
1916
|
let sumSquaredDiff = 0;
|
|
1964
|
-
for (let j = 0; j <
|
|
1917
|
+
for (let j = 0; j < length2; j++) {
|
|
1965
1918
|
const timeRank = j + 1;
|
|
1966
1919
|
const diff = ranks[j] - timeRank;
|
|
1967
1920
|
sumSquaredDiff += diff * diff;
|
|
1968
1921
|
}
|
|
1969
|
-
const n =
|
|
1922
|
+
const n = length2;
|
|
1970
1923
|
const base = (n * n * n - n) / 12;
|
|
1971
1924
|
let tieCorrection = 0;
|
|
1972
1925
|
for (let j = 0; j < sorted.length; ) {
|
|
@@ -1992,11 +1945,11 @@ function rci(source, length) {
|
|
|
1992
1945
|
return result;
|
|
1993
1946
|
}
|
|
1994
1947
|
function ichimoku(conversionPeriods, basePeriods, laggingSpan2Periods, displacement, high2, low2, close2) {
|
|
1995
|
-
const
|
|
1948
|
+
const length2 = high2.length;
|
|
1996
1949
|
const highestConversion = highest(high2, conversionPeriods);
|
|
1997
1950
|
const lowestConversion = lowest(low2, conversionPeriods);
|
|
1998
1951
|
const tenkanSen = [];
|
|
1999
|
-
for (let i = 0; i <
|
|
1952
|
+
for (let i = 0; i < length2; i++) {
|
|
2000
1953
|
if (isNaN(highestConversion[i]) || isNaN(lowestConversion[i])) {
|
|
2001
1954
|
tenkanSen.push(NaN);
|
|
2002
1955
|
} else {
|
|
@@ -2006,7 +1959,7 @@ function ichimoku(conversionPeriods, basePeriods, laggingSpan2Periods, displacem
|
|
|
2006
1959
|
const highestBase = highest(high2, basePeriods);
|
|
2007
1960
|
const lowestBase = lowest(low2, basePeriods);
|
|
2008
1961
|
const kijunSen = [];
|
|
2009
|
-
for (let i = 0; i <
|
|
1962
|
+
for (let i = 0; i < length2; i++) {
|
|
2010
1963
|
if (isNaN(highestBase[i]) || isNaN(lowestBase[i])) {
|
|
2011
1964
|
kijunSen.push(NaN);
|
|
2012
1965
|
} else {
|
|
@@ -2014,7 +1967,7 @@ function ichimoku(conversionPeriods, basePeriods, laggingSpan2Periods, displacem
|
|
|
2014
1967
|
}
|
|
2015
1968
|
}
|
|
2016
1969
|
const senkouSpanA = [];
|
|
2017
|
-
for (let i = 0; i <
|
|
1970
|
+
for (let i = 0; i < length2; i++) {
|
|
2018
1971
|
const sourceIndex = i - displacement;
|
|
2019
1972
|
if (sourceIndex < 0 || isNaN(tenkanSen[sourceIndex]) || isNaN(kijunSen[sourceIndex])) {
|
|
2020
1973
|
senkouSpanA.push(NaN);
|
|
@@ -2025,7 +1978,7 @@ function ichimoku(conversionPeriods, basePeriods, laggingSpan2Periods, displacem
|
|
|
2025
1978
|
const highestLagging = highest(high2, laggingSpan2Periods);
|
|
2026
1979
|
const lowestLagging = lowest(low2, laggingSpan2Periods);
|
|
2027
1980
|
const senkouSpanB = [];
|
|
2028
|
-
for (let i = 0; i <
|
|
1981
|
+
for (let i = 0; i < length2; i++) {
|
|
2029
1982
|
const sourceIndex = i - displacement;
|
|
2030
1983
|
if (sourceIndex < 0 || isNaN(highestLagging[sourceIndex]) || isNaN(lowestLagging[sourceIndex])) {
|
|
2031
1984
|
senkouSpanB.push(NaN);
|
|
@@ -2034,9 +1987,9 @@ function ichimoku(conversionPeriods, basePeriods, laggingSpan2Periods, displacem
|
|
|
2034
1987
|
}
|
|
2035
1988
|
}
|
|
2036
1989
|
const chikouSpan = [];
|
|
2037
|
-
for (let i = 0; i <
|
|
1990
|
+
for (let i = 0; i < length2; i++) {
|
|
2038
1991
|
const sourceIndex = i + displacement;
|
|
2039
|
-
if (sourceIndex >=
|
|
1992
|
+
if (sourceIndex >= length2 || isNaN(close2[sourceIndex])) {
|
|
2040
1993
|
chikouSpan.push(NaN);
|
|
2041
1994
|
} else {
|
|
2042
1995
|
chikouSpan.push(close2[sourceIndex]);
|
|
@@ -2058,13 +2011,13 @@ function zigzag(deviation = 5, depth = 10, backstep = 3, source, high2, low2) {
|
|
|
2058
2011
|
"ta.zigzag() requires either source series or high/low series. Either pass them explicitly or use createContext({ chart: { high, low, close } }) for implicit data."
|
|
2059
2012
|
);
|
|
2060
2013
|
}
|
|
2061
|
-
const
|
|
2062
|
-
if (lowSource.length !==
|
|
2014
|
+
const length2 = highSource.length;
|
|
2015
|
+
if (lowSource.length !== length2) {
|
|
2063
2016
|
throw new Error("ta.zigzag: high and low must have the same length");
|
|
2064
2017
|
}
|
|
2065
|
-
const zigzagValues = new Array(
|
|
2066
|
-
const directions = new Array(
|
|
2067
|
-
const isPivot = new Array(
|
|
2018
|
+
const zigzagValues = new Array(length2).fill(NaN);
|
|
2019
|
+
const directions = new Array(length2).fill(0);
|
|
2020
|
+
const isPivot = new Array(length2).fill(false);
|
|
2068
2021
|
const getDeviation = (price1, price2) => {
|
|
2069
2022
|
if (Math.abs(price1) < 1e-10 || isNaN(price1) || isNaN(price2)) return 0;
|
|
2070
2023
|
return Math.abs((price2 - price1) / price1) * 100;
|
|
@@ -2078,7 +2031,7 @@ function zigzag(deviation = 5, depth = 10, backstep = 3, source, high2, low2) {
|
|
|
2078
2031
|
let initialLowest = Infinity;
|
|
2079
2032
|
let initialHighIndex = -1;
|
|
2080
2033
|
let initialLowIndex = -1;
|
|
2081
|
-
for (let i = 0; i < Math.min(depth,
|
|
2034
|
+
for (let i = 0; i < Math.min(depth, length2); i++) {
|
|
2082
2035
|
if (!isNaN(highSource[i]) && highSource[i] > initialHighest) {
|
|
2083
2036
|
initialHighest = highSource[i];
|
|
2084
2037
|
initialHighIndex = i;
|
|
@@ -2101,7 +2054,7 @@ function zigzag(deviation = 5, depth = 10, backstep = 3, source, high2, low2) {
|
|
|
2101
2054
|
} else {
|
|
2102
2055
|
startIndex = depth;
|
|
2103
2056
|
}
|
|
2104
|
-
for (let i = Math.max(startIndex, depth); i <
|
|
2057
|
+
for (let i = Math.max(startIndex, depth); i < length2; i++) {
|
|
2105
2058
|
const currentHigh = highSource[i];
|
|
2106
2059
|
const currentLow = lowSource[i];
|
|
2107
2060
|
if (isNaN(currentHigh) || isNaN(currentLow)) {
|
|
@@ -2179,53 +2132,116 @@ function zigzag(deviation = 5, depth = 10, backstep = 3, source, high2, low2) {
|
|
|
2179
2132
|
if (potentialPivot) {
|
|
2180
2133
|
confirmedPivots.push(potentialPivot);
|
|
2181
2134
|
}
|
|
2182
|
-
for (const
|
|
2183
|
-
zigzagValues[
|
|
2184
|
-
isPivot[
|
|
2135
|
+
for (const pivot2 of confirmedPivots) {
|
|
2136
|
+
zigzagValues[pivot2.index] = pivot2.price;
|
|
2137
|
+
isPivot[pivot2.index] = true;
|
|
2185
2138
|
}
|
|
2186
2139
|
let currentDir = 0;
|
|
2187
2140
|
let pivotIdx = 0;
|
|
2188
2141
|
const numConfirmed = lastPotentialWasAdded ? confirmedPivots.length - 1 : confirmedPivots.length;
|
|
2189
|
-
for (let i = 0; i <
|
|
2142
|
+
for (let i = 0; i < length2; i++) {
|
|
2190
2143
|
while (pivotIdx < numConfirmed && confirmedPivots[pivotIdx].index <= i) {
|
|
2191
|
-
const
|
|
2192
|
-
currentDir =
|
|
2144
|
+
const pivot2 = confirmedPivots[pivotIdx];
|
|
2145
|
+
currentDir = pivot2.type === "low" ? 1 : -1;
|
|
2193
2146
|
pivotIdx++;
|
|
2194
2147
|
}
|
|
2195
2148
|
directions[i] = currentDir;
|
|
2196
2149
|
}
|
|
2197
2150
|
return [zigzagValues, directions, isPivot];
|
|
2198
2151
|
}
|
|
2152
|
+
function obv(close2, volume2) {
|
|
2153
|
+
return cum(close2.map((c, i) => i === 0 ? NaN : Math.sign(c - close2[i - 1]) * volume2[i]));
|
|
2154
|
+
}
|
|
2155
|
+
function pvt(close2, volume2) {
|
|
2156
|
+
return cum(
|
|
2157
|
+
close2.map((c, i) => i === 0 ? NaN : (c - close2[i - 1]) / close2[i - 1] * volume2[i])
|
|
2158
|
+
);
|
|
2159
|
+
}
|
|
2160
|
+
function accdist(high2, low2, close2, volume2) {
|
|
2161
|
+
return cum(
|
|
2162
|
+
close2.map((c, i) => {
|
|
2163
|
+
const h = high2[i];
|
|
2164
|
+
const l = low2[i];
|
|
2165
|
+
return h === l ? 0 : (2 * c - l - h) / (h - l) * volume2[i];
|
|
2166
|
+
})
|
|
2167
|
+
);
|
|
2168
|
+
}
|
|
2169
|
+
function iii(high2, low2, close2, volume2) {
|
|
2170
|
+
return close2.map((c, i) => {
|
|
2171
|
+
const range3 = high2[i] - low2[i];
|
|
2172
|
+
return range3 === 0 ? NaN : (2 * c - high2[i] - low2[i]) / range3 * volume2[i];
|
|
2173
|
+
});
|
|
2174
|
+
}
|
|
2175
|
+
function wvad(open2, high2, low2, close2, volume2) {
|
|
2176
|
+
return close2.map((c, i) => {
|
|
2177
|
+
const range3 = high2[i] - low2[i];
|
|
2178
|
+
return range3 === 0 ? NaN : (c - open2[i]) / range3 * volume2[i];
|
|
2179
|
+
});
|
|
2180
|
+
}
|
|
2181
|
+
function wad(high2, low2, close2) {
|
|
2182
|
+
return cum(
|
|
2183
|
+
close2.map((c, i) => {
|
|
2184
|
+
const prev = i === 0 ? NaN : close2[i - 1];
|
|
2185
|
+
const mom3 = c - prev;
|
|
2186
|
+
if (mom3 > 0) return c - Math.min(low2[i], prev);
|
|
2187
|
+
if (mom3 < 0) return c - Math.max(high2[i], prev);
|
|
2188
|
+
return 0;
|
|
2189
|
+
})
|
|
2190
|
+
);
|
|
2191
|
+
}
|
|
2192
|
+
function volumeIndex(close2, volume2, use) {
|
|
2193
|
+
const result = [];
|
|
2194
|
+
let prevIndex = NaN;
|
|
2195
|
+
for (let i = 0; i < close2.length; i++) {
|
|
2196
|
+
const prev = !prevIndex ? 1 : prevIndex;
|
|
2197
|
+
const c = close2[i];
|
|
2198
|
+
const prevC = i === 0 ? NaN : close2[i - 1];
|
|
2199
|
+
let value = prev;
|
|
2200
|
+
if (c && prevC) {
|
|
2201
|
+
const prevV = i === 0 || Number.isNaN(volume2[i - 1]) ? 0 : volume2[i - 1];
|
|
2202
|
+
if (use(volume2[i], prevV)) value = prev + (c - prevC) / prevC * prev;
|
|
2203
|
+
}
|
|
2204
|
+
result.push(value);
|
|
2205
|
+
prevIndex = value;
|
|
2206
|
+
}
|
|
2207
|
+
return result;
|
|
2208
|
+
}
|
|
2209
|
+
function nvi(close2, volume2) {
|
|
2210
|
+
return volumeIndex(close2, volume2, (v, prevV) => v < prevV);
|
|
2211
|
+
}
|
|
2212
|
+
function pvi(close2, volume2) {
|
|
2213
|
+
return volumeIndex(close2, volume2, (v, prevV) => v > prevV);
|
|
2214
|
+
}
|
|
2199
2215
|
|
|
2200
2216
|
// src/ta-series.ts
|
|
2201
|
-
function sma2(source,
|
|
2217
|
+
function sma2(source, length2) {
|
|
2202
2218
|
const bars2 = source.bars;
|
|
2203
2219
|
const sourceValues = source.toArray();
|
|
2204
|
-
const result = sma(sourceValues,
|
|
2220
|
+
const result = sma(sourceValues, length2);
|
|
2205
2221
|
return Series.fromArray(bars2, result);
|
|
2206
2222
|
}
|
|
2207
|
-
function ema2(source,
|
|
2223
|
+
function ema2(source, length2) {
|
|
2208
2224
|
const bars2 = source.bars;
|
|
2209
2225
|
const sourceValues = source.toArray();
|
|
2210
|
-
const result = ema(sourceValues,
|
|
2226
|
+
const result = ema(sourceValues, length2);
|
|
2211
2227
|
return Series.fromArray(bars2, result);
|
|
2212
2228
|
}
|
|
2213
|
-
function wma2(source,
|
|
2229
|
+
function wma2(source, length2) {
|
|
2214
2230
|
const bars2 = source.bars;
|
|
2215
2231
|
const sourceValues = source.toArray();
|
|
2216
|
-
const result = wma(sourceValues,
|
|
2232
|
+
const result = wma(sourceValues, length2);
|
|
2217
2233
|
return Series.fromArray(bars2, result);
|
|
2218
2234
|
}
|
|
2219
|
-
function rma2(source,
|
|
2235
|
+
function rma2(source, length2) {
|
|
2220
2236
|
const bars2 = source.bars;
|
|
2221
2237
|
const sourceValues = source.toArray();
|
|
2222
|
-
const result = rma(sourceValues,
|
|
2238
|
+
const result = rma(sourceValues, length2);
|
|
2223
2239
|
return Series.fromArray(bars2, result);
|
|
2224
2240
|
}
|
|
2225
|
-
function rsi2(source,
|
|
2241
|
+
function rsi2(source, length2) {
|
|
2226
2242
|
const bars2 = source.bars;
|
|
2227
2243
|
const sourceValues = source.toArray();
|
|
2228
|
-
const result = rsi(sourceValues,
|
|
2244
|
+
const result = rsi(sourceValues, length2);
|
|
2229
2245
|
return Series.fromArray(bars2, result);
|
|
2230
2246
|
}
|
|
2231
2247
|
function macd2(source, fastLength, slowLength, signalLength) {
|
|
@@ -2237,26 +2253,24 @@ function macd2(source, fastLength, slowLength, signalLength) {
|
|
|
2237
2253
|
const histSeries = Series.fromArray(bars2, histVals);
|
|
2238
2254
|
return [macdSeries, signalSeries, histSeries];
|
|
2239
2255
|
}
|
|
2240
|
-
function bb2(source,
|
|
2256
|
+
function bb2(source, length2, mult) {
|
|
2241
2257
|
const bars2 = source.bars;
|
|
2242
2258
|
const sourceValues = source.toArray();
|
|
2243
|
-
const [upperVals, basisVals, lowerVals] = bb(sourceValues,
|
|
2259
|
+
const [upperVals, basisVals, lowerVals] = bb(sourceValues, length2, mult);
|
|
2244
2260
|
const upperSeries = Series.fromArray(bars2, upperVals);
|
|
2245
2261
|
const basisSeries = Series.fromArray(bars2, basisVals);
|
|
2246
2262
|
const lowerSeries = Series.fromArray(bars2, lowerVals);
|
|
2247
2263
|
return [upperSeries, basisSeries, lowerSeries];
|
|
2248
2264
|
}
|
|
2249
|
-
function stdev2(source,
|
|
2265
|
+
function stdev2(source, length2, biased = true) {
|
|
2250
2266
|
const bars2 = source.bars;
|
|
2251
|
-
|
|
2252
|
-
const result = stdev(sourceValues, length);
|
|
2253
|
-
return Series.fromArray(bars2, result);
|
|
2267
|
+
return Series.fromArray(bars2, stdev(source.toArray(), length2, biased));
|
|
2254
2268
|
}
|
|
2255
|
-
function atr2(bars2,
|
|
2269
|
+
function atr2(bars2, length2) {
|
|
2256
2270
|
const high2 = bars2.map((b2) => b2.high);
|
|
2257
2271
|
const low2 = bars2.map((b2) => b2.low);
|
|
2258
2272
|
const close2 = bars2.map((b2) => b2.close);
|
|
2259
|
-
const result = atr(
|
|
2273
|
+
const result = atr(length2, high2, low2, close2);
|
|
2260
2274
|
return Series.fromArray(bars2, result);
|
|
2261
2275
|
}
|
|
2262
2276
|
function tr2(bars2, handle_na = false) {
|
|
@@ -2266,12 +2280,46 @@ function tr2(bars2, handle_na = false) {
|
|
|
2266
2280
|
const result = tr(handle_na, high2, low2, close2);
|
|
2267
2281
|
return Series.fromArray(bars2, result);
|
|
2268
2282
|
}
|
|
2269
|
-
|
|
2283
|
+
var col = (bars2, f) => bars2.map((b2) => b2[f] ?? NaN);
|
|
2284
|
+
function obv2(bars2) {
|
|
2285
|
+
return Series.fromArray(bars2, obv(col(bars2, "close"), col(bars2, "volume")));
|
|
2286
|
+
}
|
|
2287
|
+
function pvt2(bars2) {
|
|
2288
|
+
return Series.fromArray(bars2, pvt(col(bars2, "close"), col(bars2, "volume")));
|
|
2289
|
+
}
|
|
2290
|
+
function accdist2(bars2) {
|
|
2291
|
+
return Series.fromArray(
|
|
2292
|
+
bars2,
|
|
2293
|
+
accdist(col(bars2, "high"), col(bars2, "low"), col(bars2, "close"), col(bars2, "volume"))
|
|
2294
|
+
);
|
|
2295
|
+
}
|
|
2296
|
+
function nvi2(bars2) {
|
|
2297
|
+
return Series.fromArray(bars2, nvi(col(bars2, "close"), col(bars2, "volume")));
|
|
2298
|
+
}
|
|
2299
|
+
function pvi2(bars2) {
|
|
2300
|
+
return Series.fromArray(bars2, pvi(col(bars2, "close"), col(bars2, "volume")));
|
|
2301
|
+
}
|
|
2302
|
+
function iii2(bars2) {
|
|
2303
|
+
return Series.fromArray(
|
|
2304
|
+
bars2,
|
|
2305
|
+
iii(col(bars2, "high"), col(bars2, "low"), col(bars2, "close"), col(bars2, "volume"))
|
|
2306
|
+
);
|
|
2307
|
+
}
|
|
2308
|
+
function wad2(bars2) {
|
|
2309
|
+
return Series.fromArray(bars2, wad(col(bars2, "high"), col(bars2, "low"), col(bars2, "close")));
|
|
2310
|
+
}
|
|
2311
|
+
function wvad2(bars2) {
|
|
2312
|
+
return Series.fromArray(
|
|
2313
|
+
bars2,
|
|
2314
|
+
wvad(col(bars2, "open"), col(bars2, "high"), col(bars2, "low"), col(bars2, "close"), col(bars2, "volume"))
|
|
2315
|
+
);
|
|
2316
|
+
}
|
|
2317
|
+
function stoch2(source, high2, low2, length2) {
|
|
2270
2318
|
const bars2 = source.bars;
|
|
2271
2319
|
const sourceValues = source.toArray();
|
|
2272
2320
|
const highValues = high2.toArray();
|
|
2273
2321
|
const lowValues = low2.toArray();
|
|
2274
|
-
const result = stoch(sourceValues, highValues, lowValues,
|
|
2322
|
+
const result = stoch(sourceValues, highValues, lowValues, length2);
|
|
2275
2323
|
return Series.fromArray(bars2, result);
|
|
2276
2324
|
}
|
|
2277
2325
|
function crossover2(source1, source2) {
|
|
@@ -2298,47 +2346,47 @@ function cross2(source1, source2) {
|
|
|
2298
2346
|
const numResult = result.map((b2) => b2 ? 1 : 0);
|
|
2299
2347
|
return Series.fromArray(bars2, numResult);
|
|
2300
2348
|
}
|
|
2301
|
-
function change2(source,
|
|
2349
|
+
function change2(source, length2 = 1) {
|
|
2302
2350
|
const bars2 = source.bars;
|
|
2303
2351
|
const sourceValues = source.toArray();
|
|
2304
|
-
const result = change(sourceValues,
|
|
2352
|
+
const result = change(sourceValues, length2);
|
|
2305
2353
|
return Series.fromArray(bars2, result);
|
|
2306
2354
|
}
|
|
2307
|
-
function mom2(source,
|
|
2355
|
+
function mom2(source, length2) {
|
|
2308
2356
|
const bars2 = source.bars;
|
|
2309
2357
|
const sourceValues = source.toArray();
|
|
2310
|
-
const result = mom(sourceValues,
|
|
2358
|
+
const result = mom(sourceValues, length2);
|
|
2311
2359
|
return Series.fromArray(bars2, result);
|
|
2312
2360
|
}
|
|
2313
|
-
function roc2(source,
|
|
2361
|
+
function roc2(source, length2) {
|
|
2314
2362
|
const bars2 = source.bars;
|
|
2315
2363
|
const sourceValues = source.toArray();
|
|
2316
|
-
const result = roc(sourceValues,
|
|
2364
|
+
const result = roc(sourceValues, length2);
|
|
2317
2365
|
return Series.fromArray(bars2, result);
|
|
2318
2366
|
}
|
|
2319
|
-
function highest2(source,
|
|
2367
|
+
function highest2(source, length2) {
|
|
2320
2368
|
const bars2 = source.bars;
|
|
2321
2369
|
const sourceValues = source.toArray();
|
|
2322
|
-
const result = highest(sourceValues,
|
|
2370
|
+
const result = highest(sourceValues, length2);
|
|
2323
2371
|
return Series.fromArray(bars2, result);
|
|
2324
2372
|
}
|
|
2325
|
-
function lowest2(source,
|
|
2373
|
+
function lowest2(source, length2) {
|
|
2326
2374
|
const bars2 = source.bars;
|
|
2327
2375
|
const sourceValues = source.toArray();
|
|
2328
|
-
const result = lowest(sourceValues,
|
|
2376
|
+
const result = lowest(sourceValues, length2);
|
|
2329
2377
|
return Series.fromArray(bars2, result);
|
|
2330
2378
|
}
|
|
2331
|
-
function rising2(source,
|
|
2379
|
+
function rising2(source, length2) {
|
|
2332
2380
|
const bars2 = source.bars;
|
|
2333
2381
|
const sourceValues = source.toArray();
|
|
2334
|
-
const result = rising(sourceValues,
|
|
2382
|
+
const result = rising(sourceValues, length2);
|
|
2335
2383
|
const numResult = result.map((b2) => b2 ? 1 : 0);
|
|
2336
2384
|
return Series.fromArray(bars2, numResult);
|
|
2337
2385
|
}
|
|
2338
|
-
function falling2(source,
|
|
2386
|
+
function falling2(source, length2) {
|
|
2339
2387
|
const bars2 = source.bars;
|
|
2340
2388
|
const sourceValues = source.toArray();
|
|
2341
|
-
const result = falling(sourceValues,
|
|
2389
|
+
const result = falling(sourceValues, length2);
|
|
2342
2390
|
const numResult = result.map((b2) => b2 ? 1 : 0);
|
|
2343
2391
|
return Series.fromArray(bars2, numResult);
|
|
2344
2392
|
}
|
|
@@ -2357,12 +2405,14 @@ function supertrend2(bars2, factor, atrLength) {
|
|
|
2357
2405
|
const dirSeries = Series.fromArray(bars2, dirVals);
|
|
2358
2406
|
return [trendSeries, dirSeries];
|
|
2359
2407
|
}
|
|
2360
|
-
function vwap2(source, volume2) {
|
|
2408
|
+
function vwap2(source, volume2, anchor) {
|
|
2361
2409
|
const bars2 = source.bars;
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2410
|
+
return Series.fromArray(bars2, vwap(source.toArray(), volume2.toArray(), anchor?.toArray()));
|
|
2411
|
+
}
|
|
2412
|
+
function vwapBands(source, volume2, anchor, stdev_mult) {
|
|
2413
|
+
const bars2 = source.bars;
|
|
2414
|
+
const [m, u, l] = vwap(source.toArray(), volume2.toArray(), anchor?.toArray(), stdev_mult);
|
|
2415
|
+
return [Series.fromArray(bars2, m), Series.fromArray(bars2, u), Series.fromArray(bars2, l)];
|
|
2366
2416
|
}
|
|
2367
2417
|
function ichimoku2(bars2, conversionPeriods, basePeriods, laggingSpan2Periods, displacement) {
|
|
2368
2418
|
const high2 = bars2.map((b2) => b2.high);
|
|
@@ -2385,23 +2435,23 @@ function ichimoku2(bars2, conversionPeriods, basePeriods, laggingSpan2Periods, d
|
|
|
2385
2435
|
Series.fromArray(bars2, chikou)
|
|
2386
2436
|
];
|
|
2387
2437
|
}
|
|
2388
|
-
function vwma2(source,
|
|
2438
|
+
function vwma2(source, length2, volume2) {
|
|
2389
2439
|
const bars2 = source.bars;
|
|
2390
2440
|
const sourceValues = source.toArray();
|
|
2391
2441
|
const volumeValues = volume2.toArray();
|
|
2392
|
-
const result = vwma(sourceValues,
|
|
2442
|
+
const result = vwma(sourceValues, length2, volumeValues);
|
|
2393
2443
|
return Series.fromArray(bars2, result);
|
|
2394
2444
|
}
|
|
2395
|
-
function linreg2(source,
|
|
2445
|
+
function linreg2(source, length2, offset = 0) {
|
|
2396
2446
|
const bars2 = source.bars;
|
|
2397
2447
|
const sourceValues = source.toArray();
|
|
2398
|
-
const result = linreg(sourceValues,
|
|
2448
|
+
const result = linreg(sourceValues, length2, offset);
|
|
2399
2449
|
return Series.fromArray(bars2, result);
|
|
2400
2450
|
}
|
|
2401
|
-
function alma2(source,
|
|
2451
|
+
function alma2(source, length2 = 9, offset = 0.85, sigma = 6, floor2 = false) {
|
|
2402
2452
|
const bars2 = source.bars;
|
|
2403
2453
|
const sourceValues = source.toArray();
|
|
2404
|
-
const result = alma(sourceValues,
|
|
2454
|
+
const result = alma(sourceValues, length2, offset, sigma, floor2);
|
|
2405
2455
|
return Series.fromArray(bars2, result);
|
|
2406
2456
|
}
|
|
2407
2457
|
function zigzag2(bars2, deviation = 5, depth = 10, backstep = 3) {
|
|
@@ -2421,10 +2471,10 @@ function zigzag2(bars2, deviation = 5, depth = 10, backstep = 3) {
|
|
|
2421
2471
|
Series.fromArray(bars2, pivotVals.map((b2) => b2 ? 1 : 0))
|
|
2422
2472
|
];
|
|
2423
2473
|
}
|
|
2424
|
-
function cci2(source,
|
|
2474
|
+
function cci2(source, length2) {
|
|
2425
2475
|
const bars2 = source.bars;
|
|
2426
2476
|
const sourceValues = source.toArray();
|
|
2427
|
-
const result = cci(sourceValues,
|
|
2477
|
+
const result = cci(sourceValues, length2);
|
|
2428
2478
|
return Series.fromArray(bars2, result);
|
|
2429
2479
|
}
|
|
2430
2480
|
function sar2(bars2, start = 0.02, inc = 0.02, max4 = 0.2) {
|
|
@@ -2434,19 +2484,19 @@ function sar2(bars2, start = 0.02, inc = 0.02, max4 = 0.2) {
|
|
|
2434
2484
|
const result = sar(start, inc, max4, high2, low2, close2);
|
|
2435
2485
|
return Series.fromArray(bars2, result);
|
|
2436
2486
|
}
|
|
2437
|
-
function dev2(source,
|
|
2487
|
+
function dev2(source, length2) {
|
|
2438
2488
|
const bars2 = source.bars;
|
|
2439
|
-
const result = dev(source.toArray(),
|
|
2489
|
+
const result = dev(source.toArray(), length2);
|
|
2440
2490
|
return Series.fromArray(bars2, result);
|
|
2441
2491
|
}
|
|
2442
|
-
function variance2(source,
|
|
2492
|
+
function variance2(source, length2, biased = true) {
|
|
2443
2493
|
const bars2 = source.bars;
|
|
2444
|
-
const result = variance(source.toArray(),
|
|
2494
|
+
const result = variance(source.toArray(), length2, biased);
|
|
2445
2495
|
return Series.fromArray(bars2, result);
|
|
2446
2496
|
}
|
|
2447
|
-
function median2(source,
|
|
2497
|
+
function median2(source, length2) {
|
|
2448
2498
|
const bars2 = source.bars;
|
|
2449
|
-
const result = median(source.toArray(),
|
|
2499
|
+
const result = median(source.toArray(), length2);
|
|
2450
2500
|
return Series.fromArray(bars2, result);
|
|
2451
2501
|
}
|
|
2452
2502
|
function swma2(source) {
|
|
@@ -2454,24 +2504,24 @@ function swma2(source) {
|
|
|
2454
2504
|
const result = swma(source.toArray());
|
|
2455
2505
|
return Series.fromArray(bars2, result);
|
|
2456
2506
|
}
|
|
2457
|
-
function correlation2(source1, source2,
|
|
2507
|
+
function correlation2(source1, source2, length2) {
|
|
2458
2508
|
const bars2 = source1.bars;
|
|
2459
|
-
const result = correlation(source1.toArray(), source2.toArray(),
|
|
2509
|
+
const result = correlation(source1.toArray(), source2.toArray(), length2);
|
|
2460
2510
|
return Series.fromArray(bars2, result);
|
|
2461
2511
|
}
|
|
2462
|
-
function percentrank2(source,
|
|
2512
|
+
function percentrank2(source, length2) {
|
|
2463
2513
|
const bars2 = source.bars;
|
|
2464
|
-
const result = percentrank(source.toArray(),
|
|
2514
|
+
const result = percentrank(source.toArray(), length2);
|
|
2465
2515
|
return Series.fromArray(bars2, result);
|
|
2466
2516
|
}
|
|
2467
|
-
function mfi2(source,
|
|
2517
|
+
function mfi2(source, length2, volume2) {
|
|
2468
2518
|
const bars2 = source.bars;
|
|
2469
|
-
const result = mfi(source.toArray(),
|
|
2519
|
+
const result = mfi(source.toArray(), length2, volume2.toArray());
|
|
2470
2520
|
return Series.fromArray(bars2, result);
|
|
2471
2521
|
}
|
|
2472
|
-
function hma2(source,
|
|
2522
|
+
function hma2(source, length2) {
|
|
2473
2523
|
const bars2 = source.bars;
|
|
2474
|
-
const result = hma(source.toArray(),
|
|
2524
|
+
const result = hma(source.toArray(), length2);
|
|
2475
2525
|
return Series.fromArray(bars2, result);
|
|
2476
2526
|
}
|
|
2477
2527
|
function pivothigh2(source, leftbars, rightbars) {
|
|
@@ -2512,89 +2562,86 @@ function tsi2(source, shortLength, longLength) {
|
|
|
2512
2562
|
const result = tsi(source.toArray(), shortLength, longLength);
|
|
2513
2563
|
return Series.fromArray(bars2, result);
|
|
2514
2564
|
}
|
|
2515
|
-
function cmo2(source,
|
|
2565
|
+
function cmo2(source, length2) {
|
|
2516
2566
|
const bars2 = source.bars;
|
|
2517
|
-
const result = cmo(source.toArray(),
|
|
2567
|
+
const result = cmo(source.toArray(), length2);
|
|
2518
2568
|
return Series.fromArray(bars2, result);
|
|
2519
2569
|
}
|
|
2520
|
-
function kc2(bars2, source,
|
|
2570
|
+
function kc2(bars2, source, length2, mult, useTrueRange = true) {
|
|
2521
2571
|
const high2 = bars2.map((b2) => b2.high);
|
|
2522
2572
|
const low2 = bars2.map((b2) => b2.low);
|
|
2523
2573
|
const close2 = bars2.map((b2) => b2.close);
|
|
2524
|
-
const [middle,
|
|
2574
|
+
const [middle, upper2, lower2] = kc(source.toArray(), length2, mult, useTrueRange, high2, low2, close2);
|
|
2525
2575
|
return [
|
|
2526
2576
|
Series.fromArray(bars2, middle),
|
|
2527
|
-
Series.fromArray(bars2,
|
|
2528
|
-
Series.fromArray(bars2,
|
|
2577
|
+
Series.fromArray(bars2, upper2),
|
|
2578
|
+
Series.fromArray(bars2, lower2)
|
|
2529
2579
|
];
|
|
2530
2580
|
}
|
|
2531
|
-
function bbw2(source,
|
|
2581
|
+
function bbw2(source, length2, mult) {
|
|
2532
2582
|
const bars2 = source.bars;
|
|
2533
|
-
const result = bbw(source.toArray(),
|
|
2583
|
+
const result = bbw(source.toArray(), length2, mult);
|
|
2534
2584
|
return Series.fromArray(bars2, result);
|
|
2535
2585
|
}
|
|
2536
|
-
function wpr2(bars2,
|
|
2586
|
+
function wpr2(bars2, length2 = 14) {
|
|
2537
2587
|
const high2 = bars2.map((b2) => b2.high);
|
|
2538
2588
|
const low2 = bars2.map((b2) => b2.low);
|
|
2539
2589
|
const close2 = bars2.map((b2) => b2.close);
|
|
2540
|
-
const result = wpr(high2, low2, close2,
|
|
2590
|
+
const result = wpr(high2, low2, close2, length2);
|
|
2541
2591
|
return Series.fromArray(bars2, result);
|
|
2542
2592
|
}
|
|
2543
|
-
function kcw2(bars2, source,
|
|
2593
|
+
function kcw2(bars2, source, length2 = 20, mult = 2, useTrueRange = true) {
|
|
2544
2594
|
const high2 = bars2.map((b2) => b2.high);
|
|
2545
2595
|
const low2 = bars2.map((b2) => b2.low);
|
|
2546
2596
|
const close2 = bars2.map((b2) => b2.close);
|
|
2547
|
-
const result = kcw(source.toArray(),
|
|
2597
|
+
const result = kcw(source.toArray(), length2, mult, useTrueRange, high2, low2, close2);
|
|
2548
2598
|
return Series.fromArray(bars2, result);
|
|
2549
2599
|
}
|
|
2550
|
-
function range2(
|
|
2551
|
-
const bars2 =
|
|
2552
|
-
|
|
2553
|
-
return Series.fromArray(bars2, result);
|
|
2600
|
+
function range2(source, length2) {
|
|
2601
|
+
const bars2 = source.bars;
|
|
2602
|
+
return Series.fromArray(bars2, range(source.toArray(), length2));
|
|
2554
2603
|
}
|
|
2555
|
-
function highestbars2(source,
|
|
2604
|
+
function highestbars2(source, length2) {
|
|
2556
2605
|
const bars2 = source.bars;
|
|
2557
|
-
const result = highestbars(source.toArray(),
|
|
2606
|
+
const result = highestbars(source.toArray(), length2);
|
|
2558
2607
|
return Series.fromArray(bars2, result);
|
|
2559
2608
|
}
|
|
2560
|
-
function lowestbars2(source,
|
|
2609
|
+
function lowestbars2(source, length2) {
|
|
2561
2610
|
const bars2 = source.bars;
|
|
2562
|
-
const result = lowestbars(source.toArray(),
|
|
2611
|
+
const result = lowestbars(source.toArray(), length2);
|
|
2563
2612
|
return Series.fromArray(bars2, result);
|
|
2564
2613
|
}
|
|
2565
|
-
function max2(
|
|
2566
|
-
const bars2 =
|
|
2567
|
-
|
|
2568
|
-
return Series.fromArray(bars2, result);
|
|
2614
|
+
function max2(source) {
|
|
2615
|
+
const bars2 = source.bars;
|
|
2616
|
+
return Series.fromArray(bars2, max(source.toArray()));
|
|
2569
2617
|
}
|
|
2570
|
-
function min2(
|
|
2571
|
-
const bars2 =
|
|
2572
|
-
|
|
2573
|
-
return Series.fromArray(bars2, result);
|
|
2618
|
+
function min2(source) {
|
|
2619
|
+
const bars2 = source.bars;
|
|
2620
|
+
return Series.fromArray(bars2, min(source.toArray()));
|
|
2574
2621
|
}
|
|
2575
|
-
function cog2(source,
|
|
2622
|
+
function cog2(source, length2 = 10) {
|
|
2576
2623
|
const bars2 = source.bars;
|
|
2577
|
-
const result = cog(source.toArray(),
|
|
2624
|
+
const result = cog(source.toArray(), length2);
|
|
2578
2625
|
return Series.fromArray(bars2, result);
|
|
2579
2626
|
}
|
|
2580
|
-
function mode2(source,
|
|
2627
|
+
function mode2(source, length2) {
|
|
2581
2628
|
const bars2 = source.bars;
|
|
2582
|
-
const result = mode(source.toArray(),
|
|
2629
|
+
const result = mode(source.toArray(), length2);
|
|
2583
2630
|
return Series.fromArray(bars2, result);
|
|
2584
2631
|
}
|
|
2585
|
-
function percentile_linear_interpolation2(source,
|
|
2632
|
+
function percentile_linear_interpolation2(source, length2, percentage) {
|
|
2586
2633
|
const bars2 = source.bars;
|
|
2587
|
-
const result = percentile_linear_interpolation(source.toArray(),
|
|
2634
|
+
const result = percentile_linear_interpolation(source.toArray(), length2, percentage);
|
|
2588
2635
|
return Series.fromArray(bars2, result);
|
|
2589
2636
|
}
|
|
2590
|
-
function percentile_nearest_rank2(source,
|
|
2637
|
+
function percentile_nearest_rank2(source, length2, percentage) {
|
|
2591
2638
|
const bars2 = source.bars;
|
|
2592
|
-
const result = percentile_nearest_rank(source.toArray(),
|
|
2639
|
+
const result = percentile_nearest_rank(source.toArray(), length2, percentage);
|
|
2593
2640
|
return Series.fromArray(bars2, result);
|
|
2594
2641
|
}
|
|
2595
|
-
function rci2(source,
|
|
2642
|
+
function rci2(source, length2) {
|
|
2596
2643
|
const bars2 = source.bars;
|
|
2597
|
-
const result = rci(source.toArray(),
|
|
2644
|
+
const result = rci(source.toArray(), length2);
|
|
2598
2645
|
return Series.fromArray(bars2, result);
|
|
2599
2646
|
}
|
|
2600
2647
|
var ta = {
|
|
@@ -2653,6 +2700,15 @@ var ta = {
|
|
|
2653
2700
|
lowestbars: lowestbars2,
|
|
2654
2701
|
max: max2,
|
|
2655
2702
|
min: min2,
|
|
2703
|
+
vwapBands,
|
|
2704
|
+
obv: obv2,
|
|
2705
|
+
pvt: pvt2,
|
|
2706
|
+
accdist: accdist2,
|
|
2707
|
+
nvi: nvi2,
|
|
2708
|
+
pvi: pvi2,
|
|
2709
|
+
iii: iii2,
|
|
2710
|
+
wad: wad2,
|
|
2711
|
+
wvad: wvad2,
|
|
2656
2712
|
cog: cog2,
|
|
2657
2713
|
mode: mode2,
|
|
2658
2714
|
percentile_linear_interpolation: percentile_linear_interpolation2,
|
|
@@ -2725,52 +2781,59 @@ function t(clr) {
|
|
|
2725
2781
|
}
|
|
2726
2782
|
function parseColor(clr) {
|
|
2727
2783
|
if (typeof clr === "string") {
|
|
2728
|
-
const
|
|
2729
|
-
if (
|
|
2784
|
+
const hex = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(clr.trim());
|
|
2785
|
+
if (hex) {
|
|
2786
|
+
let digits = hex[1];
|
|
2787
|
+
if (digits.length <= 4) digits = [...digits].map((c) => c + c).join("");
|
|
2788
|
+
const byte = (k) => parseInt(digits.slice(k, k + 2), 16);
|
|
2789
|
+
return { r: byte(0), g: byte(2), b: byte(4), t: digits.length === 8 ? (1 - byte(6) / 255) * 100 : 0 };
|
|
2790
|
+
}
|
|
2791
|
+
const match2 = clr.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
|
|
2792
|
+
if (match2) {
|
|
2730
2793
|
return {
|
|
2731
|
-
r: parseInt(
|
|
2732
|
-
g: parseInt(
|
|
2733
|
-
b: parseInt(
|
|
2734
|
-
t:
|
|
2794
|
+
r: parseInt(match2[1]),
|
|
2795
|
+
g: parseInt(match2[2]),
|
|
2796
|
+
b: parseInt(match2[3]),
|
|
2797
|
+
t: match2[4] ? (1 - parseFloat(match2[4])) * 100 : 0
|
|
2735
2798
|
};
|
|
2736
2799
|
}
|
|
2737
2800
|
}
|
|
2738
2801
|
return { r: 0, g: 0, b: 0, t: 0 };
|
|
2739
2802
|
}
|
|
2740
|
-
var aqua = "#
|
|
2741
|
-
var black = "#
|
|
2742
|
-
var blue = "#
|
|
2743
|
-
var fuchsia = "#
|
|
2744
|
-
var gray = "#
|
|
2745
|
-
var green = "#
|
|
2746
|
-
var lime = "#
|
|
2747
|
-
var maroon = "#
|
|
2748
|
-
var navy = "#
|
|
2803
|
+
var aqua = "#00BCD4";
|
|
2804
|
+
var black = "#363A45";
|
|
2805
|
+
var blue = "#2962FF";
|
|
2806
|
+
var fuchsia = "#E040FB";
|
|
2807
|
+
var gray = "#787B86";
|
|
2808
|
+
var green = "#4CAF50";
|
|
2809
|
+
var lime = "#00E676";
|
|
2810
|
+
var maroon = "#880E4F";
|
|
2811
|
+
var navy = "#311B92";
|
|
2749
2812
|
var olive = "#808000";
|
|
2750
|
-
var orange = "#
|
|
2751
|
-
var purple = "#
|
|
2752
|
-
var red = "#
|
|
2753
|
-
var silver = "#
|
|
2754
|
-
var teal = "#
|
|
2813
|
+
var orange = "#FF9800";
|
|
2814
|
+
var purple = "#9C27B0";
|
|
2815
|
+
var red = "#F23645";
|
|
2816
|
+
var silver = "#B2B5BE";
|
|
2817
|
+
var teal = "#089981";
|
|
2755
2818
|
var white = "#FFFFFF";
|
|
2756
|
-
var yellow = "#
|
|
2819
|
+
var yellow = "#FDD835";
|
|
2757
2820
|
function from_gradient(value, bottom_value, top_value, bottom_color, top_color) {
|
|
2758
|
-
const parseColor2 = (
|
|
2759
|
-
if (typeof
|
|
2760
|
-
if (
|
|
2761
|
-
const hex =
|
|
2821
|
+
const parseColor2 = (col2) => {
|
|
2822
|
+
if (typeof col2 === "string") {
|
|
2823
|
+
if (col2.startsWith("#")) {
|
|
2824
|
+
const hex = col2.slice(1);
|
|
2762
2825
|
const r4 = parseInt(hex.slice(0, 2), 16);
|
|
2763
2826
|
const g4 = parseInt(hex.slice(2, 4), 16);
|
|
2764
2827
|
const b4 = parseInt(hex.slice(4, 6), 16);
|
|
2765
2828
|
return [r4, g4, b4, 1];
|
|
2766
2829
|
}
|
|
2767
|
-
const
|
|
2768
|
-
if (
|
|
2830
|
+
const match2 = col2.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
|
|
2831
|
+
if (match2) {
|
|
2769
2832
|
return [
|
|
2770
|
-
parseInt(
|
|
2771
|
-
parseInt(
|
|
2772
|
-
parseInt(
|
|
2773
|
-
|
|
2833
|
+
parseInt(match2[1]),
|
|
2834
|
+
parseInt(match2[2]),
|
|
2835
|
+
parseInt(match2[3]),
|
|
2836
|
+
match2[4] ? parseFloat(match2[4]) : 1
|
|
2774
2837
|
];
|
|
2775
2838
|
}
|
|
2776
2839
|
}
|
|
@@ -2796,81 +2859,2065 @@ function from_gradient(value, bottom_value, top_value, bottom_color, top_color)
|
|
|
2796
2859
|
return `rgba(${r3}, ${g3}, ${b3}, ${a})`;
|
|
2797
2860
|
}
|
|
2798
2861
|
|
|
2862
|
+
// src/drawing/registry.ts
|
|
2863
|
+
var DEFAULT_MAX_COUNT = 50;
|
|
2864
|
+
var SLACK = 5;
|
|
2865
|
+
var live = { line: [], label: [], box: [], polyline: [], linefill: [] };
|
|
2866
|
+
var limits = {
|
|
2867
|
+
line: DEFAULT_MAX_COUNT,
|
|
2868
|
+
label: DEFAULT_MAX_COUNT,
|
|
2869
|
+
box: DEFAULT_MAX_COUNT,
|
|
2870
|
+
polyline: DEFAULT_MAX_COUNT
|
|
2871
|
+
};
|
|
2872
|
+
var deleted = /* @__PURE__ */ new WeakSet();
|
|
2873
|
+
var COORDINATES = {
|
|
2874
|
+
line: ["x1", "y1", "x2", "y2"],
|
|
2875
|
+
label: ["x", "y"],
|
|
2876
|
+
box: ["left", "top", "right", "bottom"],
|
|
2877
|
+
polyline: [],
|
|
2878
|
+
linefill: []
|
|
2879
|
+
};
|
|
2880
|
+
function markDeleted(kind, obj, explicit) {
|
|
2881
|
+
deleted.add(obj);
|
|
2882
|
+
for (const field2 of COORDINATES[kind]) obj[field2] = NaN;
|
|
2883
|
+
if (kind === "line" && explicit) {
|
|
2884
|
+
for (const fill2 of live.linefill.filter((f) => f.line1 === obj || f.line2 === obj)) remove("linefill", fill2);
|
|
2885
|
+
}
|
|
2886
|
+
}
|
|
2887
|
+
function register(kind, obj) {
|
|
2888
|
+
const list = live[kind];
|
|
2889
|
+
list.push(obj);
|
|
2890
|
+
const max4 = limits[kind === "linefill" ? "line" : kind];
|
|
2891
|
+
if (list.length > max4 + SLACK) {
|
|
2892
|
+
for (const old of list.splice(0, list.length - max4)) markDeleted(kind, old, false);
|
|
2893
|
+
}
|
|
2894
|
+
return obj;
|
|
2895
|
+
}
|
|
2896
|
+
function remove(kind, obj) {
|
|
2897
|
+
const list = live[kind];
|
|
2898
|
+
const index = list.indexOf(obj);
|
|
2899
|
+
if (index !== -1) list.splice(index, 1);
|
|
2900
|
+
if (!deleted.has(obj)) markDeleted(kind, obj, true);
|
|
2901
|
+
}
|
|
2902
|
+
function isDeleted(obj) {
|
|
2903
|
+
return typeof obj === "object" && obj !== null && deleted.has(obj);
|
|
2904
|
+
}
|
|
2905
|
+
function all(kind) {
|
|
2906
|
+
return [...live[kind]];
|
|
2907
|
+
}
|
|
2908
|
+
function resetDrawings(newLimits = {}) {
|
|
2909
|
+
for (const kind of Object.keys(live)) live[kind].length = 0;
|
|
2910
|
+
limits = {
|
|
2911
|
+
line: newLimits.line ?? DEFAULT_MAX_COUNT,
|
|
2912
|
+
label: newLimits.label ?? DEFAULT_MAX_COUNT,
|
|
2913
|
+
box: newLimits.box ?? DEFAULT_MAX_COUNT,
|
|
2914
|
+
polyline: newLimits.polyline ?? DEFAULT_MAX_COUNT
|
|
2915
|
+
};
|
|
2916
|
+
}
|
|
2917
|
+
function setDrawingLimits(newLimits) {
|
|
2918
|
+
limits = { ...limits, ...Object.fromEntries(Object.entries(newLimits).filter(([, v]) => v !== void 0)) };
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2799
2921
|
// src/utils/index.ts
|
|
2800
2922
|
function isNA(value) {
|
|
2801
|
-
return value === null || value === void 0 || Number.isNaN(value);
|
|
2923
|
+
return value === null || value === void 0 || Number.isNaN(value) || isDeleted(value);
|
|
2802
2924
|
}
|
|
2803
2925
|
function nz(value, defaultValue = 0) {
|
|
2804
2926
|
return isNA(value) ? defaultValue : value;
|
|
2805
2927
|
}
|
|
2928
|
+
function fixnan(source) {
|
|
2929
|
+
let last;
|
|
2930
|
+
let seen = false;
|
|
2931
|
+
return source.map((v) => {
|
|
2932
|
+
if (!isNA(v)) {
|
|
2933
|
+
last = v;
|
|
2934
|
+
seen = true;
|
|
2935
|
+
return v;
|
|
2936
|
+
}
|
|
2937
|
+
return seen ? last : v;
|
|
2938
|
+
});
|
|
2939
|
+
}
|
|
2806
2940
|
|
|
2807
|
-
// src/
|
|
2808
|
-
var
|
|
2809
|
-
__export(
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
sum: () => sum,
|
|
2835
|
-
tan: () => tan,
|
|
2836
|
-
todegrees: () => todegrees,
|
|
2837
|
-
toradians: () => toradians
|
|
2941
|
+
// src/line/index.ts
|
|
2942
|
+
var line_exports = {};
|
|
2943
|
+
__export(line_exports, {
|
|
2944
|
+
all: () => all2,
|
|
2945
|
+
copy: () => copy,
|
|
2946
|
+
delete: () => delete_line,
|
|
2947
|
+
delete_line: () => delete_line,
|
|
2948
|
+
get_price: () => get_price,
|
|
2949
|
+
get_x1: () => get_x1,
|
|
2950
|
+
get_x2: () => get_x2,
|
|
2951
|
+
get_y1: () => get_y1,
|
|
2952
|
+
get_y2: () => get_y2,
|
|
2953
|
+
new: () => new_line,
|
|
2954
|
+
new_line: () => new_line,
|
|
2955
|
+
set_color: () => set_color,
|
|
2956
|
+
set_extend: () => set_extend,
|
|
2957
|
+
set_first_point: () => set_first_point,
|
|
2958
|
+
set_second_point: () => set_second_point,
|
|
2959
|
+
set_style: () => set_style,
|
|
2960
|
+
set_width: () => set_width,
|
|
2961
|
+
set_x1: () => set_x1,
|
|
2962
|
+
set_x2: () => set_x2,
|
|
2963
|
+
set_xloc: () => set_xloc,
|
|
2964
|
+
set_xy1: () => set_xy1,
|
|
2965
|
+
set_xy2: () => set_xy2,
|
|
2966
|
+
set_y1: () => set_y1,
|
|
2967
|
+
set_y2: () => set_y2
|
|
2838
2968
|
});
|
|
2839
|
-
function
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
const
|
|
2843
|
-
const
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2969
|
+
function new_line(...args) {
|
|
2970
|
+
let x1, y1, x2, y2, rest;
|
|
2971
|
+
if (typeof args[0] === "object" && args[0] !== null) {
|
|
2972
|
+
const [p1, p2, ...others] = args;
|
|
2973
|
+
const xloc2 = others[0] ?? "bar_index";
|
|
2974
|
+
[x1, y1, x2, y2, rest] = [pointX(p1, xloc2), p1.price, pointX(p2, xloc2), p2.price, others];
|
|
2975
|
+
} else {
|
|
2976
|
+
[x1, y1, x2, y2] = args;
|
|
2977
|
+
rest = args.slice(4);
|
|
2978
|
+
}
|
|
2979
|
+
const [xloc, extend, lineColor, style, width, force_overlay] = rest;
|
|
2980
|
+
return register("line", {
|
|
2981
|
+
x1,
|
|
2982
|
+
y1,
|
|
2983
|
+
x2,
|
|
2984
|
+
y2,
|
|
2985
|
+
xloc: xloc ?? "bar_index",
|
|
2986
|
+
extend: extend ?? "none",
|
|
2987
|
+
color: lineColor,
|
|
2988
|
+
style: style || "solid",
|
|
2989
|
+
width: width || 1,
|
|
2990
|
+
force_overlay: force_overlay ?? false
|
|
2991
|
+
});
|
|
2852
2992
|
}
|
|
2853
|
-
function
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2993
|
+
function get_price(id, x) {
|
|
2994
|
+
const { x1, y1, x2, y2, extend, xloc } = id;
|
|
2995
|
+
if (xloc === "bar_time") {
|
|
2996
|
+
throw new Error("line.get_price() only works with xloc.bar_index lines, not xloc.bar_time");
|
|
2997
|
+
}
|
|
2998
|
+
if (x2 === x1) {
|
|
2999
|
+
return NaN;
|
|
3000
|
+
}
|
|
3001
|
+
const slope = (y2 - y1) / (x2 - x1);
|
|
3002
|
+
const price = y1 + slope * (x - x1);
|
|
3003
|
+
if (extend === "none") {
|
|
3004
|
+
if (x < Math.min(x1, x2) || x > Math.max(x1, x2)) {
|
|
3005
|
+
return NaN;
|
|
3006
|
+
}
|
|
3007
|
+
} else if (extend === "left") {
|
|
3008
|
+
if (x > Math.max(x1, x2)) {
|
|
3009
|
+
return NaN;
|
|
3010
|
+
}
|
|
3011
|
+
} else if (extend === "right") {
|
|
3012
|
+
if (x < Math.min(x1, x2)) {
|
|
3013
|
+
return NaN;
|
|
2862
3014
|
}
|
|
2863
|
-
return Series.fromArray(bars2, result);
|
|
2864
3015
|
}
|
|
2865
|
-
return
|
|
3016
|
+
return price;
|
|
2866
3017
|
}
|
|
2867
|
-
function
|
|
2868
|
-
|
|
3018
|
+
function get_x1(id) {
|
|
3019
|
+
return id.x1;
|
|
3020
|
+
}
|
|
3021
|
+
function get_x2(id) {
|
|
3022
|
+
return id.x2;
|
|
3023
|
+
}
|
|
3024
|
+
function get_y1(id) {
|
|
3025
|
+
return id.y1;
|
|
3026
|
+
}
|
|
3027
|
+
function get_y2(id) {
|
|
3028
|
+
return id.y2;
|
|
3029
|
+
}
|
|
3030
|
+
function copy(id) {
|
|
3031
|
+
return register("line", { ...id });
|
|
3032
|
+
}
|
|
3033
|
+
function set_x1(id, x) {
|
|
3034
|
+
if (isDeleted(id)) return id;
|
|
3035
|
+
id.x1 = x;
|
|
3036
|
+
return id;
|
|
3037
|
+
}
|
|
3038
|
+
function set_x2(id, x) {
|
|
3039
|
+
if (isDeleted(id)) return id;
|
|
3040
|
+
id.x2 = x;
|
|
3041
|
+
return id;
|
|
3042
|
+
}
|
|
3043
|
+
function set_y1(id, y) {
|
|
3044
|
+
if (isDeleted(id)) return id;
|
|
3045
|
+
id.y1 = y;
|
|
3046
|
+
return id;
|
|
3047
|
+
}
|
|
3048
|
+
function set_y2(id, y) {
|
|
3049
|
+
if (isDeleted(id)) return id;
|
|
3050
|
+
id.y2 = y;
|
|
3051
|
+
return id;
|
|
3052
|
+
}
|
|
3053
|
+
function set_xy1(id, x, y) {
|
|
3054
|
+
if (isDeleted(id)) return id;
|
|
3055
|
+
id.x1 = x;
|
|
3056
|
+
id.y1 = y;
|
|
3057
|
+
return id;
|
|
3058
|
+
}
|
|
3059
|
+
function set_xy2(id, x, y) {
|
|
3060
|
+
if (isDeleted(id)) return id;
|
|
3061
|
+
id.x2 = x;
|
|
3062
|
+
id.y2 = y;
|
|
3063
|
+
return id;
|
|
3064
|
+
}
|
|
3065
|
+
function set_xloc(id, x1, x2, xloc) {
|
|
3066
|
+
if (isDeleted(id)) return id;
|
|
3067
|
+
id.x1 = x1;
|
|
3068
|
+
id.x2 = x2;
|
|
3069
|
+
id.xloc = xloc;
|
|
3070
|
+
return id;
|
|
3071
|
+
}
|
|
3072
|
+
function set_extend(id, extend) {
|
|
3073
|
+
if (isDeleted(id)) return id;
|
|
3074
|
+
id.extend = extend;
|
|
3075
|
+
return id;
|
|
3076
|
+
}
|
|
3077
|
+
function set_color(id, lineColor) {
|
|
3078
|
+
if (isDeleted(id)) return id;
|
|
3079
|
+
id.color = lineColor;
|
|
3080
|
+
return id;
|
|
3081
|
+
}
|
|
3082
|
+
function set_style(id, style) {
|
|
3083
|
+
if (isDeleted(id)) return id;
|
|
3084
|
+
id.style = style;
|
|
3085
|
+
return id;
|
|
3086
|
+
}
|
|
3087
|
+
function set_width(id, width) {
|
|
3088
|
+
if (isDeleted(id)) return id;
|
|
3089
|
+
id.width = width;
|
|
3090
|
+
return id;
|
|
3091
|
+
}
|
|
3092
|
+
function delete_line(id) {
|
|
3093
|
+
remove("line", id);
|
|
3094
|
+
}
|
|
3095
|
+
function pointX(point, xloc) {
|
|
3096
|
+
const x = xloc === "bar_time" ? point.time : point.index;
|
|
3097
|
+
return x ?? NaN;
|
|
3098
|
+
}
|
|
3099
|
+
function all2() {
|
|
3100
|
+
return all("line");
|
|
3101
|
+
}
|
|
3102
|
+
function set_first_point(id, point) {
|
|
3103
|
+
if (isDeleted(id)) return id;
|
|
3104
|
+
id.x1 = pointX(point, id.xloc);
|
|
3105
|
+
id.y1 = point.price;
|
|
3106
|
+
return id;
|
|
3107
|
+
}
|
|
3108
|
+
function set_second_point(id, point) {
|
|
3109
|
+
if (isDeleted(id)) return id;
|
|
3110
|
+
id.x2 = pointX(point, id.xloc);
|
|
3111
|
+
id.y2 = point.price;
|
|
3112
|
+
return id;
|
|
3113
|
+
}
|
|
3114
|
+
|
|
3115
|
+
// src/label/index.ts
|
|
3116
|
+
var label_exports = {};
|
|
3117
|
+
__export(label_exports, {
|
|
3118
|
+
all: () => all3,
|
|
3119
|
+
copy: () => copy2,
|
|
3120
|
+
delete: () => delete_label,
|
|
3121
|
+
delete_label: () => delete_label,
|
|
3122
|
+
get_text: () => get_text,
|
|
3123
|
+
get_x: () => get_x,
|
|
3124
|
+
get_y: () => get_y,
|
|
3125
|
+
new: () => new_label,
|
|
3126
|
+
new_label: () => new_label,
|
|
3127
|
+
set_color: () => set_color2,
|
|
3128
|
+
set_point: () => set_point,
|
|
3129
|
+
set_size: () => set_size,
|
|
3130
|
+
set_style: () => set_style2,
|
|
3131
|
+
set_text: () => set_text,
|
|
3132
|
+
set_text_font_family: () => set_text_font_family,
|
|
3133
|
+
set_text_formatting: () => set_text_formatting,
|
|
3134
|
+
set_textalign: () => set_textalign,
|
|
3135
|
+
set_textcolor: () => set_textcolor,
|
|
3136
|
+
set_tooltip: () => set_tooltip,
|
|
3137
|
+
set_x: () => set_x,
|
|
3138
|
+
set_xloc: () => set_xloc2,
|
|
3139
|
+
set_xy: () => set_xy,
|
|
3140
|
+
set_y: () => set_y,
|
|
3141
|
+
set_yloc: () => set_yloc
|
|
3142
|
+
});
|
|
3143
|
+
function new_label(...args) {
|
|
3144
|
+
let x, y, rest;
|
|
3145
|
+
if (typeof args[0] === "object" && args[0] !== null) {
|
|
3146
|
+
const point = args[0];
|
|
3147
|
+
rest = args.slice(1);
|
|
3148
|
+
x = pointX2(point, rest[1] ?? "bar_index");
|
|
3149
|
+
y = point.price;
|
|
3150
|
+
} else {
|
|
3151
|
+
[x, y] = args;
|
|
3152
|
+
rest = args.slice(2);
|
|
3153
|
+
}
|
|
3154
|
+
const [
|
|
3155
|
+
text2,
|
|
3156
|
+
xloc,
|
|
3157
|
+
yloc,
|
|
3158
|
+
labelColor,
|
|
3159
|
+
style,
|
|
3160
|
+
textcolor,
|
|
3161
|
+
size,
|
|
3162
|
+
textalign,
|
|
3163
|
+
tooltip,
|
|
3164
|
+
text_font_family,
|
|
3165
|
+
force_overlay,
|
|
3166
|
+
text_formatting
|
|
3167
|
+
] = rest;
|
|
3168
|
+
return register("label", {
|
|
3169
|
+
x,
|
|
3170
|
+
y,
|
|
3171
|
+
xloc: xloc ?? "bar_index",
|
|
3172
|
+
yloc: yloc ?? "price",
|
|
3173
|
+
text: text2,
|
|
3174
|
+
tooltip,
|
|
3175
|
+
color: labelColor,
|
|
3176
|
+
style,
|
|
3177
|
+
textcolor,
|
|
3178
|
+
size,
|
|
3179
|
+
textalign,
|
|
3180
|
+
text_font_family,
|
|
3181
|
+
force_overlay: force_overlay ?? false,
|
|
3182
|
+
text_formatting
|
|
3183
|
+
});
|
|
3184
|
+
}
|
|
3185
|
+
function get_x(id) {
|
|
3186
|
+
return id.x;
|
|
3187
|
+
}
|
|
3188
|
+
function get_y(id) {
|
|
3189
|
+
return id.y;
|
|
3190
|
+
}
|
|
3191
|
+
function get_text(id) {
|
|
3192
|
+
return id.text;
|
|
3193
|
+
}
|
|
3194
|
+
function copy2(id) {
|
|
3195
|
+
return register("label", { ...id });
|
|
3196
|
+
}
|
|
3197
|
+
function set_x(id, x) {
|
|
3198
|
+
if (isDeleted(id)) return id;
|
|
3199
|
+
id.x = x;
|
|
3200
|
+
return id;
|
|
3201
|
+
}
|
|
3202
|
+
function set_y(id, y) {
|
|
3203
|
+
if (isDeleted(id)) return id;
|
|
3204
|
+
id.y = y;
|
|
3205
|
+
return id;
|
|
3206
|
+
}
|
|
3207
|
+
function set_xy(id, x, y) {
|
|
3208
|
+
if (isDeleted(id)) return id;
|
|
3209
|
+
id.x = x;
|
|
3210
|
+
id.y = y;
|
|
3211
|
+
return id;
|
|
3212
|
+
}
|
|
3213
|
+
function set_xloc2(id, x, xloc) {
|
|
3214
|
+
if (isDeleted(id)) return id;
|
|
3215
|
+
id.x = x;
|
|
3216
|
+
id.xloc = xloc;
|
|
3217
|
+
return id;
|
|
3218
|
+
}
|
|
3219
|
+
function set_yloc(id, yloc) {
|
|
3220
|
+
if (isDeleted(id)) return id;
|
|
3221
|
+
id.yloc = yloc;
|
|
3222
|
+
return id;
|
|
3223
|
+
}
|
|
3224
|
+
function set_text(id, text2) {
|
|
3225
|
+
if (isDeleted(id)) return id;
|
|
3226
|
+
id.text = text2;
|
|
3227
|
+
return id;
|
|
3228
|
+
}
|
|
3229
|
+
function set_tooltip(id, tooltip) {
|
|
3230
|
+
if (isDeleted(id)) return id;
|
|
3231
|
+
id.tooltip = tooltip;
|
|
3232
|
+
return id;
|
|
3233
|
+
}
|
|
3234
|
+
function set_color2(id, labelColor) {
|
|
3235
|
+
if (isDeleted(id)) return id;
|
|
3236
|
+
id.color = labelColor;
|
|
3237
|
+
return id;
|
|
3238
|
+
}
|
|
3239
|
+
function set_textcolor(id, textColor) {
|
|
3240
|
+
if (isDeleted(id)) return id;
|
|
3241
|
+
id.textcolor = textColor;
|
|
3242
|
+
return id;
|
|
3243
|
+
}
|
|
3244
|
+
function set_style2(id, style) {
|
|
3245
|
+
if (isDeleted(id)) return id;
|
|
3246
|
+
id.style = style;
|
|
3247
|
+
return id;
|
|
3248
|
+
}
|
|
3249
|
+
function set_size(id, size) {
|
|
3250
|
+
if (isDeleted(id)) return id;
|
|
3251
|
+
id.size = size;
|
|
3252
|
+
return id;
|
|
3253
|
+
}
|
|
3254
|
+
function set_textalign(id, align) {
|
|
3255
|
+
if (isDeleted(id)) return id;
|
|
3256
|
+
id.textalign = align;
|
|
3257
|
+
return id;
|
|
3258
|
+
}
|
|
3259
|
+
function set_text_font_family(id, font) {
|
|
3260
|
+
if (isDeleted(id)) return id;
|
|
3261
|
+
id.text_font_family = font;
|
|
3262
|
+
return id;
|
|
3263
|
+
}
|
|
3264
|
+
function delete_label(id) {
|
|
3265
|
+
remove("label", id);
|
|
3266
|
+
}
|
|
3267
|
+
function pointX2(point, xloc) {
|
|
3268
|
+
const x = xloc === "bar_time" ? point.time : point.index;
|
|
3269
|
+
return x ?? NaN;
|
|
3270
|
+
}
|
|
3271
|
+
function all3() {
|
|
3272
|
+
return all("label");
|
|
3273
|
+
}
|
|
3274
|
+
function set_point(id, point) {
|
|
3275
|
+
if (isDeleted(id)) return id;
|
|
3276
|
+
id.x = pointX2(point, id.xloc);
|
|
3277
|
+
id.y = point.price;
|
|
3278
|
+
return id;
|
|
3279
|
+
}
|
|
3280
|
+
function set_text_formatting(id, formatting) {
|
|
3281
|
+
if (isDeleted(id)) return id;
|
|
3282
|
+
id.text_formatting = formatting;
|
|
3283
|
+
return id;
|
|
3284
|
+
}
|
|
3285
|
+
|
|
3286
|
+
// src/box/index.ts
|
|
3287
|
+
var box_exports = {};
|
|
3288
|
+
__export(box_exports, {
|
|
3289
|
+
all: () => all4,
|
|
3290
|
+
copy: () => copy3,
|
|
3291
|
+
delete: () => delete_box,
|
|
3292
|
+
delete_box: () => delete_box,
|
|
3293
|
+
get_bottom: () => get_bottom,
|
|
3294
|
+
get_left: () => get_left,
|
|
3295
|
+
get_right: () => get_right,
|
|
3296
|
+
get_top: () => get_top,
|
|
3297
|
+
new: () => new_box,
|
|
3298
|
+
new_box: () => new_box,
|
|
3299
|
+
set_bgcolor: () => set_bgcolor,
|
|
3300
|
+
set_border_color: () => set_border_color,
|
|
3301
|
+
set_border_style: () => set_border_style,
|
|
3302
|
+
set_border_width: () => set_border_width,
|
|
3303
|
+
set_bottom: () => set_bottom,
|
|
3304
|
+
set_bottom_right_point: () => set_bottom_right_point,
|
|
3305
|
+
set_extend: () => set_extend2,
|
|
3306
|
+
set_left: () => set_left,
|
|
3307
|
+
set_lefttop: () => set_lefttop,
|
|
3308
|
+
set_right: () => set_right,
|
|
3309
|
+
set_rightbottom: () => set_rightbottom,
|
|
3310
|
+
set_text: () => set_text2,
|
|
3311
|
+
set_text_color: () => set_text_color,
|
|
3312
|
+
set_text_font_family: () => set_text_font_family2,
|
|
3313
|
+
set_text_formatting: () => set_text_formatting2,
|
|
3314
|
+
set_text_halign: () => set_text_halign,
|
|
3315
|
+
set_text_size: () => set_text_size,
|
|
3316
|
+
set_text_valign: () => set_text_valign,
|
|
3317
|
+
set_text_wrap: () => set_text_wrap,
|
|
3318
|
+
set_top: () => set_top,
|
|
3319
|
+
set_top_left_point: () => set_top_left_point,
|
|
3320
|
+
set_xloc: () => set_xloc3
|
|
3321
|
+
});
|
|
3322
|
+
function new_box(...args) {
|
|
3323
|
+
let left, top, right, bottom, rest;
|
|
3324
|
+
if (typeof args[0] === "object" && args[0] !== null) {
|
|
3325
|
+
const [tl, br, ...others] = args;
|
|
3326
|
+
const xloc2 = others[4] ?? "bar_index";
|
|
3327
|
+
[left, top, right, bottom, rest] = [pointX3(tl, xloc2), tl.price, pointX3(br, xloc2), br.price, others];
|
|
3328
|
+
} else {
|
|
3329
|
+
[left, top, right, bottom] = args;
|
|
3330
|
+
rest = args.slice(4);
|
|
3331
|
+
}
|
|
3332
|
+
const [
|
|
3333
|
+
border_color,
|
|
3334
|
+
border_width,
|
|
3335
|
+
border_style,
|
|
3336
|
+
extend,
|
|
3337
|
+
xloc,
|
|
3338
|
+
bgcolor2,
|
|
3339
|
+
text2,
|
|
3340
|
+
text_size,
|
|
3341
|
+
text_color,
|
|
3342
|
+
text_halign,
|
|
3343
|
+
text_valign,
|
|
3344
|
+
text_wrap,
|
|
3345
|
+
text_font_family,
|
|
3346
|
+
force_overlay,
|
|
3347
|
+
text_formatting
|
|
3348
|
+
] = rest;
|
|
3349
|
+
return register("box", {
|
|
3350
|
+
left,
|
|
3351
|
+
top,
|
|
3352
|
+
right,
|
|
3353
|
+
bottom,
|
|
3354
|
+
xloc: xloc ?? "bar_index",
|
|
3355
|
+
extend: extend ?? "none",
|
|
3356
|
+
border_color,
|
|
3357
|
+
border_width: border_width || 1,
|
|
3358
|
+
border_style: border_style || "solid",
|
|
3359
|
+
bgcolor: bgcolor2,
|
|
3360
|
+
text: text2,
|
|
3361
|
+
text_size,
|
|
3362
|
+
text_color,
|
|
3363
|
+
text_halign,
|
|
3364
|
+
text_valign,
|
|
3365
|
+
text_wrap,
|
|
3366
|
+
text_font_family,
|
|
3367
|
+
force_overlay: force_overlay ?? false,
|
|
3368
|
+
text_formatting
|
|
3369
|
+
});
|
|
3370
|
+
}
|
|
3371
|
+
function get_left(id) {
|
|
3372
|
+
return id.left;
|
|
3373
|
+
}
|
|
3374
|
+
function get_right(id) {
|
|
3375
|
+
return id.right;
|
|
3376
|
+
}
|
|
3377
|
+
function get_top(id) {
|
|
3378
|
+
return id.top;
|
|
3379
|
+
}
|
|
3380
|
+
function get_bottom(id) {
|
|
3381
|
+
return id.bottom;
|
|
3382
|
+
}
|
|
3383
|
+
function copy3(id) {
|
|
3384
|
+
return register("box", { ...id });
|
|
3385
|
+
}
|
|
3386
|
+
function set_left(id, left) {
|
|
3387
|
+
if (isDeleted(id)) return id;
|
|
3388
|
+
id.left = left;
|
|
3389
|
+
return id;
|
|
3390
|
+
}
|
|
3391
|
+
function set_right(id, right) {
|
|
3392
|
+
if (isDeleted(id)) return id;
|
|
3393
|
+
id.right = right;
|
|
3394
|
+
return id;
|
|
3395
|
+
}
|
|
3396
|
+
function set_top(id, top) {
|
|
3397
|
+
if (isDeleted(id)) return id;
|
|
3398
|
+
id.top = top;
|
|
3399
|
+
return id;
|
|
3400
|
+
}
|
|
3401
|
+
function set_bottom(id, bottom) {
|
|
3402
|
+
if (isDeleted(id)) return id;
|
|
3403
|
+
id.bottom = bottom;
|
|
3404
|
+
return id;
|
|
3405
|
+
}
|
|
3406
|
+
function set_lefttop(id, left, top) {
|
|
3407
|
+
if (isDeleted(id)) return id;
|
|
3408
|
+
id.left = left;
|
|
3409
|
+
id.top = top;
|
|
3410
|
+
return id;
|
|
3411
|
+
}
|
|
3412
|
+
function set_rightbottom(id, right, bottom) {
|
|
3413
|
+
if (isDeleted(id)) return id;
|
|
3414
|
+
id.right = right;
|
|
3415
|
+
id.bottom = bottom;
|
|
3416
|
+
return id;
|
|
3417
|
+
}
|
|
3418
|
+
function set_xloc3(id, left, right, xloc) {
|
|
3419
|
+
if (isDeleted(id)) return id;
|
|
3420
|
+
id.left = left;
|
|
3421
|
+
id.right = right;
|
|
3422
|
+
id.xloc = xloc;
|
|
3423
|
+
return id;
|
|
3424
|
+
}
|
|
3425
|
+
function set_extend2(id, extend) {
|
|
3426
|
+
if (isDeleted(id)) return id;
|
|
3427
|
+
id.extend = extend;
|
|
3428
|
+
return id;
|
|
3429
|
+
}
|
|
3430
|
+
function set_border_color(id, borderColor) {
|
|
3431
|
+
if (isDeleted(id)) return id;
|
|
3432
|
+
id.border_color = borderColor;
|
|
3433
|
+
return id;
|
|
3434
|
+
}
|
|
3435
|
+
function set_border_width(id, width) {
|
|
3436
|
+
if (isDeleted(id)) return id;
|
|
3437
|
+
id.border_width = width;
|
|
3438
|
+
return id;
|
|
3439
|
+
}
|
|
3440
|
+
function set_border_style(id, style) {
|
|
3441
|
+
if (isDeleted(id)) return id;
|
|
3442
|
+
id.border_style = style;
|
|
3443
|
+
return id;
|
|
3444
|
+
}
|
|
3445
|
+
function set_bgcolor(id, bgColor) {
|
|
3446
|
+
if (isDeleted(id)) return id;
|
|
3447
|
+
id.bgcolor = bgColor;
|
|
3448
|
+
return id;
|
|
3449
|
+
}
|
|
3450
|
+
function set_text2(id, text2) {
|
|
3451
|
+
if (isDeleted(id)) return id;
|
|
3452
|
+
id.text = text2;
|
|
3453
|
+
return id;
|
|
3454
|
+
}
|
|
3455
|
+
function set_text_color(id, textColor) {
|
|
3456
|
+
if (isDeleted(id)) return id;
|
|
3457
|
+
id.text_color = textColor;
|
|
3458
|
+
return id;
|
|
3459
|
+
}
|
|
3460
|
+
function set_text_size(id, size) {
|
|
3461
|
+
if (isDeleted(id)) return id;
|
|
3462
|
+
id.text_size = size;
|
|
3463
|
+
return id;
|
|
3464
|
+
}
|
|
3465
|
+
function set_text_halign(id, align) {
|
|
3466
|
+
if (isDeleted(id)) return id;
|
|
3467
|
+
id.text_halign = align;
|
|
3468
|
+
return id;
|
|
3469
|
+
}
|
|
3470
|
+
function set_text_valign(id, align) {
|
|
3471
|
+
if (isDeleted(id)) return id;
|
|
3472
|
+
id.text_valign = align;
|
|
3473
|
+
return id;
|
|
3474
|
+
}
|
|
3475
|
+
function set_text_wrap(id, wrap) {
|
|
3476
|
+
if (isDeleted(id)) return id;
|
|
3477
|
+
id.text_wrap = wrap;
|
|
3478
|
+
return id;
|
|
3479
|
+
}
|
|
3480
|
+
function set_text_font_family2(id, font) {
|
|
3481
|
+
if (isDeleted(id)) return id;
|
|
3482
|
+
id.text_font_family = font;
|
|
3483
|
+
return id;
|
|
3484
|
+
}
|
|
3485
|
+
function delete_box(id) {
|
|
3486
|
+
remove("box", id);
|
|
3487
|
+
}
|
|
3488
|
+
function pointX3(point, xloc) {
|
|
3489
|
+
const x = xloc === "bar_time" ? point.time : point.index;
|
|
3490
|
+
return x ?? NaN;
|
|
3491
|
+
}
|
|
3492
|
+
function all4() {
|
|
3493
|
+
return all("box");
|
|
3494
|
+
}
|
|
3495
|
+
function set_top_left_point(id, point) {
|
|
3496
|
+
if (isDeleted(id)) return id;
|
|
3497
|
+
id.left = pointX3(point, id.xloc);
|
|
3498
|
+
id.top = point.price;
|
|
3499
|
+
return id;
|
|
3500
|
+
}
|
|
3501
|
+
function set_bottom_right_point(id, point) {
|
|
3502
|
+
if (isDeleted(id)) return id;
|
|
3503
|
+
id.right = pointX3(point, id.xloc);
|
|
3504
|
+
id.bottom = point.price;
|
|
3505
|
+
return id;
|
|
3506
|
+
}
|
|
3507
|
+
function set_text_formatting2(id, formatting) {
|
|
3508
|
+
if (isDeleted(id)) return id;
|
|
3509
|
+
id.text_formatting = formatting;
|
|
3510
|
+
return id;
|
|
3511
|
+
}
|
|
3512
|
+
|
|
3513
|
+
// src/linefill/index.ts
|
|
3514
|
+
var linefill_exports = {};
|
|
3515
|
+
__export(linefill_exports, {
|
|
3516
|
+
all: () => all5,
|
|
3517
|
+
delete: () => delete_linefill,
|
|
3518
|
+
delete_linefill: () => delete_linefill,
|
|
3519
|
+
get_line1: () => get_line1,
|
|
3520
|
+
get_line2: () => get_line2,
|
|
3521
|
+
new: () => new_linefill,
|
|
3522
|
+
new_linefill: () => new_linefill,
|
|
3523
|
+
set_color: () => set_color3
|
|
3524
|
+
});
|
|
3525
|
+
function new_linefill(line1, line2, fillColor) {
|
|
3526
|
+
return register("linefill", {
|
|
3527
|
+
line1,
|
|
3528
|
+
line2,
|
|
3529
|
+
color: fillColor
|
|
3530
|
+
});
|
|
3531
|
+
}
|
|
3532
|
+
function get_line1(id) {
|
|
3533
|
+
return id.line1;
|
|
3534
|
+
}
|
|
3535
|
+
function get_line2(id) {
|
|
3536
|
+
return id.line2;
|
|
3537
|
+
}
|
|
3538
|
+
function set_color3(id, fillColor) {
|
|
3539
|
+
if (isDeleted(id)) return id;
|
|
3540
|
+
id.color = fillColor;
|
|
3541
|
+
return id;
|
|
3542
|
+
}
|
|
3543
|
+
function delete_linefill(id) {
|
|
3544
|
+
remove("linefill", id);
|
|
3545
|
+
}
|
|
3546
|
+
function all5() {
|
|
3547
|
+
return all("linefill");
|
|
3548
|
+
}
|
|
3549
|
+
|
|
3550
|
+
// src/polyline/index.ts
|
|
3551
|
+
var polyline_exports = {};
|
|
3552
|
+
__export(polyline_exports, {
|
|
3553
|
+
all: () => all6,
|
|
3554
|
+
clear_all: () => clear_all,
|
|
3555
|
+
delete: () => delete_polyline,
|
|
3556
|
+
delete_polyline: () => delete_polyline,
|
|
3557
|
+
get_all: () => get_all,
|
|
3558
|
+
new: () => new_polyline,
|
|
3559
|
+
new_polyline: () => new_polyline,
|
|
3560
|
+
reset_id_counter: () => reset_id_counter
|
|
3561
|
+
});
|
|
3562
|
+
var polylineIdCounter = 0;
|
|
3563
|
+
function generateId() {
|
|
3564
|
+
return `polyline_${++polylineIdCounter}`;
|
|
3565
|
+
}
|
|
3566
|
+
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) {
|
|
3567
|
+
if (curved) {
|
|
3568
|
+
console.warn(
|
|
3569
|
+
"polyline.new(): curved polylines are not yet supported. Using straight-line connections."
|
|
3570
|
+
);
|
|
3571
|
+
}
|
|
3572
|
+
if (line_width < 1) {
|
|
3573
|
+
console.warn("polyline.new(): line_width must be at least 1. Using 1.");
|
|
3574
|
+
line_width = 1;
|
|
3575
|
+
}
|
|
3576
|
+
const polyline2 = {
|
|
3577
|
+
id: generateId(),
|
|
3578
|
+
points: [...points],
|
|
3579
|
+
// Create a copy of the points array
|
|
3580
|
+
curved,
|
|
3581
|
+
closed,
|
|
3582
|
+
xloc,
|
|
3583
|
+
line_color,
|
|
3584
|
+
fill_color,
|
|
3585
|
+
line_style,
|
|
3586
|
+
line_width,
|
|
3587
|
+
force_overlay
|
|
3588
|
+
};
|
|
3589
|
+
return register("polyline", polyline2);
|
|
3590
|
+
}
|
|
3591
|
+
function delete_polyline(id) {
|
|
3592
|
+
remove("polyline", id);
|
|
3593
|
+
}
|
|
3594
|
+
function get_all() {
|
|
3595
|
+
return all("polyline");
|
|
3596
|
+
}
|
|
3597
|
+
function all6() {
|
|
3598
|
+
return all("polyline");
|
|
3599
|
+
}
|
|
3600
|
+
function clear_all() {
|
|
3601
|
+
for (const p of all("polyline")) remove("polyline", p);
|
|
3602
|
+
}
|
|
3603
|
+
function reset_id_counter() {
|
|
3604
|
+
polylineIdCounter = 0;
|
|
3605
|
+
}
|
|
3606
|
+
|
|
3607
|
+
// src/chartpoint/index.ts
|
|
3608
|
+
var chartpoint_exports = {};
|
|
3609
|
+
__export(chartpoint_exports, {
|
|
3610
|
+
copy: () => copy4,
|
|
3611
|
+
from_index: () => from_index,
|
|
3612
|
+
from_time: () => from_time,
|
|
3613
|
+
new: () => new_point,
|
|
3614
|
+
new_point: () => new_point
|
|
3615
|
+
});
|
|
3616
|
+
function new_point(time2, index, price) {
|
|
3617
|
+
return {
|
|
3618
|
+
time: time2,
|
|
3619
|
+
index,
|
|
3620
|
+
price
|
|
3621
|
+
};
|
|
3622
|
+
}
|
|
3623
|
+
function from_time(time2, price) {
|
|
3624
|
+
return {
|
|
3625
|
+
time: time2,
|
|
3626
|
+
index: null,
|
|
3627
|
+
price
|
|
3628
|
+
};
|
|
3629
|
+
}
|
|
3630
|
+
function from_index(index, price) {
|
|
3631
|
+
return {
|
|
3632
|
+
time: null,
|
|
3633
|
+
index,
|
|
3634
|
+
price
|
|
3635
|
+
};
|
|
3636
|
+
}
|
|
3637
|
+
function copy4(point) {
|
|
3638
|
+
return {
|
|
3639
|
+
time: point.time,
|
|
3640
|
+
index: point.index,
|
|
3641
|
+
price: point.price
|
|
3642
|
+
};
|
|
3643
|
+
}
|
|
3644
|
+
|
|
3645
|
+
// src/text/index.ts
|
|
3646
|
+
var text_exports = {};
|
|
3647
|
+
__export(text_exports, {
|
|
3648
|
+
format_bold: () => format_bold,
|
|
3649
|
+
format_italic: () => format_italic,
|
|
3650
|
+
format_none: () => format_none
|
|
3651
|
+
});
|
|
3652
|
+
var format_none = 0;
|
|
3653
|
+
var format_bold = 1;
|
|
3654
|
+
var format_italic = 2;
|
|
3655
|
+
|
|
3656
|
+
// src/timeframe/index.ts
|
|
3657
|
+
var timeframe_exports = {};
|
|
3658
|
+
__export(timeframe_exports, {
|
|
3659
|
+
from_seconds: () => from_seconds,
|
|
3660
|
+
in_seconds: () => in_seconds,
|
|
3661
|
+
info: () => info
|
|
3662
|
+
});
|
|
3663
|
+
var SECONDS_PER_MINUTE = 60;
|
|
3664
|
+
var SECONDS_PER_DAY = 86400;
|
|
3665
|
+
var SECONDS_PER_WEEK = 604800;
|
|
3666
|
+
var SECONDS_PER_MONTH = 2628003;
|
|
3667
|
+
var SECONDS_365_DAYS = 365 * SECONDS_PER_DAY;
|
|
3668
|
+
var UNIT_SECONDS = {
|
|
3669
|
+
S: 1,
|
|
3670
|
+
"": SECONDS_PER_MINUTE,
|
|
3671
|
+
D: SECONDS_PER_DAY,
|
|
3672
|
+
W: SECONDS_PER_WEEK,
|
|
3673
|
+
M: SECONDS_PER_MONTH
|
|
3674
|
+
};
|
|
3675
|
+
var SECOND_TIMEFRAMES = [1, 5, 10, 15, 30];
|
|
3676
|
+
function in_seconds(timeframe2) {
|
|
3677
|
+
const text2 = timeframe2.trim();
|
|
3678
|
+
if (text2 === "") {
|
|
3679
|
+
throw new RangeError("timeframe.in_seconds() needs a timeframe: the chart timeframe is not known here");
|
|
3680
|
+
}
|
|
3681
|
+
const before = /^(\d*)([SDWMT]?)$/.exec(text2);
|
|
3682
|
+
const after = before ? null : /^([SDWMT])(\d+)$/.exec(text2);
|
|
3683
|
+
if (!before && !after) throw new RangeError(`Invalid timeframe "${timeframe2}"`);
|
|
3684
|
+
const [digits, unit] = before ? [before[1], before[2]] : [after[2], after[1]];
|
|
3685
|
+
if (unit === "T") return NaN;
|
|
3686
|
+
const multiplier = digits === "" ? 1 : Number(digits);
|
|
3687
|
+
return multiplier * UNIT_SECONDS[unit];
|
|
3688
|
+
}
|
|
3689
|
+
function from_seconds(seconds) {
|
|
3690
|
+
if (Number.isNaN(seconds)) throw new RangeError("timeframe.from_seconds() needs a number of seconds");
|
|
3691
|
+
if (seconds >= SECONDS_365_DAYS) return "12M";
|
|
3692
|
+
if (seconds > 0) {
|
|
3693
|
+
if (seconds % SECONDS_PER_MONTH === 0) return `${seconds / SECONDS_PER_MONTH}M`;
|
|
3694
|
+
if (seconds % SECONDS_PER_WEEK === 0) return `${seconds / SECONDS_PER_WEEK}W`;
|
|
3695
|
+
if (seconds % SECONDS_PER_DAY === 0) return `${seconds / SECONDS_PER_DAY}D`;
|
|
3696
|
+
if (seconds % SECONDS_PER_MINUTE === 0 && seconds < SECONDS_PER_DAY) return `${seconds / SECONDS_PER_MINUTE}`;
|
|
3697
|
+
}
|
|
3698
|
+
const second3 = SECOND_TIMEFRAMES.find((m) => seconds <= m);
|
|
3699
|
+
if (second3 !== void 0) return `${second3}S`;
|
|
3700
|
+
if (seconds < SECONDS_PER_DAY) return `${Math.ceil(seconds / SECONDS_PER_MINUTE)}`;
|
|
3701
|
+
return `${Math.ceil(seconds / SECONDS_PER_DAY)}D`;
|
|
3702
|
+
}
|
|
3703
|
+
function info(timeframe2) {
|
|
3704
|
+
const text2 = timeframe2.trim();
|
|
3705
|
+
const m = /^(\d*)([SDWMT]?)$/.exec(text2);
|
|
3706
|
+
if (!m || text2 === "") throw new RangeError(`Invalid timeframe "${timeframe2}"`);
|
|
3707
|
+
const unit = m[2];
|
|
3708
|
+
const multiplier = m[1] === "" ? 1 : Number(m[1]);
|
|
3709
|
+
return {
|
|
3710
|
+
period: unit === "" ? String(multiplier) : `${multiplier}${unit}`,
|
|
3711
|
+
multiplier,
|
|
3712
|
+
isintraday: unit === "" || unit === "S" || unit === "T",
|
|
3713
|
+
isdaily: unit === "D",
|
|
3714
|
+
isweekly: unit === "W",
|
|
3715
|
+
ismonthly: unit === "M",
|
|
3716
|
+
isminutes: unit === "",
|
|
3717
|
+
isseconds: unit === "S",
|
|
3718
|
+
isticks: unit === "T",
|
|
3719
|
+
isdwm: unit === "D" || unit === "W" || unit === "M"
|
|
3720
|
+
};
|
|
3721
|
+
}
|
|
3722
|
+
|
|
3723
|
+
// src/time/timezone.ts
|
|
3724
|
+
var MS_PER_SECOND = 1e3;
|
|
3725
|
+
var MS_PER_DAY = 864e5;
|
|
3726
|
+
var MAX_OFFSET_SECONDS = 18 * 3600;
|
|
3727
|
+
var OFFSET_NOTATION = /^(?:UTC|GMT)(?:([+-])(\d{1,2})(?::?(\d{2})(?::?(\d{2}))?)?)?$/;
|
|
3728
|
+
var REJECTED_NAMES = /* @__PURE__ */ new Set(["EST", "MST", "HST"]);
|
|
3729
|
+
var canonicalNames;
|
|
3730
|
+
function hasTimeZoneCase(name) {
|
|
3731
|
+
if (name.split("/").some((segment) => !/^[A-Z]/.test(segment))) return false;
|
|
3732
|
+
canonicalNames ??= new Map(Intl.supportedValuesOf("timeZone").map((n) => [n.toLowerCase(), n]));
|
|
3733
|
+
const canonical = canonicalNames.get(name.toLowerCase());
|
|
3734
|
+
return canonical === void 0 || canonical === name;
|
|
3735
|
+
}
|
|
3736
|
+
var zones = /* @__PURE__ */ new Map();
|
|
3737
|
+
function resolveZone(timezone) {
|
|
3738
|
+
let zone = zones.get(timezone);
|
|
3739
|
+
if (zone) return zone;
|
|
3740
|
+
const invalid = () => new RangeError(
|
|
3741
|
+
`Invalid time zone "${timezone}": use UTC/GMT offset notation ("UTC-5", "GMT+0530") or an IANA name ("America/New_York")`
|
|
3742
|
+
);
|
|
3743
|
+
const m = OFFSET_NOTATION.exec(timezone);
|
|
3744
|
+
if (m) {
|
|
3745
|
+
const [, sign2, h = "0", mi = "0", s] = m;
|
|
3746
|
+
const minutes = Number(mi);
|
|
3747
|
+
const seconds = s === void 0 ? 0 : Number(s);
|
|
3748
|
+
if (minutes > 59 || seconds > 59 || s !== void 0 && h.length !== 2) throw invalid();
|
|
3749
|
+
const offsetSeconds = Number(h) * 3600 + minutes * 60 + seconds;
|
|
3750
|
+
if (offsetSeconds > MAX_OFFSET_SECONDS) throw invalid();
|
|
3751
|
+
zone = { kind: "fixed", offsetMs: (sign2 === "-" ? -offsetSeconds : offsetSeconds) * MS_PER_SECOND };
|
|
3752
|
+
} else {
|
|
3753
|
+
if (REJECTED_NAMES.has(timezone) || !hasTimeZoneCase(timezone)) throw invalid();
|
|
3754
|
+
let format2;
|
|
3755
|
+
try {
|
|
3756
|
+
format2 = new Intl.DateTimeFormat("en-US", {
|
|
3757
|
+
timeZone: timezone,
|
|
3758
|
+
hourCycle: "h23",
|
|
3759
|
+
year: "numeric",
|
|
3760
|
+
month: "numeric",
|
|
3761
|
+
day: "numeric",
|
|
3762
|
+
hour: "numeric",
|
|
3763
|
+
minute: "numeric",
|
|
3764
|
+
second: "numeric"
|
|
3765
|
+
});
|
|
3766
|
+
} catch {
|
|
3767
|
+
throw invalid();
|
|
3768
|
+
}
|
|
3769
|
+
zone = { kind: "iana", format: format2 };
|
|
3770
|
+
}
|
|
3771
|
+
zones.set(timezone, zone);
|
|
3772
|
+
return zone;
|
|
3773
|
+
}
|
|
3774
|
+
function offsetAt(zone, time2) {
|
|
3775
|
+
if (zone.kind === "fixed") return zone.offsetMs;
|
|
3776
|
+
const wholeSecond = Math.floor(time2 / 1e3) * 1e3;
|
|
3777
|
+
const f = {};
|
|
3778
|
+
for (const part of zone.format.formatToParts(wholeSecond)) {
|
|
3779
|
+
if (part.type !== "literal") f[part.type] = Number(part.value);
|
|
3780
|
+
}
|
|
3781
|
+
const local = Date.UTC(f.year, f.month - 1, f.day, f.hour, f.minute, f.second);
|
|
3782
|
+
return local - wholeSecond;
|
|
3783
|
+
}
|
|
3784
|
+
function zoneOffset(time2, timezone) {
|
|
3785
|
+
return offsetAt(resolveZone(timezone), time2);
|
|
3786
|
+
}
|
|
3787
|
+
function zonedFields(time2, timezone) {
|
|
3788
|
+
const local = new Date(time2 + offsetAt(resolveZone(timezone), time2));
|
|
3789
|
+
return {
|
|
3790
|
+
year: local.getUTCFullYear(),
|
|
3791
|
+
month: local.getUTCMonth() + 1,
|
|
3792
|
+
day: local.getUTCDate(),
|
|
3793
|
+
hour: local.getUTCHours(),
|
|
3794
|
+
minute: local.getUTCMinutes(),
|
|
3795
|
+
second: local.getUTCSeconds(),
|
|
3796
|
+
dayOfWeek: local.getUTCDay() + 1
|
|
3797
|
+
};
|
|
3798
|
+
}
|
|
3799
|
+
function zonedToUnix(timezone, year3, month3, day, hour3 = 0, minute3 = 0, second3 = 0) {
|
|
3800
|
+
const zone = resolveZone(timezone);
|
|
3801
|
+
const local = Date.UTC(year3, month3 - 1, day, hour3, minute3, second3);
|
|
3802
|
+
if (zone.kind === "fixed") return local - zone.offsetMs;
|
|
3803
|
+
const before = offsetAt(zone, local - MS_PER_DAY);
|
|
3804
|
+
const after = offsetAt(zone, local + MS_PER_DAY);
|
|
3805
|
+
const candidates = [local - before, local - after].filter((t2) => local - offsetAt(zone, t2) === t2);
|
|
3806
|
+
if (candidates.length) return Math.max(...candidates);
|
|
3807
|
+
return local - before;
|
|
3808
|
+
}
|
|
3809
|
+
|
|
3810
|
+
// src/time/datestring.ts
|
|
3811
|
+
var MONTHS = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"];
|
|
3812
|
+
var FULL_MONTHS = [
|
|
3813
|
+
"january",
|
|
3814
|
+
"february",
|
|
3815
|
+
"march",
|
|
3816
|
+
"april",
|
|
3817
|
+
"may",
|
|
3818
|
+
"june",
|
|
3819
|
+
"july",
|
|
3820
|
+
"august",
|
|
3821
|
+
"september",
|
|
3822
|
+
"october",
|
|
3823
|
+
"november",
|
|
3824
|
+
"december"
|
|
3825
|
+
];
|
|
3826
|
+
var ZONE_NAMES = {
|
|
3827
|
+
ut: 0,
|
|
3828
|
+
utc: 0,
|
|
3829
|
+
gmt: 0,
|
|
3830
|
+
est: -5,
|
|
3831
|
+
edt: -4,
|
|
3832
|
+
cst: -6,
|
|
3833
|
+
cdt: -5,
|
|
3834
|
+
mst: -7,
|
|
3835
|
+
mdt: -6,
|
|
3836
|
+
pst: -8,
|
|
3837
|
+
pdt: -7
|
|
3838
|
+
};
|
|
3839
|
+
var TIME = String.raw`(\d{1,2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3})\d*)?)?`;
|
|
3840
|
+
var ZONE = String.raw`(ut|utc|gmt|[ecmp][sd]t|(?:utc|gmt)?\s*[+-]\d{1,2}(?::?\d{2})?)`;
|
|
3841
|
+
var NUMERIC_ZONE = String.raw`([+-]\d{2}(?::?\d{2})?)`;
|
|
3842
|
+
var DATE = String.raw`(\d{4})([-/])(\d{1,2})\2(\d{1,2})`;
|
|
3843
|
+
var WEEKDAY = String.raw`(?:[a-z]{3,9},?\s+)?`;
|
|
3844
|
+
var ISO_T = new RegExp(String.raw`^${DATE}t${TIME}\s*${NUMERIC_ZONE}?$`, "i");
|
|
3845
|
+
var ISO = new RegExp(String.raw`^${DATE}(?:\s+${TIME})?\s*${ZONE}?$`, "i");
|
|
3846
|
+
var DAY_FIRST = new RegExp(String.raw`^${WEEKDAY}(\d{1,2})(?:\s+|-)([a-z]+)\.?,?(?:\s+|-)(\d{4})(?:,?\s+${TIME})?\s*${ZONE}?$`, "i");
|
|
3847
|
+
var MONTH_FIRST = new RegExp(String.raw`^${WEEKDAY}([a-z]+)\.?\s+(\d{1,2}),?\s+(\d{4})(?:,?\s+${TIME})?\s*${ZONE}?$`, "i");
|
|
3848
|
+
function monthNumber(name) {
|
|
3849
|
+
const lower2 = name.toLowerCase();
|
|
3850
|
+
const i = FULL_MONTHS.findIndex((full, k) => lower2.startsWith(MONTHS[k]) && full.startsWith(lower2));
|
|
3851
|
+
return i + 1;
|
|
3852
|
+
}
|
|
3853
|
+
function zoneMinutes(zone) {
|
|
3854
|
+
if (!zone) return 0;
|
|
3855
|
+
const lower2 = zone.toLowerCase().replace(/\s+/g, "");
|
|
3856
|
+
const named = ZONE_NAMES[lower2];
|
|
3857
|
+
if (named !== void 0) return named * 60;
|
|
3858
|
+
const m = /^(?:utc|gmt)?([+-])(\d{1,2})(?::?(\d{2}))?$/.exec(lower2);
|
|
3859
|
+
if (!m) return NaN;
|
|
3860
|
+
const minutes = Number(m[2]) * 60 + (m[3] ? Number(m[3]) : 0);
|
|
3861
|
+
return m[1] === "-" ? -minutes : minutes;
|
|
3862
|
+
}
|
|
3863
|
+
function parseDateString(dateString) {
|
|
3864
|
+
const text2 = dateString.trim();
|
|
3865
|
+
let year3, month3, day;
|
|
3866
|
+
let rest;
|
|
3867
|
+
let m;
|
|
3868
|
+
if (m = ISO_T.exec(text2) ?? ISO.exec(text2)) {
|
|
3869
|
+
[year3, month3, day] = [m[1], Number(m[3]), m[4]];
|
|
3870
|
+
rest = m.slice(5);
|
|
3871
|
+
} else if (m = DAY_FIRST.exec(text2)) {
|
|
3872
|
+
[day, month3, year3] = [m[1], monthNumber(m[2]), m[3]];
|
|
3873
|
+
rest = m.slice(4);
|
|
3874
|
+
} else if (m = MONTH_FIRST.exec(text2)) {
|
|
3875
|
+
[month3, day, year3] = [monthNumber(m[1]), m[2], m[3]];
|
|
3876
|
+
rest = m.slice(4);
|
|
3877
|
+
} else {
|
|
3878
|
+
throw new SyntaxError(`Invalid date string "${dateString}": use RFC 2822 or ISO 8601 ("20 Feb 2020", "2020-02-20T14:48:00")`);
|
|
3879
|
+
}
|
|
3880
|
+
const [hour3 = "0", minute3 = "0", second3 = "0", millis = "0", zone] = rest;
|
|
3881
|
+
const d = Number(day);
|
|
3882
|
+
const h = Number(hour3);
|
|
3883
|
+
const mi = Number(minute3);
|
|
3884
|
+
const s = Number(second3);
|
|
3885
|
+
const offset = zoneMinutes(zone);
|
|
3886
|
+
const endOfDay = h === 24 && mi === 0 && s === 0 && Number(millis) === 0;
|
|
3887
|
+
if (month3 < 1 || month3 > 12 || d < 1 || d > 31 || h > 23 && !endOfDay || mi > 59 || s > 59 || Number.isNaN(offset)) {
|
|
3888
|
+
throw new SyntaxError(`Invalid date string "${dateString}": a field is out of range`);
|
|
3889
|
+
}
|
|
3890
|
+
const ms = Number(millis.padEnd(3, "0"));
|
|
3891
|
+
return Date.UTC(Number(year3), month3 - 1, d, h, mi, s, ms) - offset * 6e4;
|
|
3892
|
+
}
|
|
3893
|
+
|
|
3894
|
+
// src/time/session.ts
|
|
3895
|
+
var PERIOD = /^(\d{2})(\d{2})-(\d{2})(\d{2})$/;
|
|
3896
|
+
var sessions = /* @__PURE__ */ new Map();
|
|
3897
|
+
function parseSession(session2) {
|
|
3898
|
+
let parsed = sessions.get(session2);
|
|
3899
|
+
if (parsed) return parsed;
|
|
3900
|
+
const invalid = () => new SyntaxError(`Invalid session "${session2}": expected "HHmm-HHmm[,HHmm-HHmm...][:days]"`);
|
|
3901
|
+
const text2 = session2.trim() === "24x7" ? "0000-0000" : session2.replace(/\s+/g, "");
|
|
3902
|
+
const [periodText = "", dayText, extra] = text2.split(":");
|
|
3903
|
+
if (extra !== void 0 || periodText === "") throw invalid();
|
|
3904
|
+
const periods = periodText.split(",").map((p) => {
|
|
3905
|
+
const m = PERIOD.exec(p);
|
|
3906
|
+
if (!m) throw invalid();
|
|
3907
|
+
const [h1, m1, h2, m2] = [m[1], m[2], m[3], m[4]].map(Number);
|
|
3908
|
+
if (h1 > 23 || h2 > 23 || m1 > 59 || m2 > 59) throw invalid();
|
|
3909
|
+
return { start: h1 * 60 + m1, end: h2 * 60 + m2 };
|
|
3910
|
+
});
|
|
3911
|
+
const dayDigits = dayText ?? (periods.length > 1 ? "23456" : "1234567");
|
|
3912
|
+
if (!/^[1-7]+$/.test(dayDigits)) throw invalid();
|
|
3913
|
+
const days = new Array(8).fill(false);
|
|
3914
|
+
for (const d of dayDigits) days[Number(d)] = true;
|
|
3915
|
+
parsed = { periods, days };
|
|
3916
|
+
sessions.set(session2, parsed);
|
|
3917
|
+
return parsed;
|
|
3918
|
+
}
|
|
3919
|
+
function inSession(time2, session2, timezone) {
|
|
3920
|
+
if (Number.isNaN(time2)) return false;
|
|
3921
|
+
const { periods, days } = parseSession(session2);
|
|
3922
|
+
const f = zonedFields(time2, timezone);
|
|
3923
|
+
const minute3 = f.hour * 60 + f.minute;
|
|
3924
|
+
const nextDay = f.dayOfWeek % 7 + 1;
|
|
3925
|
+
for (const { start, end } of periods) {
|
|
3926
|
+
if (start < end || start === 0 && end === 0) {
|
|
3927
|
+
if (minute3 >= start && (minute3 < end || end === 0) && days[f.dayOfWeek]) return true;
|
|
3928
|
+
} else {
|
|
3929
|
+
if (minute3 >= start && days[nextDay]) return true;
|
|
3930
|
+
if (minute3 < end && days[f.dayOfWeek]) return true;
|
|
3931
|
+
}
|
|
3932
|
+
}
|
|
3933
|
+
return false;
|
|
3934
|
+
}
|
|
3935
|
+
|
|
3936
|
+
// src/time/index.ts
|
|
3937
|
+
function timestamp(first, ...rest) {
|
|
3938
|
+
if (typeof first === "string") {
|
|
3939
|
+
if (rest.length === 0) return parseDateString(first);
|
|
3940
|
+
const [year3, month4, day2, hour4, minute4, second4] = rest;
|
|
3941
|
+
return zonedToUnix(first, year3, month4, day2, hour4 ?? 0, minute4 ?? 0, second4 ?? 0);
|
|
3942
|
+
}
|
|
3943
|
+
const [month3, day, hour3, minute3, second3] = rest;
|
|
3944
|
+
return new Date(first, month3 - 1, day, hour3 || 0, minute3 || 0, second3 || 0).getTime();
|
|
3945
|
+
}
|
|
3946
|
+
function field(time2, timezone, pick) {
|
|
3947
|
+
return Number.isNaN(time2) ? NaN : pick(zonedFields(time2, timezone));
|
|
3948
|
+
}
|
|
3949
|
+
function year(time2, timezone) {
|
|
3950
|
+
return field(time2, timezone, (f) => f.year);
|
|
3951
|
+
}
|
|
3952
|
+
function month(time2, timezone) {
|
|
3953
|
+
return field(time2, timezone, (f) => f.month);
|
|
3954
|
+
}
|
|
3955
|
+
function dayofmonth(time2, timezone) {
|
|
3956
|
+
return field(time2, timezone, (f) => f.day);
|
|
3957
|
+
}
|
|
3958
|
+
function dayofweek(time2, timezone) {
|
|
3959
|
+
return field(time2, timezone, (f) => f.dayOfWeek);
|
|
3960
|
+
}
|
|
3961
|
+
function weekofyear(time2, timezone) {
|
|
3962
|
+
return field(time2, timezone, (f) => {
|
|
3963
|
+
const date = Date.UTC(f.year, f.month - 1, f.day);
|
|
3964
|
+
const mondayBased = (f.dayOfWeek + 5) % 7;
|
|
3965
|
+
const thursday = new Date(date + (3 - mondayBased) * 864e5);
|
|
3966
|
+
const yearStart = Date.UTC(thursday.getUTCFullYear(), 0, 1);
|
|
3967
|
+
return 1 + Math.floor((thursday.getTime() - yearStart) / (7 * 864e5));
|
|
3968
|
+
});
|
|
3969
|
+
}
|
|
3970
|
+
function hour(time2, timezone) {
|
|
3971
|
+
return field(time2, timezone, (f) => f.hour);
|
|
3972
|
+
}
|
|
3973
|
+
function minute(time2, timezone) {
|
|
3974
|
+
return field(time2, timezone, (f) => f.minute);
|
|
3975
|
+
}
|
|
3976
|
+
function second(time2, timezone) {
|
|
3977
|
+
return field(time2, timezone, (f) => f.second);
|
|
3978
|
+
}
|
|
3979
|
+
function inSession2(time2, session2, timezone) {
|
|
3980
|
+
return inSession(time2, session2, timezone);
|
|
3981
|
+
}
|
|
3982
|
+
|
|
3983
|
+
// src/str/index.ts
|
|
3984
|
+
var str_exports = {};
|
|
3985
|
+
__export(str_exports, {
|
|
3986
|
+
charAt: () => charAt,
|
|
3987
|
+
concat: () => concat,
|
|
3988
|
+
contains: () => contains,
|
|
3989
|
+
endswith: () => endswith,
|
|
3990
|
+
format: () => format,
|
|
3991
|
+
format_time: () => format_time,
|
|
3992
|
+
length: () => length,
|
|
3993
|
+
lower: () => lower,
|
|
3994
|
+
match: () => match,
|
|
3995
|
+
pos: () => pos,
|
|
3996
|
+
repeat: () => repeat,
|
|
3997
|
+
replace: () => replace,
|
|
3998
|
+
replace_all: () => replace_all,
|
|
3999
|
+
split: () => split,
|
|
4000
|
+
startswith: () => startswith,
|
|
4001
|
+
substring: () => substring,
|
|
4002
|
+
tonumber: () => tonumber,
|
|
4003
|
+
tostring: () => tostring,
|
|
4004
|
+
trim: () => trim,
|
|
4005
|
+
trimLeft: () => trimLeft,
|
|
4006
|
+
trimRight: () => trimRight,
|
|
4007
|
+
upper: () => upper
|
|
4008
|
+
});
|
|
4009
|
+
|
|
4010
|
+
// src/str/numberformat.ts
|
|
4011
|
+
var patterns = /* @__PURE__ */ new Map();
|
|
4012
|
+
function parsePattern(pattern) {
|
|
4013
|
+
const cached = patterns.get(pattern);
|
|
4014
|
+
if (cached) return cached;
|
|
4015
|
+
let prefix = "";
|
|
4016
|
+
let suffix = "";
|
|
4017
|
+
let number2 = "";
|
|
4018
|
+
let percent = false;
|
|
4019
|
+
let phase = "prefix";
|
|
4020
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
4021
|
+
const ch = pattern[i];
|
|
4022
|
+
let literal;
|
|
4023
|
+
if (ch === "'") {
|
|
4024
|
+
const end = pattern.indexOf("'", i + 1);
|
|
4025
|
+
if (end === i + 1) {
|
|
4026
|
+
literal = "'";
|
|
4027
|
+
i = end;
|
|
4028
|
+
} else {
|
|
4029
|
+
literal = pattern.slice(i + 1, end === -1 ? void 0 : end);
|
|
4030
|
+
i = end === -1 ? pattern.length : end;
|
|
4031
|
+
}
|
|
4032
|
+
} else if (phase !== "suffix" && ("#0,.".includes(ch) || phase === "number" && ch === "E")) {
|
|
4033
|
+
phase = "number";
|
|
4034
|
+
number2 += ch;
|
|
4035
|
+
continue;
|
|
4036
|
+
} else {
|
|
4037
|
+
if (ch === "%") percent = true;
|
|
4038
|
+
literal = ch;
|
|
4039
|
+
}
|
|
4040
|
+
if (phase === "number") phase = "suffix";
|
|
4041
|
+
if (phase === "prefix") prefix += literal;
|
|
4042
|
+
else suffix += literal;
|
|
4043
|
+
}
|
|
4044
|
+
const [mantissa = "", exp2] = number2.split("E");
|
|
4045
|
+
const [intPart = "", fracPart = ""] = mantissa.split(".");
|
|
4046
|
+
const lastComma = intPart.lastIndexOf(",");
|
|
4047
|
+
const parsed = {
|
|
4048
|
+
prefix,
|
|
4049
|
+
suffix,
|
|
4050
|
+
// as in Java, a pattern with a decimal point and no '0' at all ("#.##") shows one integer digit
|
|
4051
|
+
minInt: !mantissa.includes("0") && mantissa.includes(".") ? 1 : [...intPart].filter((c) => c === "0").length,
|
|
4052
|
+
minFrac: [...fracPart].filter((c) => c === "0").length,
|
|
4053
|
+
maxFrac: [...fracPart].filter((c) => c === "0" || c === "#").length,
|
|
4054
|
+
grouping: lastComma === -1 ? 0 : intPart.length - lastComma - 1,
|
|
4055
|
+
percent,
|
|
4056
|
+
exponent: exp2 === void 0 ? null : exp2.length,
|
|
4057
|
+
hasDigits: /[0#]/.test(mantissa)
|
|
4058
|
+
};
|
|
4059
|
+
patterns.set(pattern, parsed);
|
|
4060
|
+
return parsed;
|
|
4061
|
+
}
|
|
4062
|
+
function shortestDigits(x) {
|
|
4063
|
+
const m = /^(\d+)(?:\.(\d+))?(?:e([+-]\d+))?$/.exec(String(Math.abs(x)));
|
|
4064
|
+
const all7 = m[1] + (m[2] ?? "");
|
|
4065
|
+
let intLen = m[1].length + Number(m[3] ?? 0);
|
|
4066
|
+
const lead = all7.length - all7.replace(/^0+/, "").length;
|
|
4067
|
+
intLen -= lead;
|
|
4068
|
+
const digits = all7.slice(lead).replace(/0+$/, "");
|
|
4069
|
+
return { digits, intLen: digits ? intLen : 0 };
|
|
4070
|
+
}
|
|
4071
|
+
function exactDigits(x) {
|
|
4072
|
+
const abs2 = Math.abs(x);
|
|
4073
|
+
if (abs2 === 0) return { digits: "", intLen: 0 };
|
|
4074
|
+
const view = new DataView(new ArrayBuffer(8));
|
|
4075
|
+
view.setFloat64(0, abs2);
|
|
4076
|
+
const bits = view.getBigUint64(0);
|
|
4077
|
+
const expBits = Number(bits >> 52n & 0x7ffn);
|
|
4078
|
+
let mant = bits & 0xfffffffffffffn;
|
|
4079
|
+
const e2 = expBits === 0 ? -1074 : expBits - 1075;
|
|
4080
|
+
if (expBits !== 0) mant |= 1n << 52n;
|
|
4081
|
+
let str2;
|
|
4082
|
+
let fracDigits;
|
|
4083
|
+
if (e2 >= 0) {
|
|
4084
|
+
str2 = (mant << BigInt(e2)).toString();
|
|
4085
|
+
fracDigits = 0;
|
|
4086
|
+
} else {
|
|
4087
|
+
str2 = (mant * 5n ** BigInt(-e2)).toString();
|
|
4088
|
+
fracDigits = -e2;
|
|
4089
|
+
}
|
|
4090
|
+
const intLen = str2.length - fracDigits;
|
|
4091
|
+
const lead = str2.length - str2.replace(/^0+/, "").length;
|
|
4092
|
+
const digits = str2.slice(lead).replace(/0+$/, "");
|
|
4093
|
+
return { digits, intLen: intLen - lead };
|
|
4094
|
+
}
|
|
4095
|
+
function roundDigits(d, frac, mode3) {
|
|
4096
|
+
const keep = d.intLen + frac;
|
|
4097
|
+
if (keep >= d.digits.length) return d;
|
|
4098
|
+
if (keep < 0) return { digits: "", intLen: 0 };
|
|
4099
|
+
const first = d.digits.charCodeAt(keep) - 48;
|
|
4100
|
+
let up;
|
|
4101
|
+
if (mode3 === "halfUpShortest") up = first >= 5;
|
|
4102
|
+
else if (first !== 5) up = first > 5;
|
|
4103
|
+
else if (d.digits.length > keep + 1) up = true;
|
|
4104
|
+
else up = keep > 0 && (d.digits.charCodeAt(keep - 1) - 48) % 2 === 1;
|
|
4105
|
+
let kept = d.digits.slice(0, keep);
|
|
4106
|
+
let intLen = d.intLen;
|
|
4107
|
+
if (up) {
|
|
4108
|
+
const n = (BigInt(kept || "0") + 1n).toString();
|
|
4109
|
+
if (n.length > kept.length) intLen += 1;
|
|
4110
|
+
kept = n;
|
|
4111
|
+
}
|
|
4112
|
+
kept = kept.replace(/0+$/, "");
|
|
4113
|
+
return { digits: kept, intLen: kept ? intLen : 0 };
|
|
4114
|
+
}
|
|
4115
|
+
function group(int, size) {
|
|
4116
|
+
if (!size || int.length <= size) return int;
|
|
4117
|
+
const parts = [];
|
|
4118
|
+
for (let end = int.length; end > 0; end -= size) parts.unshift(int.slice(Math.max(0, end - size), end));
|
|
4119
|
+
return parts.join(",");
|
|
4120
|
+
}
|
|
4121
|
+
function layout(d, p) {
|
|
4122
|
+
let int = d.intLen > 0 ? d.digits.slice(0, d.intLen).padEnd(d.intLen, "0") : "";
|
|
4123
|
+
int = int.replace(/^0+/, "").padStart(p.minInt, "0");
|
|
4124
|
+
let frac = d.intLen < 0 ? "0".repeat(-d.intLen) + d.digits : d.digits.slice(Math.max(0, d.intLen));
|
|
4125
|
+
frac = frac.slice(0, p.maxFrac).replace(/0+$/, "").padEnd(p.minFrac, "0");
|
|
4126
|
+
if (!int && !frac) int = "0";
|
|
4127
|
+
return group(int, p.grouping) + (frac ? "." + frac : "");
|
|
4128
|
+
}
|
|
4129
|
+
function formatNumber(value, pattern, mode3) {
|
|
4130
|
+
if (Number.isNaN(value)) return "NaN";
|
|
4131
|
+
const p = parsePattern(pattern);
|
|
4132
|
+
if (!Number.isFinite(value)) return (value < 0 ? "-" : "") + p.prefix + "\u221E" + p.suffix;
|
|
4133
|
+
const x = p.percent ? value * 100 : value;
|
|
4134
|
+
const toDigits = mode3 === "halfUpShortest" ? shortestDigits : exactDigits;
|
|
4135
|
+
let body;
|
|
4136
|
+
let isZero;
|
|
4137
|
+
if (p.exponent !== null) {
|
|
4138
|
+
const rounded = roundDigits(toDigits(x), p.maxFrac, mode3);
|
|
4139
|
+
const intDigits = Math.max(p.minInt, 1);
|
|
4140
|
+
isZero = rounded.digits === "";
|
|
4141
|
+
let exponent = isZero ? 0 : rounded.intLen - intDigits;
|
|
4142
|
+
let mant = roundDigits({ digits: rounded.digits, intLen: isZero ? 0 : intDigits }, p.maxFrac, mode3);
|
|
4143
|
+
if (mant.intLen > intDigits) {
|
|
4144
|
+
exponent += 1;
|
|
4145
|
+
mant = { digits: mant.digits, intLen: intDigits };
|
|
4146
|
+
}
|
|
4147
|
+
const e2 = String(Math.abs(exponent)).padStart(p.exponent, "0");
|
|
4148
|
+
body = layout(mant, p) + "E" + (exponent < 0 ? "-" : "") + e2;
|
|
4149
|
+
} else {
|
|
4150
|
+
const rounded = roundDigits(toDigits(x), p.hasDigits ? p.maxFrac : 0, mode3);
|
|
4151
|
+
isZero = rounded.digits === "";
|
|
4152
|
+
body = p.hasDigits ? layout(rounded, p) : layout(rounded, { ...p, minInt: 0, maxFrac: 0, minFrac: 0 });
|
|
4153
|
+
}
|
|
4154
|
+
const negative = x < 0 && (!isZero || !p.hasDigits);
|
|
4155
|
+
return (negative ? "-" : "") + p.prefix + body + p.suffix;
|
|
4156
|
+
}
|
|
4157
|
+
|
|
4158
|
+
// src/str/dateformat.ts
|
|
4159
|
+
var MONTHS2 = [
|
|
4160
|
+
"January",
|
|
4161
|
+
"February",
|
|
4162
|
+
"March",
|
|
4163
|
+
"April",
|
|
4164
|
+
"May",
|
|
4165
|
+
"June",
|
|
4166
|
+
"July",
|
|
4167
|
+
"August",
|
|
4168
|
+
"September",
|
|
4169
|
+
"October",
|
|
4170
|
+
"November",
|
|
4171
|
+
"December"
|
|
4172
|
+
];
|
|
4173
|
+
var DAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
4174
|
+
var pad = (n, width) => String(n).padStart(width, "0");
|
|
4175
|
+
function zoneName(time2, timezone, offsetMs) {
|
|
4176
|
+
if (timezone === "Etc/UTC") return "UTC";
|
|
4177
|
+
if (/^(UTC|GMT)/.test(timezone)) {
|
|
4178
|
+
if (offsetMs === 0) return "GMT";
|
|
4179
|
+
const minutes = Math.abs(offsetMs) / 6e4;
|
|
4180
|
+
return `GMT${offsetMs < 0 ? "-" : "+"}${pad(Math.floor(minutes / 60), 2)}:${pad(minutes % 60, 2)}`;
|
|
4181
|
+
}
|
|
4182
|
+
const part = new Intl.DateTimeFormat("en-US", { timeZone: timezone, timeZoneName: "short" }).formatToParts(time2).find((p) => p.type === "timeZoneName");
|
|
4183
|
+
return part?.value ?? timezone;
|
|
4184
|
+
}
|
|
4185
|
+
function weekOfYear(year3, month3, day) {
|
|
4186
|
+
const date = Date.UTC(year3, month3 - 1, day);
|
|
4187
|
+
const dow = new Date(date).getUTCDay();
|
|
4188
|
+
const weekStart2 = date - dow * 864e5;
|
|
4189
|
+
if (weekStart2 + 6 * 864e5 >= Date.UTC(year3 + 1, 0, 1)) return 1;
|
|
4190
|
+
const jan1 = Date.UTC(year3, 0, 1);
|
|
4191
|
+
const jan1Dow = new Date(jan1).getUTCDay();
|
|
4192
|
+
return Math.floor((date - jan1 + jan1Dow * 864e5) / (7 * 864e5)) + 1;
|
|
4193
|
+
}
|
|
4194
|
+
function formatDate(time2, pattern, timezone) {
|
|
4195
|
+
if (Number.isNaN(time2)) return "NaN";
|
|
4196
|
+
const f = zonedFields(time2, timezone);
|
|
4197
|
+
const offset = zoneOffset(time2, timezone);
|
|
4198
|
+
const ms = (time2 % 1e3 + 1e3) % 1e3;
|
|
4199
|
+
const dayOfYear = (Date.UTC(f.year, f.month - 1, f.day) - Date.UTC(f.year, 0, 1)) / 864e5 + 1;
|
|
4200
|
+
let out = "";
|
|
4201
|
+
for (let i = 0; i < pattern.length; ) {
|
|
4202
|
+
const ch = pattern[i];
|
|
4203
|
+
if (ch === "'") {
|
|
4204
|
+
const end = pattern.indexOf("'", i + 1);
|
|
4205
|
+
if (end === i + 1) {
|
|
4206
|
+
out += "'";
|
|
4207
|
+
i += 2;
|
|
4208
|
+
} else {
|
|
4209
|
+
out += pattern.slice(i + 1, end === -1 ? void 0 : end);
|
|
4210
|
+
i = end === -1 ? pattern.length : end + 1;
|
|
4211
|
+
}
|
|
4212
|
+
continue;
|
|
4213
|
+
}
|
|
4214
|
+
if (!/[A-Za-z]/.test(ch)) {
|
|
4215
|
+
out += ch;
|
|
4216
|
+
i++;
|
|
4217
|
+
continue;
|
|
4218
|
+
}
|
|
4219
|
+
let n = 1;
|
|
4220
|
+
while (pattern[i + n] === ch) n++;
|
|
4221
|
+
i += n;
|
|
4222
|
+
const hour12 = f.hour % 12;
|
|
4223
|
+
switch (ch) {
|
|
4224
|
+
case "y":
|
|
4225
|
+
out += n === 2 ? pad(f.year % 100, 2) : pad(f.year, n);
|
|
4226
|
+
break;
|
|
4227
|
+
case "M":
|
|
4228
|
+
out += n >= 4 ? MONTHS2[f.month - 1] : n === 3 ? MONTHS2[f.month - 1].slice(0, 3) : pad(f.month, n);
|
|
4229
|
+
break;
|
|
4230
|
+
case "d":
|
|
4231
|
+
out += pad(f.day, n);
|
|
4232
|
+
break;
|
|
4233
|
+
case "E":
|
|
4234
|
+
out += n >= 4 ? DAYS[f.dayOfWeek - 1] : DAYS[f.dayOfWeek - 1].slice(0, 3);
|
|
4235
|
+
break;
|
|
4236
|
+
case "u":
|
|
4237
|
+
out += pad(f.dayOfWeek === 1 ? 7 : f.dayOfWeek - 1, n);
|
|
4238
|
+
break;
|
|
4239
|
+
case "D":
|
|
4240
|
+
out += pad(dayOfYear, n);
|
|
4241
|
+
break;
|
|
4242
|
+
case "w":
|
|
4243
|
+
out += pad(weekOfYear(f.year, f.month, f.day), n);
|
|
4244
|
+
break;
|
|
4245
|
+
case "H":
|
|
4246
|
+
out += pad(f.hour, n);
|
|
4247
|
+
break;
|
|
4248
|
+
case "k":
|
|
4249
|
+
out += pad(f.hour === 0 ? 24 : f.hour, n);
|
|
4250
|
+
break;
|
|
4251
|
+
case "K":
|
|
4252
|
+
out += pad(hour12, n);
|
|
4253
|
+
break;
|
|
4254
|
+
case "h":
|
|
4255
|
+
out += pad(hour12 === 0 ? 12 : hour12, n);
|
|
4256
|
+
break;
|
|
4257
|
+
case "a":
|
|
4258
|
+
out += f.hour < 12 ? "AM" : "PM";
|
|
4259
|
+
break;
|
|
4260
|
+
case "m":
|
|
4261
|
+
out += pad(f.minute, n);
|
|
4262
|
+
break;
|
|
4263
|
+
case "s":
|
|
4264
|
+
out += pad(f.second, n);
|
|
4265
|
+
break;
|
|
4266
|
+
case "S":
|
|
4267
|
+
out += pad(ms, n);
|
|
4268
|
+
break;
|
|
4269
|
+
case "Z": {
|
|
4270
|
+
const minutes = Math.abs(offset) / 6e4;
|
|
4271
|
+
out += (offset < 0 ? "-" : "+") + pad(Math.floor(minutes / 60), 2) + pad(minutes % 60, 2);
|
|
4272
|
+
break;
|
|
4273
|
+
}
|
|
4274
|
+
case "z":
|
|
4275
|
+
out += zoneName(time2, timezone, offset);
|
|
4276
|
+
break;
|
|
4277
|
+
default:
|
|
4278
|
+
throw new SyntaxError(`Unsupported date pattern letter "${ch}" in "${pattern}"`);
|
|
4279
|
+
}
|
|
4280
|
+
}
|
|
4281
|
+
return out;
|
|
4282
|
+
}
|
|
4283
|
+
|
|
4284
|
+
// src/str/messageformat.ts
|
|
4285
|
+
var DATE_STYLES = {
|
|
4286
|
+
short: "M/d/yy",
|
|
4287
|
+
medium: "MMM d, yyyy",
|
|
4288
|
+
long: "MMMM d, yyyy",
|
|
4289
|
+
full: "EEEE, MMMM d, yyyy"
|
|
4290
|
+
};
|
|
4291
|
+
var TIME_STYLES = {
|
|
4292
|
+
short: "h:mm\u202Fa",
|
|
4293
|
+
medium: "h:mm:ss\u202Fa",
|
|
4294
|
+
long: "h:mm:ss\u202Fa z",
|
|
4295
|
+
full: "h:mm:ss\u202Fa z"
|
|
4296
|
+
};
|
|
4297
|
+
function number(value, pattern) {
|
|
4298
|
+
return typeof value === "number" ? formatNumber(value, pattern, "halfEvenExact") : String(value);
|
|
4299
|
+
}
|
|
4300
|
+
function choice(value, spec) {
|
|
4301
|
+
const options = spec.split("|").map((part) => {
|
|
4302
|
+
const m = /^\s*(-?[\d.]+|-?∞)\s*([#<≤])(.*)$/.exec(part);
|
|
4303
|
+
if (!m) throw new SyntaxError(`Invalid choice format "${spec}"`);
|
|
4304
|
+
const limit = m[1].includes("\u221E") ? m[1].startsWith("-") ? -Infinity : Infinity : Number(m[1]);
|
|
4305
|
+
return { limit: m[2] === "<" ? limit + Number.EPSILON * Math.max(1, Math.abs(limit)) : limit, text: m[3] };
|
|
4306
|
+
});
|
|
4307
|
+
let chosen = options[0];
|
|
4308
|
+
for (const o of options) if (value >= o.limit) chosen = o;
|
|
4309
|
+
return chosen.text;
|
|
4310
|
+
}
|
|
4311
|
+
function formatArgument(value, type, style, timezone) {
|
|
4312
|
+
if (value === void 0) return "";
|
|
4313
|
+
if (!type) return typeof value === "number" ? number(value, "#,##0.###") : String(value);
|
|
4314
|
+
switch (type.trim()) {
|
|
4315
|
+
case "number": {
|
|
4316
|
+
const s = style?.trim();
|
|
4317
|
+
if (!s) return number(value, "#,##0.###");
|
|
4318
|
+
if (s === "integer") return number(value, "#,##0");
|
|
4319
|
+
if (s === "percent") return number(value, "#,##0%");
|
|
4320
|
+
if (s === "currency") return number(value, "'$'#,##0.00");
|
|
4321
|
+
return number(value, style);
|
|
4322
|
+
}
|
|
4323
|
+
case "date":
|
|
4324
|
+
case "time": {
|
|
4325
|
+
const styles = type.trim() === "date" ? DATE_STYLES : TIME_STYLES;
|
|
4326
|
+
const s = style?.trim() ?? "medium";
|
|
4327
|
+
return formatDate(Number(value), styles[s] ?? style, typeof timezone === "function" ? timezone() : timezone);
|
|
4328
|
+
}
|
|
4329
|
+
case "choice":
|
|
4330
|
+
return choice(Number(value), style ?? "");
|
|
4331
|
+
default:
|
|
4332
|
+
throw new SyntaxError(`Unknown format type "${type}"`);
|
|
4333
|
+
}
|
|
4334
|
+
}
|
|
4335
|
+
function formatMessage(pattern, args, timezone) {
|
|
4336
|
+
let out = "";
|
|
4337
|
+
for (let i = 0; i < pattern.length; ) {
|
|
4338
|
+
const ch = pattern[i];
|
|
4339
|
+
if (ch === "'") {
|
|
4340
|
+
if (pattern[i + 1] === "'") {
|
|
4341
|
+
out += "'";
|
|
4342
|
+
i += 2;
|
|
4343
|
+
continue;
|
|
4344
|
+
}
|
|
4345
|
+
const end = pattern.indexOf("'", i + 1);
|
|
4346
|
+
out += pattern.slice(i + 1, end === -1 ? void 0 : end);
|
|
4347
|
+
i = end === -1 ? pattern.length : end + 1;
|
|
4348
|
+
continue;
|
|
4349
|
+
}
|
|
4350
|
+
if (ch !== "{") {
|
|
4351
|
+
out += ch;
|
|
4352
|
+
i++;
|
|
4353
|
+
continue;
|
|
4354
|
+
}
|
|
4355
|
+
let depth = 1;
|
|
4356
|
+
let j = i + 1;
|
|
4357
|
+
let inQuote = false;
|
|
4358
|
+
for (; j < pattern.length && depth > 0; j++) {
|
|
4359
|
+
const c = pattern[j];
|
|
4360
|
+
if (c === "'") inQuote = !inQuote;
|
|
4361
|
+
else if (!inQuote && c === "{") depth++;
|
|
4362
|
+
else if (!inQuote && c === "}") depth--;
|
|
4363
|
+
}
|
|
4364
|
+
const inner = pattern.slice(i + 1, j - 1);
|
|
4365
|
+
const [index = "", type, ...rest] = inner.split(",");
|
|
4366
|
+
const style = rest.length ? rest.join(",") : void 0;
|
|
4367
|
+
const n = Number(index.trim());
|
|
4368
|
+
out += n < args.length ? formatArgument(args[n], type, style, timezone) : `{${inner}}`;
|
|
4369
|
+
i = j;
|
|
4370
|
+
}
|
|
4371
|
+
return out;
|
|
4372
|
+
}
|
|
4373
|
+
|
|
4374
|
+
// src/str/index.ts
|
|
4375
|
+
function length(str2) {
|
|
4376
|
+
return str2.length;
|
|
4377
|
+
}
|
|
4378
|
+
function tostring(value, format2) {
|
|
4379
|
+
if (typeof value !== "number") return String(value);
|
|
4380
|
+
if (!Number.isFinite(value)) return String(value);
|
|
4381
|
+
if (format2 === void 0 || format2 === "") {
|
|
4382
|
+
if (Math.abs(value) >= 1e21 && Number.isFinite(value)) {
|
|
4383
|
+
return String(value).replace("e+", "E").replace(/\.0+E/, "E");
|
|
4384
|
+
}
|
|
4385
|
+
return formatNumber(value, "#.##########", "halfUpShortest");
|
|
4386
|
+
}
|
|
4387
|
+
switch (format2) {
|
|
4388
|
+
case "percent":
|
|
4389
|
+
return formatNumber(value, "0.00", "halfUpShortest") + "%";
|
|
4390
|
+
case "volume": {
|
|
4391
|
+
const abs2 = Math.abs(value);
|
|
4392
|
+
for (const [size, unit] of [[1e12, "T"], [1e9, "B"], [1e6, "M"], [1e3, "K"]]) {
|
|
4393
|
+
if (abs2 >= size) return formatNumber(value / size, "#.###", "halfUpShortest") + unit;
|
|
4394
|
+
}
|
|
4395
|
+
return formatNumber(value, "#", "halfUpShortest");
|
|
4396
|
+
}
|
|
4397
|
+
case "mintick":
|
|
4398
|
+
throw new Error("str.tostring(x, format.mintick) needs the symbol tick size (syminfo.mintick), which is not known here");
|
|
4399
|
+
default:
|
|
4400
|
+
return formatNumber(value, format2, "halfUpShortest");
|
|
4401
|
+
}
|
|
4402
|
+
}
|
|
4403
|
+
function tonumber(str2) {
|
|
4404
|
+
const num = parseFloat(str2);
|
|
4405
|
+
return isNaN(num) ? null : num;
|
|
4406
|
+
}
|
|
4407
|
+
function substring(str2, begin, end) {
|
|
4408
|
+
return str2.substring(begin, end);
|
|
4409
|
+
}
|
|
4410
|
+
function upper(str2) {
|
|
4411
|
+
return str2.toUpperCase();
|
|
4412
|
+
}
|
|
4413
|
+
function lower(str2) {
|
|
4414
|
+
return str2.toLowerCase();
|
|
4415
|
+
}
|
|
4416
|
+
function contains(source, str2) {
|
|
4417
|
+
return source.includes(str2);
|
|
4418
|
+
}
|
|
4419
|
+
function pos(source, str2) {
|
|
4420
|
+
return source.indexOf(str2);
|
|
4421
|
+
}
|
|
4422
|
+
function replace(source, target, replacement, occurrence) {
|
|
4423
|
+
if (occurrence === 0) {
|
|
4424
|
+
return source.replace(target, replacement);
|
|
4425
|
+
} else {
|
|
4426
|
+
return source.replaceAll(target, replacement);
|
|
4427
|
+
}
|
|
4428
|
+
}
|
|
4429
|
+
function replace_all(source, target, replacement) {
|
|
4430
|
+
return source.replaceAll(target, replacement);
|
|
4431
|
+
}
|
|
4432
|
+
function split(str2, separator) {
|
|
4433
|
+
return str2.split(separator);
|
|
4434
|
+
}
|
|
4435
|
+
function concat(...strings) {
|
|
4436
|
+
return strings.join("");
|
|
4437
|
+
}
|
|
4438
|
+
function format(formatStr, ...args) {
|
|
4439
|
+
return formatMessage(formatStr, args, "Etc/UTC");
|
|
4440
|
+
}
|
|
4441
|
+
function startswith(source, str2) {
|
|
4442
|
+
return source.startsWith(str2);
|
|
4443
|
+
}
|
|
4444
|
+
function endswith(source, str2) {
|
|
4445
|
+
return source.endsWith(str2);
|
|
4446
|
+
}
|
|
4447
|
+
function charAt(str2, pos2) {
|
|
4448
|
+
return str2.charAt(pos2);
|
|
4449
|
+
}
|
|
4450
|
+
function trim(str2) {
|
|
4451
|
+
return str2.trim();
|
|
4452
|
+
}
|
|
4453
|
+
function trimLeft(str2) {
|
|
4454
|
+
return str2.trimStart();
|
|
4455
|
+
}
|
|
4456
|
+
function trimRight(str2) {
|
|
4457
|
+
return str2.trimEnd();
|
|
4458
|
+
}
|
|
4459
|
+
function match(source, regex) {
|
|
4460
|
+
return new RegExp(regex).test(source);
|
|
4461
|
+
}
|
|
4462
|
+
function repeat(source, count, separator = "") {
|
|
4463
|
+
if (source == null) return null;
|
|
4464
|
+
if (count <= 0) return "";
|
|
4465
|
+
return Array(count).fill(source).join(separator);
|
|
4466
|
+
}
|
|
4467
|
+
function format_time(time2, format2 = "yyyy-MM-dd'T'HH:mm:ssZ", timezone = "Etc/UTC") {
|
|
4468
|
+
return formatDate(time2, format2, timezone);
|
|
4469
|
+
}
|
|
4470
|
+
|
|
4471
|
+
// src/session/calendar.ts
|
|
4472
|
+
var toDateNum = (y, m, d) => y * 1e4 + m * 100 + d;
|
|
4473
|
+
var utcOf = (date) => Date.UTC(Math.floor(date / 1e4), Math.floor(date / 100) % 100 - 1, date % 100);
|
|
4474
|
+
var fromUtc = (ms) => {
|
|
4475
|
+
const d = new Date(ms);
|
|
4476
|
+
return toDateNum(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate());
|
|
4477
|
+
};
|
|
4478
|
+
var addDays = (date, n) => fromUtc(utcOf(date) + n * 864e5);
|
|
4479
|
+
var weekdayOf = (date) => new Date(utcOf(date)).getUTCDay() + 1;
|
|
4480
|
+
var dateUtcMs = utcOf;
|
|
4481
|
+
function parseTime(token, spec) {
|
|
4482
|
+
const m = /^(\d{2})(\d{2})(?:F(\d+))?$/.exec(token.trim());
|
|
4483
|
+
if (!m) throw new SyntaxError(`Invalid session "${spec}"`);
|
|
4484
|
+
return { minutes: Number(m[1]) * 60 + Number(m[2]), offset: m[3] === void 0 ? void 0 : Number(m[3]) };
|
|
4485
|
+
}
|
|
4486
|
+
function parsePeriods(text2, spec) {
|
|
4487
|
+
if (text2.trim() === "24x7") return [{ start: 0, end: 1440, startOffset: 0, endOffset: 0 }];
|
|
4488
|
+
return text2.split(",").map((p) => {
|
|
4489
|
+
const [a = "", b2 = ""] = p.split("-");
|
|
4490
|
+
const s = parseTime(a, spec);
|
|
4491
|
+
const e2 = parseTime(b2, spec);
|
|
4492
|
+
if (s.minutes === 0 && e2.minutes === 0 && s.offset === void 0 && e2.offset === void 0) {
|
|
4493
|
+
return { start: 0, end: 1440, startOffset: 0, endOffset: 0 };
|
|
4494
|
+
}
|
|
4495
|
+
return {
|
|
4496
|
+
start: s.minutes,
|
|
4497
|
+
end: e2.minutes,
|
|
4498
|
+
startOffset: s.offset ?? (e2.minutes <= s.minutes ? 1 : 0),
|
|
4499
|
+
endOffset: e2.offset ?? 0
|
|
4500
|
+
};
|
|
4501
|
+
});
|
|
4502
|
+
}
|
|
4503
|
+
function parseVersion(text2, from, spec, rule) {
|
|
4504
|
+
const [periodText = "", dayText] = text2.trim().split(":");
|
|
4505
|
+
const periods = parsePeriods(periodText, spec);
|
|
4506
|
+
const allDays = periodText.trim() === "24x7" || rule === "pine" && periods.length === 1;
|
|
4507
|
+
const digits = dayText ?? (allDays ? "1234567" : "23456");
|
|
4508
|
+
if (!/^[1-7]+$/.test(digits)) throw new SyntaxError(`Invalid session days in "${spec}"`);
|
|
4509
|
+
const days = new Array(8).fill(false);
|
|
4510
|
+
for (const d of digits) days[Number(d)] = true;
|
|
4511
|
+
return { from, periods, days };
|
|
4512
|
+
}
|
|
4513
|
+
var TradingCalendar = class {
|
|
4514
|
+
/**
|
|
4515
|
+
* @param timezone - Time zone of the session hours (the exchange time zone)
|
|
4516
|
+
* @param spec - Session information (TradingView format)
|
|
4517
|
+
* @param rule - Days without ":days": 'symbol' (Monday to Friday) or 'pine' (PineScript session strings)
|
|
4518
|
+
*/
|
|
4519
|
+
constructor(timezone, spec, rule = "symbol") {
|
|
4520
|
+
this.timezone = timezone;
|
|
4521
|
+
const [first = "", ...changes] = spec.session.split("#");
|
|
4522
|
+
this.versions = [parseVersion(first, 0, spec.session, rule)];
|
|
4523
|
+
for (const change3 of changes) {
|
|
4524
|
+
const m = /^(\d{8})\/(.+)$/.exec(change3.trim());
|
|
4525
|
+
if (!m) throw new SyntaxError(`Invalid session change in "${spec.session}"`);
|
|
4526
|
+
this.versions.push(parseVersion(m[2], Number(m[1]), spec.session, rule));
|
|
4527
|
+
}
|
|
4528
|
+
for (const part of (spec.corrections ?? "").split(";").filter((p) => p.trim())) {
|
|
4529
|
+
const i = part.lastIndexOf(":");
|
|
4530
|
+
const text2 = part.slice(0, i).trim();
|
|
4531
|
+
const periods = text2 === "dayoff" ? null : parsePeriods(text2, part);
|
|
4532
|
+
for (const date of part.slice(i + 1).split(",")) this.corrections.set(Number(date), periods);
|
|
4533
|
+
}
|
|
4534
|
+
const holidays = Array.isArray(spec.holidays) ? spec.holidays : (spec.holidays ?? "").split(",");
|
|
4535
|
+
this.holidays = new Set(holidays.filter((h) => h.trim()).map(Number));
|
|
4536
|
+
}
|
|
4537
|
+
timezone;
|
|
4538
|
+
versions;
|
|
4539
|
+
corrections = /* @__PURE__ */ new Map();
|
|
4540
|
+
holidays;
|
|
4541
|
+
cache = /* @__PURE__ */ new Map();
|
|
4542
|
+
/** Session periods [start, end) of the trading day `date`; empty when the day has no session. */
|
|
4543
|
+
periods(date) {
|
|
4544
|
+
let out = this.cache.get(date);
|
|
4545
|
+
if (out) return out;
|
|
4546
|
+
let periods = [];
|
|
4547
|
+
const correction = this.corrections.get(date);
|
|
4548
|
+
if (correction !== void 0) {
|
|
4549
|
+
periods = correction ?? [];
|
|
4550
|
+
} else if (!this.holidays.has(date)) {
|
|
4551
|
+
const version = [...this.versions].reverse().find((v) => v.from <= date);
|
|
4552
|
+
if (version.days[weekdayOf(date)]) periods = version.periods;
|
|
4553
|
+
}
|
|
4554
|
+
const y = Math.floor(date / 1e4);
|
|
4555
|
+
const m = Math.floor(date / 100) % 100;
|
|
4556
|
+
const d = date % 100;
|
|
4557
|
+
out = periods.map((p) => [
|
|
4558
|
+
zonedToUnix(this.timezone, y, m, d - p.startOffset, Math.floor(p.start / 60), p.start % 60),
|
|
4559
|
+
zonedToUnix(this.timezone, y, m, d - p.endOffset, Math.floor(p.end / 60), p.end % 60)
|
|
4560
|
+
]);
|
|
4561
|
+
this.cache.set(date, out);
|
|
4562
|
+
return out;
|
|
4563
|
+
}
|
|
4564
|
+
isTradingDay(date) {
|
|
4565
|
+
return this.periods(date).length > 0;
|
|
4566
|
+
}
|
|
4567
|
+
/**
|
|
4568
|
+
* Trading day and period of a time: the period that contains it, else the last period that started
|
|
4569
|
+
* before it. Null when no trading day is found near the time.
|
|
4570
|
+
*/
|
|
4571
|
+
locate(time2) {
|
|
4572
|
+
const f = zonedFields(time2, this.timezone);
|
|
4573
|
+
const local = toDateNum(f.year, f.month, f.day);
|
|
4574
|
+
for (let k = 0; k <= 5; k++) {
|
|
4575
|
+
const date = addDays(local, k);
|
|
4576
|
+
const index = this.periods(date).findIndex(([s, e2]) => s <= time2 && time2 < e2);
|
|
4577
|
+
if (index !== -1) return { date, index, inside: true };
|
|
4578
|
+
}
|
|
4579
|
+
for (let k = 5; k >= -7; k--) {
|
|
4580
|
+
const date = addDays(local, k);
|
|
4581
|
+
const periods = this.periods(date);
|
|
4582
|
+
let index = -1;
|
|
4583
|
+
periods.forEach(([s], i) => {
|
|
4584
|
+
if (s <= time2) index = i;
|
|
4585
|
+
});
|
|
4586
|
+
if (index !== -1) return { date, index, inside: false };
|
|
4587
|
+
}
|
|
4588
|
+
return null;
|
|
4589
|
+
}
|
|
4590
|
+
/** First trading day in [from, to] (dates), or null. */
|
|
4591
|
+
firstTradingDay(from, to) {
|
|
4592
|
+
for (let date = from; date <= to; date = addDays(date, 1)) if (this.isTradingDay(date)) return date;
|
|
4593
|
+
return null;
|
|
4594
|
+
}
|
|
4595
|
+
/** Last trading day in [from, to] (dates), or null. */
|
|
4596
|
+
lastTradingDay(from, to) {
|
|
4597
|
+
for (let date = to; date >= from; date = addDays(date, -1)) if (this.isTradingDay(date)) return date;
|
|
4598
|
+
return null;
|
|
4599
|
+
}
|
|
4600
|
+
};
|
|
4601
|
+
var weekStart = (date) => addDays(date, -((weekdayOf(date) + 5) % 7));
|
|
4602
|
+
var monthStart = (date) => Math.floor(date / 100) * 100 + 1;
|
|
4603
|
+
var monthEnd = (date) => addDays(monthStart(addDays(monthStart(date), 32)), -1);
|
|
4604
|
+
|
|
4605
|
+
// src/session/bars.ts
|
|
4606
|
+
function unitOf(tf) {
|
|
4607
|
+
return { unit: tf.isdaily ? "D" : tf.isweekly ? "W" : "M", n: tf.multiplier };
|
|
4608
|
+
}
|
|
4609
|
+
var yearOf = (date) => Math.floor(date / 1e4);
|
|
4610
|
+
var firstMonday = (year3) => {
|
|
4611
|
+
const jan1 = year3 * 1e4 + 101;
|
|
4612
|
+
const monday = weekStart(jan1);
|
|
4613
|
+
return monday === jan1 ? jan1 : addDays(monday, 7);
|
|
4614
|
+
};
|
|
4615
|
+
var SessionBars = class {
|
|
4616
|
+
constructor(calendar2, chartTimeframe2) {
|
|
4617
|
+
this.calendar = calendar2;
|
|
4618
|
+
this.chart = info(chartTimeframe2);
|
|
4619
|
+
}
|
|
4620
|
+
calendar;
|
|
4621
|
+
chart;
|
|
4622
|
+
yearDays = /* @__PURE__ */ new Map();
|
|
4623
|
+
/** Trading days of a calendar year, in order. */
|
|
4624
|
+
tradingDaysOf(year3) {
|
|
4625
|
+
let days = this.yearDays.get(year3);
|
|
4626
|
+
if (!days) {
|
|
4627
|
+
days = [];
|
|
4628
|
+
for (let date = year3 * 1e4 + 101; yearOf(date) === year3; date = addDays(date, 1)) {
|
|
4629
|
+
if (this.calendar.isTradingDay(date)) days.push(date);
|
|
4630
|
+
}
|
|
4631
|
+
this.yearDays.set(year3, days);
|
|
4632
|
+
}
|
|
4633
|
+
return days;
|
|
4634
|
+
}
|
|
4635
|
+
/**
|
|
4636
|
+
* Dates [from, to] of the `n`-`unit` period that contains `date` (for "D": its first and last trading days).
|
|
4637
|
+
* Periods restart each calendar year.
|
|
4638
|
+
*/
|
|
4639
|
+
periodRange(date, unit, n) {
|
|
4640
|
+
if (unit === "D") {
|
|
4641
|
+
if (n === 1) return [date, date];
|
|
4642
|
+
const days = this.tradingDaysOf(yearOf(date));
|
|
4643
|
+
let k = days.findIndex((d) => d >= date);
|
|
4644
|
+
if (k === -1) return this.periodRange(yearOf(date) * 1e4 + 1e4 + 101, unit, n);
|
|
4645
|
+
k -= k % n;
|
|
4646
|
+
return [days[k], days[Math.min(k + n, days.length) - 1]];
|
|
4647
|
+
}
|
|
4648
|
+
if (unit === "W") {
|
|
4649
|
+
const monday = weekStart(date);
|
|
4650
|
+
const year4 = yearOf(monday);
|
|
4651
|
+
const first = firstMonday(year4);
|
|
4652
|
+
const next = firstMonday(year4 + 1);
|
|
4653
|
+
const k = Math.round((dateUtcMs(monday) - dateUtcMs(first)) / (7 * 864e5));
|
|
4654
|
+
const from = addDays(first, (k - k % n) * 7);
|
|
4655
|
+
const to = addDays(from, n * 7 - 1);
|
|
4656
|
+
return [from, to < next ? to : addDays(next, -1)];
|
|
4657
|
+
}
|
|
4658
|
+
const year3 = yearOf(date);
|
|
4659
|
+
const month3 = Math.floor(date / 100) % 100;
|
|
4660
|
+
const firstMonth = month3 - (month3 - 1) % n;
|
|
4661
|
+
const lastMonth = Math.min(firstMonth + n - 1, 12);
|
|
4662
|
+
return [monthStart(year3 * 1e4 + firstMonth * 100 + 1), monthEnd(year3 * 1e4 + lastMonth * 100 + 1)];
|
|
4663
|
+
}
|
|
4664
|
+
dayStart(date) {
|
|
4665
|
+
return this.calendar.periods(date)[0][0];
|
|
4666
|
+
}
|
|
4667
|
+
dayEnd(date) {
|
|
4668
|
+
const p = this.calendar.periods(date);
|
|
4669
|
+
return p[p.length - 1][1];
|
|
4670
|
+
}
|
|
4671
|
+
/** PineScript `time(tf)` for a bar that opens at `time`; NaN when no trading day is found. */
|
|
4672
|
+
timeOf(time2, timeframe2) {
|
|
4673
|
+
const tf = info(timeframe2);
|
|
4674
|
+
const at = this.calendar.locate(time2);
|
|
4675
|
+
if (!at) return NaN;
|
|
4676
|
+
if (tf.isintraday) {
|
|
4677
|
+
if (this.chart.isdwm) return time2;
|
|
4678
|
+
const [start] = this.calendar.periods(at.date)[at.index];
|
|
4679
|
+
const ms = in_seconds(tf.period) * 1e3;
|
|
4680
|
+
return start + Math.floor((time2 - start) / ms) * ms;
|
|
4681
|
+
}
|
|
4682
|
+
const { unit, n } = unitOf(tf);
|
|
4683
|
+
const [from, to] = this.periodRange(at.date, unit, n);
|
|
4684
|
+
const first = this.calendar.firstTradingDay(from, to);
|
|
4685
|
+
return first === null ? NaN : this.dayStart(first);
|
|
4686
|
+
}
|
|
4687
|
+
/** PineScript `time_close(tf)` for a bar that opens at `time`. */
|
|
4688
|
+
closeOf(time2, timeframe2) {
|
|
4689
|
+
const tf = info(timeframe2);
|
|
4690
|
+
const at = this.calendar.locate(time2);
|
|
4691
|
+
if (!at) return NaN;
|
|
4692
|
+
if (tf.isintraday) {
|
|
4693
|
+
const [, end] = this.calendar.periods(at.date)[at.index];
|
|
4694
|
+
if (this.chart.isdwm) return end;
|
|
4695
|
+
return Math.min(this.timeOf(time2, timeframe2) + in_seconds(tf.period) * 1e3, end);
|
|
4696
|
+
}
|
|
4697
|
+
const { unit, n } = unitOf(tf);
|
|
4698
|
+
const [from, to] = this.periodRange(at.date, unit, n);
|
|
4699
|
+
if (this.chart.isintraday && (unit !== "D" || n > 1)) {
|
|
4700
|
+
const [nextFrom, nextTo] = this.periodRange(addDays(to, 1), unit, n);
|
|
4701
|
+
const first = this.calendar.firstTradingDay(nextFrom, addDays(nextTo, 31));
|
|
4702
|
+
return first === null ? NaN : this.dayStart(first);
|
|
4703
|
+
}
|
|
4704
|
+
const last = this.calendar.lastTradingDay(from, to);
|
|
4705
|
+
return last === null ? NaN : this.dayEnd(last);
|
|
4706
|
+
}
|
|
4707
|
+
/** Trading day of a bar: on D / W / M charts the last trading day of the chart period. */
|
|
4708
|
+
tradingDay(time2) {
|
|
4709
|
+
const at = this.calendar.locate(time2);
|
|
4710
|
+
if (!at) return null;
|
|
4711
|
+
if (this.chart.isdwm) {
|
|
4712
|
+
const { unit, n } = unitOf(this.chart);
|
|
4713
|
+
const [from, to] = this.periodRange(at.date, unit, n);
|
|
4714
|
+
return this.calendar.lastTradingDay(from, to);
|
|
4715
|
+
}
|
|
4716
|
+
return at.date;
|
|
4717
|
+
}
|
|
4718
|
+
/**
|
|
4719
|
+
* End of the `timeframe` period that contains `time`: the intraday close, the session end of the day,
|
|
4720
|
+
* or the session end of the last trading day of the period. Used to know whether the last loaded
|
|
4721
|
+
* bar completes a higher-timeframe period (request.security).
|
|
4722
|
+
*/
|
|
4723
|
+
periodEnd(time2, timeframe2) {
|
|
4724
|
+
const tf = info(timeframe2);
|
|
4725
|
+
const at = this.calendar.locate(time2);
|
|
4726
|
+
if (!at) return NaN;
|
|
4727
|
+
if (tf.isintraday) {
|
|
4728
|
+
const [, end] = this.calendar.periods(at.date)[at.index];
|
|
4729
|
+
return Math.min(this.timeOf(time2, timeframe2) + in_seconds(tf.period) * 1e3, end);
|
|
4730
|
+
}
|
|
4731
|
+
const { unit, n } = unitOf(tf);
|
|
4732
|
+
const [from, to] = this.periodRange(at.date, unit, n);
|
|
4733
|
+
const last = this.calendar.lastTradingDay(from, to);
|
|
4734
|
+
return last === null ? NaN : this.dayEnd(last);
|
|
4735
|
+
}
|
|
4736
|
+
/** PineScript `time_tradingday`: 00:00 UTC of the trading day. */
|
|
4737
|
+
tradingDayTime(time2) {
|
|
4738
|
+
const day = this.tradingDay(time2);
|
|
4739
|
+
return day === null ? NaN : dateUtcMs(day);
|
|
4740
|
+
}
|
|
4741
|
+
/** True when the bar at `time` is inside the session. */
|
|
4742
|
+
inside(time2) {
|
|
4743
|
+
return this.calendar.locate(time2)?.inside ?? false;
|
|
4744
|
+
}
|
|
4745
|
+
/** Session start and end of the trading day of `time`, or null. */
|
|
4746
|
+
dayBounds(time2) {
|
|
4747
|
+
const at = this.calendar.locate(time2);
|
|
4748
|
+
return at ? { date: at.date, start: this.dayStart(at.date), end: this.dayEnd(at.date) } : null;
|
|
4749
|
+
}
|
|
4750
|
+
};
|
|
4751
|
+
function sessionFlags(times, bars2, regular) {
|
|
4752
|
+
const n = times.length;
|
|
4753
|
+
const flag2 = () => new Array(n).fill(false);
|
|
4754
|
+
const out = {
|
|
4755
|
+
isfirstbar: flag2(),
|
|
4756
|
+
islastbar: flag2(),
|
|
4757
|
+
ismarket: flag2(),
|
|
4758
|
+
ispremarket: flag2(),
|
|
4759
|
+
ispostmarket: flag2(),
|
|
4760
|
+
isfirstbar_regular: flag2(),
|
|
4761
|
+
islastbar_regular: flag2()
|
|
4762
|
+
};
|
|
4763
|
+
const chart2 = bars2.chart;
|
|
4764
|
+
let previousPeriod = "";
|
|
4765
|
+
let previousRegular = "";
|
|
4766
|
+
for (let i = 0; i < n; i++) {
|
|
4767
|
+
const t2 = times[i];
|
|
4768
|
+
if (chart2.isdwm) {
|
|
4769
|
+
for (const k of ["isfirstbar", "islastbar", "ismarket", "isfirstbar_regular", "islastbar_regular"]) out[k][i] = true;
|
|
4770
|
+
continue;
|
|
4771
|
+
}
|
|
4772
|
+
const at = bars2.calendar.locate(t2);
|
|
4773
|
+
if (!at) {
|
|
4774
|
+
previousPeriod = previousRegular = "";
|
|
4775
|
+
continue;
|
|
4776
|
+
}
|
|
4777
|
+
const close2 = bars2.closeOf(t2, chart2.period);
|
|
4778
|
+
const [, end] = bars2.calendar.periods(at.date)[at.index];
|
|
4779
|
+
const period = `${at.date}/${at.index}`;
|
|
4780
|
+
out.isfirstbar[i] = period !== previousPeriod;
|
|
4781
|
+
out.islastbar[i] = close2 >= end;
|
|
4782
|
+
const regularPeriods = regular.calendar.periods(at.date);
|
|
4783
|
+
const r2 = regularPeriods.findIndex(([s, e2]) => s <= t2 && t2 < e2);
|
|
4784
|
+
const market = r2 !== -1;
|
|
4785
|
+
out.ismarket[i] = market;
|
|
4786
|
+
if (!market && regularPeriods.length) {
|
|
4787
|
+
out.ispremarket[i] = t2 < regularPeriods[0][0];
|
|
4788
|
+
out.ispostmarket[i] = t2 >= regularPeriods[regularPeriods.length - 1][1];
|
|
4789
|
+
}
|
|
4790
|
+
const regularPeriod = market ? `${at.date}/${r2}` : "";
|
|
4791
|
+
out.isfirstbar_regular[i] = market && regularPeriod !== previousRegular;
|
|
4792
|
+
out.islastbar_regular[i] = market && close2 >= regularPeriods[r2][1];
|
|
4793
|
+
previousPeriod = period;
|
|
4794
|
+
previousRegular = regularPeriod;
|
|
4795
|
+
}
|
|
4796
|
+
return out;
|
|
4797
|
+
}
|
|
4798
|
+
|
|
4799
|
+
// src/security/resample.ts
|
|
4800
|
+
function resample(bars2, periodStart) {
|
|
4801
|
+
const out = [];
|
|
4802
|
+
const group2 = [];
|
|
4803
|
+
bars2.forEach((b2, i) => {
|
|
4804
|
+
const start = periodStart[i];
|
|
4805
|
+
const last = out[out.length - 1];
|
|
4806
|
+
if (!last || last.time !== start) {
|
|
4807
|
+
out.push({ time: start, open: b2.open, high: b2.high, low: b2.low, close: b2.close, volume: b2.volume ?? NaN });
|
|
4808
|
+
} else {
|
|
4809
|
+
last.high = Math.max(last.high, b2.high);
|
|
4810
|
+
last.low = Math.min(last.low, b2.low);
|
|
4811
|
+
last.close = b2.close;
|
|
4812
|
+
last.volume = (last.volume ?? 0) + (b2.volume ?? NaN);
|
|
4813
|
+
}
|
|
4814
|
+
group2.push(out.length - 1);
|
|
4815
|
+
});
|
|
4816
|
+
return { bars: out, group: group2 };
|
|
4817
|
+
}
|
|
4818
|
+
function periodsOf(starts, dayPeriods, reaches) {
|
|
4819
|
+
const n = starts.length;
|
|
4820
|
+
const group2 = [];
|
|
4821
|
+
starts.forEach((s, i) => group2.push(i === 0 ? 0 : group2[i - 1] + (s !== starts[i - 1] ? 1 : 0)));
|
|
4822
|
+
const latest = [];
|
|
4823
|
+
starts.forEach((s, i) => {
|
|
4824
|
+
let done = i === 0 ? -1 : latest[i - 1];
|
|
4825
|
+
if (i > 0 && group2[i] !== group2[i - 1]) done = Math.max(done, group2[i] - 1);
|
|
4826
|
+
const ends = i < n - 1 ? starts[i + 1] !== s || dayPeriods[i + 1] !== dayPeriods[i] : true;
|
|
4827
|
+
if (ends && reaches[i]) done = Math.max(done, group2[i]);
|
|
4828
|
+
latest.push(done);
|
|
4829
|
+
});
|
|
4830
|
+
return { group: group2, latest };
|
|
4831
|
+
}
|
|
4832
|
+
function mapToChart(values, group2, latest, lookahead, gaps) {
|
|
4833
|
+
return group2.map((g2, i) => {
|
|
4834
|
+
if (lookahead) {
|
|
4835
|
+
const first = i === 0 || group2[i - 1] !== g2;
|
|
4836
|
+
return gaps && !first ? NaN : values[g2] ?? NaN;
|
|
4837
|
+
}
|
|
4838
|
+
const done = latest[i];
|
|
4839
|
+
if (done < 0 || gaps && i > 0 && latest[i - 1] === done) return NaN;
|
|
4840
|
+
return values[done] ?? NaN;
|
|
4841
|
+
});
|
|
4842
|
+
}
|
|
4843
|
+
function heikinAshi(bars2) {
|
|
4844
|
+
const out = [];
|
|
4845
|
+
bars2.forEach((b2, i) => {
|
|
4846
|
+
const close2 = (b2.open + b2.high + b2.low + b2.close) / 4;
|
|
4847
|
+
const prev = out[i - 1];
|
|
4848
|
+
const open2 = prev ? (prev.open + prev.close) / 2 : (b2.open + b2.close) / 2;
|
|
4849
|
+
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 });
|
|
4850
|
+
});
|
|
4851
|
+
return out;
|
|
4852
|
+
}
|
|
4853
|
+
|
|
4854
|
+
// src/math/index.ts
|
|
4855
|
+
var math_exports = {};
|
|
4856
|
+
__export(math_exports, {
|
|
4857
|
+
abs: () => abs,
|
|
4858
|
+
acos: () => acos,
|
|
4859
|
+
asin: () => asin,
|
|
4860
|
+
atan: () => atan,
|
|
4861
|
+
avg: () => avg,
|
|
4862
|
+
ceil: () => ceil,
|
|
4863
|
+
cos: () => cos,
|
|
4864
|
+
e: () => e,
|
|
4865
|
+
exp: () => exp,
|
|
4866
|
+
floor: () => floor,
|
|
4867
|
+
log: () => log,
|
|
4868
|
+
log10: () => log10,
|
|
4869
|
+
max: () => max3,
|
|
4870
|
+
min: () => min3,
|
|
4871
|
+
phi: () => phi,
|
|
4872
|
+
pi: () => pi,
|
|
4873
|
+
pow: () => pow,
|
|
4874
|
+
random: () => random,
|
|
4875
|
+
round: () => round,
|
|
4876
|
+
round_to_mintick: () => round_to_mintick,
|
|
4877
|
+
rphi: () => rphi,
|
|
4878
|
+
sign: () => sign,
|
|
4879
|
+
sin: () => sin,
|
|
4880
|
+
sqrt: () => sqrt,
|
|
4881
|
+
sum: () => sum,
|
|
4882
|
+
tan: () => tan,
|
|
4883
|
+
todegrees: () => todegrees,
|
|
4884
|
+
toradians: () => toradians
|
|
4885
|
+
});
|
|
4886
|
+
function abs(value) {
|
|
4887
|
+
if (value instanceof Series) {
|
|
4888
|
+
const bars2 = value.bars;
|
|
4889
|
+
const valueArray = value.toArray();
|
|
4890
|
+
const length2 = bars2.length;
|
|
4891
|
+
const result = [];
|
|
4892
|
+
for (let i = 0; i < length2; i++) {
|
|
4893
|
+
const v = valueArray[i] ?? NaN;
|
|
4894
|
+
result.push(Math.abs(v));
|
|
4895
|
+
}
|
|
4896
|
+
return Series.fromArray(bars2, result);
|
|
4897
|
+
}
|
|
4898
|
+
return Math.abs(value);
|
|
4899
|
+
}
|
|
4900
|
+
function ceil(value) {
|
|
4901
|
+
if (value instanceof Series) {
|
|
2869
4902
|
const bars2 = value.bars;
|
|
2870
4903
|
const valueArray = value.toArray();
|
|
2871
|
-
const
|
|
4904
|
+
const length2 = bars2.length;
|
|
2872
4905
|
const result = [];
|
|
2873
|
-
for (let i = 0; i <
|
|
4906
|
+
for (let i = 0; i < length2; i++) {
|
|
4907
|
+
const v = valueArray[i] ?? NaN;
|
|
4908
|
+
result.push(Math.ceil(v));
|
|
4909
|
+
}
|
|
4910
|
+
return Series.fromArray(bars2, result);
|
|
4911
|
+
}
|
|
4912
|
+
return Math.ceil(value);
|
|
4913
|
+
}
|
|
4914
|
+
function floor(value) {
|
|
4915
|
+
if (value instanceof Series) {
|
|
4916
|
+
const bars2 = value.bars;
|
|
4917
|
+
const valueArray = value.toArray();
|
|
4918
|
+
const length2 = bars2.length;
|
|
4919
|
+
const result = [];
|
|
4920
|
+
for (let i = 0; i < length2; i++) {
|
|
2874
4921
|
const v = valueArray[i] ?? NaN;
|
|
2875
4922
|
result.push(Math.floor(v));
|
|
2876
4923
|
}
|
|
@@ -2882,16 +4929,16 @@ function round(value, precision) {
|
|
|
2882
4929
|
if (value instanceof Series) {
|
|
2883
4930
|
const bars2 = value.bars;
|
|
2884
4931
|
const valueArray = value.toArray();
|
|
2885
|
-
const
|
|
4932
|
+
const length2 = bars2.length;
|
|
2886
4933
|
const result = [];
|
|
2887
4934
|
if (precision === void 0) {
|
|
2888
|
-
for (let i = 0; i <
|
|
4935
|
+
for (let i = 0; i < length2; i++) {
|
|
2889
4936
|
const v = valueArray[i] ?? NaN;
|
|
2890
4937
|
result.push(Math.round(v));
|
|
2891
4938
|
}
|
|
2892
4939
|
} else {
|
|
2893
4940
|
const multiplier2 = Math.pow(10, precision);
|
|
2894
|
-
for (let i = 0; i <
|
|
4941
|
+
for (let i = 0; i < length2; i++) {
|
|
2895
4942
|
const v = valueArray[i] ?? NaN;
|
|
2896
4943
|
result.push(Math.round(v * multiplier2) / multiplier2);
|
|
2897
4944
|
}
|
|
@@ -2911,12 +4958,12 @@ function max3(...values) {
|
|
|
2911
4958
|
}
|
|
2912
4959
|
const firstSeries = values.find((v) => v instanceof Series);
|
|
2913
4960
|
const bars2 = firstSeries.bars;
|
|
2914
|
-
const
|
|
4961
|
+
const length2 = bars2.length;
|
|
2915
4962
|
const valueArrays = values.map(
|
|
2916
4963
|
(v) => v instanceof Series ? v.toArray() : null
|
|
2917
4964
|
);
|
|
2918
4965
|
const result = [];
|
|
2919
|
-
for (let i = 0; i <
|
|
4966
|
+
for (let i = 0; i < length2; i++) {
|
|
2920
4967
|
const nums = values.map(
|
|
2921
4968
|
(v, idx) => valueArrays[idx] ? valueArrays[idx][i] ?? NaN : v
|
|
2922
4969
|
);
|
|
@@ -2931,12 +4978,12 @@ function min3(...values) {
|
|
|
2931
4978
|
}
|
|
2932
4979
|
const firstSeries = values.find((v) => v instanceof Series);
|
|
2933
4980
|
const bars2 = firstSeries.bars;
|
|
2934
|
-
const
|
|
4981
|
+
const length2 = bars2.length;
|
|
2935
4982
|
const valueArrays = values.map(
|
|
2936
4983
|
(v) => v instanceof Series ? v.toArray() : null
|
|
2937
4984
|
);
|
|
2938
4985
|
const result = [];
|
|
2939
|
-
for (let i = 0; i <
|
|
4986
|
+
for (let i = 0; i < length2; i++) {
|
|
2940
4987
|
const nums = values.map(
|
|
2941
4988
|
(v, idx) => valueArrays[idx] ? valueArrays[idx][i] ?? NaN : v
|
|
2942
4989
|
);
|
|
@@ -2951,12 +4998,12 @@ function avg(...values) {
|
|
|
2951
4998
|
}
|
|
2952
4999
|
const firstSeries = values.find((v) => v instanceof Series);
|
|
2953
5000
|
const bars2 = firstSeries.bars;
|
|
2954
|
-
const
|
|
5001
|
+
const length2 = bars2.length;
|
|
2955
5002
|
const valueArrays = values.map(
|
|
2956
5003
|
(v) => v instanceof Series ? v.toArray() : null
|
|
2957
5004
|
);
|
|
2958
5005
|
const result = [];
|
|
2959
|
-
for (let i = 0; i <
|
|
5006
|
+
for (let i = 0; i < length2; i++) {
|
|
2960
5007
|
const nums = values.map(
|
|
2961
5008
|
(v, idx) => valueArrays[idx] ? valueArrays[idx][i] ?? NaN : v
|
|
2962
5009
|
);
|
|
@@ -2965,15 +5012,15 @@ function avg(...values) {
|
|
|
2965
5012
|
}
|
|
2966
5013
|
return Series.fromArray(bars2, result);
|
|
2967
5014
|
}
|
|
2968
|
-
function sum(source,
|
|
5015
|
+
function sum(source, length2) {
|
|
2969
5016
|
const sourceArray = source instanceof Series ? source.toArray() : source;
|
|
2970
5017
|
const result = [];
|
|
2971
5018
|
for (let i = 0; i < sourceArray.length; i++) {
|
|
2972
|
-
if (i <
|
|
5019
|
+
if (i < length2 - 1) {
|
|
2973
5020
|
result.push(NaN);
|
|
2974
5021
|
} else {
|
|
2975
5022
|
let total = 0;
|
|
2976
|
-
for (let j = 0; j <
|
|
5023
|
+
for (let j = 0; j < length2; j++) {
|
|
2977
5024
|
total += sourceArray[i - j];
|
|
2978
5025
|
}
|
|
2979
5026
|
result.push(total);
|
|
@@ -2988,9 +5035,9 @@ function sqrt(value) {
|
|
|
2988
5035
|
if (value instanceof Series) {
|
|
2989
5036
|
const bars2 = value.bars;
|
|
2990
5037
|
const valueArray = value.toArray();
|
|
2991
|
-
const
|
|
5038
|
+
const length2 = bars2.length;
|
|
2992
5039
|
const result = [];
|
|
2993
|
-
for (let i = 0; i <
|
|
5040
|
+
for (let i = 0; i < length2; i++) {
|
|
2994
5041
|
const v = valueArray[i] ?? NaN;
|
|
2995
5042
|
result.push(Math.sqrt(v));
|
|
2996
5043
|
}
|
|
@@ -3007,9 +5054,9 @@ function pow(base, exponent) {
|
|
|
3007
5054
|
const bars2 = baseIsSeries ? base.bars : exponent.bars;
|
|
3008
5055
|
const baseArray = baseIsSeries ? base.toArray() : null;
|
|
3009
5056
|
const expArray = expIsSeries ? exponent.toArray() : null;
|
|
3010
|
-
const
|
|
5057
|
+
const length2 = bars2.length;
|
|
3011
5058
|
const result = [];
|
|
3012
|
-
for (let i = 0; i <
|
|
5059
|
+
for (let i = 0; i < length2; i++) {
|
|
3013
5060
|
const b2 = baseArray ? baseArray[i] ?? NaN : base;
|
|
3014
5061
|
const e2 = expArray ? expArray[i] ?? NaN : exponent;
|
|
3015
5062
|
result.push(Math.pow(b2, e2));
|
|
@@ -3020,9 +5067,9 @@ function exp(value) {
|
|
|
3020
5067
|
if (value instanceof Series) {
|
|
3021
5068
|
const bars2 = value.bars;
|
|
3022
5069
|
const valueArray = value.toArray();
|
|
3023
|
-
const
|
|
5070
|
+
const length2 = bars2.length;
|
|
3024
5071
|
const result = [];
|
|
3025
|
-
for (let i = 0; i <
|
|
5072
|
+
for (let i = 0; i < length2; i++) {
|
|
3026
5073
|
const v = valueArray[i] ?? NaN;
|
|
3027
5074
|
result.push(Math.exp(v));
|
|
3028
5075
|
}
|
|
@@ -3034,9 +5081,9 @@ function log(value) {
|
|
|
3034
5081
|
if (value instanceof Series) {
|
|
3035
5082
|
const bars2 = value.bars;
|
|
3036
5083
|
const valueArray = value.toArray();
|
|
3037
|
-
const
|
|
5084
|
+
const length2 = bars2.length;
|
|
3038
5085
|
const result = [];
|
|
3039
|
-
for (let i = 0; i <
|
|
5086
|
+
for (let i = 0; i < length2; i++) {
|
|
3040
5087
|
const v = valueArray[i] ?? NaN;
|
|
3041
5088
|
result.push(Math.log(v));
|
|
3042
5089
|
}
|
|
@@ -3048,9 +5095,9 @@ function log10(value) {
|
|
|
3048
5095
|
if (value instanceof Series) {
|
|
3049
5096
|
const bars2 = value.bars;
|
|
3050
5097
|
const valueArray = value.toArray();
|
|
3051
|
-
const
|
|
5098
|
+
const length2 = bars2.length;
|
|
3052
5099
|
const result = [];
|
|
3053
|
-
for (let i = 0; i <
|
|
5100
|
+
for (let i = 0; i < length2; i++) {
|
|
3054
5101
|
const v = valueArray[i] ?? NaN;
|
|
3055
5102
|
result.push(Math.log10(v));
|
|
3056
5103
|
}
|
|
@@ -3062,9 +5109,9 @@ function sin(value) {
|
|
|
3062
5109
|
if (value instanceof Series) {
|
|
3063
5110
|
const bars2 = value.bars;
|
|
3064
5111
|
const valueArray = value.toArray();
|
|
3065
|
-
const
|
|
5112
|
+
const length2 = bars2.length;
|
|
3066
5113
|
const result = [];
|
|
3067
|
-
for (let i = 0; i <
|
|
5114
|
+
for (let i = 0; i < length2; i++) {
|
|
3068
5115
|
const v = valueArray[i] ?? NaN;
|
|
3069
5116
|
result.push(Math.sin(v));
|
|
3070
5117
|
}
|
|
@@ -3076,9 +5123,9 @@ function cos(value) {
|
|
|
3076
5123
|
if (value instanceof Series) {
|
|
3077
5124
|
const bars2 = value.bars;
|
|
3078
5125
|
const valueArray = value.toArray();
|
|
3079
|
-
const
|
|
5126
|
+
const length2 = bars2.length;
|
|
3080
5127
|
const result = [];
|
|
3081
|
-
for (let i = 0; i <
|
|
5128
|
+
for (let i = 0; i < length2; i++) {
|
|
3082
5129
|
const v = valueArray[i] ?? NaN;
|
|
3083
5130
|
result.push(Math.cos(v));
|
|
3084
5131
|
}
|
|
@@ -3090,9 +5137,9 @@ function tan(value) {
|
|
|
3090
5137
|
if (value instanceof Series) {
|
|
3091
5138
|
const bars2 = value.bars;
|
|
3092
5139
|
const valueArray = value.toArray();
|
|
3093
|
-
const
|
|
5140
|
+
const length2 = bars2.length;
|
|
3094
5141
|
const result = [];
|
|
3095
|
-
for (let i = 0; i <
|
|
5142
|
+
for (let i = 0; i < length2; i++) {
|
|
3096
5143
|
const v = valueArray[i] ?? NaN;
|
|
3097
5144
|
result.push(Math.tan(v));
|
|
3098
5145
|
}
|
|
@@ -3104,9 +5151,9 @@ function asin(value) {
|
|
|
3104
5151
|
if (value instanceof Series) {
|
|
3105
5152
|
const bars2 = value.bars;
|
|
3106
5153
|
const valueArray = value.toArray();
|
|
3107
|
-
const
|
|
5154
|
+
const length2 = bars2.length;
|
|
3108
5155
|
const result = [];
|
|
3109
|
-
for (let i = 0; i <
|
|
5156
|
+
for (let i = 0; i < length2; i++) {
|
|
3110
5157
|
const v = valueArray[i] ?? NaN;
|
|
3111
5158
|
result.push(Math.asin(v));
|
|
3112
5159
|
}
|
|
@@ -3118,9 +5165,9 @@ function acos(value) {
|
|
|
3118
5165
|
if (value instanceof Series) {
|
|
3119
5166
|
const bars2 = value.bars;
|
|
3120
5167
|
const valueArray = value.toArray();
|
|
3121
|
-
const
|
|
5168
|
+
const length2 = bars2.length;
|
|
3122
5169
|
const result = [];
|
|
3123
|
-
for (let i = 0; i <
|
|
5170
|
+
for (let i = 0; i < length2; i++) {
|
|
3124
5171
|
const v = valueArray[i] ?? NaN;
|
|
3125
5172
|
result.push(Math.acos(v));
|
|
3126
5173
|
}
|
|
@@ -3132,9 +5179,9 @@ function atan(value) {
|
|
|
3132
5179
|
if (value instanceof Series) {
|
|
3133
5180
|
const bars2 = value.bars;
|
|
3134
5181
|
const valueArray = value.toArray();
|
|
3135
|
-
const
|
|
5182
|
+
const length2 = bars2.length;
|
|
3136
5183
|
const result = [];
|
|
3137
|
-
for (let i = 0; i <
|
|
5184
|
+
for (let i = 0; i < length2; i++) {
|
|
3138
5185
|
const v = valueArray[i] ?? NaN;
|
|
3139
5186
|
result.push(Math.atan(v));
|
|
3140
5187
|
}
|
|
@@ -3146,9 +5193,9 @@ function toradians(degrees) {
|
|
|
3146
5193
|
if (degrees instanceof Series) {
|
|
3147
5194
|
const bars2 = degrees.bars;
|
|
3148
5195
|
const valueArray = degrees.toArray();
|
|
3149
|
-
const
|
|
5196
|
+
const length2 = bars2.length;
|
|
3150
5197
|
const result = [];
|
|
3151
|
-
for (let i = 0; i <
|
|
5198
|
+
for (let i = 0; i < length2; i++) {
|
|
3152
5199
|
const v = valueArray[i] ?? NaN;
|
|
3153
5200
|
result.push(v * (Math.PI / 180));
|
|
3154
5201
|
}
|
|
@@ -3160,9 +5207,9 @@ function todegrees(radians) {
|
|
|
3160
5207
|
if (radians instanceof Series) {
|
|
3161
5208
|
const bars2 = radians.bars;
|
|
3162
5209
|
const valueArray = radians.toArray();
|
|
3163
|
-
const
|
|
5210
|
+
const length2 = bars2.length;
|
|
3164
5211
|
const result = [];
|
|
3165
|
-
for (let i = 0; i <
|
|
5212
|
+
for (let i = 0; i < length2; i++) {
|
|
3166
5213
|
const v = valueArray[i] ?? NaN;
|
|
3167
5214
|
result.push(v * (180 / Math.PI));
|
|
3168
5215
|
}
|
|
@@ -3181,9 +5228,9 @@ function sign(value) {
|
|
|
3181
5228
|
if (value instanceof Series) {
|
|
3182
5229
|
const bars2 = value.bars;
|
|
3183
5230
|
const valueArray = value.toArray();
|
|
3184
|
-
const
|
|
5231
|
+
const length2 = bars2.length;
|
|
3185
5232
|
const result = [];
|
|
3186
|
-
for (let i = 0; i <
|
|
5233
|
+
for (let i = 0; i < length2; i++) {
|
|
3187
5234
|
const v = valueArray[i] ?? NaN;
|
|
3188
5235
|
result.push(v > 0 ? 1 : v < 0 ? -1 : 0);
|
|
3189
5236
|
}
|
|
@@ -3191,11 +5238,11 @@ function sign(value) {
|
|
|
3191
5238
|
}
|
|
3192
5239
|
return value > 0 ? 1 : value < 0 ? -1 : 0;
|
|
3193
5240
|
}
|
|
3194
|
-
function round_to_mintick(
|
|
3195
|
-
if (
|
|
3196
|
-
const bars2 =
|
|
3197
|
-
const valueArray =
|
|
3198
|
-
const
|
|
5241
|
+
function round_to_mintick(number2, mintick) {
|
|
5242
|
+
if (number2 instanceof Series) {
|
|
5243
|
+
const bars2 = number2.bars;
|
|
5244
|
+
const valueArray = number2.toArray();
|
|
5245
|
+
const length2 = bars2.length;
|
|
3199
5246
|
if (mintick === void 0) {
|
|
3200
5247
|
throw new Error(
|
|
3201
5248
|
"math.round_to_mintick() requires mintick value. Either pass it explicitly or use createContext({ syminfo: { mintick } }) for implicit data."
|
|
@@ -3203,11 +5250,11 @@ function round_to_mintick(number, mintick) {
|
|
|
3203
5250
|
}
|
|
3204
5251
|
const result = [];
|
|
3205
5252
|
if (mintick === 0) {
|
|
3206
|
-
for (let i = 0; i <
|
|
5253
|
+
for (let i = 0; i < length2; i++) {
|
|
3207
5254
|
result.push(valueArray[i] ?? NaN);
|
|
3208
5255
|
}
|
|
3209
5256
|
} else {
|
|
3210
|
-
for (let i = 0; i <
|
|
5257
|
+
for (let i = 0; i < length2; i++) {
|
|
3211
5258
|
const v = valueArray[i];
|
|
3212
5259
|
if (v === void 0 || isNaN(v)) {
|
|
3213
5260
|
result.push(NaN);
|
|
@@ -3218,7 +5265,7 @@ function round_to_mintick(number, mintick) {
|
|
|
3218
5265
|
}
|
|
3219
5266
|
return Series.fromArray(bars2, result);
|
|
3220
5267
|
}
|
|
3221
|
-
if (isNaN(
|
|
5268
|
+
if (isNaN(number2)) {
|
|
3222
5269
|
return NaN;
|
|
3223
5270
|
}
|
|
3224
5271
|
if (mintick === void 0) {
|
|
@@ -3227,9 +5274,9 @@ function round_to_mintick(number, mintick) {
|
|
|
3227
5274
|
);
|
|
3228
5275
|
}
|
|
3229
5276
|
if (mintick === 0) {
|
|
3230
|
-
return
|
|
5277
|
+
return number2;
|
|
3231
5278
|
}
|
|
3232
|
-
return Math.round(
|
|
5279
|
+
return Math.round(number2 / mintick) * mintick;
|
|
3233
5280
|
}
|
|
3234
5281
|
var pi = Math.PI;
|
|
3235
5282
|
var e = Math.E;
|
|
@@ -3276,9 +5323,11 @@ function slugId(title, fallback, taken) {
|
|
|
3276
5323
|
taken.add(id);
|
|
3277
5324
|
return id;
|
|
3278
5325
|
}
|
|
3279
|
-
function executeScript(body, barsInput, inputs = {}) {
|
|
5326
|
+
function executeScript(body, barsInput, inputs = {}, chart2 = {}) {
|
|
3280
5327
|
ctxBars.setAll(barsInput);
|
|
5328
|
+
chartCtx = { ...chart2 };
|
|
3281
5329
|
ctx = freshCollector(inputs);
|
|
5330
|
+
resetDrawings();
|
|
3282
5331
|
try {
|
|
3283
5332
|
body();
|
|
3284
5333
|
const c = ctx;
|
|
@@ -3319,6 +5368,12 @@ function indicator(title, options = {}) {
|
|
|
3319
5368
|
c.overlay = options.overlay ?? true;
|
|
3320
5369
|
c.precision = options.precision;
|
|
3321
5370
|
c.format = options.format;
|
|
5371
|
+
setDrawingLimits({
|
|
5372
|
+
line: options.max_lines_count,
|
|
5373
|
+
label: options.max_labels_count,
|
|
5374
|
+
box: options.max_boxes_count,
|
|
5375
|
+
polyline: options.max_polylines_count
|
|
5376
|
+
});
|
|
3322
5377
|
}
|
|
3323
5378
|
function registerInput(config, fallbackId) {
|
|
3324
5379
|
const c = collector();
|
|
@@ -3355,6 +5410,19 @@ var input = {
|
|
|
3355
5410
|
source(defval = "close", title) {
|
|
3356
5411
|
const name = registerInput({ type: "source", defval, title }, "input_source");
|
|
3357
5412
|
return sourceSeries(name);
|
|
5413
|
+
},
|
|
5414
|
+
/** Timeframe string ("60", "1D", "W"). As in PineScript, "" means the chart timeframe. */
|
|
5415
|
+
timeframe(defval, title, opts = {}) {
|
|
5416
|
+
return registerInput({ type: "timeframe", defval, title, options: opts.options }, "input_timeframe");
|
|
5417
|
+
},
|
|
5418
|
+
/** Session string ("0930-1600", "0930-1600:23456"). */
|
|
5419
|
+
session(defval, title, opts = {}) {
|
|
5420
|
+
return registerInput({ type: "session", defval, title, options: opts.options }, "input_session");
|
|
5421
|
+
},
|
|
5422
|
+
/** Date and time as a UNIX time in milliseconds, e.g. `input.time(timestamp('2024-01-01'), 'Start')`. */
|
|
5423
|
+
time(defval, title) {
|
|
5424
|
+
const v = registerInput({ type: "time", defval, title }, "input_time");
|
|
5425
|
+
return typeof v === "number" ? v : defval;
|
|
3358
5426
|
}
|
|
3359
5427
|
};
|
|
3360
5428
|
var open = Series.fromBars(ctxBars, "open");
|
|
@@ -3371,18 +5439,60 @@ function sourceSeries(name) {
|
|
|
3371
5439
|
return SOURCES[name] ?? close;
|
|
3372
5440
|
}
|
|
3373
5441
|
var bars = () => ctxBars.bars;
|
|
5442
|
+
function barsSeries(compute) {
|
|
5443
|
+
let version = -1;
|
|
5444
|
+
let values = [];
|
|
5445
|
+
return new Series(ctxBars, (_bar, i, data) => {
|
|
5446
|
+
if (version !== ctxBars.version) {
|
|
5447
|
+
values = compute(data).toArray();
|
|
5448
|
+
version = ctxBars.version;
|
|
5449
|
+
}
|
|
5450
|
+
return values[i] ?? NaN;
|
|
5451
|
+
});
|
|
5452
|
+
}
|
|
3374
5453
|
var ta2 = {
|
|
3375
5454
|
...ta_series_exports,
|
|
3376
5455
|
tr: (handleNa = false) => tr2(bars(), handleNa),
|
|
3377
|
-
atr: (
|
|
5456
|
+
atr: (length2) => atr2(bars(), length2),
|
|
3378
5457
|
sar: (start, inc, max4) => sar2(bars(), start, inc, max4),
|
|
3379
|
-
wpr: (
|
|
5458
|
+
wpr: (length2) => wpr2(bars(), length2),
|
|
3380
5459
|
supertrend: (factor, atrLength) => supertrend2(bars(), factor, atrLength),
|
|
3381
5460
|
dmi: (diLength, adxSmoothing) => dmi2(bars(), diLength, adxSmoothing),
|
|
3382
|
-
kc: (source,
|
|
3383
|
-
kcw: (source,
|
|
3384
|
-
ichimoku: (conversionPeriods, basePeriods, laggingSpan2Periods, displacement) => ichimoku2(bars(), conversionPeriods, basePeriods, laggingSpan2Periods, displacement)
|
|
5461
|
+
kc: (source, length2, mult, useTrueRange) => kc2(bars(), source, length2, mult, useTrueRange),
|
|
5462
|
+
kcw: (source, length2, mult, useTrueRange) => kcw2(bars(), source, length2, mult, useTrueRange),
|
|
5463
|
+
ichimoku: (conversionPeriods, basePeriods, laggingSpan2Periods, displacement) => ichimoku2(bars(), conversionPeriods, basePeriods, laggingSpan2Periods, displacement),
|
|
5464
|
+
/** `ta.highest(source, length)` or `ta.highest(length)` (source = high). */
|
|
5465
|
+
highest: (sourceOrLength, length2) => typeof sourceOrLength === "number" ? highest2(high, sourceOrLength) : highest2(sourceOrLength, length2),
|
|
5466
|
+
/** `ta.lowest(source, length)` or `ta.lowest(length)` (source = low). */
|
|
5467
|
+
lowest: (sourceOrLength, length2) => typeof sourceOrLength === "number" ? lowest2(low, sourceOrLength) : lowest2(sourceOrLength, length2),
|
|
5468
|
+
/** `ta.highestbars(source, length)` or `ta.highestbars(length)` (source = high); offsets are 0 or negative. */
|
|
5469
|
+
highestbars: (sourceOrLength, length2) => typeof sourceOrLength === "number" ? highestbars2(high, sourceOrLength) : highestbars2(sourceOrLength, length2),
|
|
5470
|
+
/** `ta.lowestbars(source, length)` or `ta.lowestbars(length)` (source = low); offsets are 0 or negative. */
|
|
5471
|
+
lowestbars: (sourceOrLength, length2) => typeof sourceOrLength === "number" ? lowestbars2(low, sourceOrLength) : lowestbars2(sourceOrLength, length2),
|
|
5472
|
+
/** `ta.vwap(source, anchor?, stdev_mult?)` with the chart volume; the default anchor is a new trading
|
|
5473
|
+
* day (`timeframe.change("1D")`), which needs the chart context (timeframe, time zone, session). */
|
|
5474
|
+
vwap: ((source, anchor, stdev_mult) => {
|
|
5475
|
+
const a = anchor ?? changeOf("1D");
|
|
5476
|
+
return stdev_mult === void 0 ? vwap2(source, volume, a) : vwapBands(source, volume, a, stdev_mult);
|
|
5477
|
+
}),
|
|
5478
|
+
/** `ta.pivothigh(source, leftbars, rightbars)` or `ta.pivothigh(leftbars, rightbars)` (source = high).
|
|
5479
|
+
* The value appears `rightbars` bars after the pivot bar, as in PineScript. */
|
|
5480
|
+
pivothigh: (sourceOrLeft, leftOrRight, rightbars) => typeof sourceOrLeft === "number" ? pivothigh2(high, sourceOrLeft, leftOrRight) : pivothigh2(sourceOrLeft, leftOrRight, rightbars),
|
|
5481
|
+
/** `ta.pivotlow(source, leftbars, rightbars)` or `ta.pivotlow(leftbars, rightbars)` (source = low). */
|
|
5482
|
+
pivotlow: (sourceOrLeft, leftOrRight, rightbars) => typeof sourceOrLeft === "number" ? pivotlow2(low, sourceOrLeft, leftOrRight) : pivotlow2(sourceOrLeft, leftOrRight, rightbars),
|
|
5483
|
+
// PineScript variables of the chart bars: `ta.obv`, not `ta.obv()`.
|
|
5484
|
+
obv: barsSeries(obv2),
|
|
5485
|
+
pvt: barsSeries(pvt2),
|
|
5486
|
+
accdist: barsSeries(accdist2),
|
|
5487
|
+
nvi: barsSeries(nvi2),
|
|
5488
|
+
pvi: barsSeries(pvi2),
|
|
5489
|
+
iii: barsSeries(iii2),
|
|
5490
|
+
wad: barsSeries(wad2),
|
|
5491
|
+
wvad: barsSeries(wvad2)
|
|
3385
5492
|
};
|
|
5493
|
+
function fixnan2(source) {
|
|
5494
|
+
return source instanceof Series ? Series.fromArray(ctxBars, fixnan(source.toArray())) : fixnan(source);
|
|
5495
|
+
}
|
|
3386
5496
|
function colorWhen(cond, colorTrue, colorFalse) {
|
|
3387
5497
|
return cond.toArray().map((v) => !isNA(v) && v !== 0 ? colorTrue : colorFalse);
|
|
3388
5498
|
}
|
|
@@ -3394,8 +5504,8 @@ var color = {
|
|
|
3394
5504
|
function plot(series, title, options = {}) {
|
|
3395
5505
|
const c = collector();
|
|
3396
5506
|
const id = `plot${c.plotConfig.length}`;
|
|
3397
|
-
const
|
|
3398
|
-
const staticColor = typeof options.color === "string" ? options.color :
|
|
5507
|
+
const perBar2 = Array.isArray(options.color) ? options.color : void 0;
|
|
5508
|
+
const staticColor = typeof options.color === "string" ? options.color : perBar2?.[perBar2.length - 1] ?? "#2962FF";
|
|
3399
5509
|
c.plotConfig.push({
|
|
3400
5510
|
id,
|
|
3401
5511
|
title: title ?? id,
|
|
@@ -3411,7 +5521,7 @@ function plot(series, title, options = {}) {
|
|
|
3411
5521
|
for (let i = 0; i < b2.length; i++) {
|
|
3412
5522
|
const value = values[i];
|
|
3413
5523
|
if (value === void 0 || Number.isNaN(value)) continue;
|
|
3414
|
-
data.push(
|
|
5524
|
+
data.push(perBar2 ? { time: b2[i].time, value, color: perBar2[i] } : { time: b2[i].time, value });
|
|
3415
5525
|
}
|
|
3416
5526
|
c.plots[id] = data;
|
|
3417
5527
|
return { id, kind: "plot" };
|
|
@@ -3431,7 +5541,7 @@ function hline(price, title, options = {}) {
|
|
|
3431
5541
|
}
|
|
3432
5542
|
function fill(a, b2, options = {}) {
|
|
3433
5543
|
const c = collector();
|
|
3434
|
-
const
|
|
5544
|
+
const perBar2 = Array.isArray(options.color) ? options.color : void 0;
|
|
3435
5545
|
const staticColor = typeof options.color === "string" ? options.color : void 0;
|
|
3436
5546
|
if (a.kind === "hline" && b2.kind === "hline") {
|
|
3437
5547
|
c.fillConfig.push({
|
|
@@ -3439,7 +5549,7 @@ function fill(a, b2, options = {}) {
|
|
|
3439
5549
|
plot1: a.id,
|
|
3440
5550
|
plot2: b2.id,
|
|
3441
5551
|
color: staticColor,
|
|
3442
|
-
colors:
|
|
5552
|
+
colors: perBar2,
|
|
3443
5553
|
title: options.title
|
|
3444
5554
|
});
|
|
3445
5555
|
return;
|
|
@@ -3448,7 +5558,7 @@ function fill(a, b2, options = {}) {
|
|
|
3448
5558
|
plot1: a.id,
|
|
3449
5559
|
plot2: b2.id,
|
|
3450
5560
|
options: { color: staticColor, title: options.title },
|
|
3451
|
-
colors:
|
|
5561
|
+
colors: perBar2
|
|
3452
5562
|
});
|
|
3453
5563
|
}
|
|
3454
5564
|
function emitMarkers(kind, condition, title, options) {
|
|
@@ -3507,11 +5617,11 @@ function emitBarColors(kind, colors, options) {
|
|
|
3507
5617
|
const off = options.offset ?? 0;
|
|
3508
5618
|
const target = kind === "bgcolor" ? c.bgcolors : c.barcolors;
|
|
3509
5619
|
for (let i = 0; i < b2.length; i++) {
|
|
3510
|
-
const
|
|
3511
|
-
if (!
|
|
5620
|
+
const col2 = typeof colors === "string" ? colors : colors[i];
|
|
5621
|
+
if (!col2) continue;
|
|
3512
5622
|
const j = i + off;
|
|
3513
5623
|
if (j < 0 || j >= b2.length) continue;
|
|
3514
|
-
target.push({ time: b2[j].time, color:
|
|
5624
|
+
target.push({ time: b2[j].time, color: col2 });
|
|
3515
5625
|
}
|
|
3516
5626
|
}
|
|
3517
5627
|
function bgcolor(colors, options = {}) {
|
|
@@ -3563,12 +5673,335 @@ function eachBar(fn) {
|
|
|
3563
5673
|
return j >= 0 ? out[j] : NaN;
|
|
3564
5674
|
}
|
|
3565
5675
|
};
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
5676
|
+
try {
|
|
5677
|
+
for (idx = 0; idx < b2.length; idx++) {
|
|
5678
|
+
currentBar = idx;
|
|
5679
|
+
const r2 = fn(ctx2);
|
|
5680
|
+
out[idx] = typeof r2 === "number" ? r2 : typeof r2 === "boolean" ? r2 ? 1 : 0 : NaN;
|
|
5681
|
+
}
|
|
5682
|
+
} finally {
|
|
5683
|
+
currentBar = -1;
|
|
3569
5684
|
}
|
|
3570
5685
|
return Series.fromArray(ctxBars, out);
|
|
3571
5686
|
}
|
|
5687
|
+
var currentBar = -1;
|
|
5688
|
+
var chartCtx = {};
|
|
5689
|
+
function chartTimeframe() {
|
|
5690
|
+
collector();
|
|
5691
|
+
if (!chartCtx.timeframe) {
|
|
5692
|
+
throw new Error("The chart timeframe is not known: pass it as executeScript(body, bars, inputs, { timeframe }).");
|
|
5693
|
+
}
|
|
5694
|
+
return info(chartCtx.timeframe);
|
|
5695
|
+
}
|
|
5696
|
+
function exchangeTimezone() {
|
|
5697
|
+
collector();
|
|
5698
|
+
if (!chartCtx.timezone) {
|
|
5699
|
+
throw new Error("The exchange time zone is not known: pass it as executeScript(body, bars, inputs, { timezone }).");
|
|
5700
|
+
}
|
|
5701
|
+
return chartCtx.timezone;
|
|
5702
|
+
}
|
|
5703
|
+
var timeframe = {
|
|
5704
|
+
...timeframe_exports,
|
|
5705
|
+
get period() {
|
|
5706
|
+
return chartTimeframe().period;
|
|
5707
|
+
},
|
|
5708
|
+
get main_period() {
|
|
5709
|
+
return chartTimeframe().period;
|
|
5710
|
+
},
|
|
5711
|
+
get multiplier() {
|
|
5712
|
+
return chartTimeframe().multiplier;
|
|
5713
|
+
},
|
|
5714
|
+
get isintraday() {
|
|
5715
|
+
return chartTimeframe().isintraday;
|
|
5716
|
+
},
|
|
5717
|
+
get isdaily() {
|
|
5718
|
+
return chartTimeframe().isdaily;
|
|
5719
|
+
},
|
|
5720
|
+
get isweekly() {
|
|
5721
|
+
return chartTimeframe().isweekly;
|
|
5722
|
+
},
|
|
5723
|
+
get ismonthly() {
|
|
5724
|
+
return chartTimeframe().ismonthly;
|
|
5725
|
+
},
|
|
5726
|
+
get isminutes() {
|
|
5727
|
+
return chartTimeframe().isminutes;
|
|
5728
|
+
},
|
|
5729
|
+
get isseconds() {
|
|
5730
|
+
return chartTimeframe().isseconds;
|
|
5731
|
+
},
|
|
5732
|
+
get isticks() {
|
|
5733
|
+
return chartTimeframe().isticks;
|
|
5734
|
+
},
|
|
5735
|
+
get isdwm() {
|
|
5736
|
+
return chartTimeframe().isdwm;
|
|
5737
|
+
},
|
|
5738
|
+
/** PineScript `timeframe.change(tf)`: 1 on bars that open a new `tf` period (0 on the first bar). */
|
|
5739
|
+
change(tf) {
|
|
5740
|
+
return changeOf(tf || chartTimeframe().period);
|
|
5741
|
+
},
|
|
5742
|
+
/** Seconds in `timeframe`; without it (or with "") the chart timeframe, as in PineScript. */
|
|
5743
|
+
in_seconds(tf) {
|
|
5744
|
+
return in_seconds(tf === void 0 || tf === "" ? chartTimeframe().period : tf);
|
|
5745
|
+
}
|
|
5746
|
+
};
|
|
5747
|
+
var syminfo = {
|
|
5748
|
+
get timezone() {
|
|
5749
|
+
return exchangeTimezone();
|
|
5750
|
+
},
|
|
5751
|
+
get tickerid() {
|
|
5752
|
+
collector();
|
|
5753
|
+
if (!chartCtx.tickerid) {
|
|
5754
|
+
throw new Error("The chart symbol is not known: pass it as executeScript(body, bars, inputs, { tickerid }).");
|
|
5755
|
+
}
|
|
5756
|
+
return chartCtx.tickerid;
|
|
5757
|
+
},
|
|
5758
|
+
get session() {
|
|
5759
|
+
collector();
|
|
5760
|
+
return chartCtx.sessionType ?? "regular";
|
|
5761
|
+
}
|
|
5762
|
+
};
|
|
5763
|
+
function calendar(fn) {
|
|
5764
|
+
return ((time2, timezone) => {
|
|
5765
|
+
const tz = timezone ?? exchangeTimezone();
|
|
5766
|
+
return time2 instanceof Series ? Series.fromArray(ctxBars, time2.toArray().map((t2) => fn(t2, tz))) : fn(time2, tz);
|
|
5767
|
+
});
|
|
5768
|
+
}
|
|
5769
|
+
var year2 = calendar(year);
|
|
5770
|
+
var month2 = calendar(month);
|
|
5771
|
+
var weekofyear2 = calendar(weekofyear);
|
|
5772
|
+
var dayofmonth2 = calendar(dayofmonth);
|
|
5773
|
+
var dayofweek2 = calendar(dayofweek);
|
|
5774
|
+
var hour2 = calendar(hour);
|
|
5775
|
+
var minute2 = calendar(minute);
|
|
5776
|
+
var second2 = calendar(second);
|
|
5777
|
+
function timestamp2(first, ...rest) {
|
|
5778
|
+
if (typeof first === "number") {
|
|
5779
|
+
const [m2, d2, h2, mi2, s2] = rest;
|
|
5780
|
+
return timestamp(exchangeTimezone(), first, m2, d2, h2, mi2, s2);
|
|
5781
|
+
}
|
|
5782
|
+
if (rest.length === 0) return timestamp(first);
|
|
5783
|
+
const [y, m, d, h, mi, s] = rest;
|
|
5784
|
+
return timestamp(first, y, m, d, h, mi, s);
|
|
5785
|
+
}
|
|
5786
|
+
function inSession3(time2, session2, timezone) {
|
|
5787
|
+
return inSession2(time2, session2, timezone ?? exchangeTimezone());
|
|
5788
|
+
}
|
|
5789
|
+
var str = {
|
|
5790
|
+
...str_exports,
|
|
5791
|
+
format_time(time2, format2 = "yyyy-MM-dd'T'HH:mm:ssZ", timezone) {
|
|
5792
|
+
return format_time(time2, format2, timezone ?? exchangeTimezone());
|
|
5793
|
+
},
|
|
5794
|
+
format(pattern, ...args) {
|
|
5795
|
+
return formatMessage(pattern, args, exchangeTimezone);
|
|
5796
|
+
}
|
|
5797
|
+
};
|
|
5798
|
+
function barTime(bar) {
|
|
5799
|
+
return bar.time * (chartCtx.timeUnit === "ms" ? 1 : 1e3);
|
|
5800
|
+
}
|
|
5801
|
+
var toSpec = (s) => typeof s === "string" ? { session: s } : s;
|
|
5802
|
+
var sessionCache = null;
|
|
5803
|
+
function sessionBars() {
|
|
5804
|
+
const tz = exchangeTimezone();
|
|
5805
|
+
const tf = chartTimeframe().period;
|
|
5806
|
+
if (!chartCtx.session) {
|
|
5807
|
+
throw new Error("The session is not known: pass it as executeScript(body, bars, inputs, { session }).");
|
|
5808
|
+
}
|
|
5809
|
+
if (sessionCache?.ctx !== chartCtx) {
|
|
5810
|
+
const loaded = toSpec(chartCtx.session);
|
|
5811
|
+
const regular = chartCtx.regularSession ? toSpec(chartCtx.regularSession) : loaded;
|
|
5812
|
+
sessionCache = {
|
|
5813
|
+
ctx: chartCtx,
|
|
5814
|
+
bars: new SessionBars(new TradingCalendar(tz, loaded), tf),
|
|
5815
|
+
regular: new SessionBars(new TradingCalendar(tz, { holidays: loaded.holidays, ...regular }), tf)
|
|
5816
|
+
};
|
|
5817
|
+
}
|
|
5818
|
+
return sessionCache;
|
|
5819
|
+
}
|
|
5820
|
+
function calendarFor(session2, timezone) {
|
|
5821
|
+
const { bars: bars2 } = sessionBars();
|
|
5822
|
+
if (!session2 && !timezone) return { bars: bars2, test: false };
|
|
5823
|
+
const tz = timezone ?? exchangeTimezone();
|
|
5824
|
+
const spec = session2 ? { session: session2 } : { session: toSpec(chartCtx.session).session };
|
|
5825
|
+
return { bars: new SessionBars(new TradingCalendar(tz, spec, session2 ? "pine" : "symbol"), bars2.chart.period), test: true };
|
|
5826
|
+
}
|
|
5827
|
+
function perBar(fn) {
|
|
5828
|
+
const times = ctxBars.bars.map(barTime);
|
|
5829
|
+
return Series.fromArray(ctxBars, times.map((t2, i) => fn(t2, i, times)));
|
|
5830
|
+
}
|
|
5831
|
+
function callableSeries(series, fn) {
|
|
5832
|
+
Object.setPrototypeOf(fn, Series.prototype);
|
|
5833
|
+
Object.assign(fn, series);
|
|
5834
|
+
return fn;
|
|
5835
|
+
}
|
|
5836
|
+
function timeFunction(tf, session2, timezone) {
|
|
5837
|
+
collector();
|
|
5838
|
+
const { bars: bars2, test } = calendarFor(session2, timezone);
|
|
5839
|
+
const timeframeString = tf || chartTimeframe().period;
|
|
5840
|
+
return perBar((t2) => test && !bars2.inside(t2) ? NaN : bars2.timeOf(t2, timeframeString));
|
|
5841
|
+
}
|
|
5842
|
+
function timeCloseFunction(tf, session2, timezone) {
|
|
5843
|
+
collector();
|
|
5844
|
+
const { bars: bars2, test } = calendarFor(session2, timezone);
|
|
5845
|
+
const timeframeString = tf || chartTimeframe().period;
|
|
5846
|
+
return perBar((t2) => test && !bars2.inside(t2) ? NaN : bars2.closeOf(t2, timeframeString));
|
|
5847
|
+
}
|
|
5848
|
+
var time = callableSeries(new Series(ctxBars, (b2) => barTime(b2)), timeFunction);
|
|
5849
|
+
var time_close = callableSeries(
|
|
5850
|
+
new Series(ctxBars, (_b, i) => sessionBars().bars.closeOf(barTime(ctxBars.bars[i]), chartTimeframe().period)),
|
|
5851
|
+
timeCloseFunction
|
|
5852
|
+
);
|
|
5853
|
+
var time_tradingday = new Series(ctxBars, (b2) => sessionBars().bars.tradingDayTime(barTime(b2)));
|
|
5854
|
+
function changeOf(tf) {
|
|
5855
|
+
const { bars: bars2 } = sessionBars();
|
|
5856
|
+
return perBar((t2, i, times) => i > 0 && bars2.timeOf(t2, tf) !== bars2.timeOf(times[i - 1], tf) ? 1 : 0);
|
|
5857
|
+
}
|
|
5858
|
+
function flag(key) {
|
|
5859
|
+
const { bars: bars2, regular } = sessionBars();
|
|
5860
|
+
const values = sessionFlags(ctxBars.bars.map(barTime), bars2, regular)[key];
|
|
5861
|
+
return Series.fromArray(ctxBars, values.map((v) => v ? 1 : 0));
|
|
5862
|
+
}
|
|
5863
|
+
var session = {
|
|
5864
|
+
regular: "regular",
|
|
5865
|
+
extended: "extended",
|
|
5866
|
+
get isfirstbar() {
|
|
5867
|
+
return flag("isfirstbar");
|
|
5868
|
+
},
|
|
5869
|
+
get islastbar() {
|
|
5870
|
+
return flag("islastbar");
|
|
5871
|
+
},
|
|
5872
|
+
get ismarket() {
|
|
5873
|
+
return flag("ismarket");
|
|
5874
|
+
},
|
|
5875
|
+
get ispremarket() {
|
|
5876
|
+
return flag("ispremarket");
|
|
5877
|
+
},
|
|
5878
|
+
get ispostmarket() {
|
|
5879
|
+
return flag("ispostmarket");
|
|
5880
|
+
},
|
|
5881
|
+
get isfirstbar_regular() {
|
|
5882
|
+
return flag("isfirstbar_regular");
|
|
5883
|
+
},
|
|
5884
|
+
get islastbar_regular() {
|
|
5885
|
+
return flag("islastbar_regular");
|
|
5886
|
+
}
|
|
5887
|
+
};
|
|
5888
|
+
var barmerge = {
|
|
5889
|
+
gaps_on: "gaps_on",
|
|
5890
|
+
gaps_off: "gaps_off",
|
|
5891
|
+
lookahead_on: "lookahead_on",
|
|
5892
|
+
lookahead_off: "lookahead_off"
|
|
5893
|
+
};
|
|
5894
|
+
var HEIKIN_ASHI = "heikinashi:";
|
|
5895
|
+
var ticker = {
|
|
5896
|
+
heikinashi(symbol) {
|
|
5897
|
+
return HEIKIN_ASHI + symbol;
|
|
5898
|
+
},
|
|
5899
|
+
standard(symbol) {
|
|
5900
|
+
return symbol.startsWith(HEIKIN_ASHI) ? symbol.slice(HEIKIN_ASHI.length) : symbol;
|
|
5901
|
+
}
|
|
5902
|
+
};
|
|
5903
|
+
function valuesOf(value, length2) {
|
|
5904
|
+
return value instanceof Series ? value.toArray().slice() : new Array(length2).fill(Number(value));
|
|
5905
|
+
}
|
|
5906
|
+
function security(symbol, timeframe2, expression, gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_off) {
|
|
5907
|
+
collector();
|
|
5908
|
+
const heikin = symbol.startsWith(HEIKIN_ASHI);
|
|
5909
|
+
const base = heikin ? symbol.slice(HEIKIN_ASHI.length) : symbol;
|
|
5910
|
+
if (base !== "" && base !== chartCtx.tickerid) {
|
|
5911
|
+
throw new Error(`request.security: "${symbol}" is not the chart symbol; other symbols need external data.`);
|
|
5912
|
+
}
|
|
5913
|
+
const chart2 = chartTimeframe();
|
|
5914
|
+
const tf = info(timeframe2 || chart2.period).period;
|
|
5915
|
+
if (in_seconds(tf) < in_seconds(chart2.period)) {
|
|
5916
|
+
throw new Error(`request.security: timeframe "${tf}" is lower than the chart timeframe "${chart2.period}".`);
|
|
5917
|
+
}
|
|
5918
|
+
const chartBars = ctxBars.bars;
|
|
5919
|
+
const times = chartBars.map(barTime);
|
|
5920
|
+
let htf;
|
|
5921
|
+
let group2;
|
|
5922
|
+
let latest;
|
|
5923
|
+
if (tf === chart2.period) {
|
|
5924
|
+
htf = chartBars;
|
|
5925
|
+
group2 = chartBars.map((_, i) => i);
|
|
5926
|
+
latest = group2;
|
|
5927
|
+
} else {
|
|
5928
|
+
const { bars: loaded, regular } = sessionBars();
|
|
5929
|
+
const calendar2 = info(tf).isdwm ? regular : loaded;
|
|
5930
|
+
const starts = times.map((t2) => calendar2.timeOf(t2, tf));
|
|
5931
|
+
const dayPeriods = times.map((t2, i) => {
|
|
5932
|
+
const at = loaded.calendar.locate(t2);
|
|
5933
|
+
const periods = at ? calendar2.calendar.periods(at.date) : [];
|
|
5934
|
+
return periods.length ? calendar2.timeOf(periods[0][0], tf) : starts[i];
|
|
5935
|
+
});
|
|
5936
|
+
const reaches = times.map((t2) => loaded.closeOf(t2, chart2.period) >= calendar2.periodEnd(t2, tf));
|
|
5937
|
+
({ group: group2, latest } = periodsOf(starts, dayPeriods, reaches));
|
|
5938
|
+
const unit = chartCtx.timeUnit === "ms" ? 1 : 1e3;
|
|
5939
|
+
htf = resample(chartBars, starts.map((s) => s / unit)).bars;
|
|
5940
|
+
}
|
|
5941
|
+
if (heikin) htf = heikinAshi(htf);
|
|
5942
|
+
const savedCtx = chartCtx;
|
|
5943
|
+
let result;
|
|
5944
|
+
let values;
|
|
5945
|
+
ctxBars.setAll(htf);
|
|
5946
|
+
chartCtx = { ...chartCtx, timeframe: tf };
|
|
5947
|
+
try {
|
|
5948
|
+
result = expression();
|
|
5949
|
+
const parts = Array.isArray(result) ? result : [result];
|
|
5950
|
+
values = parts.map((p) => valuesOf(p, htf.length));
|
|
5951
|
+
} finally {
|
|
5952
|
+
ctxBars.setAll(chartBars);
|
|
5953
|
+
chartCtx = savedCtx;
|
|
5954
|
+
}
|
|
5955
|
+
const mapped = values.map(
|
|
5956
|
+
(v) => Series.fromArray(ctxBars, mapToChart(v, group2, latest, lookahead === barmerge.lookahead_on, gaps === barmerge.gaps_on))
|
|
5957
|
+
);
|
|
5958
|
+
return Array.isArray(result) ? mapped : mapped[0];
|
|
5959
|
+
}
|
|
5960
|
+
var request = { security };
|
|
5961
|
+
var line = {
|
|
5962
|
+
...line_exports,
|
|
5963
|
+
get all() {
|
|
5964
|
+
return all2();
|
|
5965
|
+
}
|
|
5966
|
+
};
|
|
5967
|
+
var label = {
|
|
5968
|
+
...label_exports,
|
|
5969
|
+
get all() {
|
|
5970
|
+
return all3();
|
|
5971
|
+
}
|
|
5972
|
+
};
|
|
5973
|
+
var box = {
|
|
5974
|
+
...box_exports,
|
|
5975
|
+
get all() {
|
|
5976
|
+
return all4();
|
|
5977
|
+
}
|
|
5978
|
+
};
|
|
5979
|
+
var linefill = {
|
|
5980
|
+
...linefill_exports,
|
|
5981
|
+
get all() {
|
|
5982
|
+
return all5();
|
|
5983
|
+
}
|
|
5984
|
+
};
|
|
5985
|
+
var polyline = {
|
|
5986
|
+
...polyline_exports,
|
|
5987
|
+
get all() {
|
|
5988
|
+
return all6();
|
|
5989
|
+
}
|
|
5990
|
+
};
|
|
5991
|
+
var text = { ...text_exports };
|
|
5992
|
+
var chart = {
|
|
5993
|
+
point: {
|
|
5994
|
+
...chartpoint_exports,
|
|
5995
|
+
now(price) {
|
|
5996
|
+
collector();
|
|
5997
|
+
if (currentBar < 0) {
|
|
5998
|
+
throw new Error("chart.point.now() needs a current bar: call it inside eachBar().");
|
|
5999
|
+
}
|
|
6000
|
+
const bar = ctxBars.bars[currentBar];
|
|
6001
|
+
return new_point(barTime(bar), currentBar, price ?? bar.close);
|
|
6002
|
+
}
|
|
6003
|
+
}
|
|
6004
|
+
};
|
|
3572
6005
|
function seriesOf(values) {
|
|
3573
6006
|
collector();
|
|
3574
6007
|
return Series.fromArray(ctxBars, values);
|
|
@@ -3585,21 +6018,35 @@ export {
|
|
|
3585
6018
|
Series,
|
|
3586
6019
|
alertcondition,
|
|
3587
6020
|
barcolor,
|
|
6021
|
+
barmerge,
|
|
3588
6022
|
bgcolor,
|
|
6023
|
+
box,
|
|
6024
|
+
chart,
|
|
3589
6025
|
close,
|
|
3590
6026
|
color,
|
|
6027
|
+
compare_exports as compare,
|
|
6028
|
+
dayofmonth2 as dayofmonth,
|
|
6029
|
+
dayofweek2 as dayofweek,
|
|
3591
6030
|
eachBar,
|
|
3592
6031
|
executeScript,
|
|
3593
6032
|
fill,
|
|
6033
|
+
fixnan2 as fixnan,
|
|
3594
6034
|
high,
|
|
3595
6035
|
hl2,
|
|
3596
6036
|
hlc3,
|
|
3597
6037
|
hlcc4,
|
|
3598
6038
|
hline,
|
|
6039
|
+
hour2 as hour,
|
|
6040
|
+
inSession3 as inSession,
|
|
3599
6041
|
indicator,
|
|
3600
6042
|
input,
|
|
6043
|
+
label,
|
|
6044
|
+
line,
|
|
6045
|
+
linefill,
|
|
3601
6046
|
low,
|
|
3602
6047
|
math_exports as math,
|
|
6048
|
+
minute2 as minute,
|
|
6049
|
+
month2 as month,
|
|
3603
6050
|
isNA as na,
|
|
3604
6051
|
nz,
|
|
3605
6052
|
ohlc4,
|
|
@@ -3607,7 +6054,22 @@ export {
|
|
|
3607
6054
|
plot,
|
|
3608
6055
|
plotchar,
|
|
3609
6056
|
plotshape,
|
|
6057
|
+
polyline,
|
|
6058
|
+
request,
|
|
6059
|
+
second2 as second,
|
|
3610
6060
|
seriesOf,
|
|
6061
|
+
session,
|
|
6062
|
+
str,
|
|
6063
|
+
syminfo,
|
|
3611
6064
|
ta2 as ta,
|
|
3612
|
-
|
|
6065
|
+
text,
|
|
6066
|
+
ticker,
|
|
6067
|
+
time,
|
|
6068
|
+
time_close,
|
|
6069
|
+
time_tradingday,
|
|
6070
|
+
timeframe,
|
|
6071
|
+
timestamp2 as timestamp,
|
|
6072
|
+
volume,
|
|
6073
|
+
weekofyear2 as weekofyear,
|
|
6074
|
+
year2 as year
|
|
3613
6075
|
};
|