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