oakscriptjs 0.7.2 → 0.8.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/dist/callsite/index.d.ts +6 -0
- package/dist/callsite/index.d.ts.map +1 -0
- package/dist/index.cjs +258 -130
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +258 -130
- package/dist/script/index.cjs +1775 -1580
- package/dist/script/index.d.ts +100 -2
- package/dist/script/index.d.ts.map +1 -1
- package/dist/script/index.mjs +1775 -1580
- package/dist/strategy/index.d.ts +195 -0
- package/dist/strategy/index.d.ts.map +1 -0
- package/dist/ta/index.d.ts.map +1 -1
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/script/index.mjs
CHANGED
|
@@ -817,7 +817,7 @@ function tr(handle_na = false, high2, low2, close2) {
|
|
|
817
817
|
const result = [];
|
|
818
818
|
for (let i = 0; i < high2.length; i++) {
|
|
819
819
|
if (i === 0) {
|
|
820
|
-
result.push(high2[i] - low2[i]);
|
|
820
|
+
result.push(handle_na ? high2[i] - low2[i] : NaN);
|
|
821
821
|
} else {
|
|
822
822
|
const prevClose = close2[i - 1];
|
|
823
823
|
if (isNaN(prevClose)) {
|
|
@@ -844,7 +844,7 @@ function atr(length2, high2, low2, close2) {
|
|
|
844
844
|
"ta.atr() requires high, low, and close series. Either pass them explicitly or use createContext({ chart: { high, low, close } }) for implicit data."
|
|
845
845
|
);
|
|
846
846
|
}
|
|
847
|
-
const trueRange = tr(
|
|
847
|
+
const trueRange = tr(true, high2, low2, close2);
|
|
848
848
|
return rma(trueRange, length2);
|
|
849
849
|
}
|
|
850
850
|
function supertrend(factor, atrPeriod, high2, low2, close2, wicks = false) {
|
|
@@ -1321,48 +1321,26 @@ function mfi(source, length2, volume2) {
|
|
|
1321
1321
|
"ta.mfi() requires volume series. Either pass it explicitly or use createContext({ chart: { ..., volume } }) for implicit data."
|
|
1322
1322
|
);
|
|
1323
1323
|
}
|
|
1324
|
-
const
|
|
1325
|
-
const
|
|
1326
|
-
for (let i = 1; i < source.length; i++) {
|
|
1327
|
-
changes.push(source[i] - source[i - 1]);
|
|
1328
|
-
}
|
|
1329
|
-
const positiveFlow = [];
|
|
1330
|
-
const negativeFlow = [];
|
|
1331
|
-
for (let i = 0; i < source.length; i++) {
|
|
1332
|
-
if (i === 0 || isNaN(changes[i])) {
|
|
1333
|
-
positiveFlow.push(0);
|
|
1334
|
-
negativeFlow.push(0);
|
|
1335
|
-
} else if (changes[i] > 0) {
|
|
1336
|
-
positiveFlow.push(volume2[i] * source[i]);
|
|
1337
|
-
negativeFlow.push(0);
|
|
1338
|
-
} else if (changes[i] < 0) {
|
|
1339
|
-
positiveFlow.push(0);
|
|
1340
|
-
negativeFlow.push(volume2[i] * source[i]);
|
|
1341
|
-
} else {
|
|
1342
|
-
positiveFlow.push(0);
|
|
1343
|
-
negativeFlow.push(0);
|
|
1344
|
-
}
|
|
1345
|
-
}
|
|
1324
|
+
const upperFlow = [];
|
|
1325
|
+
const lowerFlow = [];
|
|
1346
1326
|
for (let i = 0; i < source.length; i++) {
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
}
|
|
1365
|
-
return result;
|
|
1327
|
+
const change3 = i === 0 ? NaN : source[i] - source[i - 1];
|
|
1328
|
+
const flow = volume2[i] * source[i];
|
|
1329
|
+
upperFlow.push(le(change3, 0) ? 0 : flow);
|
|
1330
|
+
lowerFlow.push(ge(change3, 0) ? 0 : flow);
|
|
1331
|
+
}
|
|
1332
|
+
const sumAt = (flow, i) => {
|
|
1333
|
+
const values = lastValues(flow, i, Math.floor(length2));
|
|
1334
|
+
return values ? values.reduce((a, b2) => a + b2, 0) : NaN;
|
|
1335
|
+
};
|
|
1336
|
+
const upper2 = upperFlow.map((_, i) => sumAt(upperFlow, i));
|
|
1337
|
+
const lower2 = lowerFlow.map((_, i) => sumAt(lowerFlow, i));
|
|
1338
|
+
return upper2.map((u, i) => {
|
|
1339
|
+
const l = lower2[i];
|
|
1340
|
+
if (Number.isNaN(u) || Number.isNaN(l)) return NaN;
|
|
1341
|
+
if (l === 0) return 100;
|
|
1342
|
+
return 100 - 100 / (1 + u / l);
|
|
1343
|
+
});
|
|
1366
1344
|
}
|
|
1367
1345
|
function hma(source, length2) {
|
|
1368
1346
|
const halfLength = Math.floor(length2 / 2);
|
|
@@ -1526,50 +1504,32 @@ function dmi(diLength, adxSmoothing, high2, low2, close2) {
|
|
|
1526
1504
|
const len = Math.max(high2.length, low2.length, close2.length);
|
|
1527
1505
|
const plusDM = [];
|
|
1528
1506
|
const minusDM = [];
|
|
1529
|
-
const trueRangeValues = tr(false, high2, low2, close2);
|
|
1530
|
-
for (let i = 0; i < len; i++) {
|
|
1531
|
-
if (i === 0) {
|
|
1532
|
-
plusDM.push(0);
|
|
1533
|
-
minusDM.push(0);
|
|
1534
|
-
} else {
|
|
1535
|
-
const upMove = high2[i] - high2[i - 1];
|
|
1536
|
-
const downMove = low2[i - 1] - low2[i];
|
|
1537
|
-
let plusDMVal = 0;
|
|
1538
|
-
let minusDMVal = 0;
|
|
1539
|
-
if (upMove > downMove && upMove > 0) {
|
|
1540
|
-
plusDMVal = upMove;
|
|
1541
|
-
}
|
|
1542
|
-
if (downMove > upMove && downMove > 0) {
|
|
1543
|
-
minusDMVal = downMove;
|
|
1544
|
-
}
|
|
1545
|
-
plusDM.push(plusDMVal);
|
|
1546
|
-
minusDM.push(minusDMVal);
|
|
1547
|
-
}
|
|
1548
|
-
}
|
|
1549
|
-
const smoothedPlusDM = rma(plusDM, diLength);
|
|
1550
|
-
const smoothedMinusDM = rma(minusDM, diLength);
|
|
1551
|
-
const smoothedTR = rma(trueRangeValues, diLength);
|
|
1552
|
-
const plusDI = [];
|
|
1553
|
-
const minusDI = [];
|
|
1554
|
-
for (let i = 0; i < len; i++) {
|
|
1555
|
-
if (smoothedTR[i] === 0) {
|
|
1556
|
-
plusDI.push(0);
|
|
1557
|
-
minusDI.push(0);
|
|
1558
|
-
} else {
|
|
1559
|
-
plusDI.push(smoothedPlusDM[i] / smoothedTR[i] * 100);
|
|
1560
|
-
minusDI.push(smoothedMinusDM[i] / smoothedTR[i] * 100);
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
|
-
const dx = [];
|
|
1564
1507
|
for (let i = 0; i < len; i++) {
|
|
1565
|
-
const
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
const
|
|
1508
|
+
const up = i === 0 ? NaN : high2[i] - high2[i - 1];
|
|
1509
|
+
const down = i === 0 ? NaN : low2[i - 1] - low2[i];
|
|
1510
|
+
plusDM.push(Number.isNaN(up) ? NaN : gt(up, down) && gt(up, 0) ? up : 0);
|
|
1511
|
+
minusDM.push(Number.isNaN(down) ? NaN : gt(down, up) && gt(down, 0) ? down : 0);
|
|
1512
|
+
}
|
|
1513
|
+
const trur = rma(tr(false, high2, low2, close2), diLength);
|
|
1514
|
+
const smoothedPlus = rma(plusDM, diLength);
|
|
1515
|
+
const smoothedMinus = rma(minusDM, diLength);
|
|
1516
|
+
const directional = (smoothed) => {
|
|
1517
|
+
let last = NaN;
|
|
1518
|
+
return smoothed.map((v, i) => {
|
|
1519
|
+
const t2 = trur[i];
|
|
1520
|
+
const value = t2 === 0 ? NaN : 100 * v / t2;
|
|
1521
|
+
if (!Number.isNaN(value)) last = value;
|
|
1522
|
+
return last;
|
|
1523
|
+
});
|
|
1524
|
+
};
|
|
1525
|
+
const plusDI = directional(smoothedPlus);
|
|
1526
|
+
const minusDI = directional(smoothedMinus);
|
|
1527
|
+
const dx = plusDI.map((plus, i) => {
|
|
1528
|
+
const minus = minusDI[i];
|
|
1529
|
+
const sum2 = plus + minus;
|
|
1530
|
+
return Math.abs(plus - minus) / (eq(sum2, 0) ? 1 : sum2);
|
|
1531
|
+
});
|
|
1532
|
+
const adx = rma(dx, adxSmoothing).map((v) => 100 * v);
|
|
1573
1533
|
return [plusDI, minusDI, adx];
|
|
1574
1534
|
}
|
|
1575
1535
|
function tsi(source, shortLength, longLength) {
|
|
@@ -3654,1640 +3614,1706 @@ var format_none = 0;
|
|
|
3654
3614
|
var format_bold = 1;
|
|
3655
3615
|
var format_italic = 2;
|
|
3656
3616
|
|
|
3657
|
-
// src/
|
|
3658
|
-
var
|
|
3659
|
-
__export(
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3617
|
+
// src/math/index.ts
|
|
3618
|
+
var math_exports = {};
|
|
3619
|
+
__export(math_exports, {
|
|
3620
|
+
abs: () => abs,
|
|
3621
|
+
acos: () => acos,
|
|
3622
|
+
asin: () => asin,
|
|
3623
|
+
atan: () => atan,
|
|
3624
|
+
avg: () => avg,
|
|
3625
|
+
ceil: () => ceil,
|
|
3626
|
+
cos: () => cos,
|
|
3627
|
+
e: () => e,
|
|
3628
|
+
exp: () => exp,
|
|
3629
|
+
floor: () => floor,
|
|
3630
|
+
log: () => log,
|
|
3631
|
+
log10: () => log10,
|
|
3632
|
+
max: () => max3,
|
|
3633
|
+
min: () => min3,
|
|
3634
|
+
phi: () => phi,
|
|
3635
|
+
pi: () => pi,
|
|
3636
|
+
pow: () => pow,
|
|
3637
|
+
random: () => random,
|
|
3638
|
+
round: () => round,
|
|
3639
|
+
round_to_mintick: () => round_to_mintick,
|
|
3640
|
+
rphi: () => rphi,
|
|
3641
|
+
sign: () => sign,
|
|
3642
|
+
sin: () => sin,
|
|
3643
|
+
sqrt: () => sqrt,
|
|
3644
|
+
sum: () => sum,
|
|
3645
|
+
tan: () => tan,
|
|
3646
|
+
todegrees: () => todegrees,
|
|
3647
|
+
toradians: () => toradians
|
|
3663
3648
|
});
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
};
|
|
3676
|
-
var SECOND_TIMEFRAMES = [1, 5, 10, 15, 30];
|
|
3677
|
-
function in_seconds(timeframe2) {
|
|
3678
|
-
const text2 = timeframe2.trim();
|
|
3679
|
-
if (text2 === "") {
|
|
3680
|
-
throw new RangeError("timeframe.in_seconds() needs a timeframe: the chart timeframe is not known here");
|
|
3649
|
+
function abs(value) {
|
|
3650
|
+
if (value instanceof Series) {
|
|
3651
|
+
const bars2 = value.bars;
|
|
3652
|
+
const valueArray = value.toArray();
|
|
3653
|
+
const length2 = bars2.length;
|
|
3654
|
+
const result = [];
|
|
3655
|
+
for (let i = 0; i < length2; i++) {
|
|
3656
|
+
const v = valueArray[i] ?? NaN;
|
|
3657
|
+
result.push(Math.abs(v));
|
|
3658
|
+
}
|
|
3659
|
+
return Series.fromArray(bars2, result);
|
|
3681
3660
|
}
|
|
3682
|
-
|
|
3683
|
-
const after = before ? null : /^([SDWMT])(\d+)$/.exec(text2);
|
|
3684
|
-
if (!before && !after) throw new RangeError(`Invalid timeframe "${timeframe2}"`);
|
|
3685
|
-
const [digits, unit] = before ? [before[1], before[2]] : [after[2], after[1]];
|
|
3686
|
-
if (unit === "T") return NaN;
|
|
3687
|
-
const multiplier = digits === "" ? 1 : Number(digits);
|
|
3688
|
-
return multiplier * UNIT_SECONDS[unit];
|
|
3661
|
+
return Math.abs(value);
|
|
3689
3662
|
}
|
|
3690
|
-
function
|
|
3691
|
-
if (
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3663
|
+
function ceil(value) {
|
|
3664
|
+
if (value instanceof Series) {
|
|
3665
|
+
const bars2 = value.bars;
|
|
3666
|
+
const valueArray = value.toArray();
|
|
3667
|
+
const length2 = bars2.length;
|
|
3668
|
+
const result = [];
|
|
3669
|
+
for (let i = 0; i < length2; i++) {
|
|
3670
|
+
const v = valueArray[i] ?? NaN;
|
|
3671
|
+
result.push(Math.ceil(v));
|
|
3672
|
+
}
|
|
3673
|
+
return Series.fromArray(bars2, result);
|
|
3698
3674
|
}
|
|
3699
|
-
|
|
3700
|
-
if (second3 !== void 0) return `${second3}S`;
|
|
3701
|
-
if (seconds < SECONDS_PER_DAY) return `${Math.ceil(seconds / SECONDS_PER_MINUTE)}`;
|
|
3702
|
-
return `${Math.ceil(seconds / SECONDS_PER_DAY)}D`;
|
|
3703
|
-
}
|
|
3704
|
-
function info(timeframe2) {
|
|
3705
|
-
const text2 = timeframe2.trim();
|
|
3706
|
-
const m = /^(\d*)([SDWMT]?)$/.exec(text2);
|
|
3707
|
-
if (!m || text2 === "") throw new RangeError(`Invalid timeframe "${timeframe2}"`);
|
|
3708
|
-
const unit = m[2];
|
|
3709
|
-
const multiplier = m[1] === "" ? 1 : Number(m[1]);
|
|
3710
|
-
return {
|
|
3711
|
-
period: unit === "" ? String(multiplier) : `${multiplier}${unit}`,
|
|
3712
|
-
multiplier,
|
|
3713
|
-
isintraday: unit === "" || unit === "S" || unit === "T",
|
|
3714
|
-
isdaily: unit === "D",
|
|
3715
|
-
isweekly: unit === "W",
|
|
3716
|
-
ismonthly: unit === "M",
|
|
3717
|
-
isminutes: unit === "",
|
|
3718
|
-
isseconds: unit === "S",
|
|
3719
|
-
isticks: unit === "T",
|
|
3720
|
-
isdwm: unit === "D" || unit === "W" || unit === "M"
|
|
3721
|
-
};
|
|
3722
|
-
}
|
|
3723
|
-
|
|
3724
|
-
// src/time/timezone.ts
|
|
3725
|
-
var MS_PER_SECOND = 1e3;
|
|
3726
|
-
var MS_PER_DAY = 864e5;
|
|
3727
|
-
var MAX_OFFSET_SECONDS = 18 * 3600;
|
|
3728
|
-
var OFFSET_NOTATION = /^(?:UTC|GMT)(?:([+-])(\d{1,2})(?::?(\d{2})(?::?(\d{2}))?)?)?$/;
|
|
3729
|
-
var REJECTED_NAMES = /* @__PURE__ */ new Set(["EST", "MST", "HST"]);
|
|
3730
|
-
var canonicalNames;
|
|
3731
|
-
function hasTimeZoneCase(name) {
|
|
3732
|
-
if (name.split("/").some((segment) => !/^[A-Z]/.test(segment))) return false;
|
|
3733
|
-
canonicalNames ??= new Map(Intl.supportedValuesOf("timeZone").map((n) => [n.toLowerCase(), n]));
|
|
3734
|
-
const canonical = canonicalNames.get(name.toLowerCase());
|
|
3735
|
-
return canonical === void 0 || canonical === name;
|
|
3675
|
+
return Math.ceil(value);
|
|
3736
3676
|
}
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
const [, sign2, h = "0", mi = "0", s] = m;
|
|
3747
|
-
const minutes = Number(mi);
|
|
3748
|
-
const seconds = s === void 0 ? 0 : Number(s);
|
|
3749
|
-
if (minutes > 59 || seconds > 59 || s !== void 0 && h.length !== 2) throw invalid();
|
|
3750
|
-
const offsetSeconds = Number(h) * 3600 + minutes * 60 + seconds;
|
|
3751
|
-
if (offsetSeconds > MAX_OFFSET_SECONDS) throw invalid();
|
|
3752
|
-
zone = { kind: "fixed", offsetMs: (sign2 === "-" ? -offsetSeconds : offsetSeconds) * MS_PER_SECOND };
|
|
3753
|
-
} else {
|
|
3754
|
-
if (REJECTED_NAMES.has(timezone) || !hasTimeZoneCase(timezone)) throw invalid();
|
|
3755
|
-
let format2;
|
|
3756
|
-
try {
|
|
3757
|
-
format2 = new Intl.DateTimeFormat("en-US", {
|
|
3758
|
-
timeZone: timezone,
|
|
3759
|
-
hourCycle: "h23",
|
|
3760
|
-
year: "numeric",
|
|
3761
|
-
month: "numeric",
|
|
3762
|
-
day: "numeric",
|
|
3763
|
-
hour: "numeric",
|
|
3764
|
-
minute: "numeric",
|
|
3765
|
-
second: "numeric"
|
|
3766
|
-
});
|
|
3767
|
-
} catch {
|
|
3768
|
-
throw invalid();
|
|
3677
|
+
function floor(value) {
|
|
3678
|
+
if (value instanceof Series) {
|
|
3679
|
+
const bars2 = value.bars;
|
|
3680
|
+
const valueArray = value.toArray();
|
|
3681
|
+
const length2 = bars2.length;
|
|
3682
|
+
const result = [];
|
|
3683
|
+
for (let i = 0; i < length2; i++) {
|
|
3684
|
+
const v = valueArray[i] ?? NaN;
|
|
3685
|
+
result.push(Math.floor(v));
|
|
3769
3686
|
}
|
|
3770
|
-
|
|
3687
|
+
return Series.fromArray(bars2, result);
|
|
3771
3688
|
}
|
|
3772
|
-
|
|
3773
|
-
return zone;
|
|
3689
|
+
return Math.floor(value);
|
|
3774
3690
|
}
|
|
3775
|
-
function
|
|
3776
|
-
if (
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3691
|
+
function round(value, precision) {
|
|
3692
|
+
if (value instanceof Series) {
|
|
3693
|
+
const bars2 = value.bars;
|
|
3694
|
+
const valueArray = value.toArray();
|
|
3695
|
+
const length2 = bars2.length;
|
|
3696
|
+
const result = [];
|
|
3697
|
+
if (precision === void 0) {
|
|
3698
|
+
for (let i = 0; i < length2; i++) {
|
|
3699
|
+
const v = valueArray[i] ?? NaN;
|
|
3700
|
+
result.push(Math.round(v));
|
|
3701
|
+
}
|
|
3702
|
+
} else {
|
|
3703
|
+
const multiplier2 = Math.pow(10, precision);
|
|
3704
|
+
for (let i = 0; i < length2; i++) {
|
|
3705
|
+
const v = valueArray[i] ?? NaN;
|
|
3706
|
+
result.push(Math.round(v * multiplier2) / multiplier2);
|
|
3707
|
+
}
|
|
3708
|
+
}
|
|
3709
|
+
return Series.fromArray(bars2, result);
|
|
3781
3710
|
}
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
}
|
|
3785
|
-
|
|
3786
|
-
return
|
|
3711
|
+
if (precision === void 0) {
|
|
3712
|
+
return Math.round(value);
|
|
3713
|
+
}
|
|
3714
|
+
const multiplier = Math.pow(10, precision);
|
|
3715
|
+
return Math.round(value * multiplier) / multiplier;
|
|
3787
3716
|
}
|
|
3788
|
-
function
|
|
3789
|
-
const
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
if (candidates.length) return Math.max(...candidates);
|
|
3808
|
-
return local - before;
|
|
3809
|
-
}
|
|
3810
|
-
|
|
3811
|
-
// src/time/datestring.ts
|
|
3812
|
-
var MONTHS = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"];
|
|
3813
|
-
var FULL_MONTHS = [
|
|
3814
|
-
"january",
|
|
3815
|
-
"february",
|
|
3816
|
-
"march",
|
|
3817
|
-
"april",
|
|
3818
|
-
"may",
|
|
3819
|
-
"june",
|
|
3820
|
-
"july",
|
|
3821
|
-
"august",
|
|
3822
|
-
"september",
|
|
3823
|
-
"october",
|
|
3824
|
-
"november",
|
|
3825
|
-
"december"
|
|
3826
|
-
];
|
|
3827
|
-
var ZONE_NAMES = {
|
|
3828
|
-
ut: 0,
|
|
3829
|
-
utc: 0,
|
|
3830
|
-
gmt: 0,
|
|
3831
|
-
est: -5,
|
|
3832
|
-
edt: -4,
|
|
3833
|
-
cst: -6,
|
|
3834
|
-
cdt: -5,
|
|
3835
|
-
mst: -7,
|
|
3836
|
-
mdt: -6,
|
|
3837
|
-
pst: -8,
|
|
3838
|
-
pdt: -7
|
|
3839
|
-
};
|
|
3840
|
-
var TIME = String.raw`(\d{1,2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3})\d*)?)?`;
|
|
3841
|
-
var ZONE = String.raw`(ut|utc|gmt|[ecmp][sd]t|(?:utc|gmt)?\s*[+-]\d{1,2}(?::?\d{2})?)`;
|
|
3842
|
-
var NUMERIC_ZONE = String.raw`([+-]\d{2}(?::?\d{2})?)`;
|
|
3843
|
-
var DATE = String.raw`(\d{4})([-/])(\d{1,2})\2(\d{1,2})`;
|
|
3844
|
-
var WEEKDAY = String.raw`(?:[a-z]{3,9},?\s+)?`;
|
|
3845
|
-
var ISO_T = new RegExp(String.raw`^${DATE}t${TIME}\s*${NUMERIC_ZONE}?$`, "i");
|
|
3846
|
-
var ISO = new RegExp(String.raw`^${DATE}(?:\s+${TIME})?\s*${ZONE}?$`, "i");
|
|
3847
|
-
var DAY_FIRST = new RegExp(String.raw`^${WEEKDAY}(\d{1,2})(?:\s+|-)([a-z]+)\.?,?(?:\s+|-)(\d{4})(?:,?\s+${TIME})?\s*${ZONE}?$`, "i");
|
|
3848
|
-
var MONTH_FIRST = new RegExp(String.raw`^${WEEKDAY}([a-z]+)\.?\s+(\d{1,2}),?\s+(\d{4})(?:,?\s+${TIME})?\s*${ZONE}?$`, "i");
|
|
3849
|
-
function monthNumber(name) {
|
|
3850
|
-
const lower2 = name.toLowerCase();
|
|
3851
|
-
const i = FULL_MONTHS.findIndex((full, k) => lower2.startsWith(MONTHS[k]) && full.startsWith(lower2));
|
|
3852
|
-
return i + 1;
|
|
3853
|
-
}
|
|
3854
|
-
function zoneMinutes(zone) {
|
|
3855
|
-
if (!zone) return 0;
|
|
3856
|
-
const lower2 = zone.toLowerCase().replace(/\s+/g, "");
|
|
3857
|
-
const named = ZONE_NAMES[lower2];
|
|
3858
|
-
if (named !== void 0) return named * 60;
|
|
3859
|
-
const m = /^(?:utc|gmt)?([+-])(\d{1,2})(?::?(\d{2}))?$/.exec(lower2);
|
|
3860
|
-
if (!m) return NaN;
|
|
3861
|
-
const minutes = Number(m[2]) * 60 + (m[3] ? Number(m[3]) : 0);
|
|
3862
|
-
return m[1] === "-" ? -minutes : minutes;
|
|
3717
|
+
function max3(...values) {
|
|
3718
|
+
const hasSeries = values.some((v) => v instanceof Series);
|
|
3719
|
+
if (!hasSeries) {
|
|
3720
|
+
return Math.max(...values);
|
|
3721
|
+
}
|
|
3722
|
+
const firstSeries = values.find((v) => v instanceof Series);
|
|
3723
|
+
const bars2 = firstSeries.bars;
|
|
3724
|
+
const length2 = bars2.length;
|
|
3725
|
+
const valueArrays = values.map(
|
|
3726
|
+
(v) => v instanceof Series ? v.toArray() : null
|
|
3727
|
+
);
|
|
3728
|
+
const result = [];
|
|
3729
|
+
for (let i = 0; i < length2; i++) {
|
|
3730
|
+
const nums = values.map(
|
|
3731
|
+
(v, idx) => valueArrays[idx] ? valueArrays[idx][i] ?? NaN : v
|
|
3732
|
+
);
|
|
3733
|
+
result.push(Math.max(...nums));
|
|
3734
|
+
}
|
|
3735
|
+
return Series.fromArray(bars2, result);
|
|
3863
3736
|
}
|
|
3864
|
-
function
|
|
3865
|
-
const
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
let m;
|
|
3869
|
-
if (m = ISO_T.exec(text2) ?? ISO.exec(text2)) {
|
|
3870
|
-
[year3, month3, day] = [m[1], Number(m[3]), m[4]];
|
|
3871
|
-
rest = m.slice(5);
|
|
3872
|
-
} else if (m = DAY_FIRST.exec(text2)) {
|
|
3873
|
-
[day, month3, year3] = [m[1], monthNumber(m[2]), m[3]];
|
|
3874
|
-
rest = m.slice(4);
|
|
3875
|
-
} else if (m = MONTH_FIRST.exec(text2)) {
|
|
3876
|
-
[month3, day, year3] = [monthNumber(m[1]), m[2], m[3]];
|
|
3877
|
-
rest = m.slice(4);
|
|
3878
|
-
} else {
|
|
3879
|
-
throw new SyntaxError(`Invalid date string "${dateString}": use RFC 2822 or ISO 8601 ("20 Feb 2020", "2020-02-20T14:48:00")`);
|
|
3737
|
+
function min3(...values) {
|
|
3738
|
+
const hasSeries = values.some((v) => v instanceof Series);
|
|
3739
|
+
if (!hasSeries) {
|
|
3740
|
+
return Math.min(...values);
|
|
3880
3741
|
}
|
|
3881
|
-
const
|
|
3882
|
-
const
|
|
3883
|
-
const
|
|
3884
|
-
const
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
const
|
|
3888
|
-
|
|
3889
|
-
|
|
3742
|
+
const firstSeries = values.find((v) => v instanceof Series);
|
|
3743
|
+
const bars2 = firstSeries.bars;
|
|
3744
|
+
const length2 = bars2.length;
|
|
3745
|
+
const valueArrays = values.map(
|
|
3746
|
+
(v) => v instanceof Series ? v.toArray() : null
|
|
3747
|
+
);
|
|
3748
|
+
const result = [];
|
|
3749
|
+
for (let i = 0; i < length2; i++) {
|
|
3750
|
+
const nums = values.map(
|
|
3751
|
+
(v, idx) => valueArrays[idx] ? valueArrays[idx][i] ?? NaN : v
|
|
3752
|
+
);
|
|
3753
|
+
result.push(Math.min(...nums));
|
|
3890
3754
|
}
|
|
3891
|
-
|
|
3892
|
-
return Date.UTC(Number(year3), month3 - 1, d, h, mi, s, ms) - offset * 6e4;
|
|
3755
|
+
return Series.fromArray(bars2, result);
|
|
3893
3756
|
}
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
const
|
|
3902
|
-
const
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
const
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
const days = new Array(8).fill(false);
|
|
3915
|
-
for (const d of dayDigits) days[Number(d)] = true;
|
|
3916
|
-
parsed = { periods, days };
|
|
3917
|
-
sessions.set(session2, parsed);
|
|
3918
|
-
return parsed;
|
|
3757
|
+
function avg(...values) {
|
|
3758
|
+
const hasSeries = values.some((v) => v instanceof Series);
|
|
3759
|
+
if (!hasSeries) {
|
|
3760
|
+
return values.reduce((a, b2) => a + b2, 0) / values.length;
|
|
3761
|
+
}
|
|
3762
|
+
const firstSeries = values.find((v) => v instanceof Series);
|
|
3763
|
+
const bars2 = firstSeries.bars;
|
|
3764
|
+
const length2 = bars2.length;
|
|
3765
|
+
const valueArrays = values.map(
|
|
3766
|
+
(v) => v instanceof Series ? v.toArray() : null
|
|
3767
|
+
);
|
|
3768
|
+
const result = [];
|
|
3769
|
+
for (let i = 0; i < length2; i++) {
|
|
3770
|
+
const nums = values.map(
|
|
3771
|
+
(v, idx) => valueArrays[idx] ? valueArrays[idx][i] ?? NaN : v
|
|
3772
|
+
);
|
|
3773
|
+
const sum2 = nums.reduce((a, b2) => a + b2, 0);
|
|
3774
|
+
result.push(sum2 / nums.length);
|
|
3775
|
+
}
|
|
3776
|
+
return Series.fromArray(bars2, result);
|
|
3919
3777
|
}
|
|
3920
|
-
function
|
|
3921
|
-
|
|
3922
|
-
const
|
|
3923
|
-
const
|
|
3924
|
-
const
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
if (
|
|
3928
|
-
|
|
3778
|
+
function sum(source, length2) {
|
|
3779
|
+
const sourceArray = source instanceof Series ? source.toArray() : source;
|
|
3780
|
+
const result = [];
|
|
3781
|
+
const len = Math.floor(length2);
|
|
3782
|
+
const window = [];
|
|
3783
|
+
for (let i = 0; i < sourceArray.length; i++) {
|
|
3784
|
+
const v = sourceArray[i];
|
|
3785
|
+
if (v !== void 0 && v !== null && !Number.isNaN(v)) {
|
|
3786
|
+
window.push(v);
|
|
3787
|
+
if (window.length > len) window.shift();
|
|
3788
|
+
}
|
|
3789
|
+
if (window.length < len) {
|
|
3790
|
+
result.push(NaN);
|
|
3929
3791
|
} else {
|
|
3930
|
-
|
|
3931
|
-
|
|
3792
|
+
let total = 0;
|
|
3793
|
+
for (const x of window) total += x;
|
|
3794
|
+
result.push(total);
|
|
3932
3795
|
}
|
|
3933
3796
|
}
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
// src/time/index.ts
|
|
3938
|
-
function timestamp(first, ...rest) {
|
|
3939
|
-
if (typeof first === "string") {
|
|
3940
|
-
if (rest.length === 0) return parseDateString(first);
|
|
3941
|
-
const [year3, month4, day2, hour4, minute4, second4] = rest;
|
|
3942
|
-
return zonedToUnix(first, year3, month4, day2, hour4 ?? 0, minute4 ?? 0, second4 ?? 0);
|
|
3797
|
+
if (source instanceof Series) {
|
|
3798
|
+
return Series.fromArray(source.bars, result);
|
|
3943
3799
|
}
|
|
3944
|
-
|
|
3945
|
-
return new Date(first, month3 - 1, day, hour3 || 0, minute3 || 0, second3 || 0).getTime();
|
|
3946
|
-
}
|
|
3947
|
-
function field(time2, timezone, pick) {
|
|
3948
|
-
return Number.isNaN(time2) ? NaN : pick(zonedFields(time2, timezone));
|
|
3949
|
-
}
|
|
3950
|
-
function year(time2, timezone) {
|
|
3951
|
-
return field(time2, timezone, (f) => f.year);
|
|
3800
|
+
return result;
|
|
3952
3801
|
}
|
|
3953
|
-
function
|
|
3954
|
-
|
|
3802
|
+
function sqrt(value) {
|
|
3803
|
+
if (value instanceof Series) {
|
|
3804
|
+
const bars2 = value.bars;
|
|
3805
|
+
const valueArray = value.toArray();
|
|
3806
|
+
const length2 = bars2.length;
|
|
3807
|
+
const result = [];
|
|
3808
|
+
for (let i = 0; i < length2; i++) {
|
|
3809
|
+
const v = valueArray[i] ?? NaN;
|
|
3810
|
+
result.push(Math.sqrt(v));
|
|
3811
|
+
}
|
|
3812
|
+
return Series.fromArray(bars2, result);
|
|
3813
|
+
}
|
|
3814
|
+
return Math.sqrt(value);
|
|
3955
3815
|
}
|
|
3956
|
-
function
|
|
3957
|
-
|
|
3816
|
+
function pow(base, exponent) {
|
|
3817
|
+
const baseIsSeries = base instanceof Series;
|
|
3818
|
+
const expIsSeries = exponent instanceof Series;
|
|
3819
|
+
if (!baseIsSeries && !expIsSeries) {
|
|
3820
|
+
return Math.pow(base, exponent);
|
|
3821
|
+
}
|
|
3822
|
+
const bars2 = baseIsSeries ? base.bars : exponent.bars;
|
|
3823
|
+
const baseArray = baseIsSeries ? base.toArray() : null;
|
|
3824
|
+
const expArray = expIsSeries ? exponent.toArray() : null;
|
|
3825
|
+
const length2 = bars2.length;
|
|
3826
|
+
const result = [];
|
|
3827
|
+
for (let i = 0; i < length2; i++) {
|
|
3828
|
+
const b2 = baseArray ? baseArray[i] ?? NaN : base;
|
|
3829
|
+
const e2 = expArray ? expArray[i] ?? NaN : exponent;
|
|
3830
|
+
result.push(Math.pow(b2, e2));
|
|
3831
|
+
}
|
|
3832
|
+
return Series.fromArray(bars2, result);
|
|
3958
3833
|
}
|
|
3959
|
-
function
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
const
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
}
|
|
3971
|
-
|
|
3972
|
-
return field(time2, timezone, (f) => f.hour);
|
|
3973
|
-
}
|
|
3974
|
-
function minute(time2, timezone) {
|
|
3975
|
-
return field(time2, timezone, (f) => f.minute);
|
|
3834
|
+
function exp(value) {
|
|
3835
|
+
if (value instanceof Series) {
|
|
3836
|
+
const bars2 = value.bars;
|
|
3837
|
+
const valueArray = value.toArray();
|
|
3838
|
+
const length2 = bars2.length;
|
|
3839
|
+
const result = [];
|
|
3840
|
+
for (let i = 0; i < length2; i++) {
|
|
3841
|
+
const v = valueArray[i] ?? NaN;
|
|
3842
|
+
result.push(Math.exp(v));
|
|
3843
|
+
}
|
|
3844
|
+
return Series.fromArray(bars2, result);
|
|
3845
|
+
}
|
|
3846
|
+
return Math.exp(value);
|
|
3976
3847
|
}
|
|
3977
|
-
function
|
|
3978
|
-
|
|
3848
|
+
function log(value) {
|
|
3849
|
+
if (value instanceof Series) {
|
|
3850
|
+
const bars2 = value.bars;
|
|
3851
|
+
const valueArray = value.toArray();
|
|
3852
|
+
const length2 = bars2.length;
|
|
3853
|
+
const result = [];
|
|
3854
|
+
for (let i = 0; i < length2; i++) {
|
|
3855
|
+
const v = valueArray[i] ?? NaN;
|
|
3856
|
+
result.push(Math.log(v));
|
|
3857
|
+
}
|
|
3858
|
+
return Series.fromArray(bars2, result);
|
|
3859
|
+
}
|
|
3860
|
+
return Math.log(value);
|
|
3979
3861
|
}
|
|
3980
|
-
function
|
|
3981
|
-
|
|
3862
|
+
function log10(value) {
|
|
3863
|
+
if (value instanceof Series) {
|
|
3864
|
+
const bars2 = value.bars;
|
|
3865
|
+
const valueArray = value.toArray();
|
|
3866
|
+
const length2 = bars2.length;
|
|
3867
|
+
const result = [];
|
|
3868
|
+
for (let i = 0; i < length2; i++) {
|
|
3869
|
+
const v = valueArray[i] ?? NaN;
|
|
3870
|
+
result.push(Math.log10(v));
|
|
3871
|
+
}
|
|
3872
|
+
return Series.fromArray(bars2, result);
|
|
3873
|
+
}
|
|
3874
|
+
return Math.log10(value);
|
|
3982
3875
|
}
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
format_time: () => format_time,
|
|
3993
|
-
length: () => length,
|
|
3994
|
-
lower: () => lower,
|
|
3995
|
-
match: () => match,
|
|
3996
|
-
pos: () => pos,
|
|
3997
|
-
repeat: () => repeat,
|
|
3998
|
-
replace: () => replace,
|
|
3999
|
-
replace_all: () => replace_all,
|
|
4000
|
-
split: () => split,
|
|
4001
|
-
startswith: () => startswith,
|
|
4002
|
-
substring: () => substring,
|
|
4003
|
-
tonumber: () => tonumber,
|
|
4004
|
-
tostring: () => tostring,
|
|
4005
|
-
trim: () => trim,
|
|
4006
|
-
trimLeft: () => trimLeft,
|
|
4007
|
-
trimRight: () => trimRight,
|
|
4008
|
-
upper: () => upper
|
|
4009
|
-
});
|
|
4010
|
-
|
|
4011
|
-
// src/str/numberformat.ts
|
|
4012
|
-
var patterns = /* @__PURE__ */ new Map();
|
|
4013
|
-
function parsePattern(pattern) {
|
|
4014
|
-
const cached = patterns.get(pattern);
|
|
4015
|
-
if (cached) return cached;
|
|
4016
|
-
let prefix = "";
|
|
4017
|
-
let suffix = "";
|
|
4018
|
-
let number2 = "";
|
|
4019
|
-
let percent = false;
|
|
4020
|
-
let phase = "prefix";
|
|
4021
|
-
for (let i = 0; i < pattern.length; i++) {
|
|
4022
|
-
const ch = pattern[i];
|
|
4023
|
-
let literal;
|
|
4024
|
-
if (ch === "'") {
|
|
4025
|
-
const end = pattern.indexOf("'", i + 1);
|
|
4026
|
-
if (end === i + 1) {
|
|
4027
|
-
literal = "'";
|
|
4028
|
-
i = end;
|
|
4029
|
-
} else {
|
|
4030
|
-
literal = pattern.slice(i + 1, end === -1 ? void 0 : end);
|
|
4031
|
-
i = end === -1 ? pattern.length : end;
|
|
4032
|
-
}
|
|
4033
|
-
} else if (phase !== "suffix" && ("#0,.".includes(ch) || phase === "number" && ch === "E")) {
|
|
4034
|
-
phase = "number";
|
|
4035
|
-
number2 += ch;
|
|
4036
|
-
continue;
|
|
4037
|
-
} else {
|
|
4038
|
-
if (ch === "%") percent = true;
|
|
4039
|
-
literal = ch;
|
|
3876
|
+
function sin(value) {
|
|
3877
|
+
if (value instanceof Series) {
|
|
3878
|
+
const bars2 = value.bars;
|
|
3879
|
+
const valueArray = value.toArray();
|
|
3880
|
+
const length2 = bars2.length;
|
|
3881
|
+
const result = [];
|
|
3882
|
+
for (let i = 0; i < length2; i++) {
|
|
3883
|
+
const v = valueArray[i] ?? NaN;
|
|
3884
|
+
result.push(Math.sin(v));
|
|
4040
3885
|
}
|
|
4041
|
-
|
|
4042
|
-
if (phase === "prefix") prefix += literal;
|
|
4043
|
-
else suffix += literal;
|
|
3886
|
+
return Series.fromArray(bars2, result);
|
|
4044
3887
|
}
|
|
4045
|
-
|
|
4046
|
-
const [intPart = "", fracPart = ""] = mantissa.split(".");
|
|
4047
|
-
const lastComma = intPart.lastIndexOf(",");
|
|
4048
|
-
const parsed = {
|
|
4049
|
-
prefix,
|
|
4050
|
-
suffix,
|
|
4051
|
-
// as in Java, a pattern with a decimal point and no '0' at all ("#.##") shows one integer digit
|
|
4052
|
-
minInt: !mantissa.includes("0") && mantissa.includes(".") ? 1 : [...intPart].filter((c) => c === "0").length,
|
|
4053
|
-
minFrac: [...fracPart].filter((c) => c === "0").length,
|
|
4054
|
-
maxFrac: [...fracPart].filter((c) => c === "0" || c === "#").length,
|
|
4055
|
-
grouping: lastComma === -1 ? 0 : intPart.length - lastComma - 1,
|
|
4056
|
-
percent,
|
|
4057
|
-
exponent: exp2 === void 0 ? null : exp2.length,
|
|
4058
|
-
hasDigits: /[0#]/.test(mantissa)
|
|
4059
|
-
};
|
|
4060
|
-
patterns.set(pattern, parsed);
|
|
4061
|
-
return parsed;
|
|
3888
|
+
return Math.sin(value);
|
|
4062
3889
|
}
|
|
4063
|
-
function
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
3890
|
+
function cos(value) {
|
|
3891
|
+
if (value instanceof Series) {
|
|
3892
|
+
const bars2 = value.bars;
|
|
3893
|
+
const valueArray = value.toArray();
|
|
3894
|
+
const length2 = bars2.length;
|
|
3895
|
+
const result = [];
|
|
3896
|
+
for (let i = 0; i < length2; i++) {
|
|
3897
|
+
const v = valueArray[i] ?? NaN;
|
|
3898
|
+
result.push(Math.cos(v));
|
|
3899
|
+
}
|
|
3900
|
+
return Series.fromArray(bars2, result);
|
|
3901
|
+
}
|
|
3902
|
+
return Math.cos(value);
|
|
4071
3903
|
}
|
|
4072
|
-
function
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
let fracDigits;
|
|
4084
|
-
if (e2 >= 0) {
|
|
4085
|
-
str2 = (mant << BigInt(e2)).toString();
|
|
4086
|
-
fracDigits = 0;
|
|
4087
|
-
} else {
|
|
4088
|
-
str2 = (mant * 5n ** BigInt(-e2)).toString();
|
|
4089
|
-
fracDigits = -e2;
|
|
3904
|
+
function tan(value) {
|
|
3905
|
+
if (value instanceof Series) {
|
|
3906
|
+
const bars2 = value.bars;
|
|
3907
|
+
const valueArray = value.toArray();
|
|
3908
|
+
const length2 = bars2.length;
|
|
3909
|
+
const result = [];
|
|
3910
|
+
for (let i = 0; i < length2; i++) {
|
|
3911
|
+
const v = valueArray[i] ?? NaN;
|
|
3912
|
+
result.push(Math.tan(v));
|
|
3913
|
+
}
|
|
3914
|
+
return Series.fromArray(bars2, result);
|
|
4090
3915
|
}
|
|
4091
|
-
|
|
4092
|
-
const lead = str2.length - str2.replace(/^0+/, "").length;
|
|
4093
|
-
const digits = str2.slice(lead).replace(/0+$/, "");
|
|
4094
|
-
return { digits, intLen: intLen - lead };
|
|
3916
|
+
return Math.tan(value);
|
|
4095
3917
|
}
|
|
4096
|
-
function
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
let intLen = d.intLen;
|
|
4108
|
-
if (up) {
|
|
4109
|
-
const n = (BigInt(kept || "0") + 1n).toString();
|
|
4110
|
-
if (n.length > kept.length) intLen += 1;
|
|
4111
|
-
kept = n;
|
|
3918
|
+
function asin(value) {
|
|
3919
|
+
if (value instanceof Series) {
|
|
3920
|
+
const bars2 = value.bars;
|
|
3921
|
+
const valueArray = value.toArray();
|
|
3922
|
+
const length2 = bars2.length;
|
|
3923
|
+
const result = [];
|
|
3924
|
+
for (let i = 0; i < length2; i++) {
|
|
3925
|
+
const v = valueArray[i] ?? NaN;
|
|
3926
|
+
result.push(Math.asin(v));
|
|
3927
|
+
}
|
|
3928
|
+
return Series.fromArray(bars2, result);
|
|
4112
3929
|
}
|
|
4113
|
-
|
|
4114
|
-
return { digits: kept, intLen: kept ? intLen : 0 };
|
|
3930
|
+
return Math.asin(value);
|
|
4115
3931
|
}
|
|
4116
|
-
function
|
|
4117
|
-
if (
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
3932
|
+
function acos(value) {
|
|
3933
|
+
if (value instanceof Series) {
|
|
3934
|
+
const bars2 = value.bars;
|
|
3935
|
+
const valueArray = value.toArray();
|
|
3936
|
+
const length2 = bars2.length;
|
|
3937
|
+
const result = [];
|
|
3938
|
+
for (let i = 0; i < length2; i++) {
|
|
3939
|
+
const v = valueArray[i] ?? NaN;
|
|
3940
|
+
result.push(Math.acos(v));
|
|
3941
|
+
}
|
|
3942
|
+
return Series.fromArray(bars2, result);
|
|
3943
|
+
}
|
|
3944
|
+
return Math.acos(value);
|
|
4121
3945
|
}
|
|
4122
|
-
function
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
3946
|
+
function atan(value) {
|
|
3947
|
+
if (value instanceof Series) {
|
|
3948
|
+
const bars2 = value.bars;
|
|
3949
|
+
const valueArray = value.toArray();
|
|
3950
|
+
const length2 = bars2.length;
|
|
3951
|
+
const result = [];
|
|
3952
|
+
for (let i = 0; i < length2; i++) {
|
|
3953
|
+
const v = valueArray[i] ?? NaN;
|
|
3954
|
+
result.push(Math.atan(v));
|
|
3955
|
+
}
|
|
3956
|
+
return Series.fromArray(bars2, result);
|
|
3957
|
+
}
|
|
3958
|
+
return Math.atan(value);
|
|
4129
3959
|
}
|
|
4130
|
-
function
|
|
4131
|
-
if (
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
const rounded = roundDigits(toDigits(x), p.maxFrac, mode3);
|
|
4140
|
-
const intDigits = Math.max(p.minInt, 1);
|
|
4141
|
-
isZero = rounded.digits === "";
|
|
4142
|
-
let exponent = isZero ? 0 : rounded.intLen - intDigits;
|
|
4143
|
-
let mant = roundDigits({ digits: rounded.digits, intLen: isZero ? 0 : intDigits }, p.maxFrac, mode3);
|
|
4144
|
-
if (mant.intLen > intDigits) {
|
|
4145
|
-
exponent += 1;
|
|
4146
|
-
mant = { digits: mant.digits, intLen: intDigits };
|
|
3960
|
+
function toradians(degrees) {
|
|
3961
|
+
if (degrees instanceof Series) {
|
|
3962
|
+
const bars2 = degrees.bars;
|
|
3963
|
+
const valueArray = degrees.toArray();
|
|
3964
|
+
const length2 = bars2.length;
|
|
3965
|
+
const result = [];
|
|
3966
|
+
for (let i = 0; i < length2; i++) {
|
|
3967
|
+
const v = valueArray[i] ?? NaN;
|
|
3968
|
+
result.push(v * (Math.PI / 180));
|
|
4147
3969
|
}
|
|
4148
|
-
|
|
4149
|
-
body = layout(mant, p) + "E" + (exponent < 0 ? "-" : "") + e2;
|
|
4150
|
-
} else {
|
|
4151
|
-
const rounded = roundDigits(toDigits(x), p.hasDigits ? p.maxFrac : 0, mode3);
|
|
4152
|
-
isZero = rounded.digits === "";
|
|
4153
|
-
body = p.hasDigits ? layout(rounded, p) : layout(rounded, { ...p, minInt: 0, maxFrac: 0, minFrac: 0 });
|
|
3970
|
+
return Series.fromArray(bars2, result);
|
|
4154
3971
|
}
|
|
4155
|
-
|
|
4156
|
-
return (negative ? "-" : "") + p.prefix + body + p.suffix;
|
|
3972
|
+
return degrees * (Math.PI / 180);
|
|
4157
3973
|
}
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
"September",
|
|
4170
|
-
"October",
|
|
4171
|
-
"November",
|
|
4172
|
-
"December"
|
|
4173
|
-
];
|
|
4174
|
-
var DAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
4175
|
-
var pad = (n, width) => String(n).padStart(width, "0");
|
|
4176
|
-
function zoneName(time2, timezone, offsetMs) {
|
|
4177
|
-
if (timezone === "Etc/UTC") return "UTC";
|
|
4178
|
-
if (/^(UTC|GMT)/.test(timezone)) {
|
|
4179
|
-
if (offsetMs === 0) return "GMT";
|
|
4180
|
-
const minutes = Math.abs(offsetMs) / 6e4;
|
|
4181
|
-
return `GMT${offsetMs < 0 ? "-" : "+"}${pad(Math.floor(minutes / 60), 2)}:${pad(minutes % 60, 2)}`;
|
|
3974
|
+
function todegrees(radians) {
|
|
3975
|
+
if (radians instanceof Series) {
|
|
3976
|
+
const bars2 = radians.bars;
|
|
3977
|
+
const valueArray = radians.toArray();
|
|
3978
|
+
const length2 = bars2.length;
|
|
3979
|
+
const result = [];
|
|
3980
|
+
for (let i = 0; i < length2; i++) {
|
|
3981
|
+
const v = valueArray[i] ?? NaN;
|
|
3982
|
+
result.push(v * (180 / Math.PI));
|
|
3983
|
+
}
|
|
3984
|
+
return Series.fromArray(bars2, result);
|
|
4182
3985
|
}
|
|
4183
|
-
|
|
4184
|
-
return part?.value ?? timezone;
|
|
3986
|
+
return radians * (180 / Math.PI);
|
|
4185
3987
|
}
|
|
4186
|
-
function
|
|
4187
|
-
const
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
const jan1Dow = new Date(jan1).getUTCDay();
|
|
4193
|
-
return Math.floor((date - jan1 + jan1Dow * 864e5) / (7 * 864e5)) + 1;
|
|
3988
|
+
function random(min4, max4, _seed) {
|
|
3989
|
+
const rand = Math.random();
|
|
3990
|
+
if (min4 !== void 0 && max4 !== void 0) {
|
|
3991
|
+
return min4 + rand * (max4 - min4);
|
|
3992
|
+
}
|
|
3993
|
+
return rand;
|
|
4194
3994
|
}
|
|
4195
|
-
function
|
|
4196
|
-
if (
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
if (ch === "'") {
|
|
4205
|
-
const end = pattern.indexOf("'", i + 1);
|
|
4206
|
-
if (end === i + 1) {
|
|
4207
|
-
out += "'";
|
|
4208
|
-
i += 2;
|
|
4209
|
-
} else {
|
|
4210
|
-
out += pattern.slice(i + 1, end === -1 ? void 0 : end);
|
|
4211
|
-
i = end === -1 ? pattern.length : end + 1;
|
|
4212
|
-
}
|
|
4213
|
-
continue;
|
|
3995
|
+
function sign(value) {
|
|
3996
|
+
if (value instanceof Series) {
|
|
3997
|
+
const bars2 = value.bars;
|
|
3998
|
+
const valueArray = value.toArray();
|
|
3999
|
+
const length2 = bars2.length;
|
|
4000
|
+
const result = [];
|
|
4001
|
+
for (let i = 0; i < length2; i++) {
|
|
4002
|
+
const v = valueArray[i] ?? NaN;
|
|
4003
|
+
result.push(v > 0 ? 1 : v < 0 ? -1 : 0);
|
|
4214
4004
|
}
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4005
|
+
return Series.fromArray(bars2, result);
|
|
4006
|
+
}
|
|
4007
|
+
return value > 0 ? 1 : value < 0 ? -1 : 0;
|
|
4008
|
+
}
|
|
4009
|
+
function round_to_mintick(number2, mintick) {
|
|
4010
|
+
if (number2 instanceof Series) {
|
|
4011
|
+
const bars2 = number2.bars;
|
|
4012
|
+
const valueArray = number2.toArray();
|
|
4013
|
+
const length2 = bars2.length;
|
|
4014
|
+
if (mintick === void 0) {
|
|
4015
|
+
throw new Error(
|
|
4016
|
+
"math.round_to_mintick() requires mintick value. Either pass it explicitly or use createContext({ syminfo: { mintick } }) for implicit data."
|
|
4017
|
+
);
|
|
4219
4018
|
}
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
break;
|
|
4234
|
-
case "E":
|
|
4235
|
-
out += n >= 4 ? DAYS[f.dayOfWeek - 1] : DAYS[f.dayOfWeek - 1].slice(0, 3);
|
|
4236
|
-
break;
|
|
4237
|
-
case "u":
|
|
4238
|
-
out += pad(f.dayOfWeek === 1 ? 7 : f.dayOfWeek - 1, n);
|
|
4239
|
-
break;
|
|
4240
|
-
case "D":
|
|
4241
|
-
out += pad(dayOfYear, n);
|
|
4242
|
-
break;
|
|
4243
|
-
case "w":
|
|
4244
|
-
out += pad(weekOfYear(f.year, f.month, f.day), n);
|
|
4245
|
-
break;
|
|
4246
|
-
case "H":
|
|
4247
|
-
out += pad(f.hour, n);
|
|
4248
|
-
break;
|
|
4249
|
-
case "k":
|
|
4250
|
-
out += pad(f.hour === 0 ? 24 : f.hour, n);
|
|
4251
|
-
break;
|
|
4252
|
-
case "K":
|
|
4253
|
-
out += pad(hour12, n);
|
|
4254
|
-
break;
|
|
4255
|
-
case "h":
|
|
4256
|
-
out += pad(hour12 === 0 ? 12 : hour12, n);
|
|
4257
|
-
break;
|
|
4258
|
-
case "a":
|
|
4259
|
-
out += f.hour < 12 ? "AM" : "PM";
|
|
4260
|
-
break;
|
|
4261
|
-
case "m":
|
|
4262
|
-
out += pad(f.minute, n);
|
|
4263
|
-
break;
|
|
4264
|
-
case "s":
|
|
4265
|
-
out += pad(f.second, n);
|
|
4266
|
-
break;
|
|
4267
|
-
case "S":
|
|
4268
|
-
out += pad(ms, n);
|
|
4269
|
-
break;
|
|
4270
|
-
case "Z": {
|
|
4271
|
-
const minutes = Math.abs(offset) / 6e4;
|
|
4272
|
-
out += (offset < 0 ? "-" : "+") + pad(Math.floor(minutes / 60), 2) + pad(minutes % 60, 2);
|
|
4273
|
-
break;
|
|
4019
|
+
const result = [];
|
|
4020
|
+
if (mintick === 0) {
|
|
4021
|
+
for (let i = 0; i < length2; i++) {
|
|
4022
|
+
result.push(valueArray[i] ?? NaN);
|
|
4023
|
+
}
|
|
4024
|
+
} else {
|
|
4025
|
+
for (let i = 0; i < length2; i++) {
|
|
4026
|
+
const v = valueArray[i];
|
|
4027
|
+
if (v === void 0 || isNaN(v)) {
|
|
4028
|
+
result.push(NaN);
|
|
4029
|
+
} else {
|
|
4030
|
+
result.push(Math.round(v / mintick) * mintick);
|
|
4031
|
+
}
|
|
4274
4032
|
}
|
|
4275
|
-
case "z":
|
|
4276
|
-
out += zoneName(time2, timezone, offset);
|
|
4277
|
-
break;
|
|
4278
|
-
default:
|
|
4279
|
-
throw new SyntaxError(`Unsupported date pattern letter "${ch}" in "${pattern}"`);
|
|
4280
4033
|
}
|
|
4034
|
+
return Series.fromArray(bars2, result);
|
|
4281
4035
|
}
|
|
4282
|
-
|
|
4036
|
+
if (isNaN(number2)) {
|
|
4037
|
+
return NaN;
|
|
4038
|
+
}
|
|
4039
|
+
if (mintick === void 0) {
|
|
4040
|
+
throw new Error(
|
|
4041
|
+
"math.round_to_mintick() requires mintick value. Either pass it explicitly or use createContext({ syminfo: { mintick } }) for implicit data."
|
|
4042
|
+
);
|
|
4043
|
+
}
|
|
4044
|
+
if (mintick === 0) {
|
|
4045
|
+
return number2;
|
|
4046
|
+
}
|
|
4047
|
+
return Math.round(number2 / mintick) * mintick;
|
|
4283
4048
|
}
|
|
4049
|
+
var pi = Math.PI;
|
|
4050
|
+
var e = Math.E;
|
|
4051
|
+
var phi = 1.618033988749895;
|
|
4052
|
+
var rphi = 0.618033988749895;
|
|
4284
4053
|
|
|
4285
|
-
// src/
|
|
4286
|
-
var
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
};
|
|
4292
|
-
var
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
for (const o of options) if (value >= o.limit) chosen = o;
|
|
4310
|
-
return chosen.text;
|
|
4311
|
-
}
|
|
4312
|
-
function formatArgument(value, type, style, timezone) {
|
|
4313
|
-
if (value === void 0) return "";
|
|
4314
|
-
if (!type) return typeof value === "number" ? number(value, "#,##0.###") : String(value);
|
|
4315
|
-
switch (type.trim()) {
|
|
4316
|
-
case "number": {
|
|
4317
|
-
const s = style?.trim();
|
|
4318
|
-
if (!s) return number(value, "#,##0.###");
|
|
4319
|
-
if (s === "integer") return number(value, "#,##0");
|
|
4320
|
-
if (s === "percent") return number(value, "#,##0%");
|
|
4321
|
-
if (s === "currency") return number(value, "'$'#,##0.00");
|
|
4322
|
-
return number(value, style);
|
|
4323
|
-
}
|
|
4324
|
-
case "date":
|
|
4325
|
-
case "time": {
|
|
4326
|
-
const styles = type.trim() === "date" ? DATE_STYLES : TIME_STYLES;
|
|
4327
|
-
const s = style?.trim() ?? "medium";
|
|
4328
|
-
return formatDate(Number(value), styles[s] ?? style, typeof timezone === "function" ? timezone() : timezone);
|
|
4329
|
-
}
|
|
4330
|
-
case "choice":
|
|
4331
|
-
return choice(Number(value), style ?? "");
|
|
4332
|
-
default:
|
|
4333
|
-
throw new SyntaxError(`Unknown format type "${type}"`);
|
|
4054
|
+
// src/timeframe/index.ts
|
|
4055
|
+
var timeframe_exports = {};
|
|
4056
|
+
__export(timeframe_exports, {
|
|
4057
|
+
from_seconds: () => from_seconds,
|
|
4058
|
+
in_seconds: () => in_seconds,
|
|
4059
|
+
info: () => info
|
|
4060
|
+
});
|
|
4061
|
+
var SECONDS_PER_MINUTE = 60;
|
|
4062
|
+
var SECONDS_PER_DAY = 86400;
|
|
4063
|
+
var SECONDS_PER_WEEK = 604800;
|
|
4064
|
+
var SECONDS_PER_MONTH = 2628003;
|
|
4065
|
+
var SECONDS_365_DAYS = 365 * SECONDS_PER_DAY;
|
|
4066
|
+
var UNIT_SECONDS = {
|
|
4067
|
+
S: 1,
|
|
4068
|
+
"": SECONDS_PER_MINUTE,
|
|
4069
|
+
D: SECONDS_PER_DAY,
|
|
4070
|
+
W: SECONDS_PER_WEEK,
|
|
4071
|
+
M: SECONDS_PER_MONTH
|
|
4072
|
+
};
|
|
4073
|
+
var SECOND_TIMEFRAMES = [1, 5, 10, 15, 30];
|
|
4074
|
+
function in_seconds(timeframe2) {
|
|
4075
|
+
const text2 = timeframe2.trim();
|
|
4076
|
+
if (text2 === "") {
|
|
4077
|
+
throw new RangeError("timeframe.in_seconds() needs a timeframe: the chart timeframe is not known here");
|
|
4334
4078
|
}
|
|
4079
|
+
const before = /^(\d*)([SDWMT]?)$/.exec(text2);
|
|
4080
|
+
const after = before ? null : /^([SDWMT])(\d+)$/.exec(text2);
|
|
4081
|
+
if (!before && !after) throw new RangeError(`Invalid timeframe "${timeframe2}"`);
|
|
4082
|
+
const [digits, unit] = before ? [before[1], before[2]] : [after[2], after[1]];
|
|
4083
|
+
if (unit === "T") return NaN;
|
|
4084
|
+
const multiplier = digits === "" ? 1 : Number(digits);
|
|
4085
|
+
return multiplier * UNIT_SECONDS[unit];
|
|
4335
4086
|
}
|
|
4336
|
-
function
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
if (
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
continue;
|
|
4345
|
-
}
|
|
4346
|
-
const end = pattern.indexOf("'", i + 1);
|
|
4347
|
-
out += pattern.slice(i + 1, end === -1 ? void 0 : end);
|
|
4348
|
-
i = end === -1 ? pattern.length : end + 1;
|
|
4349
|
-
continue;
|
|
4350
|
-
}
|
|
4351
|
-
if (ch !== "{") {
|
|
4352
|
-
out += ch;
|
|
4353
|
-
i++;
|
|
4354
|
-
continue;
|
|
4355
|
-
}
|
|
4356
|
-
let depth = 1;
|
|
4357
|
-
let j = i + 1;
|
|
4358
|
-
let inQuote = false;
|
|
4359
|
-
for (; j < pattern.length && depth > 0; j++) {
|
|
4360
|
-
const c = pattern[j];
|
|
4361
|
-
if (c === "'") inQuote = !inQuote;
|
|
4362
|
-
else if (!inQuote && c === "{") depth++;
|
|
4363
|
-
else if (!inQuote && c === "}") depth--;
|
|
4364
|
-
}
|
|
4365
|
-
const inner = pattern.slice(i + 1, j - 1);
|
|
4366
|
-
const [index = "", type, ...rest] = inner.split(",");
|
|
4367
|
-
const style = rest.length ? rest.join(",") : void 0;
|
|
4368
|
-
const n = Number(index.trim());
|
|
4369
|
-
out += n < args.length ? formatArgument(args[n], type, style, timezone) : `{${inner}}`;
|
|
4370
|
-
i = j;
|
|
4087
|
+
function from_seconds(seconds) {
|
|
4088
|
+
if (Number.isNaN(seconds)) throw new RangeError("timeframe.from_seconds() needs a number of seconds");
|
|
4089
|
+
if (seconds >= SECONDS_365_DAYS) return "12M";
|
|
4090
|
+
if (seconds > 0) {
|
|
4091
|
+
if (seconds % SECONDS_PER_MONTH === 0) return `${seconds / SECONDS_PER_MONTH}M`;
|
|
4092
|
+
if (seconds % SECONDS_PER_WEEK === 0) return `${seconds / SECONDS_PER_WEEK}W`;
|
|
4093
|
+
if (seconds % SECONDS_PER_DAY === 0) return `${seconds / SECONDS_PER_DAY}D`;
|
|
4094
|
+
if (seconds % SECONDS_PER_MINUTE === 0 && seconds < SECONDS_PER_DAY) return `${seconds / SECONDS_PER_MINUTE}`;
|
|
4371
4095
|
}
|
|
4372
|
-
|
|
4096
|
+
const second3 = SECOND_TIMEFRAMES.find((m) => seconds <= m);
|
|
4097
|
+
if (second3 !== void 0) return `${second3}S`;
|
|
4098
|
+
if (seconds < SECONDS_PER_DAY) return `${Math.ceil(seconds / SECONDS_PER_MINUTE)}`;
|
|
4099
|
+
return `${Math.ceil(seconds / SECONDS_PER_DAY)}D`;
|
|
4100
|
+
}
|
|
4101
|
+
function info(timeframe2) {
|
|
4102
|
+
const text2 = timeframe2.trim();
|
|
4103
|
+
const m = /^(\d*)([SDWMT]?)$/.exec(text2);
|
|
4104
|
+
if (!m || text2 === "") throw new RangeError(`Invalid timeframe "${timeframe2}"`);
|
|
4105
|
+
const unit = m[2];
|
|
4106
|
+
const multiplier = m[1] === "" ? 1 : Number(m[1]);
|
|
4107
|
+
return {
|
|
4108
|
+
period: unit === "" ? String(multiplier) : `${multiplier}${unit}`,
|
|
4109
|
+
multiplier,
|
|
4110
|
+
isintraday: unit === "" || unit === "S" || unit === "T",
|
|
4111
|
+
isdaily: unit === "D",
|
|
4112
|
+
isweekly: unit === "W",
|
|
4113
|
+
ismonthly: unit === "M",
|
|
4114
|
+
isminutes: unit === "",
|
|
4115
|
+
isseconds: unit === "S",
|
|
4116
|
+
isticks: unit === "T",
|
|
4117
|
+
isdwm: unit === "D" || unit === "W" || unit === "M"
|
|
4118
|
+
};
|
|
4373
4119
|
}
|
|
4374
4120
|
|
|
4375
|
-
// src/
|
|
4376
|
-
|
|
4377
|
-
|
|
4121
|
+
// src/time/timezone.ts
|
|
4122
|
+
var MS_PER_SECOND = 1e3;
|
|
4123
|
+
var MS_PER_DAY = 864e5;
|
|
4124
|
+
var MAX_OFFSET_SECONDS = 18 * 3600;
|
|
4125
|
+
var OFFSET_NOTATION = /^(?:UTC|GMT)(?:([+-])(\d{1,2})(?::?(\d{2})(?::?(\d{2}))?)?)?$/;
|
|
4126
|
+
var REJECTED_NAMES = /* @__PURE__ */ new Set(["EST", "MST", "HST"]);
|
|
4127
|
+
var canonicalNames;
|
|
4128
|
+
function hasTimeZoneCase(name) {
|
|
4129
|
+
if (name.split("/").some((segment) => !/^[A-Z]/.test(segment))) return false;
|
|
4130
|
+
canonicalNames ??= new Map(Intl.supportedValuesOf("timeZone").map((n) => [n.toLowerCase(), n]));
|
|
4131
|
+
const canonical = canonicalNames.get(name.toLowerCase());
|
|
4132
|
+
return canonical === void 0 || canonical === name;
|
|
4378
4133
|
}
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
if (
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4134
|
+
var zones = /* @__PURE__ */ new Map();
|
|
4135
|
+
function resolveZone(timezone) {
|
|
4136
|
+
let zone = zones.get(timezone);
|
|
4137
|
+
if (zone) return zone;
|
|
4138
|
+
const invalid = () => new RangeError(
|
|
4139
|
+
`Invalid time zone "${timezone}": use UTC/GMT offset notation ("UTC-5", "GMT+0530") or an IANA name ("America/New_York")`
|
|
4140
|
+
);
|
|
4141
|
+
const m = OFFSET_NOTATION.exec(timezone);
|
|
4142
|
+
if (m) {
|
|
4143
|
+
const [, sign2, h = "0", mi = "0", s] = m;
|
|
4144
|
+
const minutes = Number(mi);
|
|
4145
|
+
const seconds = s === void 0 ? 0 : Number(s);
|
|
4146
|
+
if (minutes > 59 || seconds > 59 || s !== void 0 && h.length !== 2) throw invalid();
|
|
4147
|
+
const offsetSeconds = Number(h) * 3600 + minutes * 60 + seconds;
|
|
4148
|
+
if (offsetSeconds > MAX_OFFSET_SECONDS) throw invalid();
|
|
4149
|
+
zone = { kind: "fixed", offsetMs: (sign2 === "-" ? -offsetSeconds : offsetSeconds) * MS_PER_SECOND };
|
|
4150
|
+
} else {
|
|
4151
|
+
if (REJECTED_NAMES.has(timezone) || !hasTimeZoneCase(timezone)) throw invalid();
|
|
4152
|
+
let format2;
|
|
4153
|
+
try {
|
|
4154
|
+
format2 = new Intl.DateTimeFormat("en-US", {
|
|
4155
|
+
timeZone: timezone,
|
|
4156
|
+
hourCycle: "h23",
|
|
4157
|
+
year: "numeric",
|
|
4158
|
+
month: "numeric",
|
|
4159
|
+
day: "numeric",
|
|
4160
|
+
hour: "numeric",
|
|
4161
|
+
minute: "numeric",
|
|
4162
|
+
second: "numeric"
|
|
4163
|
+
});
|
|
4164
|
+
} catch {
|
|
4165
|
+
throw invalid();
|
|
4397
4166
|
}
|
|
4398
|
-
|
|
4399
|
-
throw new Error("str.tostring(x, format.mintick) needs the symbol tick size (syminfo.mintick), which is not known here");
|
|
4400
|
-
default:
|
|
4401
|
-
return formatNumber(value, format2, "halfUpShortest");
|
|
4167
|
+
zone = { kind: "iana", format: format2 };
|
|
4402
4168
|
}
|
|
4169
|
+
zones.set(timezone, zone);
|
|
4170
|
+
return zone;
|
|
4403
4171
|
}
|
|
4404
|
-
function
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
}
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
}
|
|
4411
|
-
function upper(str2) {
|
|
4412
|
-
return str2.toUpperCase();
|
|
4413
|
-
}
|
|
4414
|
-
function lower(str2) {
|
|
4415
|
-
return str2.toLowerCase();
|
|
4416
|
-
}
|
|
4417
|
-
function contains(source, str2) {
|
|
4418
|
-
return source.includes(str2);
|
|
4419
|
-
}
|
|
4420
|
-
function pos(source, str2) {
|
|
4421
|
-
return source.indexOf(str2);
|
|
4422
|
-
}
|
|
4423
|
-
function replace(source, target, replacement, occurrence) {
|
|
4424
|
-
if (occurrence === 0) {
|
|
4425
|
-
return source.replace(target, replacement);
|
|
4426
|
-
} else {
|
|
4427
|
-
return source.replaceAll(target, replacement);
|
|
4172
|
+
function offsetAt(zone, time2) {
|
|
4173
|
+
if (zone.kind === "fixed") return zone.offsetMs;
|
|
4174
|
+
const wholeSecond = Math.floor(time2 / 1e3) * 1e3;
|
|
4175
|
+
const f = {};
|
|
4176
|
+
for (const part of zone.format.formatToParts(wholeSecond)) {
|
|
4177
|
+
if (part.type !== "literal") f[part.type] = Number(part.value);
|
|
4428
4178
|
}
|
|
4179
|
+
const local = Date.UTC(f.year, f.month - 1, f.day, f.hour, f.minute, f.second);
|
|
4180
|
+
return local - wholeSecond;
|
|
4429
4181
|
}
|
|
4430
|
-
function
|
|
4431
|
-
return
|
|
4432
|
-
}
|
|
4433
|
-
function split(str2, separator) {
|
|
4434
|
-
return str2.split(separator);
|
|
4435
|
-
}
|
|
4436
|
-
function concat(...strings) {
|
|
4437
|
-
return strings.join("");
|
|
4182
|
+
function zoneOffset(time2, timezone) {
|
|
4183
|
+
return offsetAt(resolveZone(timezone), time2);
|
|
4438
4184
|
}
|
|
4439
|
-
function
|
|
4440
|
-
|
|
4185
|
+
function zonedFields(time2, timezone) {
|
|
4186
|
+
const local = new Date(time2 + offsetAt(resolveZone(timezone), time2));
|
|
4187
|
+
return {
|
|
4188
|
+
year: local.getUTCFullYear(),
|
|
4189
|
+
month: local.getUTCMonth() + 1,
|
|
4190
|
+
day: local.getUTCDate(),
|
|
4191
|
+
hour: local.getUTCHours(),
|
|
4192
|
+
minute: local.getUTCMinutes(),
|
|
4193
|
+
second: local.getUTCSeconds(),
|
|
4194
|
+
dayOfWeek: local.getUTCDay() + 1
|
|
4195
|
+
};
|
|
4441
4196
|
}
|
|
4442
|
-
function
|
|
4443
|
-
|
|
4197
|
+
function zonedToUnix(timezone, year3, month3, day, hour3 = 0, minute3 = 0, second3 = 0) {
|
|
4198
|
+
const zone = resolveZone(timezone);
|
|
4199
|
+
const local = Date.UTC(year3, month3 - 1, day, hour3, minute3, second3);
|
|
4200
|
+
if (zone.kind === "fixed") return local - zone.offsetMs;
|
|
4201
|
+
const before = offsetAt(zone, local - MS_PER_DAY);
|
|
4202
|
+
const after = offsetAt(zone, local + MS_PER_DAY);
|
|
4203
|
+
const candidates = [local - before, local - after].filter((t2) => local - offsetAt(zone, t2) === t2);
|
|
4204
|
+
if (candidates.length) return Math.max(...candidates);
|
|
4205
|
+
return local - before;
|
|
4444
4206
|
}
|
|
4445
|
-
|
|
4446
|
-
|
|
4207
|
+
|
|
4208
|
+
// src/time/datestring.ts
|
|
4209
|
+
var MONTHS = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"];
|
|
4210
|
+
var FULL_MONTHS = [
|
|
4211
|
+
"january",
|
|
4212
|
+
"february",
|
|
4213
|
+
"march",
|
|
4214
|
+
"april",
|
|
4215
|
+
"may",
|
|
4216
|
+
"june",
|
|
4217
|
+
"july",
|
|
4218
|
+
"august",
|
|
4219
|
+
"september",
|
|
4220
|
+
"october",
|
|
4221
|
+
"november",
|
|
4222
|
+
"december"
|
|
4223
|
+
];
|
|
4224
|
+
var ZONE_NAMES = {
|
|
4225
|
+
ut: 0,
|
|
4226
|
+
utc: 0,
|
|
4227
|
+
gmt: 0,
|
|
4228
|
+
est: -5,
|
|
4229
|
+
edt: -4,
|
|
4230
|
+
cst: -6,
|
|
4231
|
+
cdt: -5,
|
|
4232
|
+
mst: -7,
|
|
4233
|
+
mdt: -6,
|
|
4234
|
+
pst: -8,
|
|
4235
|
+
pdt: -7
|
|
4236
|
+
};
|
|
4237
|
+
var TIME = String.raw`(\d{1,2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3})\d*)?)?`;
|
|
4238
|
+
var ZONE = String.raw`(ut|utc|gmt|[ecmp][sd]t|(?:utc|gmt)?\s*[+-]\d{1,2}(?::?\d{2})?)`;
|
|
4239
|
+
var NUMERIC_ZONE = String.raw`([+-]\d{2}(?::?\d{2})?)`;
|
|
4240
|
+
var DATE = String.raw`(\d{4})([-/])(\d{1,2})\2(\d{1,2})`;
|
|
4241
|
+
var WEEKDAY = String.raw`(?:[a-z]{3,9},?\s+)?`;
|
|
4242
|
+
var ISO_T = new RegExp(String.raw`^${DATE}t${TIME}\s*${NUMERIC_ZONE}?$`, "i");
|
|
4243
|
+
var ISO = new RegExp(String.raw`^${DATE}(?:\s+${TIME})?\s*${ZONE}?$`, "i");
|
|
4244
|
+
var DAY_FIRST = new RegExp(String.raw`^${WEEKDAY}(\d{1,2})(?:\s+|-)([a-z]+)\.?,?(?:\s+|-)(\d{4})(?:,?\s+${TIME})?\s*${ZONE}?$`, "i");
|
|
4245
|
+
var MONTH_FIRST = new RegExp(String.raw`^${WEEKDAY}([a-z]+)\.?\s+(\d{1,2}),?\s+(\d{4})(?:,?\s+${TIME})?\s*${ZONE}?$`, "i");
|
|
4246
|
+
function monthNumber(name) {
|
|
4247
|
+
const lower2 = name.toLowerCase();
|
|
4248
|
+
const i = FULL_MONTHS.findIndex((full, k) => lower2.startsWith(MONTHS[k]) && full.startsWith(lower2));
|
|
4249
|
+
return i + 1;
|
|
4447
4250
|
}
|
|
4448
|
-
function
|
|
4449
|
-
|
|
4251
|
+
function zoneMinutes(zone) {
|
|
4252
|
+
if (!zone) return 0;
|
|
4253
|
+
const lower2 = zone.toLowerCase().replace(/\s+/g, "");
|
|
4254
|
+
const named = ZONE_NAMES[lower2];
|
|
4255
|
+
if (named !== void 0) return named * 60;
|
|
4256
|
+
const m = /^(?:utc|gmt)?([+-])(\d{1,2})(?::?(\d{2}))?$/.exec(lower2);
|
|
4257
|
+
if (!m) return NaN;
|
|
4258
|
+
const minutes = Number(m[2]) * 60 + (m[3] ? Number(m[3]) : 0);
|
|
4259
|
+
return m[1] === "-" ? -minutes : minutes;
|
|
4450
4260
|
}
|
|
4451
|
-
function
|
|
4452
|
-
|
|
4261
|
+
function parseDateString(dateString) {
|
|
4262
|
+
const text2 = dateString.trim();
|
|
4263
|
+
let year3, month3, day;
|
|
4264
|
+
let rest;
|
|
4265
|
+
let m;
|
|
4266
|
+
if (m = ISO_T.exec(text2) ?? ISO.exec(text2)) {
|
|
4267
|
+
[year3, month3, day] = [m[1], Number(m[3]), m[4]];
|
|
4268
|
+
rest = m.slice(5);
|
|
4269
|
+
} else if (m = DAY_FIRST.exec(text2)) {
|
|
4270
|
+
[day, month3, year3] = [m[1], monthNumber(m[2]), m[3]];
|
|
4271
|
+
rest = m.slice(4);
|
|
4272
|
+
} else if (m = MONTH_FIRST.exec(text2)) {
|
|
4273
|
+
[month3, day, year3] = [monthNumber(m[1]), m[2], m[3]];
|
|
4274
|
+
rest = m.slice(4);
|
|
4275
|
+
} else {
|
|
4276
|
+
throw new SyntaxError(`Invalid date string "${dateString}": use RFC 2822 or ISO 8601 ("20 Feb 2020", "2020-02-20T14:48:00")`);
|
|
4277
|
+
}
|
|
4278
|
+
const [hour3 = "0", minute3 = "0", second3 = "0", millis = "0", zone] = rest;
|
|
4279
|
+
const d = Number(day);
|
|
4280
|
+
const h = Number(hour3);
|
|
4281
|
+
const mi = Number(minute3);
|
|
4282
|
+
const s = Number(second3);
|
|
4283
|
+
const offset = zoneMinutes(zone);
|
|
4284
|
+
const endOfDay = h === 24 && mi === 0 && s === 0 && Number(millis) === 0;
|
|
4285
|
+
if (month3 < 1 || month3 > 12 || d < 1 || d > 31 || h > 23 && !endOfDay || mi > 59 || s > 59 || Number.isNaN(offset)) {
|
|
4286
|
+
throw new SyntaxError(`Invalid date string "${dateString}": a field is out of range`);
|
|
4287
|
+
}
|
|
4288
|
+
const ms = Number(millis.padEnd(3, "0"));
|
|
4289
|
+
return Date.UTC(Number(year3), month3 - 1, d, h, mi, s, ms) - offset * 6e4;
|
|
4453
4290
|
}
|
|
4454
|
-
|
|
4455
|
-
|
|
4291
|
+
|
|
4292
|
+
// src/time/session.ts
|
|
4293
|
+
var PERIOD = /^(\d{2})(\d{2})-(\d{2})(\d{2})$/;
|
|
4294
|
+
var sessions = /* @__PURE__ */ new Map();
|
|
4295
|
+
function parseSession(session2) {
|
|
4296
|
+
let parsed = sessions.get(session2);
|
|
4297
|
+
if (parsed) return parsed;
|
|
4298
|
+
const invalid = () => new SyntaxError(`Invalid session "${session2}": expected "HHmm-HHmm[,HHmm-HHmm...][:days]"`);
|
|
4299
|
+
const text2 = session2.trim() === "24x7" ? "0000-0000" : session2.replace(/\s+/g, "");
|
|
4300
|
+
const [periodText = "", dayText, extra] = text2.split(":");
|
|
4301
|
+
if (extra !== void 0 || periodText === "") throw invalid();
|
|
4302
|
+
const periods = periodText.split(",").map((p) => {
|
|
4303
|
+
const m = PERIOD.exec(p);
|
|
4304
|
+
if (!m) throw invalid();
|
|
4305
|
+
const [h1, m1, h2, m2] = [m[1], m[2], m[3], m[4]].map(Number);
|
|
4306
|
+
if (h1 > 23 || h2 > 23 || m1 > 59 || m2 > 59) throw invalid();
|
|
4307
|
+
return { start: h1 * 60 + m1, end: h2 * 60 + m2 };
|
|
4308
|
+
});
|
|
4309
|
+
const dayDigits = dayText ?? (periods.length > 1 ? "23456" : "1234567");
|
|
4310
|
+
if (!/^[1-7]+$/.test(dayDigits)) throw invalid();
|
|
4311
|
+
const days = new Array(8).fill(false);
|
|
4312
|
+
for (const d of dayDigits) days[Number(d)] = true;
|
|
4313
|
+
parsed = { periods, days };
|
|
4314
|
+
sessions.set(session2, parsed);
|
|
4315
|
+
return parsed;
|
|
4456
4316
|
}
|
|
4457
|
-
function
|
|
4458
|
-
|
|
4317
|
+
function inSession(time2, session2, timezone) {
|
|
4318
|
+
if (Number.isNaN(time2)) return false;
|
|
4319
|
+
const { periods, days } = parseSession(session2);
|
|
4320
|
+
const f = zonedFields(time2, timezone);
|
|
4321
|
+
const minute3 = f.hour * 60 + f.minute;
|
|
4322
|
+
const nextDay = f.dayOfWeek % 7 + 1;
|
|
4323
|
+
for (const { start, end } of periods) {
|
|
4324
|
+
if (start < end || start === 0 && end === 0) {
|
|
4325
|
+
if (minute3 >= start && (minute3 < end || end === 0) && days[f.dayOfWeek]) return true;
|
|
4326
|
+
} else {
|
|
4327
|
+
if (minute3 >= start && days[nextDay]) return true;
|
|
4328
|
+
if (minute3 < end && days[f.dayOfWeek]) return true;
|
|
4329
|
+
}
|
|
4330
|
+
}
|
|
4331
|
+
return false;
|
|
4459
4332
|
}
|
|
4460
|
-
|
|
4461
|
-
|
|
4333
|
+
|
|
4334
|
+
// src/time/index.ts
|
|
4335
|
+
function timestamp(first, ...rest) {
|
|
4336
|
+
if (typeof first === "string") {
|
|
4337
|
+
if (rest.length === 0) return parseDateString(first);
|
|
4338
|
+
const [year3, month4, day2, hour4, minute4, second4] = rest;
|
|
4339
|
+
return zonedToUnix(first, year3, month4, day2, hour4 ?? 0, minute4 ?? 0, second4 ?? 0);
|
|
4340
|
+
}
|
|
4341
|
+
const [month3, day, hour3, minute3, second3] = rest;
|
|
4342
|
+
return new Date(first, month3 - 1, day, hour3 || 0, minute3 || 0, second3 || 0).getTime();
|
|
4462
4343
|
}
|
|
4463
|
-
function
|
|
4464
|
-
|
|
4465
|
-
if (count <= 0) return "";
|
|
4466
|
-
return Array(count).fill(source).join(separator);
|
|
4344
|
+
function field(time2, timezone, pick) {
|
|
4345
|
+
return Number.isNaN(time2) ? NaN : pick(zonedFields(time2, timezone));
|
|
4467
4346
|
}
|
|
4468
|
-
function
|
|
4469
|
-
return
|
|
4347
|
+
function year(time2, timezone) {
|
|
4348
|
+
return field(time2, timezone, (f) => f.year);
|
|
4470
4349
|
}
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
var toDateNum = (y, m, d) => y * 1e4 + m * 100 + d;
|
|
4474
|
-
var utcOf = (date) => Date.UTC(Math.floor(date / 1e4), Math.floor(date / 100) % 100 - 1, date % 100);
|
|
4475
|
-
var fromUtc = (ms) => {
|
|
4476
|
-
const d = new Date(ms);
|
|
4477
|
-
return toDateNum(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate());
|
|
4478
|
-
};
|
|
4479
|
-
var addDays = (date, n) => fromUtc(utcOf(date) + n * 864e5);
|
|
4480
|
-
var weekdayOf = (date) => new Date(utcOf(date)).getUTCDay() + 1;
|
|
4481
|
-
var dateUtcMs = utcOf;
|
|
4482
|
-
function parseTime(token, spec) {
|
|
4483
|
-
const m = /^(\d{2})(\d{2})(?:F(\d+))?$/.exec(token.trim());
|
|
4484
|
-
if (!m) throw new SyntaxError(`Invalid session "${spec}"`);
|
|
4485
|
-
return { minutes: Number(m[1]) * 60 + Number(m[2]), offset: m[3] === void 0 ? void 0 : Number(m[3]) };
|
|
4350
|
+
function month(time2, timezone) {
|
|
4351
|
+
return field(time2, timezone, (f) => f.month);
|
|
4486
4352
|
}
|
|
4487
|
-
function
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
endOffset: e2.offset ?? 0
|
|
4501
|
-
};
|
|
4353
|
+
function dayofmonth(time2, timezone) {
|
|
4354
|
+
return field(time2, timezone, (f) => f.day);
|
|
4355
|
+
}
|
|
4356
|
+
function dayofweek(time2, timezone) {
|
|
4357
|
+
return field(time2, timezone, (f) => f.dayOfWeek);
|
|
4358
|
+
}
|
|
4359
|
+
function weekofyear(time2, timezone) {
|
|
4360
|
+
return field(time2, timezone, (f) => {
|
|
4361
|
+
const date = Date.UTC(f.year, f.month - 1, f.day);
|
|
4362
|
+
const mondayBased = (f.dayOfWeek + 5) % 7;
|
|
4363
|
+
const thursday = new Date(date + (3 - mondayBased) * 864e5);
|
|
4364
|
+
const yearStart = Date.UTC(thursday.getUTCFullYear(), 0, 1);
|
|
4365
|
+
return 1 + Math.floor((thursday.getTime() - yearStart) / (7 * 864e5));
|
|
4502
4366
|
});
|
|
4503
4367
|
}
|
|
4504
|
-
function
|
|
4505
|
-
|
|
4506
|
-
const periods = parsePeriods(periodText, spec);
|
|
4507
|
-
const allDays = periodText.trim() === "24x7" || rule === "pine" && periods.length === 1;
|
|
4508
|
-
const digits = dayText ?? (allDays ? "1234567" : "23456");
|
|
4509
|
-
if (!/^[1-7]+$/.test(digits)) throw new SyntaxError(`Invalid session days in "${spec}"`);
|
|
4510
|
-
const days = new Array(8).fill(false);
|
|
4511
|
-
for (const d of digits) days[Number(d)] = true;
|
|
4512
|
-
return { from, periods, days };
|
|
4368
|
+
function hour(time2, timezone) {
|
|
4369
|
+
return field(time2, timezone, (f) => f.hour);
|
|
4513
4370
|
}
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
if (
|
|
4579
|
-
|
|
4580
|
-
for (let k = 5; k >= -7; k--) {
|
|
4581
|
-
const date = addDays(local, k);
|
|
4582
|
-
const periods = this.periods(date);
|
|
4583
|
-
let index = -1;
|
|
4584
|
-
periods.forEach(([s], i) => {
|
|
4585
|
-
if (s <= time2) index = i;
|
|
4586
|
-
});
|
|
4587
|
-
if (index !== -1) return { date, index, inside: false };
|
|
4371
|
+
function minute(time2, timezone) {
|
|
4372
|
+
return field(time2, timezone, (f) => f.minute);
|
|
4373
|
+
}
|
|
4374
|
+
function second(time2, timezone) {
|
|
4375
|
+
return field(time2, timezone, (f) => f.second);
|
|
4376
|
+
}
|
|
4377
|
+
function inSession2(time2, session2, timezone) {
|
|
4378
|
+
return inSession(time2, session2, timezone);
|
|
4379
|
+
}
|
|
4380
|
+
|
|
4381
|
+
// src/str/index.ts
|
|
4382
|
+
var str_exports = {};
|
|
4383
|
+
__export(str_exports, {
|
|
4384
|
+
charAt: () => charAt,
|
|
4385
|
+
concat: () => concat,
|
|
4386
|
+
contains: () => contains,
|
|
4387
|
+
endswith: () => endswith,
|
|
4388
|
+
format: () => format,
|
|
4389
|
+
format_time: () => format_time,
|
|
4390
|
+
length: () => length,
|
|
4391
|
+
lower: () => lower,
|
|
4392
|
+
match: () => match,
|
|
4393
|
+
pos: () => pos,
|
|
4394
|
+
repeat: () => repeat,
|
|
4395
|
+
replace: () => replace,
|
|
4396
|
+
replace_all: () => replace_all,
|
|
4397
|
+
split: () => split,
|
|
4398
|
+
startswith: () => startswith,
|
|
4399
|
+
substring: () => substring,
|
|
4400
|
+
tonumber: () => tonumber,
|
|
4401
|
+
tostring: () => tostring,
|
|
4402
|
+
trim: () => trim,
|
|
4403
|
+
trimLeft: () => trimLeft,
|
|
4404
|
+
trimRight: () => trimRight,
|
|
4405
|
+
upper: () => upper
|
|
4406
|
+
});
|
|
4407
|
+
|
|
4408
|
+
// src/str/numberformat.ts
|
|
4409
|
+
var patterns = /* @__PURE__ */ new Map();
|
|
4410
|
+
function parsePattern(pattern) {
|
|
4411
|
+
const cached = patterns.get(pattern);
|
|
4412
|
+
if (cached) return cached;
|
|
4413
|
+
let prefix = "";
|
|
4414
|
+
let suffix = "";
|
|
4415
|
+
let number2 = "";
|
|
4416
|
+
let percent = false;
|
|
4417
|
+
let phase = "prefix";
|
|
4418
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
4419
|
+
const ch = pattern[i];
|
|
4420
|
+
let literal;
|
|
4421
|
+
if (ch === "'") {
|
|
4422
|
+
const end = pattern.indexOf("'", i + 1);
|
|
4423
|
+
if (end === i + 1) {
|
|
4424
|
+
literal = "'";
|
|
4425
|
+
i = end;
|
|
4426
|
+
} else {
|
|
4427
|
+
literal = pattern.slice(i + 1, end === -1 ? void 0 : end);
|
|
4428
|
+
i = end === -1 ? pattern.length : end;
|
|
4429
|
+
}
|
|
4430
|
+
} else if (phase !== "suffix" && ("#0,.".includes(ch) || phase === "number" && ch === "E")) {
|
|
4431
|
+
phase = "number";
|
|
4432
|
+
number2 += ch;
|
|
4433
|
+
continue;
|
|
4434
|
+
} else {
|
|
4435
|
+
if (ch === "%") percent = true;
|
|
4436
|
+
literal = ch;
|
|
4588
4437
|
}
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
firstTradingDay(from, to) {
|
|
4593
|
-
for (let date = from; date <= to; date = addDays(date, 1)) if (this.isTradingDay(date)) return date;
|
|
4594
|
-
return null;
|
|
4595
|
-
}
|
|
4596
|
-
/** Last trading day in [from, to] (dates), or null. */
|
|
4597
|
-
lastTradingDay(from, to) {
|
|
4598
|
-
for (let date = to; date >= from; date = addDays(date, -1)) if (this.isTradingDay(date)) return date;
|
|
4599
|
-
return null;
|
|
4438
|
+
if (phase === "number") phase = "suffix";
|
|
4439
|
+
if (phase === "prefix") prefix += literal;
|
|
4440
|
+
else suffix += literal;
|
|
4600
4441
|
}
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4442
|
+
const [mantissa = "", exp2] = number2.split("E");
|
|
4443
|
+
const [intPart = "", fracPart = ""] = mantissa.split(".");
|
|
4444
|
+
const lastComma = intPart.lastIndexOf(",");
|
|
4445
|
+
const parsed = {
|
|
4446
|
+
prefix,
|
|
4447
|
+
suffix,
|
|
4448
|
+
// as in Java, a pattern with a decimal point and no '0' at all ("#.##") shows one integer digit
|
|
4449
|
+
minInt: !mantissa.includes("0") && mantissa.includes(".") ? 1 : [...intPart].filter((c) => c === "0").length,
|
|
4450
|
+
minFrac: [...fracPart].filter((c) => c === "0").length,
|
|
4451
|
+
maxFrac: [...fracPart].filter((c) => c === "0" || c === "#").length,
|
|
4452
|
+
grouping: lastComma === -1 ? 0 : intPart.length - lastComma - 1,
|
|
4453
|
+
percent,
|
|
4454
|
+
exponent: exp2 === void 0 ? null : exp2.length,
|
|
4455
|
+
hasDigits: /[0#]/.test(mantissa)
|
|
4456
|
+
};
|
|
4457
|
+
patterns.set(pattern, parsed);
|
|
4458
|
+
return parsed;
|
|
4609
4459
|
}
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
const
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4460
|
+
function shortestDigits(x) {
|
|
4461
|
+
const m = /^(\d+)(?:\.(\d+))?(?:e([+-]\d+))?$/.exec(String(Math.abs(x)));
|
|
4462
|
+
const all7 = m[1] + (m[2] ?? "");
|
|
4463
|
+
let intLen = m[1].length + Number(m[3] ?? 0);
|
|
4464
|
+
const lead = all7.length - all7.replace(/^0+/, "").length;
|
|
4465
|
+
intLen -= lead;
|
|
4466
|
+
const digits = all7.slice(lead).replace(/0+$/, "");
|
|
4467
|
+
return { digits, intLen: digits ? intLen : 0 };
|
|
4468
|
+
}
|
|
4469
|
+
function exactDigits(x) {
|
|
4470
|
+
const abs2 = Math.abs(x);
|
|
4471
|
+
if (abs2 === 0) return { digits: "", intLen: 0 };
|
|
4472
|
+
const view = new DataView(new ArrayBuffer(8));
|
|
4473
|
+
view.setFloat64(0, abs2);
|
|
4474
|
+
const bits = view.getBigUint64(0);
|
|
4475
|
+
const expBits = Number(bits >> 52n & 0x7ffn);
|
|
4476
|
+
let mant = bits & 0xfffffffffffffn;
|
|
4477
|
+
const e2 = expBits === 0 ? -1074 : expBits - 1075;
|
|
4478
|
+
if (expBits !== 0) mant |= 1n << 52n;
|
|
4479
|
+
let str2;
|
|
4480
|
+
let fracDigits;
|
|
4481
|
+
if (e2 >= 0) {
|
|
4482
|
+
str2 = (mant << BigInt(e2)).toString();
|
|
4483
|
+
fracDigits = 0;
|
|
4484
|
+
} else {
|
|
4485
|
+
str2 = (mant * 5n ** BigInt(-e2)).toString();
|
|
4486
|
+
fracDigits = -e2;
|
|
4620
4487
|
}
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4488
|
+
const intLen = str2.length - fracDigits;
|
|
4489
|
+
const lead = str2.length - str2.replace(/^0+/, "").length;
|
|
4490
|
+
const digits = str2.slice(lead).replace(/0+$/, "");
|
|
4491
|
+
return { digits, intLen: intLen - lead };
|
|
4492
|
+
}
|
|
4493
|
+
function roundDigits(d, frac, mode3) {
|
|
4494
|
+
const keep = d.intLen + frac;
|
|
4495
|
+
if (keep >= d.digits.length) return d;
|
|
4496
|
+
if (keep < 0) return { digits: "", intLen: 0 };
|
|
4497
|
+
const first = d.digits.charCodeAt(keep) - 48;
|
|
4498
|
+
let up;
|
|
4499
|
+
if (mode3 === "halfUpShortest") up = first >= 5;
|
|
4500
|
+
else if (first !== 5) up = first > 5;
|
|
4501
|
+
else if (d.digits.length > keep + 1) up = true;
|
|
4502
|
+
else up = keep > 0 && (d.digits.charCodeAt(keep - 1) - 48) % 2 === 1;
|
|
4503
|
+
let kept = d.digits.slice(0, keep);
|
|
4504
|
+
let intLen = d.intLen;
|
|
4505
|
+
if (up) {
|
|
4506
|
+
const n = (BigInt(kept || "0") + 1n).toString();
|
|
4507
|
+
if (n.length > kept.length) intLen += 1;
|
|
4508
|
+
kept = n;
|
|
4635
4509
|
}
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4510
|
+
kept = kept.replace(/0+$/, "");
|
|
4511
|
+
return { digits: kept, intLen: kept ? intLen : 0 };
|
|
4512
|
+
}
|
|
4513
|
+
function group(int, size) {
|
|
4514
|
+
if (!size || int.length <= size) return int;
|
|
4515
|
+
const parts = [];
|
|
4516
|
+
for (let end = int.length; end > 0; end -= size) parts.unshift(int.slice(Math.max(0, end - size), end));
|
|
4517
|
+
return parts.join(",");
|
|
4518
|
+
}
|
|
4519
|
+
function layout(d, p) {
|
|
4520
|
+
let int = d.intLen > 0 ? d.digits.slice(0, d.intLen).padEnd(d.intLen, "0") : "";
|
|
4521
|
+
int = int.replace(/^0+/, "").padStart(p.minInt, "0");
|
|
4522
|
+
let frac = d.intLen < 0 ? "0".repeat(-d.intLen) + d.digits : d.digits.slice(Math.max(0, d.intLen));
|
|
4523
|
+
frac = frac.slice(0, p.maxFrac).replace(/0+$/, "").padEnd(p.minFrac, "0");
|
|
4524
|
+
if (!int && !frac) int = "0";
|
|
4525
|
+
return group(int, p.grouping) + (frac ? "." + frac : "");
|
|
4526
|
+
}
|
|
4527
|
+
function formatNumber(value, pattern, mode3) {
|
|
4528
|
+
if (Number.isNaN(value)) return "NaN";
|
|
4529
|
+
const p = parsePattern(pattern);
|
|
4530
|
+
if (!Number.isFinite(value)) return (value < 0 ? "-" : "") + p.prefix + "\u221E" + p.suffix;
|
|
4531
|
+
const x = p.percent ? value * 100 : value;
|
|
4532
|
+
const toDigits = mode3 === "halfUpShortest" ? shortestDigits : exactDigits;
|
|
4533
|
+
let body;
|
|
4534
|
+
let isZero;
|
|
4535
|
+
if (p.exponent !== null) {
|
|
4536
|
+
const rounded = roundDigits(toDigits(x), p.maxFrac, mode3);
|
|
4537
|
+
const intDigits = Math.max(p.minInt, 1);
|
|
4538
|
+
isZero = rounded.digits === "";
|
|
4539
|
+
let exponent = isZero ? 0 : rounded.intLen - intDigits;
|
|
4540
|
+
let mant = roundDigits({ digits: rounded.digits, intLen: isZero ? 0 : intDigits }, p.maxFrac, mode3);
|
|
4541
|
+
if (mant.intLen > intDigits) {
|
|
4542
|
+
exponent += 1;
|
|
4543
|
+
mant = { digits: mant.digits, intLen: intDigits };
|
|
4658
4544
|
}
|
|
4659
|
-
const
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
const
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
dayStart(date) {
|
|
4666
|
-
return this.calendar.periods(date)[0][0];
|
|
4667
|
-
}
|
|
4668
|
-
dayEnd(date) {
|
|
4669
|
-
const p = this.calendar.periods(date);
|
|
4670
|
-
return p[p.length - 1][1];
|
|
4545
|
+
const e2 = String(Math.abs(exponent)).padStart(p.exponent, "0");
|
|
4546
|
+
body = layout(mant, p) + "E" + (exponent < 0 ? "-" : "") + e2;
|
|
4547
|
+
} else {
|
|
4548
|
+
const rounded = roundDigits(toDigits(x), p.hasDigits ? p.maxFrac : 0, mode3);
|
|
4549
|
+
isZero = rounded.digits === "";
|
|
4550
|
+
body = p.hasDigits ? layout(rounded, p) : layout(rounded, { ...p, minInt: 0, maxFrac: 0, minFrac: 0 });
|
|
4671
4551
|
}
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4552
|
+
const negative = x < 0 && (!isZero || !p.hasDigits);
|
|
4553
|
+
return (negative ? "-" : "") + p.prefix + body + p.suffix;
|
|
4554
|
+
}
|
|
4555
|
+
|
|
4556
|
+
// src/str/dateformat.ts
|
|
4557
|
+
var MONTHS2 = [
|
|
4558
|
+
"January",
|
|
4559
|
+
"February",
|
|
4560
|
+
"March",
|
|
4561
|
+
"April",
|
|
4562
|
+
"May",
|
|
4563
|
+
"June",
|
|
4564
|
+
"July",
|
|
4565
|
+
"August",
|
|
4566
|
+
"September",
|
|
4567
|
+
"October",
|
|
4568
|
+
"November",
|
|
4569
|
+
"December"
|
|
4570
|
+
];
|
|
4571
|
+
var DAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
4572
|
+
var pad = (n, width) => String(n).padStart(width, "0");
|
|
4573
|
+
function zoneName(time2, timezone, offsetMs) {
|
|
4574
|
+
if (timezone === "Etc/UTC") return "UTC";
|
|
4575
|
+
if (/^(UTC|GMT)/.test(timezone)) {
|
|
4576
|
+
if (offsetMs === 0) return "GMT";
|
|
4577
|
+
const minutes = Math.abs(offsetMs) / 6e4;
|
|
4578
|
+
return `GMT${offsetMs < 0 ? "-" : "+"}${pad(Math.floor(minutes / 60), 2)}:${pad(minutes % 60, 2)}`;
|
|
4687
4579
|
}
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4580
|
+
const part = new Intl.DateTimeFormat("en-US", { timeZone: timezone, timeZoneName: "short" }).formatToParts(time2).find((p) => p.type === "timeZoneName");
|
|
4581
|
+
return part?.value ?? timezone;
|
|
4582
|
+
}
|
|
4583
|
+
function weekOfYear(year3, month3, day) {
|
|
4584
|
+
const date = Date.UTC(year3, month3 - 1, day);
|
|
4585
|
+
const dow = new Date(date).getUTCDay();
|
|
4586
|
+
const weekStart2 = date - dow * 864e5;
|
|
4587
|
+
if (weekStart2 + 6 * 864e5 >= Date.UTC(year3 + 1, 0, 1)) return 1;
|
|
4588
|
+
const jan1 = Date.UTC(year3, 0, 1);
|
|
4589
|
+
const jan1Dow = new Date(jan1).getUTCDay();
|
|
4590
|
+
return Math.floor((date - jan1 + jan1Dow * 864e5) / (7 * 864e5)) + 1;
|
|
4591
|
+
}
|
|
4592
|
+
function formatDate(time2, pattern, timezone) {
|
|
4593
|
+
if (Number.isNaN(time2)) return "NaN";
|
|
4594
|
+
const f = zonedFields(time2, timezone);
|
|
4595
|
+
const offset = zoneOffset(time2, timezone);
|
|
4596
|
+
const ms = (time2 % 1e3 + 1e3) % 1e3;
|
|
4597
|
+
const dayOfYear = (Date.UTC(f.year, f.month - 1, f.day) - Date.UTC(f.year, 0, 1)) / 864e5 + 1;
|
|
4598
|
+
let out = "";
|
|
4599
|
+
for (let i = 0; i < pattern.length; ) {
|
|
4600
|
+
const ch = pattern[i];
|
|
4601
|
+
if (ch === "'") {
|
|
4602
|
+
const end = pattern.indexOf("'", i + 1);
|
|
4603
|
+
if (end === i + 1) {
|
|
4604
|
+
out += "'";
|
|
4605
|
+
i += 2;
|
|
4606
|
+
} else {
|
|
4607
|
+
out += pattern.slice(i + 1, end === -1 ? void 0 : end);
|
|
4608
|
+
i = end === -1 ? pattern.length : end + 1;
|
|
4609
|
+
}
|
|
4610
|
+
continue;
|
|
4704
4611
|
}
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
tradingDay(time2) {
|
|
4710
|
-
const at = this.calendar.locate(time2);
|
|
4711
|
-
if (!at) return null;
|
|
4712
|
-
if (this.chart.isdwm) {
|
|
4713
|
-
const { unit, n } = unitOf(this.chart);
|
|
4714
|
-
const [from, to] = this.periodRange(at.date, unit, n);
|
|
4715
|
-
return this.calendar.lastTradingDay(from, to);
|
|
4612
|
+
if (!/[A-Za-z]/.test(ch)) {
|
|
4613
|
+
out += ch;
|
|
4614
|
+
i++;
|
|
4615
|
+
continue;
|
|
4716
4616
|
}
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4617
|
+
let n = 1;
|
|
4618
|
+
while (pattern[i + n] === ch) n++;
|
|
4619
|
+
i += n;
|
|
4620
|
+
const hour12 = f.hour % 12;
|
|
4621
|
+
switch (ch) {
|
|
4622
|
+
case "y":
|
|
4623
|
+
out += n === 2 ? pad(f.year % 100, 2) : pad(f.year, n);
|
|
4624
|
+
break;
|
|
4625
|
+
case "M":
|
|
4626
|
+
out += n >= 4 ? MONTHS2[f.month - 1] : n === 3 ? MONTHS2[f.month - 1].slice(0, 3) : pad(f.month, n);
|
|
4627
|
+
break;
|
|
4628
|
+
case "d":
|
|
4629
|
+
out += pad(f.day, n);
|
|
4630
|
+
break;
|
|
4631
|
+
case "E":
|
|
4632
|
+
out += n >= 4 ? DAYS[f.dayOfWeek - 1] : DAYS[f.dayOfWeek - 1].slice(0, 3);
|
|
4633
|
+
break;
|
|
4634
|
+
case "u":
|
|
4635
|
+
out += pad(f.dayOfWeek === 1 ? 7 : f.dayOfWeek - 1, n);
|
|
4636
|
+
break;
|
|
4637
|
+
case "D":
|
|
4638
|
+
out += pad(dayOfYear, n);
|
|
4639
|
+
break;
|
|
4640
|
+
case "w":
|
|
4641
|
+
out += pad(weekOfYear(f.year, f.month, f.day), n);
|
|
4642
|
+
break;
|
|
4643
|
+
case "H":
|
|
4644
|
+
out += pad(f.hour, n);
|
|
4645
|
+
break;
|
|
4646
|
+
case "k":
|
|
4647
|
+
out += pad(f.hour === 0 ? 24 : f.hour, n);
|
|
4648
|
+
break;
|
|
4649
|
+
case "K":
|
|
4650
|
+
out += pad(hour12, n);
|
|
4651
|
+
break;
|
|
4652
|
+
case "h":
|
|
4653
|
+
out += pad(hour12 === 0 ? 12 : hour12, n);
|
|
4654
|
+
break;
|
|
4655
|
+
case "a":
|
|
4656
|
+
out += f.hour < 12 ? "AM" : "PM";
|
|
4657
|
+
break;
|
|
4658
|
+
case "m":
|
|
4659
|
+
out += pad(f.minute, n);
|
|
4660
|
+
break;
|
|
4661
|
+
case "s":
|
|
4662
|
+
out += pad(f.second, n);
|
|
4663
|
+
break;
|
|
4664
|
+
case "S":
|
|
4665
|
+
out += pad(ms, n);
|
|
4666
|
+
break;
|
|
4667
|
+
case "Z": {
|
|
4668
|
+
const minutes = Math.abs(offset) / 6e4;
|
|
4669
|
+
out += (offset < 0 ? "-" : "+") + pad(Math.floor(minutes / 60), 2) + pad(minutes % 60, 2);
|
|
4670
|
+
break;
|
|
4671
|
+
}
|
|
4672
|
+
case "z":
|
|
4673
|
+
out += zoneName(time2, timezone, offset);
|
|
4674
|
+
break;
|
|
4675
|
+
default:
|
|
4676
|
+
throw new SyntaxError(`Unsupported date pattern letter "${ch}" in "${pattern}"`);
|
|
4731
4677
|
}
|
|
4732
|
-
const { unit, n } = unitOf(tf);
|
|
4733
|
-
const [from, to] = this.periodRange(at.date, unit, n);
|
|
4734
|
-
const last = this.calendar.lastTradingDay(from, to);
|
|
4735
|
-
return last === null ? NaN : this.dayEnd(last);
|
|
4736
|
-
}
|
|
4737
|
-
/** PineScript `time_tradingday`: 00:00 UTC of the trading day. */
|
|
4738
|
-
tradingDayTime(time2) {
|
|
4739
|
-
const day = this.tradingDay(time2);
|
|
4740
|
-
return day === null ? NaN : dateUtcMs(day);
|
|
4741
|
-
}
|
|
4742
|
-
/** True when the bar at `time` is inside the session. */
|
|
4743
|
-
inside(time2) {
|
|
4744
|
-
return this.calendar.locate(time2)?.inside ?? false;
|
|
4745
4678
|
}
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4679
|
+
return out;
|
|
4680
|
+
}
|
|
4681
|
+
|
|
4682
|
+
// src/str/messageformat.ts
|
|
4683
|
+
var DATE_STYLES = {
|
|
4684
|
+
short: "M/d/yy",
|
|
4685
|
+
medium: "MMM d, yyyy",
|
|
4686
|
+
long: "MMMM d, yyyy",
|
|
4687
|
+
full: "EEEE, MMMM d, yyyy"
|
|
4688
|
+
};
|
|
4689
|
+
var TIME_STYLES = {
|
|
4690
|
+
short: "h:mm\u202Fa",
|
|
4691
|
+
medium: "h:mm:ss\u202Fa",
|
|
4692
|
+
long: "h:mm:ss\u202Fa z",
|
|
4693
|
+
full: "h:mm:ss\u202Fa z"
|
|
4694
|
+
};
|
|
4695
|
+
function number(value, pattern) {
|
|
4696
|
+
return typeof value === "number" ? formatNumber(value, pattern, "halfEvenExact") : String(value);
|
|
4697
|
+
}
|
|
4698
|
+
function choice(value, spec) {
|
|
4699
|
+
const options = spec.split("|").map((part) => {
|
|
4700
|
+
const m = /^\s*(-?[\d.]+|-?∞)\s*([#<≤])(.*)$/.exec(part);
|
|
4701
|
+
if (!m) throw new SyntaxError(`Invalid choice format "${spec}"`);
|
|
4702
|
+
const limit = m[1].includes("\u221E") ? m[1].startsWith("-") ? -Infinity : Infinity : Number(m[1]);
|
|
4703
|
+
return { limit: m[2] === "<" ? limit + Number.EPSILON * Math.max(1, Math.abs(limit)) : limit, text: m[3] };
|
|
4704
|
+
});
|
|
4705
|
+
let chosen = options[0];
|
|
4706
|
+
for (const o of options) if (value >= o.limit) chosen = o;
|
|
4707
|
+
return chosen.text;
|
|
4708
|
+
}
|
|
4709
|
+
function formatArgument(value, type, style, timezone) {
|
|
4710
|
+
if (value === void 0) return "";
|
|
4711
|
+
if (!type) return typeof value === "number" ? number(value, "#,##0.###") : String(value);
|
|
4712
|
+
switch (type.trim()) {
|
|
4713
|
+
case "number": {
|
|
4714
|
+
const s = style?.trim();
|
|
4715
|
+
if (!s) return number(value, "#,##0.###");
|
|
4716
|
+
if (s === "integer") return number(value, "#,##0");
|
|
4717
|
+
if (s === "percent") return number(value, "#,##0%");
|
|
4718
|
+
if (s === "currency") return number(value, "'$'#,##0.00");
|
|
4719
|
+
return number(value, style);
|
|
4720
|
+
}
|
|
4721
|
+
case "date":
|
|
4722
|
+
case "time": {
|
|
4723
|
+
const styles = type.trim() === "date" ? DATE_STYLES : TIME_STYLES;
|
|
4724
|
+
const s = style?.trim() ?? "medium";
|
|
4725
|
+
return formatDate(Number(value), styles[s] ?? style, typeof timezone === "function" ? timezone() : timezone);
|
|
4726
|
+
}
|
|
4727
|
+
case "choice":
|
|
4728
|
+
return choice(Number(value), style ?? "");
|
|
4729
|
+
default:
|
|
4730
|
+
throw new SyntaxError(`Unknown format type "${type}"`);
|
|
4750
4731
|
}
|
|
4751
|
-
}
|
|
4752
|
-
function
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
let previousPeriod = "";
|
|
4766
|
-
let previousRegular = "";
|
|
4767
|
-
for (let i = 0; i < n; i++) {
|
|
4768
|
-
const t2 = times[i];
|
|
4769
|
-
if (chart2.isdwm) {
|
|
4770
|
-
for (const k of ["isfirstbar", "islastbar", "ismarket", "isfirstbar_regular", "islastbar_regular"]) out[k][i] = true;
|
|
4732
|
+
}
|
|
4733
|
+
function formatMessage(pattern, args, timezone) {
|
|
4734
|
+
let out = "";
|
|
4735
|
+
for (let i = 0; i < pattern.length; ) {
|
|
4736
|
+
const ch = pattern[i];
|
|
4737
|
+
if (ch === "'") {
|
|
4738
|
+
if (pattern[i + 1] === "'") {
|
|
4739
|
+
out += "'";
|
|
4740
|
+
i += 2;
|
|
4741
|
+
continue;
|
|
4742
|
+
}
|
|
4743
|
+
const end = pattern.indexOf("'", i + 1);
|
|
4744
|
+
out += pattern.slice(i + 1, end === -1 ? void 0 : end);
|
|
4745
|
+
i = end === -1 ? pattern.length : end + 1;
|
|
4771
4746
|
continue;
|
|
4772
4747
|
}
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4748
|
+
if (ch !== "{") {
|
|
4749
|
+
out += ch;
|
|
4750
|
+
i++;
|
|
4776
4751
|
continue;
|
|
4777
4752
|
}
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
out.ismarket[i] = market;
|
|
4787
|
-
if (!market && regularPeriods.length) {
|
|
4788
|
-
out.ispremarket[i] = t2 < regularPeriods[0][0];
|
|
4789
|
-
out.ispostmarket[i] = t2 >= regularPeriods[regularPeriods.length - 1][1];
|
|
4753
|
+
let depth = 1;
|
|
4754
|
+
let j = i + 1;
|
|
4755
|
+
let inQuote = false;
|
|
4756
|
+
for (; j < pattern.length && depth > 0; j++) {
|
|
4757
|
+
const c = pattern[j];
|
|
4758
|
+
if (c === "'") inQuote = !inQuote;
|
|
4759
|
+
else if (!inQuote && c === "{") depth++;
|
|
4760
|
+
else if (!inQuote && c === "}") depth--;
|
|
4790
4761
|
}
|
|
4791
|
-
const
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4762
|
+
const inner = pattern.slice(i + 1, j - 1);
|
|
4763
|
+
const [index = "", type, ...rest] = inner.split(",");
|
|
4764
|
+
const style = rest.length ? rest.join(",") : void 0;
|
|
4765
|
+
const n = Number(index.trim());
|
|
4766
|
+
out += n < args.length ? formatArgument(args[n], type, style, timezone) : `{${inner}}`;
|
|
4767
|
+
i = j;
|
|
4796
4768
|
}
|
|
4797
4769
|
return out;
|
|
4798
4770
|
}
|
|
4799
4771
|
|
|
4800
|
-
// src/
|
|
4801
|
-
function
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
last.high = Math.max(last.high, b2.high);
|
|
4811
|
-
last.low = Math.min(last.low, b2.low);
|
|
4812
|
-
last.close = b2.close;
|
|
4813
|
-
last.volume = (last.volume ?? 0) + (b2.volume ?? NaN);
|
|
4772
|
+
// src/str/index.ts
|
|
4773
|
+
function length(str2) {
|
|
4774
|
+
return str2.length;
|
|
4775
|
+
}
|
|
4776
|
+
function tostring(value, format2) {
|
|
4777
|
+
if (typeof value !== "number") return String(value);
|
|
4778
|
+
if (!Number.isFinite(value)) return String(value);
|
|
4779
|
+
if (format2 === void 0 || format2 === "") {
|
|
4780
|
+
if (Math.abs(value) >= 1e21 && Number.isFinite(value)) {
|
|
4781
|
+
return String(value).replace("e+", "E").replace(/\.0+E/, "E");
|
|
4814
4782
|
}
|
|
4815
|
-
|
|
4816
|
-
}
|
|
4817
|
-
|
|
4783
|
+
return formatNumber(value, "#.##########", "halfUpShortest");
|
|
4784
|
+
}
|
|
4785
|
+
switch (format2) {
|
|
4786
|
+
case "percent":
|
|
4787
|
+
return formatNumber(value, "0.00", "halfUpShortest") + "%";
|
|
4788
|
+
case "volume": {
|
|
4789
|
+
const abs2 = Math.abs(value);
|
|
4790
|
+
for (const [size, unit] of [[1e12, "T"], [1e9, "B"], [1e6, "M"], [1e3, "K"]]) {
|
|
4791
|
+
if (abs2 >= size) return formatNumber(value / size, "#.###", "halfUpShortest") + unit;
|
|
4792
|
+
}
|
|
4793
|
+
return formatNumber(value, "#", "halfUpShortest");
|
|
4794
|
+
}
|
|
4795
|
+
case "mintick":
|
|
4796
|
+
throw new Error("str.tostring(x, format.mintick) needs the symbol tick size (syminfo.mintick), which is not known here");
|
|
4797
|
+
default:
|
|
4798
|
+
return formatNumber(value, format2, "halfUpShortest");
|
|
4799
|
+
}
|
|
4818
4800
|
}
|
|
4819
|
-
function
|
|
4820
|
-
const
|
|
4821
|
-
|
|
4822
|
-
starts.forEach((s, i) => group2.push(i === 0 ? 0 : group2[i - 1] + (s !== starts[i - 1] ? 1 : 0)));
|
|
4823
|
-
const latest = [];
|
|
4824
|
-
starts.forEach((s, i) => {
|
|
4825
|
-
let done = i === 0 ? -1 : latest[i - 1];
|
|
4826
|
-
if (i > 0 && group2[i] !== group2[i - 1]) done = Math.max(done, group2[i] - 1);
|
|
4827
|
-
const ends = i < n - 1 ? starts[i + 1] !== s || dayPeriods[i + 1] !== dayPeriods[i] : true;
|
|
4828
|
-
if (ends && reaches[i]) done = Math.max(done, group2[i]);
|
|
4829
|
-
latest.push(done);
|
|
4830
|
-
});
|
|
4831
|
-
return { group: group2, latest };
|
|
4801
|
+
function tonumber(str2) {
|
|
4802
|
+
const num = parseFloat(str2);
|
|
4803
|
+
return isNaN(num) ? null : num;
|
|
4832
4804
|
}
|
|
4833
|
-
function
|
|
4834
|
-
return
|
|
4835
|
-
if (lookahead) {
|
|
4836
|
-
const first = i === 0 || group2[i - 1] !== g2;
|
|
4837
|
-
return gaps && !first ? NaN : values[g2] ?? NaN;
|
|
4838
|
-
}
|
|
4839
|
-
const done = latest[i];
|
|
4840
|
-
if (done < 0 || gaps && i > 0 && latest[i - 1] === done) return NaN;
|
|
4841
|
-
return values[done] ?? NaN;
|
|
4842
|
-
});
|
|
4805
|
+
function substring(str2, begin, end) {
|
|
4806
|
+
return str2.substring(begin, end);
|
|
4843
4807
|
}
|
|
4844
|
-
function
|
|
4845
|
-
|
|
4846
|
-
bars2.forEach((b2, i) => {
|
|
4847
|
-
const close2 = (b2.open + b2.high + b2.low + b2.close) / 4;
|
|
4848
|
-
const prev = out[i - 1];
|
|
4849
|
-
const open2 = prev ? (prev.open + prev.close) / 2 : (b2.open + b2.close) / 2;
|
|
4850
|
-
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 });
|
|
4851
|
-
});
|
|
4852
|
-
return out;
|
|
4808
|
+
function upper(str2) {
|
|
4809
|
+
return str2.toUpperCase();
|
|
4853
4810
|
}
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
log: () => log,
|
|
4869
|
-
log10: () => log10,
|
|
4870
|
-
max: () => max3,
|
|
4871
|
-
min: () => min3,
|
|
4872
|
-
phi: () => phi,
|
|
4873
|
-
pi: () => pi,
|
|
4874
|
-
pow: () => pow,
|
|
4875
|
-
random: () => random,
|
|
4876
|
-
round: () => round,
|
|
4877
|
-
round_to_mintick: () => round_to_mintick,
|
|
4878
|
-
rphi: () => rphi,
|
|
4879
|
-
sign: () => sign,
|
|
4880
|
-
sin: () => sin,
|
|
4881
|
-
sqrt: () => sqrt,
|
|
4882
|
-
sum: () => sum,
|
|
4883
|
-
tan: () => tan,
|
|
4884
|
-
todegrees: () => todegrees,
|
|
4885
|
-
toradians: () => toradians
|
|
4886
|
-
});
|
|
4887
|
-
function abs(value) {
|
|
4888
|
-
if (value instanceof Series) {
|
|
4889
|
-
const bars2 = value.bars;
|
|
4890
|
-
const valueArray = value.toArray();
|
|
4891
|
-
const length2 = bars2.length;
|
|
4892
|
-
const result = [];
|
|
4893
|
-
for (let i = 0; i < length2; i++) {
|
|
4894
|
-
const v = valueArray[i] ?? NaN;
|
|
4895
|
-
result.push(Math.abs(v));
|
|
4896
|
-
}
|
|
4897
|
-
return Series.fromArray(bars2, result);
|
|
4811
|
+
function lower(str2) {
|
|
4812
|
+
return str2.toLowerCase();
|
|
4813
|
+
}
|
|
4814
|
+
function contains(source, str2) {
|
|
4815
|
+
return source.includes(str2);
|
|
4816
|
+
}
|
|
4817
|
+
function pos(source, str2) {
|
|
4818
|
+
return source.indexOf(str2);
|
|
4819
|
+
}
|
|
4820
|
+
function replace(source, target, replacement, occurrence) {
|
|
4821
|
+
if (occurrence === 0) {
|
|
4822
|
+
return source.replace(target, replacement);
|
|
4823
|
+
} else {
|
|
4824
|
+
return source.replaceAll(target, replacement);
|
|
4898
4825
|
}
|
|
4899
|
-
return Math.abs(value);
|
|
4900
4826
|
}
|
|
4901
|
-
function
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4827
|
+
function replace_all(source, target, replacement) {
|
|
4828
|
+
return source.replaceAll(target, replacement);
|
|
4829
|
+
}
|
|
4830
|
+
function split(str2, separator) {
|
|
4831
|
+
return str2.split(separator);
|
|
4832
|
+
}
|
|
4833
|
+
function concat(...strings) {
|
|
4834
|
+
return strings.join("");
|
|
4835
|
+
}
|
|
4836
|
+
function format(formatStr, ...args) {
|
|
4837
|
+
return formatMessage(formatStr, args, "Etc/UTC");
|
|
4838
|
+
}
|
|
4839
|
+
function startswith(source, str2) {
|
|
4840
|
+
return source.startsWith(str2);
|
|
4841
|
+
}
|
|
4842
|
+
function endswith(source, str2) {
|
|
4843
|
+
return source.endsWith(str2);
|
|
4844
|
+
}
|
|
4845
|
+
function charAt(str2, pos2) {
|
|
4846
|
+
return str2.charAt(pos2);
|
|
4847
|
+
}
|
|
4848
|
+
function trim(str2) {
|
|
4849
|
+
return str2.trim();
|
|
4850
|
+
}
|
|
4851
|
+
function trimLeft(str2) {
|
|
4852
|
+
return str2.trimStart();
|
|
4914
4853
|
}
|
|
4915
|
-
function
|
|
4916
|
-
|
|
4917
|
-
const bars2 = value.bars;
|
|
4918
|
-
const valueArray = value.toArray();
|
|
4919
|
-
const length2 = bars2.length;
|
|
4920
|
-
const result = [];
|
|
4921
|
-
for (let i = 0; i < length2; i++) {
|
|
4922
|
-
const v = valueArray[i] ?? NaN;
|
|
4923
|
-
result.push(Math.floor(v));
|
|
4924
|
-
}
|
|
4925
|
-
return Series.fromArray(bars2, result);
|
|
4926
|
-
}
|
|
4927
|
-
return Math.floor(value);
|
|
4854
|
+
function trimRight(str2) {
|
|
4855
|
+
return str2.trimEnd();
|
|
4928
4856
|
}
|
|
4929
|
-
function
|
|
4930
|
-
|
|
4931
|
-
const bars2 = value.bars;
|
|
4932
|
-
const valueArray = value.toArray();
|
|
4933
|
-
const length2 = bars2.length;
|
|
4934
|
-
const result = [];
|
|
4935
|
-
if (precision === void 0) {
|
|
4936
|
-
for (let i = 0; i < length2; i++) {
|
|
4937
|
-
const v = valueArray[i] ?? NaN;
|
|
4938
|
-
result.push(Math.round(v));
|
|
4939
|
-
}
|
|
4940
|
-
} else {
|
|
4941
|
-
const multiplier2 = Math.pow(10, precision);
|
|
4942
|
-
for (let i = 0; i < length2; i++) {
|
|
4943
|
-
const v = valueArray[i] ?? NaN;
|
|
4944
|
-
result.push(Math.round(v * multiplier2) / multiplier2);
|
|
4945
|
-
}
|
|
4946
|
-
}
|
|
4947
|
-
return Series.fromArray(bars2, result);
|
|
4948
|
-
}
|
|
4949
|
-
if (precision === void 0) {
|
|
4950
|
-
return Math.round(value);
|
|
4951
|
-
}
|
|
4952
|
-
const multiplier = Math.pow(10, precision);
|
|
4953
|
-
return Math.round(value * multiplier) / multiplier;
|
|
4857
|
+
function match(source, regex) {
|
|
4858
|
+
return new RegExp(regex).test(source);
|
|
4954
4859
|
}
|
|
4955
|
-
function
|
|
4956
|
-
|
|
4957
|
-
if (
|
|
4958
|
-
|
|
4959
|
-
}
|
|
4960
|
-
const firstSeries = values.find((v) => v instanceof Series);
|
|
4961
|
-
const bars2 = firstSeries.bars;
|
|
4962
|
-
const length2 = bars2.length;
|
|
4963
|
-
const valueArrays = values.map(
|
|
4964
|
-
(v) => v instanceof Series ? v.toArray() : null
|
|
4965
|
-
);
|
|
4966
|
-
const result = [];
|
|
4967
|
-
for (let i = 0; i < length2; i++) {
|
|
4968
|
-
const nums = values.map(
|
|
4969
|
-
(v, idx) => valueArrays[idx] ? valueArrays[idx][i] ?? NaN : v
|
|
4970
|
-
);
|
|
4971
|
-
result.push(Math.max(...nums));
|
|
4972
|
-
}
|
|
4973
|
-
return Series.fromArray(bars2, result);
|
|
4860
|
+
function repeat(source, count, separator = "") {
|
|
4861
|
+
if (source == null) return null;
|
|
4862
|
+
if (count <= 0) return "";
|
|
4863
|
+
return Array(count).fill(source).join(separator);
|
|
4974
4864
|
}
|
|
4975
|
-
function
|
|
4976
|
-
|
|
4977
|
-
if (!hasSeries) {
|
|
4978
|
-
return Math.min(...values);
|
|
4979
|
-
}
|
|
4980
|
-
const firstSeries = values.find((v) => v instanceof Series);
|
|
4981
|
-
const bars2 = firstSeries.bars;
|
|
4982
|
-
const length2 = bars2.length;
|
|
4983
|
-
const valueArrays = values.map(
|
|
4984
|
-
(v) => v instanceof Series ? v.toArray() : null
|
|
4985
|
-
);
|
|
4986
|
-
const result = [];
|
|
4987
|
-
for (let i = 0; i < length2; i++) {
|
|
4988
|
-
const nums = values.map(
|
|
4989
|
-
(v, idx) => valueArrays[idx] ? valueArrays[idx][i] ?? NaN : v
|
|
4990
|
-
);
|
|
4991
|
-
result.push(Math.min(...nums));
|
|
4992
|
-
}
|
|
4993
|
-
return Series.fromArray(bars2, result);
|
|
4865
|
+
function format_time(time2, format2 = "yyyy-MM-dd'T'HH:mm:ssZ", timezone = "Etc/UTC") {
|
|
4866
|
+
return formatDate(time2, format2, timezone);
|
|
4994
4867
|
}
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
const
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
);
|
|
5011
|
-
const sum2 = nums.reduce((a, b2) => a + b2, 0);
|
|
5012
|
-
result.push(sum2 / nums.length);
|
|
5013
|
-
}
|
|
5014
|
-
return Series.fromArray(bars2, result);
|
|
4868
|
+
|
|
4869
|
+
// src/session/calendar.ts
|
|
4870
|
+
var toDateNum = (y, m, d) => y * 1e4 + m * 100 + d;
|
|
4871
|
+
var utcOf = (date) => Date.UTC(Math.floor(date / 1e4), Math.floor(date / 100) % 100 - 1, date % 100);
|
|
4872
|
+
var fromUtc = (ms) => {
|
|
4873
|
+
const d = new Date(ms);
|
|
4874
|
+
return toDateNum(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate());
|
|
4875
|
+
};
|
|
4876
|
+
var addDays = (date, n) => fromUtc(utcOf(date) + n * 864e5);
|
|
4877
|
+
var weekdayOf = (date) => new Date(utcOf(date)).getUTCDay() + 1;
|
|
4878
|
+
var dateUtcMs = utcOf;
|
|
4879
|
+
function parseTime(token, spec) {
|
|
4880
|
+
const m = /^(\d{2})(\d{2})(?:F(\d+))?$/.exec(token.trim());
|
|
4881
|
+
if (!m) throw new SyntaxError(`Invalid session "${spec}"`);
|
|
4882
|
+
return { minutes: Number(m[1]) * 60 + Number(m[2]), offset: m[3] === void 0 ? void 0 : Number(m[3]) };
|
|
5015
4883
|
}
|
|
5016
|
-
function
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
window.push(v);
|
|
5025
|
-
if (window.length > len) window.shift();
|
|
4884
|
+
function parsePeriods(text2, spec) {
|
|
4885
|
+
if (text2.trim() === "24x7") return [{ start: 0, end: 1440, startOffset: 0, endOffset: 0 }];
|
|
4886
|
+
return text2.split(",").map((p) => {
|
|
4887
|
+
const [a = "", b2 = ""] = p.split("-");
|
|
4888
|
+
const s = parseTime(a, spec);
|
|
4889
|
+
const e2 = parseTime(b2, spec);
|
|
4890
|
+
if (s.minutes === 0 && e2.minutes === 0 && s.offset === void 0 && e2.offset === void 0) {
|
|
4891
|
+
return { start: 0, end: 1440, startOffset: 0, endOffset: 0 };
|
|
5026
4892
|
}
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
4893
|
+
return {
|
|
4894
|
+
start: s.minutes,
|
|
4895
|
+
end: e2.minutes,
|
|
4896
|
+
startOffset: s.offset ?? (e2.minutes <= s.minutes ? 1 : 0),
|
|
4897
|
+
endOffset: e2.offset ?? 0
|
|
4898
|
+
};
|
|
4899
|
+
});
|
|
4900
|
+
}
|
|
4901
|
+
function parseVersion(text2, from, spec, rule) {
|
|
4902
|
+
const [periodText = "", dayText] = text2.trim().split(":");
|
|
4903
|
+
const periods = parsePeriods(periodText, spec);
|
|
4904
|
+
const allDays = periodText.trim() === "24x7" || rule === "pine" && periods.length === 1;
|
|
4905
|
+
const digits = dayText ?? (allDays ? "1234567" : "23456");
|
|
4906
|
+
if (!/^[1-7]+$/.test(digits)) throw new SyntaxError(`Invalid session days in "${spec}"`);
|
|
4907
|
+
const days = new Array(8).fill(false);
|
|
4908
|
+
for (const d of digits) days[Number(d)] = true;
|
|
4909
|
+
return { from, periods, days };
|
|
4910
|
+
}
|
|
4911
|
+
var TradingCalendar = class {
|
|
4912
|
+
/**
|
|
4913
|
+
* @param timezone - Time zone of the session hours (the exchange time zone)
|
|
4914
|
+
* @param spec - Session information (hours, corrections, holidays)
|
|
4915
|
+
* @param rule - Days without ":days": 'symbol' (Monday to Friday) or 'pine' (PineScript session strings)
|
|
4916
|
+
*/
|
|
4917
|
+
constructor(timezone, spec, rule = "symbol") {
|
|
4918
|
+
this.timezone = timezone;
|
|
4919
|
+
const [first = "", ...changes] = spec.session.split("#");
|
|
4920
|
+
this.versions = [parseVersion(first, 0, spec.session, rule)];
|
|
4921
|
+
for (const change3 of changes) {
|
|
4922
|
+
const m = /^(\d{8})\/(.+)$/.exec(change3.trim());
|
|
4923
|
+
if (!m) throw new SyntaxError(`Invalid session change in "${spec.session}"`);
|
|
4924
|
+
this.versions.push(parseVersion(m[2], Number(m[1]), spec.session, rule));
|
|
4925
|
+
}
|
|
4926
|
+
for (const part of (spec.corrections ?? "").split(";").filter((p) => p.trim())) {
|
|
4927
|
+
const i = part.lastIndexOf(":");
|
|
4928
|
+
const text2 = part.slice(0, i).trim();
|
|
4929
|
+
const periods = text2 === "dayoff" ? null : parsePeriods(text2, part);
|
|
4930
|
+
for (const date of part.slice(i + 1).split(",")) this.corrections.set(Number(date), periods);
|
|
5033
4931
|
}
|
|
4932
|
+
const holidays = Array.isArray(spec.holidays) ? spec.holidays : (spec.holidays ?? "").split(",");
|
|
4933
|
+
this.holidays = new Set(holidays.filter((h) => h.trim()).map(Number));
|
|
5034
4934
|
}
|
|
5035
|
-
|
|
5036
|
-
|
|
4935
|
+
timezone;
|
|
4936
|
+
versions;
|
|
4937
|
+
corrections = /* @__PURE__ */ new Map();
|
|
4938
|
+
holidays;
|
|
4939
|
+
cache = /* @__PURE__ */ new Map();
|
|
4940
|
+
/** Session periods [start, end) of the trading day `date`; empty when the day has no session. */
|
|
4941
|
+
periods(date) {
|
|
4942
|
+
let out = this.cache.get(date);
|
|
4943
|
+
if (out) return out;
|
|
4944
|
+
let periods = [];
|
|
4945
|
+
const correction = this.corrections.get(date);
|
|
4946
|
+
if (correction !== void 0) {
|
|
4947
|
+
periods = correction ?? [];
|
|
4948
|
+
} else if (!this.holidays.has(date)) {
|
|
4949
|
+
const version = [...this.versions].reverse().find((v) => v.from <= date);
|
|
4950
|
+
if (version.days[weekdayOf(date)]) periods = version.periods;
|
|
4951
|
+
}
|
|
4952
|
+
const y = Math.floor(date / 1e4);
|
|
4953
|
+
const m = Math.floor(date / 100) % 100;
|
|
4954
|
+
const d = date % 100;
|
|
4955
|
+
out = periods.map((p) => [
|
|
4956
|
+
zonedToUnix(this.timezone, y, m, d - p.startOffset, Math.floor(p.start / 60), p.start % 60),
|
|
4957
|
+
zonedToUnix(this.timezone, y, m, d - p.endOffset, Math.floor(p.end / 60), p.end % 60)
|
|
4958
|
+
]);
|
|
4959
|
+
this.cache.set(date, out);
|
|
4960
|
+
return out;
|
|
5037
4961
|
}
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
4962
|
+
isTradingDay(date) {
|
|
4963
|
+
return this.periods(date).length > 0;
|
|
4964
|
+
}
|
|
4965
|
+
/**
|
|
4966
|
+
* Trading day and period of a time: the period that contains it, else the last period that started
|
|
4967
|
+
* before it. Null when no trading day is found near the time.
|
|
4968
|
+
*/
|
|
4969
|
+
locate(time2) {
|
|
4970
|
+
const f = zonedFields(time2, this.timezone);
|
|
4971
|
+
const local = toDateNum(f.year, f.month, f.day);
|
|
4972
|
+
for (let k = 0; k <= 5; k++) {
|
|
4973
|
+
const date = addDays(local, k);
|
|
4974
|
+
const index = this.periods(date).findIndex(([s, e2]) => s <= time2 && time2 < e2);
|
|
4975
|
+
if (index !== -1) return { date, index, inside: true };
|
|
4976
|
+
}
|
|
4977
|
+
for (let k = 5; k >= -7; k--) {
|
|
4978
|
+
const date = addDays(local, k);
|
|
4979
|
+
const periods = this.periods(date);
|
|
4980
|
+
let index = -1;
|
|
4981
|
+
periods.forEach(([s], i) => {
|
|
4982
|
+
if (s <= time2) index = i;
|
|
4983
|
+
});
|
|
4984
|
+
if (index !== -1) return { date, index, inside: false };
|
|
5049
4985
|
}
|
|
5050
|
-
return
|
|
4986
|
+
return null;
|
|
5051
4987
|
}
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
const expIsSeries = exponent instanceof Series;
|
|
5057
|
-
if (!baseIsSeries && !expIsSeries) {
|
|
5058
|
-
return Math.pow(base, exponent);
|
|
4988
|
+
/** First trading day in [from, to] (dates), or null. */
|
|
4989
|
+
firstTradingDay(from, to) {
|
|
4990
|
+
for (let date = from; date <= to; date = addDays(date, 1)) if (this.isTradingDay(date)) return date;
|
|
4991
|
+
return null;
|
|
5059
4992
|
}
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
const result = [];
|
|
5065
|
-
for (let i = 0; i < length2; i++) {
|
|
5066
|
-
const b2 = baseArray ? baseArray[i] ?? NaN : base;
|
|
5067
|
-
const e2 = expArray ? expArray[i] ?? NaN : exponent;
|
|
5068
|
-
result.push(Math.pow(b2, e2));
|
|
4993
|
+
/** Last trading day in [from, to] (dates), or null. */
|
|
4994
|
+
lastTradingDay(from, to) {
|
|
4995
|
+
for (let date = to; date >= from; date = addDays(date, -1)) if (this.isTradingDay(date)) return date;
|
|
4996
|
+
return null;
|
|
5069
4997
|
}
|
|
5070
|
-
|
|
4998
|
+
};
|
|
4999
|
+
var weekStart = (date) => addDays(date, -((weekdayOf(date) + 5) % 7));
|
|
5000
|
+
var monthStart = (date) => Math.floor(date / 100) * 100 + 1;
|
|
5001
|
+
var monthEnd = (date) => addDays(monthStart(addDays(monthStart(date), 32)), -1);
|
|
5002
|
+
|
|
5003
|
+
// src/session/bars.ts
|
|
5004
|
+
function unitOf(tf) {
|
|
5005
|
+
return { unit: tf.isdaily ? "D" : tf.isweekly ? "W" : "M", n: tf.multiplier };
|
|
5071
5006
|
}
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
return Series.fromArray(bars2, result);
|
|
5007
|
+
var yearOf = (date) => Math.floor(date / 1e4);
|
|
5008
|
+
var firstMonday = (year3) => {
|
|
5009
|
+
const jan1 = year3 * 1e4 + 101;
|
|
5010
|
+
const monday = weekStart(jan1);
|
|
5011
|
+
return monday === jan1 ? jan1 : addDays(monday, 7);
|
|
5012
|
+
};
|
|
5013
|
+
var SessionBars = class {
|
|
5014
|
+
constructor(calendar2, chartTimeframe2) {
|
|
5015
|
+
this.calendar = calendar2;
|
|
5016
|
+
this.chart = info(chartTimeframe2);
|
|
5083
5017
|
}
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5018
|
+
calendar;
|
|
5019
|
+
chart;
|
|
5020
|
+
yearDays = /* @__PURE__ */ new Map();
|
|
5021
|
+
/** Trading days of a calendar year, in order. */
|
|
5022
|
+
tradingDaysOf(year3) {
|
|
5023
|
+
let days = this.yearDays.get(year3);
|
|
5024
|
+
if (!days) {
|
|
5025
|
+
days = [];
|
|
5026
|
+
for (let date = year3 * 1e4 + 101; yearOf(date) === year3; date = addDays(date, 1)) {
|
|
5027
|
+
if (this.calendar.isTradingDay(date)) days.push(date);
|
|
5028
|
+
}
|
|
5029
|
+
this.yearDays.set(year3, days);
|
|
5095
5030
|
}
|
|
5096
|
-
return
|
|
5031
|
+
return days;
|
|
5097
5032
|
}
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5033
|
+
/**
|
|
5034
|
+
* Dates [from, to] of the `n`-`unit` period that contains `date` (for "D": its first and last trading days).
|
|
5035
|
+
* Periods restart each calendar year.
|
|
5036
|
+
*/
|
|
5037
|
+
periodRange(date, unit, n) {
|
|
5038
|
+
if (unit === "D") {
|
|
5039
|
+
if (n === 1) return [date, date];
|
|
5040
|
+
const days = this.tradingDaysOf(yearOf(date));
|
|
5041
|
+
let k = days.findIndex((d) => d >= date);
|
|
5042
|
+
if (k === -1) return this.periodRange(yearOf(date) * 1e4 + 1e4 + 101, unit, n);
|
|
5043
|
+
k -= k % n;
|
|
5044
|
+
return [days[k], days[Math.min(k + n, days.length) - 1]];
|
|
5109
5045
|
}
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
const result = [];
|
|
5120
|
-
for (let i = 0; i < length2; i++) {
|
|
5121
|
-
const v = valueArray[i] ?? NaN;
|
|
5122
|
-
result.push(Math.sin(v));
|
|
5046
|
+
if (unit === "W") {
|
|
5047
|
+
const monday = weekStart(date);
|
|
5048
|
+
const year4 = yearOf(monday);
|
|
5049
|
+
const first = firstMonday(year4);
|
|
5050
|
+
const next = firstMonday(year4 + 1);
|
|
5051
|
+
const k = Math.round((dateUtcMs(monday) - dateUtcMs(first)) / (7 * 864e5));
|
|
5052
|
+
const from = addDays(first, (k - k % n) * 7);
|
|
5053
|
+
const to = addDays(from, n * 7 - 1);
|
|
5054
|
+
return [from, to < next ? to : addDays(next, -1)];
|
|
5123
5055
|
}
|
|
5124
|
-
|
|
5056
|
+
const year3 = yearOf(date);
|
|
5057
|
+
const month3 = Math.floor(date / 100) % 100;
|
|
5058
|
+
const firstMonth = month3 - (month3 - 1) % n;
|
|
5059
|
+
const lastMonth = Math.min(firstMonth + n - 1, 12);
|
|
5060
|
+
return [monthStart(year3 * 1e4 + firstMonth * 100 + 1), monthEnd(year3 * 1e4 + lastMonth * 100 + 1)];
|
|
5125
5061
|
}
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
function cos(value) {
|
|
5129
|
-
if (value instanceof Series) {
|
|
5130
|
-
const bars2 = value.bars;
|
|
5131
|
-
const valueArray = value.toArray();
|
|
5132
|
-
const length2 = bars2.length;
|
|
5133
|
-
const result = [];
|
|
5134
|
-
for (let i = 0; i < length2; i++) {
|
|
5135
|
-
const v = valueArray[i] ?? NaN;
|
|
5136
|
-
result.push(Math.cos(v));
|
|
5137
|
-
}
|
|
5138
|
-
return Series.fromArray(bars2, result);
|
|
5062
|
+
dayStart(date) {
|
|
5063
|
+
return this.calendar.periods(date)[0][0];
|
|
5139
5064
|
}
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
if (value instanceof Series) {
|
|
5144
|
-
const bars2 = value.bars;
|
|
5145
|
-
const valueArray = value.toArray();
|
|
5146
|
-
const length2 = bars2.length;
|
|
5147
|
-
const result = [];
|
|
5148
|
-
for (let i = 0; i < length2; i++) {
|
|
5149
|
-
const v = valueArray[i] ?? NaN;
|
|
5150
|
-
result.push(Math.tan(v));
|
|
5151
|
-
}
|
|
5152
|
-
return Series.fromArray(bars2, result);
|
|
5065
|
+
dayEnd(date) {
|
|
5066
|
+
const p = this.calendar.periods(date);
|
|
5067
|
+
return p[p.length - 1][1];
|
|
5153
5068
|
}
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
result.push(Math.asin(v));
|
|
5069
|
+
/** PineScript `time(tf)` for a bar that opens at `time`; NaN when no trading day is found. */
|
|
5070
|
+
timeOf(time2, timeframe2) {
|
|
5071
|
+
const tf = info(timeframe2);
|
|
5072
|
+
const at = this.calendar.locate(time2);
|
|
5073
|
+
if (!at) return NaN;
|
|
5074
|
+
if (tf.isintraday) {
|
|
5075
|
+
if (this.chart.isdwm) return time2;
|
|
5076
|
+
const [start] = this.calendar.periods(at.date)[at.index];
|
|
5077
|
+
const ms = in_seconds(tf.period) * 1e3;
|
|
5078
|
+
return start + Math.floor((time2 - start) / ms) * ms;
|
|
5165
5079
|
}
|
|
5166
|
-
|
|
5080
|
+
const { unit, n } = unitOf(tf);
|
|
5081
|
+
const [from, to] = this.periodRange(at.date, unit, n);
|
|
5082
|
+
const first = this.calendar.firstTradingDay(from, to);
|
|
5083
|
+
return first === null ? NaN : this.dayStart(first);
|
|
5167
5084
|
}
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
const v = valueArray[i] ?? NaN;
|
|
5178
|
-
result.push(Math.acos(v));
|
|
5085
|
+
/** PineScript `time_close(tf)` for a bar that opens at `time`. */
|
|
5086
|
+
closeOf(time2, timeframe2) {
|
|
5087
|
+
const tf = info(timeframe2);
|
|
5088
|
+
const at = this.calendar.locate(time2);
|
|
5089
|
+
if (!at) return NaN;
|
|
5090
|
+
if (tf.isintraday) {
|
|
5091
|
+
const [, end] = this.calendar.periods(at.date)[at.index];
|
|
5092
|
+
if (this.chart.isdwm) return end;
|
|
5093
|
+
return Math.min(this.timeOf(time2, timeframe2) + in_seconds(tf.period) * 1e3, end);
|
|
5179
5094
|
}
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
const bars2 = value.bars;
|
|
5187
|
-
const valueArray = value.toArray();
|
|
5188
|
-
const length2 = bars2.length;
|
|
5189
|
-
const result = [];
|
|
5190
|
-
for (let i = 0; i < length2; i++) {
|
|
5191
|
-
const v = valueArray[i] ?? NaN;
|
|
5192
|
-
result.push(Math.atan(v));
|
|
5095
|
+
const { unit, n } = unitOf(tf);
|
|
5096
|
+
const [from, to] = this.periodRange(at.date, unit, n);
|
|
5097
|
+
if (this.chart.isintraday && (unit !== "D" || n > 1)) {
|
|
5098
|
+
const [nextFrom, nextTo] = this.periodRange(addDays(to, 1), unit, n);
|
|
5099
|
+
const first = this.calendar.firstTradingDay(nextFrom, addDays(nextTo, 31));
|
|
5100
|
+
return first === null ? NaN : this.dayStart(first);
|
|
5193
5101
|
}
|
|
5194
|
-
|
|
5102
|
+
const last = this.calendar.lastTradingDay(from, to);
|
|
5103
|
+
return last === null ? NaN : this.dayEnd(last);
|
|
5195
5104
|
}
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
for (let i = 0; i < length2; i++) {
|
|
5205
|
-
const v = valueArray[i] ?? NaN;
|
|
5206
|
-
result.push(v * (Math.PI / 180));
|
|
5105
|
+
/** Trading day of a bar: on D / W / M charts the last trading day of the chart period. */
|
|
5106
|
+
tradingDay(time2) {
|
|
5107
|
+
const at = this.calendar.locate(time2);
|
|
5108
|
+
if (!at) return null;
|
|
5109
|
+
if (this.chart.isdwm) {
|
|
5110
|
+
const { unit, n } = unitOf(this.chart);
|
|
5111
|
+
const [from, to] = this.periodRange(at.date, unit, n);
|
|
5112
|
+
return this.calendar.lastTradingDay(from, to);
|
|
5207
5113
|
}
|
|
5208
|
-
return
|
|
5114
|
+
return at.date;
|
|
5209
5115
|
}
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
const
|
|
5217
|
-
const
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5116
|
+
/**
|
|
5117
|
+
* End of the `timeframe` period that contains `time`: the intraday close, the session end of the day,
|
|
5118
|
+
* or the session end of the last trading day of the period. Used to know whether the last loaded
|
|
5119
|
+
* bar completes a higher-timeframe period (request.security).
|
|
5120
|
+
*/
|
|
5121
|
+
periodEnd(time2, timeframe2) {
|
|
5122
|
+
const tf = info(timeframe2);
|
|
5123
|
+
const at = this.calendar.locate(time2);
|
|
5124
|
+
if (!at) return NaN;
|
|
5125
|
+
if (tf.isintraday) {
|
|
5126
|
+
const [, end] = this.calendar.periods(at.date)[at.index];
|
|
5127
|
+
return Math.min(this.timeOf(time2, timeframe2) + in_seconds(tf.period) * 1e3, end);
|
|
5221
5128
|
}
|
|
5222
|
-
|
|
5129
|
+
const { unit, n } = unitOf(tf);
|
|
5130
|
+
const [from, to] = this.periodRange(at.date, unit, n);
|
|
5131
|
+
const last = this.calendar.lastTradingDay(from, to);
|
|
5132
|
+
return last === null ? NaN : this.dayEnd(last);
|
|
5223
5133
|
}
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
if (min4 !== void 0 && max4 !== void 0) {
|
|
5229
|
-
return min4 + rand * (max4 - min4);
|
|
5134
|
+
/** PineScript `time_tradingday`: 00:00 UTC of the trading day. */
|
|
5135
|
+
tradingDayTime(time2) {
|
|
5136
|
+
const day = this.tradingDay(time2);
|
|
5137
|
+
return day === null ? NaN : dateUtcMs(day);
|
|
5230
5138
|
}
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
const
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5139
|
+
/** True when the bar at `time` is inside the session. */
|
|
5140
|
+
inside(time2) {
|
|
5141
|
+
return this.calendar.locate(time2)?.inside ?? false;
|
|
5142
|
+
}
|
|
5143
|
+
/** Session start and end of the trading day of `time`, or null. */
|
|
5144
|
+
dayBounds(time2) {
|
|
5145
|
+
const at = this.calendar.locate(time2);
|
|
5146
|
+
return at ? { date: at.date, start: this.dayStart(at.date), end: this.dayEnd(at.date) } : null;
|
|
5147
|
+
}
|
|
5148
|
+
};
|
|
5149
|
+
function sessionFlags(times, bars2, regular) {
|
|
5150
|
+
const n = times.length;
|
|
5151
|
+
const flag2 = () => new Array(n).fill(false);
|
|
5152
|
+
const out = {
|
|
5153
|
+
isfirstbar: flag2(),
|
|
5154
|
+
islastbar: flag2(),
|
|
5155
|
+
ismarket: flag2(),
|
|
5156
|
+
ispremarket: flag2(),
|
|
5157
|
+
ispostmarket: flag2(),
|
|
5158
|
+
isfirstbar_regular: flag2(),
|
|
5159
|
+
islastbar_regular: flag2()
|
|
5160
|
+
};
|
|
5161
|
+
const chart2 = bars2.chart;
|
|
5162
|
+
let previousPeriod = "";
|
|
5163
|
+
let previousRegular = "";
|
|
5164
|
+
for (let i = 0; i < n; i++) {
|
|
5165
|
+
const t2 = times[i];
|
|
5166
|
+
if (chart2.isdwm) {
|
|
5167
|
+
for (const k of ["isfirstbar", "islastbar", "ismarket", "isfirstbar_regular", "islastbar_regular"]) out[k][i] = true;
|
|
5168
|
+
continue;
|
|
5242
5169
|
}
|
|
5243
|
-
|
|
5170
|
+
const at = bars2.calendar.locate(t2);
|
|
5171
|
+
if (!at) {
|
|
5172
|
+
previousPeriod = previousRegular = "";
|
|
5173
|
+
continue;
|
|
5174
|
+
}
|
|
5175
|
+
const close2 = bars2.closeOf(t2, chart2.period);
|
|
5176
|
+
const [, end] = bars2.calendar.periods(at.date)[at.index];
|
|
5177
|
+
const period = `${at.date}/${at.index}`;
|
|
5178
|
+
out.isfirstbar[i] = period !== previousPeriod;
|
|
5179
|
+
out.islastbar[i] = close2 >= end;
|
|
5180
|
+
const regularPeriods = regular.calendar.periods(at.date);
|
|
5181
|
+
const r2 = regularPeriods.findIndex(([s, e2]) => s <= t2 && t2 < e2);
|
|
5182
|
+
const market = r2 !== -1;
|
|
5183
|
+
out.ismarket[i] = market;
|
|
5184
|
+
if (!market && regularPeriods.length) {
|
|
5185
|
+
out.ispremarket[i] = t2 < regularPeriods[0][0];
|
|
5186
|
+
out.ispostmarket[i] = t2 >= regularPeriods[regularPeriods.length - 1][1];
|
|
5187
|
+
}
|
|
5188
|
+
const regularPeriod = market ? `${at.date}/${r2}` : "";
|
|
5189
|
+
out.isfirstbar_regular[i] = market && regularPeriod !== previousRegular;
|
|
5190
|
+
out.islastbar_regular[i] = market && close2 >= regularPeriods[r2][1];
|
|
5191
|
+
previousPeriod = period;
|
|
5192
|
+
previousRegular = regularPeriod;
|
|
5244
5193
|
}
|
|
5245
|
-
return
|
|
5194
|
+
return out;
|
|
5246
5195
|
}
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
const result = [];
|
|
5258
|
-
if (mintick === 0) {
|
|
5259
|
-
for (let i = 0; i < length2; i++) {
|
|
5260
|
-
result.push(valueArray[i] ?? NaN);
|
|
5261
|
-
}
|
|
5196
|
+
|
|
5197
|
+
// src/security/resample.ts
|
|
5198
|
+
function resample(bars2, periodStart) {
|
|
5199
|
+
const out = [];
|
|
5200
|
+
const group2 = [];
|
|
5201
|
+
bars2.forEach((b2, i) => {
|
|
5202
|
+
const start = periodStart[i];
|
|
5203
|
+
const last = out[out.length - 1];
|
|
5204
|
+
if (!last || last.time !== start) {
|
|
5205
|
+
out.push({ time: start, open: b2.open, high: b2.high, low: b2.low, close: b2.close, volume: b2.volume ?? NaN });
|
|
5262
5206
|
} else {
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
} else {
|
|
5268
|
-
result.push(Math.round(v / mintick) * mintick);
|
|
5269
|
-
}
|
|
5270
|
-
}
|
|
5207
|
+
last.high = Math.max(last.high, b2.high);
|
|
5208
|
+
last.low = Math.min(last.low, b2.low);
|
|
5209
|
+
last.close = b2.close;
|
|
5210
|
+
last.volume = (last.volume ?? 0) + (b2.volume ?? NaN);
|
|
5271
5211
|
}
|
|
5272
|
-
|
|
5273
|
-
}
|
|
5274
|
-
|
|
5275
|
-
return NaN;
|
|
5276
|
-
}
|
|
5277
|
-
if (mintick === void 0) {
|
|
5278
|
-
throw new Error(
|
|
5279
|
-
"math.round_to_mintick() requires mintick value. Either pass it explicitly or use createContext({ syminfo: { mintick } }) for implicit data."
|
|
5280
|
-
);
|
|
5281
|
-
}
|
|
5282
|
-
if (mintick === 0) {
|
|
5283
|
-
return number2;
|
|
5284
|
-
}
|
|
5285
|
-
return Math.round(number2 / mintick) * mintick;
|
|
5212
|
+
group2.push(out.length - 1);
|
|
5213
|
+
});
|
|
5214
|
+
return { bars: out, group: group2 };
|
|
5286
5215
|
}
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5216
|
+
function periodsOf(starts, dayPeriods, reaches) {
|
|
5217
|
+
const n = starts.length;
|
|
5218
|
+
const group2 = [];
|
|
5219
|
+
starts.forEach((s, i) => group2.push(i === 0 ? 0 : group2[i - 1] + (s !== starts[i - 1] ? 1 : 0)));
|
|
5220
|
+
const latest = [];
|
|
5221
|
+
starts.forEach((s, i) => {
|
|
5222
|
+
let done = i === 0 ? -1 : latest[i - 1];
|
|
5223
|
+
if (i > 0 && group2[i] !== group2[i - 1]) done = Math.max(done, group2[i] - 1);
|
|
5224
|
+
const ends = i < n - 1 ? starts[i + 1] !== s || dayPeriods[i + 1] !== dayPeriods[i] : true;
|
|
5225
|
+
if (ends && reaches[i]) done = Math.max(done, group2[i]);
|
|
5226
|
+
latest.push(done);
|
|
5227
|
+
});
|
|
5228
|
+
return { group: group2, latest };
|
|
5229
|
+
}
|
|
5230
|
+
function mapToChart(values, group2, latest, lookahead, gaps) {
|
|
5231
|
+
return group2.map((g2, i) => {
|
|
5232
|
+
if (lookahead) {
|
|
5233
|
+
const first = i === 0 || group2[i - 1] !== g2;
|
|
5234
|
+
return gaps && !first ? NaN : values[g2] ?? NaN;
|
|
5235
|
+
}
|
|
5236
|
+
const done = latest[i];
|
|
5237
|
+
if (done < 0 || gaps && i > 0 && latest[i - 1] === done) return NaN;
|
|
5238
|
+
return values[done] ?? NaN;
|
|
5239
|
+
});
|
|
5240
|
+
}
|
|
5241
|
+
function heikinAshi(bars2) {
|
|
5242
|
+
const out = [];
|
|
5243
|
+
bars2.forEach((b2, i) => {
|
|
5244
|
+
const close2 = (b2.open + b2.high + b2.low + b2.close) / 4;
|
|
5245
|
+
const prev = out[i - 1];
|
|
5246
|
+
const open2 = prev ? (prev.open + prev.close) / 2 : (b2.open + b2.close) / 2;
|
|
5247
|
+
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 });
|
|
5248
|
+
});
|
|
5249
|
+
return out;
|
|
5250
|
+
}
|
|
5251
|
+
|
|
5252
|
+
// src/strategy/index.ts
|
|
5253
|
+
var STRATEGY_CONSTANTS = {
|
|
5254
|
+
long: "long",
|
|
5255
|
+
short: "short",
|
|
5256
|
+
fixed: "fixed",
|
|
5257
|
+
cash: "cash",
|
|
5258
|
+
percent_of_equity: "percent_of_equity",
|
|
5259
|
+
commission: { percent: "percent", cash_per_contract: "cash_per_contract", cash_per_order: "cash_per_order" },
|
|
5260
|
+
direction: { all: "all", long: "long", short: "short" },
|
|
5261
|
+
oca: { none: "none", cancel: "cancel", reduce: "reduce" }
|
|
5262
|
+
};
|
|
5263
|
+
var STRATEGY_DEFAULTS = {
|
|
5264
|
+
pyramiding: 0,
|
|
5265
|
+
calc_on_order_fills: false,
|
|
5266
|
+
calc_on_every_tick: false,
|
|
5267
|
+
backtest_fill_limits_assumption: 0,
|
|
5268
|
+
default_qty_type: "fixed",
|
|
5269
|
+
default_qty_value: 1,
|
|
5270
|
+
initial_capital: 1e6,
|
|
5271
|
+
slippage: 0,
|
|
5272
|
+
commission_type: "percent",
|
|
5273
|
+
commission_value: 0,
|
|
5274
|
+
process_orders_on_close: false,
|
|
5275
|
+
close_entries_rule: "FIFO",
|
|
5276
|
+
margin_long: 100,
|
|
5277
|
+
margin_short: 100,
|
|
5278
|
+
calc_bars_count: 0,
|
|
5279
|
+
risk_free_rate: 2,
|
|
5280
|
+
use_bar_magnifier: false,
|
|
5281
|
+
fill_orders_on_standard_ohlc: false
|
|
5282
|
+
};
|
|
5283
|
+
var STRATEGY_NUMBER_VARIABLES = [
|
|
5284
|
+
"position_size",
|
|
5285
|
+
"position_avg_price",
|
|
5286
|
+
"equity",
|
|
5287
|
+
"initial_capital",
|
|
5288
|
+
"netprofit",
|
|
5289
|
+
"netprofit_percent",
|
|
5290
|
+
"openprofit",
|
|
5291
|
+
"openprofit_percent",
|
|
5292
|
+
"grossprofit",
|
|
5293
|
+
"grossprofit_percent",
|
|
5294
|
+
"grossloss",
|
|
5295
|
+
"grossloss_percent",
|
|
5296
|
+
"opentrades",
|
|
5297
|
+
"closedtrades",
|
|
5298
|
+
"wintrades",
|
|
5299
|
+
"losstrades",
|
|
5300
|
+
"eventrades",
|
|
5301
|
+
"avg_trade",
|
|
5302
|
+
"avg_trade_percent",
|
|
5303
|
+
"avg_winning_trade",
|
|
5304
|
+
"avg_winning_trade_percent",
|
|
5305
|
+
"avg_losing_trade",
|
|
5306
|
+
"avg_losing_trade_percent",
|
|
5307
|
+
"max_drawdown",
|
|
5308
|
+
"max_drawdown_percent",
|
|
5309
|
+
"max_runup",
|
|
5310
|
+
"max_runup_percent",
|
|
5311
|
+
"max_contracts_held_all",
|
|
5312
|
+
"max_contracts_held_long",
|
|
5313
|
+
"max_contracts_held_short",
|
|
5314
|
+
"margin_liquidation_price"
|
|
5315
|
+
];
|
|
5316
|
+
var STRATEGY_TEXT_VARIABLES = ["position_entry_name", "account_currency"];
|
|
5291
5317
|
|
|
5292
5318
|
// src/script/index.ts
|
|
5293
5319
|
var ctxBars = new BarData([]);
|
|
@@ -5329,9 +5355,11 @@ function slugId(title, fallback, taken) {
|
|
|
5329
5355
|
taken.add(id);
|
|
5330
5356
|
return id;
|
|
5331
5357
|
}
|
|
5332
|
-
|
|
5358
|
+
var scriptOptions = {};
|
|
5359
|
+
function executeScript(body, barsInput, inputs = {}, chart2 = {}, options = {}) {
|
|
5333
5360
|
ctxBars.setAll(barsInput);
|
|
5334
5361
|
chartCtx = { ...chart2 };
|
|
5362
|
+
scriptOptions = options;
|
|
5335
5363
|
ctx = freshCollector(inputs);
|
|
5336
5364
|
resetDrawings();
|
|
5337
5365
|
try {
|
|
@@ -5353,6 +5381,7 @@ function executeScript(body, barsInput, inputs = {}, chart2 = {}) {
|
|
|
5353
5381
|
barColorConfig: c.barColorConfig,
|
|
5354
5382
|
defaultInputs: c.defaultInputs,
|
|
5355
5383
|
alertConfig: c.alertConfig,
|
|
5384
|
+
strategyConfig: c.strategy?.properties,
|
|
5356
5385
|
result: {
|
|
5357
5386
|
metadata: { title: c.title, shorttitle: c.shortTitle, overlay: c.overlay, precision: c.precision },
|
|
5358
5387
|
plots: c.plots,
|
|
@@ -5369,6 +5398,7 @@ function executeScript(body, barsInput, inputs = {}, chart2 = {}) {
|
|
|
5369
5398
|
}
|
|
5370
5399
|
function indicator(title, options = {}) {
|
|
5371
5400
|
const c = collector();
|
|
5401
|
+
declare(c, "indicator");
|
|
5372
5402
|
c.title = title;
|
|
5373
5403
|
c.shortTitle = options.shorttitle;
|
|
5374
5404
|
c.overlay = options.overlay ?? true;
|
|
@@ -5381,6 +5411,12 @@ function indicator(title, options = {}) {
|
|
|
5381
5411
|
polyline: options.max_polylines_count
|
|
5382
5412
|
});
|
|
5383
5413
|
}
|
|
5414
|
+
function declare(c, kind) {
|
|
5415
|
+
if (c.declaration) {
|
|
5416
|
+
throw new Error(`${kind}(): the script already declared ${c.declaration}(); a script has one declaration.`);
|
|
5417
|
+
}
|
|
5418
|
+
c.declaration = kind;
|
|
5419
|
+
}
|
|
5384
5420
|
function registerInput(config, fallbackId) {
|
|
5385
5421
|
const c = collector();
|
|
5386
5422
|
const id = slugId(config.title, fallbackId, c.inputIds);
|
|
@@ -5723,6 +5759,139 @@ function eachBar(fn) {
|
|
|
5723
5759
|
return Series.fromArray(ctxBars, out);
|
|
5724
5760
|
}
|
|
5725
5761
|
var currentBar = -1;
|
|
5762
|
+
function strategyRun(caller) {
|
|
5763
|
+
const run = collector().strategy;
|
|
5764
|
+
if (!run) throw new Error(`${caller}: declare the script with strategy() first.`);
|
|
5765
|
+
return run;
|
|
5766
|
+
}
|
|
5767
|
+
function strategyEngine(caller) {
|
|
5768
|
+
const run = strategyRun(caller);
|
|
5769
|
+
if (!run.engine) {
|
|
5770
|
+
throw new Error(
|
|
5771
|
+
`${caller}: no strategy engine; pass it as executeScript(body, bars, inputs, chart, { strategyEngine }).`
|
|
5772
|
+
);
|
|
5773
|
+
}
|
|
5774
|
+
return run.engine;
|
|
5775
|
+
}
|
|
5776
|
+
function orderEngine(caller) {
|
|
5777
|
+
const engine = strategyEngine(caller);
|
|
5778
|
+
if (!strategyRun(caller).inLoop) throw new Error(`${caller} must be called inside strategy.eachBar().`);
|
|
5779
|
+
return engine;
|
|
5780
|
+
}
|
|
5781
|
+
function given(options) {
|
|
5782
|
+
const out = {};
|
|
5783
|
+
for (const [key, value] of Object.entries(options)) {
|
|
5784
|
+
if (value === void 0 || typeof value === "number" && Number.isNaN(value)) continue;
|
|
5785
|
+
out[key] = value;
|
|
5786
|
+
}
|
|
5787
|
+
return out;
|
|
5788
|
+
}
|
|
5789
|
+
function strategyVariable(name) {
|
|
5790
|
+
const value = strategyEngine(`strategy.${name}`).get(name);
|
|
5791
|
+
if (value === void 0) throw new Error(`strategy.${name} is not provided by the strategy engine.`);
|
|
5792
|
+
return value;
|
|
5793
|
+
}
|
|
5794
|
+
function riskRule(rule) {
|
|
5795
|
+
const engine = strategyEngine(`strategy.risk.${rule.rule}()`);
|
|
5796
|
+
if (!engine.risk) throw new Error(`strategy.risk.${rule.rule}() is not provided by the strategy engine.`);
|
|
5797
|
+
engine.risk(rule);
|
|
5798
|
+
}
|
|
5799
|
+
function declareStrategy(title, options = {}) {
|
|
5800
|
+
const c = collector();
|
|
5801
|
+
declare(c, "strategy");
|
|
5802
|
+
c.title = title;
|
|
5803
|
+
c.shortTitle = options.shorttitle;
|
|
5804
|
+
c.overlay = options.overlay ?? false;
|
|
5805
|
+
c.precision = options.precision;
|
|
5806
|
+
c.format = options.format;
|
|
5807
|
+
setDrawingLimits({
|
|
5808
|
+
line: options.max_lines_count,
|
|
5809
|
+
label: options.max_labels_count,
|
|
5810
|
+
box: options.max_boxes_count,
|
|
5811
|
+
polyline: options.max_polylines_count
|
|
5812
|
+
});
|
|
5813
|
+
const properties = { ...STRATEGY_DEFAULTS };
|
|
5814
|
+
const target = properties;
|
|
5815
|
+
for (const key of [...Object.keys(STRATEGY_DEFAULTS), "currency"]) {
|
|
5816
|
+
const value = options[key];
|
|
5817
|
+
if (value !== void 0) target[key] = value;
|
|
5818
|
+
}
|
|
5819
|
+
const factory = scriptOptions.strategyEngine;
|
|
5820
|
+
c.strategy = {
|
|
5821
|
+
properties,
|
|
5822
|
+
engine: factory?.({ properties, bars: ctxBars.bars, chart: chartCtx }),
|
|
5823
|
+
looped: false,
|
|
5824
|
+
inLoop: false
|
|
5825
|
+
};
|
|
5826
|
+
}
|
|
5827
|
+
function strategyEachBar(fn) {
|
|
5828
|
+
const run = strategyRun("strategy.eachBar()");
|
|
5829
|
+
const engine = strategyEngine("strategy.eachBar()");
|
|
5830
|
+
if (run.looped) throw new Error("strategy.eachBar() runs once per script run.");
|
|
5831
|
+
run.looped = true;
|
|
5832
|
+
return eachBar((c) => {
|
|
5833
|
+
engine.processBar(c.i);
|
|
5834
|
+
run.inLoop = true;
|
|
5835
|
+
try {
|
|
5836
|
+
return fn(c);
|
|
5837
|
+
} finally {
|
|
5838
|
+
run.inLoop = false;
|
|
5839
|
+
engine.processClose(c.i);
|
|
5840
|
+
}
|
|
5841
|
+
});
|
|
5842
|
+
}
|
|
5843
|
+
var strategyMembers = {
|
|
5844
|
+
...STRATEGY_CONSTANTS,
|
|
5845
|
+
eachBar: strategyEachBar,
|
|
5846
|
+
entry(id, direction, options = {}) {
|
|
5847
|
+
orderEngine("strategy.entry()").entry(id, direction, given(options));
|
|
5848
|
+
},
|
|
5849
|
+
order(id, direction, options = {}) {
|
|
5850
|
+
orderEngine("strategy.order()").order(id, direction, given(options));
|
|
5851
|
+
},
|
|
5852
|
+
exit(id, options = {}) {
|
|
5853
|
+
orderEngine("strategy.exit()").exit(id, given(options));
|
|
5854
|
+
},
|
|
5855
|
+
close(id, options = {}) {
|
|
5856
|
+
orderEngine("strategy.close()").close(id, given(options));
|
|
5857
|
+
},
|
|
5858
|
+
close_all(options = {}) {
|
|
5859
|
+
orderEngine("strategy.close_all()").close_all(given(options));
|
|
5860
|
+
},
|
|
5861
|
+
cancel(id) {
|
|
5862
|
+
orderEngine("strategy.cancel()").cancel(id);
|
|
5863
|
+
},
|
|
5864
|
+
cancel_all() {
|
|
5865
|
+
orderEngine("strategy.cancel_all()").cancel_all();
|
|
5866
|
+
},
|
|
5867
|
+
opentrade(index) {
|
|
5868
|
+
return strategyEngine("strategy.opentrade()").openTrade(index);
|
|
5869
|
+
},
|
|
5870
|
+
closedtrade(index) {
|
|
5871
|
+
return strategyEngine("strategy.closedtrade()").closedTrade(index);
|
|
5872
|
+
},
|
|
5873
|
+
default_entry_qty(fill_price) {
|
|
5874
|
+
const engine = strategyEngine("strategy.default_entry_qty()");
|
|
5875
|
+
if (!engine.defaultEntryQty) throw new Error("strategy.default_entry_qty() is not provided by the strategy engine.");
|
|
5876
|
+
return engine.defaultEntryQty(fill_price);
|
|
5877
|
+
},
|
|
5878
|
+
risk: {
|
|
5879
|
+
allow_entry_in: (direction) => riskRule({ rule: "allow_entry_in", direction }),
|
|
5880
|
+
max_cons_loss_days: (count, alert_message) => riskRule(given({ rule: "max_cons_loss_days", count, alert_message })),
|
|
5881
|
+
max_drawdown: (value, type, alert_message) => riskRule(given({ rule: "max_drawdown", value, type, alert_message })),
|
|
5882
|
+
max_intraday_filled_orders: (count, alert_message) => riskRule(given({ rule: "max_intraday_filled_orders", count, alert_message })),
|
|
5883
|
+
max_intraday_loss: (value, type, alert_message) => riskRule(given({ rule: "max_intraday_loss", value, type, alert_message })),
|
|
5884
|
+
max_position_size: (contracts) => riskRule({ rule: "max_position_size", contracts })
|
|
5885
|
+
}
|
|
5886
|
+
};
|
|
5887
|
+
var variableGetters = {};
|
|
5888
|
+
for (const name of [...STRATEGY_NUMBER_VARIABLES, ...STRATEGY_TEXT_VARIABLES]) {
|
|
5889
|
+
variableGetters[name] = { get: () => strategyVariable(name), enumerable: true };
|
|
5890
|
+
}
|
|
5891
|
+
var strategy = Object.defineProperties(
|
|
5892
|
+
Object.assign((title, options) => declareStrategy(title, options), strategyMembers),
|
|
5893
|
+
variableGetters
|
|
5894
|
+
);
|
|
5726
5895
|
var chartCtx = {};
|
|
5727
5896
|
function chartTimeframe() {
|
|
5728
5897
|
collector();
|
|
@@ -5782,7 +5951,24 @@ var timeframe = {
|
|
|
5782
5951
|
return in_seconds(tf === void 0 || tf === "" ? chartTimeframe().period : tf);
|
|
5783
5952
|
}
|
|
5784
5953
|
};
|
|
5954
|
+
function symbolProperty(key) {
|
|
5955
|
+
collector();
|
|
5956
|
+
const value = chartCtx[key];
|
|
5957
|
+
if (value === void 0) {
|
|
5958
|
+
throw new Error(`syminfo.${key} is not known: pass it as executeScript(body, bars, inputs, { ${key} }).`);
|
|
5959
|
+
}
|
|
5960
|
+
return value;
|
|
5961
|
+
}
|
|
5785
5962
|
var syminfo = {
|
|
5963
|
+
get mintick() {
|
|
5964
|
+
return symbolProperty("mintick");
|
|
5965
|
+
},
|
|
5966
|
+
get pointvalue() {
|
|
5967
|
+
return symbolProperty("pointvalue");
|
|
5968
|
+
},
|
|
5969
|
+
get mincontract() {
|
|
5970
|
+
return symbolProperty("mincontract");
|
|
5971
|
+
},
|
|
5786
5972
|
get timezone() {
|
|
5787
5973
|
return exchangeTimezone();
|
|
5788
5974
|
},
|
|
@@ -6051,8 +6237,16 @@ function alertcondition(condition, title, message) {
|
|
|
6051
6237
|
const last = condition.length() ? condition.last() : NaN;
|
|
6052
6238
|
c.alerts.push({ id, title, message, triggered: !isNA(last) && last !== 0 });
|
|
6053
6239
|
}
|
|
6240
|
+
var math = {
|
|
6241
|
+
...math_exports,
|
|
6242
|
+
round_to_mintick: ((number2, mintick) => {
|
|
6243
|
+
const tick = mintick ?? syminfo.mintick;
|
|
6244
|
+
return number2 instanceof Series ? round_to_mintick(number2, tick) : round_to_mintick(number2, tick);
|
|
6245
|
+
})
|
|
6246
|
+
};
|
|
6054
6247
|
export {
|
|
6055
6248
|
BarData,
|
|
6249
|
+
STRATEGY_DEFAULTS,
|
|
6056
6250
|
Series,
|
|
6057
6251
|
alertcondition,
|
|
6058
6252
|
barcolor,
|
|
@@ -6082,7 +6276,7 @@ export {
|
|
|
6082
6276
|
line,
|
|
6083
6277
|
linefill,
|
|
6084
6278
|
low,
|
|
6085
|
-
|
|
6279
|
+
math,
|
|
6086
6280
|
minute2 as minute,
|
|
6087
6281
|
month2 as month,
|
|
6088
6282
|
isNA as na,
|
|
@@ -6098,6 +6292,7 @@ export {
|
|
|
6098
6292
|
seriesOf,
|
|
6099
6293
|
session,
|
|
6100
6294
|
str,
|
|
6295
|
+
strategy,
|
|
6101
6296
|
syminfo,
|
|
6102
6297
|
ta2 as ta,
|
|
6103
6298
|
text,
|