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