oakscriptjs 0.7.2 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -259,7 +259,7 @@ var Series = class _Series {
259
259
  return new _Series(this.dataSource, (bar, i, data) => {
260
260
  const a = this.extractor(bar, i, data);
261
261
  const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
262
- return b2 !== 0 ? a / b2 : NaN;
262
+ return a / b2;
263
263
  });
264
264
  }
265
265
  /**
@@ -632,7 +632,7 @@ function sma(source, length2) {
632
632
  const window = [];
633
633
  for (let i = 0; i < source.length; i++) {
634
634
  const v = source[i];
635
- if (v !== void 0 && v !== null && !Number.isNaN(v)) {
635
+ if (v !== void 0 && v !== null && Number.isFinite(v)) {
636
636
  window.push(v);
637
637
  if (window.length > len) window.shift();
638
638
  }
@@ -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(false, high2, low2, close2);
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) {
@@ -976,7 +976,7 @@ function lowest(source, length2) {
976
976
  function cum(source) {
977
977
  let sum2 = 0;
978
978
  return source.map((v) => {
979
- if (Number.isNaN(v)) return NaN;
979
+ if (!Number.isFinite(v)) return NaN;
980
980
  sum2 += v;
981
981
  return sum2;
982
982
  });
@@ -994,41 +994,24 @@ function cross(source1, source2) {
994
994
  }
995
995
  return result;
996
996
  }
997
- function rising(source, length2) {
997
+ function monotonic(source, length2, step) {
998
998
  const result = [];
999
+ const values = [];
999
1000
  for (let i = 0; i < source.length; i++) {
1000
- if (i < length2) {
1001
- result.push(false);
1002
- } else {
1003
- let isRising = true;
1004
- for (let j = 1; j <= length2; j++) {
1005
- if (source[i - j + 1] <= source[i - j]) {
1006
- isRising = false;
1007
- break;
1008
- }
1009
- }
1010
- result.push(isRising);
1011
- }
1001
+ const v = source[i];
1002
+ if (!Number.isNaN(v)) values.push(v);
1003
+ const n = values.length;
1004
+ let ok = n > length2;
1005
+ for (let j = 1; ok && j <= length2; j++) ok = step(values[n - j], values[n - j - 1]);
1006
+ result.push(ok);
1012
1007
  }
1013
1008
  return result;
1014
1009
  }
1010
+ function rising(source, length2) {
1011
+ return monotonic(source, length2, gt);
1012
+ }
1015
1013
  function falling(source, length2) {
1016
- const result = [];
1017
- for (let i = 0; i < source.length; i++) {
1018
- if (i < length2) {
1019
- result.push(false);
1020
- } else {
1021
- let isFalling = true;
1022
- for (let j = 1; j <= length2; j++) {
1023
- if (source[i - j + 1] >= source[i - j]) {
1024
- isFalling = false;
1025
- break;
1026
- }
1027
- }
1028
- result.push(isFalling);
1029
- }
1030
- }
1031
- return result;
1014
+ return monotonic(source, length2, lt);
1032
1015
  }
1033
1016
  function roc(source, length2) {
1034
1017
  const result = [];
@@ -1252,33 +1235,16 @@ function correlation(source1, source2, length2) {
1252
1235
  function percentrank(source, length2) {
1253
1236
  const result = [];
1254
1237
  for (let i = 0; i < source.length; i++) {
1255
- if (i < length2) {
1238
+ const currentValue = source[i];
1239
+ if (i < length2 || Number.isNaN(currentValue)) {
1256
1240
  result.push(NaN);
1257
- } else {
1258
- if (isNaN(source[i])) {
1259
- result.push(NaN);
1260
- continue;
1261
- }
1262
- let hasNaN = false;
1263
- for (let j = 1; j <= length2; j++) {
1264
- if (isNaN(source[i - j])) {
1265
- hasNaN = true;
1266
- break;
1267
- }
1268
- }
1269
- if (hasNaN) {
1270
- result.push(NaN);
1271
- } else {
1272
- const currentValue = source[i];
1273
- let countLessOrEqual = 0;
1274
- for (let j = 1; j <= length2; j++) {
1275
- if (source[i - j] <= currentValue) {
1276
- countLessOrEqual++;
1277
- }
1278
- }
1279
- result.push(countLessOrEqual / length2 * 100);
1280
- }
1241
+ continue;
1242
+ }
1243
+ let countLessOrEqual = 0;
1244
+ for (let j = 1; j <= length2; j++) {
1245
+ if (le(source[i - j], currentValue)) countLessOrEqual++;
1281
1246
  }
1247
+ result.push(countLessOrEqual / length2 * 100);
1282
1248
  }
1283
1249
  return result;
1284
1250
  }
@@ -1321,48 +1287,26 @@ function mfi(source, length2, volume2) {
1321
1287
  "ta.mfi() requires volume series. Either pass it explicitly or use createContext({ chart: { ..., volume } }) for implicit data."
1322
1288
  );
1323
1289
  }
1324
- const result = [];
1325
- const changes = [NaN];
1326
- for (let i = 1; i < source.length; i++) {
1327
- changes.push(source[i] - source[i - 1]);
1328
- }
1329
- const positiveFlow = [];
1330
- const negativeFlow = [];
1290
+ const upperFlow = [];
1291
+ const lowerFlow = [];
1331
1292
  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
- }
1346
- for (let i = 0; i < source.length; i++) {
1347
- if (i < length2) {
1348
- result.push(NaN);
1349
- } else {
1350
- let posSum = 0;
1351
- let negSum = 0;
1352
- for (let j = 0; j < length2; j++) {
1353
- posSum += positiveFlow[i - j];
1354
- negSum += negativeFlow[i - j];
1355
- }
1356
- if (negSum === 0) {
1357
- result.push(100);
1358
- } else {
1359
- const moneyRatio = posSum / negSum;
1360
- const mfiValue = 100 - 100 / (1 + moneyRatio);
1361
- result.push(mfiValue);
1362
- }
1363
- }
1364
- }
1365
- return result;
1293
+ const change3 = i === 0 ? NaN : source[i] - source[i - 1];
1294
+ const flow = volume2[i] * source[i];
1295
+ upperFlow.push(le(change3, 0) ? 0 : flow);
1296
+ lowerFlow.push(ge(change3, 0) ? 0 : flow);
1297
+ }
1298
+ const sumAt = (flow, i) => {
1299
+ const values = lastValues(flow, i, Math.floor(length2));
1300
+ return values ? values.reduce((a, b2) => a + b2, 0) : NaN;
1301
+ };
1302
+ const upper2 = upperFlow.map((_, i) => sumAt(upperFlow, i));
1303
+ const lower2 = lowerFlow.map((_, i) => sumAt(lowerFlow, i));
1304
+ return upper2.map((u, i) => {
1305
+ const l = lower2[i];
1306
+ if (Number.isNaN(u) || Number.isNaN(l)) return NaN;
1307
+ if (l === 0) return 100;
1308
+ return 100 - 100 / (1 + u / l);
1309
+ });
1366
1310
  }
1367
1311
  function hma(source, length2) {
1368
1312
  const halfLength = Math.floor(length2 / 2);
@@ -1526,50 +1470,32 @@ function dmi(diLength, adxSmoothing, high2, low2, close2) {
1526
1470
  const len = Math.max(high2.length, low2.length, close2.length);
1527
1471
  const plusDM = [];
1528
1472
  const minusDM = [];
1529
- const trueRangeValues = tr(false, high2, low2, close2);
1530
1473
  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
- for (let i = 0; i < len; i++) {
1565
- const sum2 = plusDI[i] + minusDI[i];
1566
- if (sum2 === 0) {
1567
- dx.push(0);
1568
- } else {
1569
- dx.push(Math.abs(plusDI[i] - minusDI[i]) / sum2 * 100);
1570
- }
1571
- }
1572
- const adx = rma(dx, adxSmoothing);
1474
+ const up = i === 0 ? NaN : high2[i] - high2[i - 1];
1475
+ const down = i === 0 ? NaN : low2[i - 1] - low2[i];
1476
+ plusDM.push(Number.isNaN(up) ? NaN : gt(up, down) && gt(up, 0) ? up : 0);
1477
+ minusDM.push(Number.isNaN(down) ? NaN : gt(down, up) && gt(down, 0) ? down : 0);
1478
+ }
1479
+ const trur = rma(tr(false, high2, low2, close2), diLength);
1480
+ const smoothedPlus = rma(plusDM, diLength);
1481
+ const smoothedMinus = rma(minusDM, diLength);
1482
+ const directional = (smoothed) => {
1483
+ let last = NaN;
1484
+ return smoothed.map((v, i) => {
1485
+ const t2 = trur[i];
1486
+ const value = t2 === 0 ? NaN : 100 * v / t2;
1487
+ if (!Number.isNaN(value)) last = value;
1488
+ return last;
1489
+ });
1490
+ };
1491
+ const plusDI = directional(smoothedPlus);
1492
+ const minusDI = directional(smoothedMinus);
1493
+ const dx = plusDI.map((plus, i) => {
1494
+ const minus = minusDI[i];
1495
+ const sum2 = plus + minus;
1496
+ return Math.abs(plus - minus) / (eq(sum2, 0) ? 1 : sum2);
1497
+ });
1498
+ const adx = rma(dx, adxSmoothing).map((v) => 100 * v);
1573
1499
  return [plusDI, minusDI, adx];
1574
1500
  }
1575
1501
  function tsi(source, shortLength, longLength) {
@@ -1845,63 +1771,36 @@ function mode(source, length2) {
1845
1771
  return result;
1846
1772
  }
1847
1773
  function percentile_linear_interpolation(source, length2, percentage) {
1774
+ return sortedWindow(source, length2, (s) => {
1775
+ const pos2 = percentage / 100 * length2 - 0.5;
1776
+ if (pos2 <= 0) return s[0];
1777
+ if (pos2 >= length2 - 1) return s[length2 - 1];
1778
+ const lo = Math.floor(pos2);
1779
+ return s[lo] + (pos2 - lo) * (s[lo + 1] - s[lo]);
1780
+ });
1781
+ }
1782
+ function sortedWindow(source, length2, fn) {
1848
1783
  const result = [];
1784
+ const values = [];
1785
+ const bars2 = [];
1849
1786
  for (let i = 0; i < source.length; i++) {
1850
- if (i < length2 - 1) {
1851
- result.push(NaN);
1852
- continue;
1853
- }
1854
- const values = [];
1855
- for (let j = 0; j < length2; j++) {
1856
- const value = source[i - j];
1857
- values.push(value);
1858
- }
1859
- if (values.some((v) => isNaN(v))) {
1860
- result.push(NaN);
1861
- continue;
1862
- }
1863
- const sorted = [...values].sort((a, b2) => a - b2);
1864
- const position = percentage / 100 * (sorted.length - 1);
1865
- const lowerIndex = Math.floor(position);
1866
- const upperIndex = Math.ceil(position);
1867
- if (lowerIndex === upperIndex) {
1868
- result.push(sorted[lowerIndex]);
1869
- } else {
1870
- const fraction = position - lowerIndex;
1871
- const interpolated = sorted[lowerIndex] + fraction * (sorted[upperIndex] - sorted[lowerIndex]);
1872
- result.push(interpolated);
1787
+ const v = source[i];
1788
+ let k = 0;
1789
+ while (k < values.length && !(values[k] >= v)) k++;
1790
+ values.splice(k, 0, v);
1791
+ bars2.splice(k, 0, i);
1792
+ if (i >= length2) {
1793
+ const old = bars2.indexOf(i - length2);
1794
+ values.splice(old, 1);
1795
+ bars2.splice(old, 1);
1873
1796
  }
1797
+ result.push(i < length2 - 1 ? NaN : fn(values));
1874
1798
  }
1875
1799
  return result;
1876
1800
  }
1877
1801
  function percentile_nearest_rank(source, length2, percentage) {
1878
- const result = [];
1879
- for (let i = 0; i < source.length; i++) {
1880
- if (i < length2 - 1) {
1881
- result.push(NaN);
1882
- continue;
1883
- }
1884
- const values = [];
1885
- for (let j = 0; j < length2; j++) {
1886
- const value = source[i - j];
1887
- if (!isNaN(value)) {
1888
- values.push(value);
1889
- }
1890
- }
1891
- if (values.length === 0) {
1892
- result.push(NaN);
1893
- continue;
1894
- }
1895
- const sorted = [...values].sort((a, b2) => a - b2);
1896
- if (percentage >= 100) {
1897
- result.push(sorted[sorted.length - 1]);
1898
- continue;
1899
- }
1900
- const rank = Math.ceil(percentage / 100 * sorted.length);
1901
- const index = Math.max(0, rank - 1);
1902
- result.push(sorted[index]);
1903
- }
1904
- return result;
1802
+ const rank = Math.min(length2, Math.max(1, Math.ceil(percentage / 100 * length2)));
1803
+ return sortedWindow(source, length2, (s) => s[rank - 1]);
1905
1804
  }
1906
1805
  function rci(source, length2) {
1907
1806
  const result = [];
@@ -2767,11 +2666,13 @@ __export(color_exports, {
2767
2666
  white: () => white,
2768
2667
  yellow: () => yellow
2769
2668
  });
2669
+ var channel = (v) => v === null || v === void 0 || Number.isNaN(v) ? 0 : Math.max(0, Math.min(255, Math.trunc(v)));
2670
+ var alphaOf = (transp) => transp === null || Number.isNaN(transp) ? 0 : 1 - Math.max(0, Math.min(100, transp)) / 100;
2770
2671
  function rgb(red2, green2, blue2, transp) {
2771
- const r2 = Math.max(0, Math.min(255, red2));
2772
- const g2 = Math.max(0, Math.min(255, green2));
2773
- const b2 = Math.max(0, Math.min(255, blue2));
2774
- const a = transp !== void 0 ? 1 - transp / 100 : 1;
2672
+ const r2 = channel(red2);
2673
+ const g2 = channel(green2);
2674
+ const b2 = channel(blue2);
2675
+ const a = transp !== void 0 ? alphaOf(transp) : 1;
2775
2676
  if (a === 1) {
2776
2677
  return `rgb(${r2}, ${g2}, ${b2})`;
2777
2678
  }
@@ -2798,7 +2699,8 @@ function b(clr) {
2798
2699
  return parseColor(clr).b;
2799
2700
  }
2800
2701
  function t(clr) {
2801
- return parseColor(clr).t;
2702
+ const alpha = Math.round((1 - parseColor(clr).t / 100) * 255);
2703
+ return Math.round((1 - alpha / 255) * 100);
2802
2704
  }
2803
2705
  function parseColor(clr) {
2804
2706
  if (typeof clr === "string") {
@@ -2851,13 +2753,12 @@ function from_gradient(value, bottom_value, top_value, bottom_color, top_color)
2851
2753
  };
2852
2754
  const c1 = rgba(bottom_color);
2853
2755
  const c2 = rgba(top_color);
2854
- const w1 = c1.a * (1 - k);
2855
- const w2 = c2.a * k;
2856
- const a = w1 + w2;
2756
+ const a = c1.a * (1 - k) + c2.a * k;
2857
2757
  if (a === 0) return transparent;
2858
- const mix = (x1, x2) => Math.floor((x1 * w1 + x2 * w2) / a);
2758
+ const mix = (x1, x2) => Math.floor((x1 / 255 * c1.a * (1 - k) + x2 / 255 * c2.a * k) / (a / 255));
2859
2759
  const [r2, g2, b2] = [mix(c1.r, c2.r), mix(c1.g, c2.g), mix(c1.b, c2.b)];
2860
- return a === 255 ? `rgb(${r2}, ${g2}, ${b2})` : `rgba(${r2}, ${g2}, ${b2}, ${a / 255})`;
2760
+ const alpha = Math.floor(a);
2761
+ return alpha === 255 ? `rgb(${r2}, ${g2}, ${b2})` : `rgba(${r2}, ${g2}, ${b2}, ${alpha / 255})`;
2861
2762
  }
2862
2763
 
2863
2764
  // src/drawing/registry.ts
@@ -2921,7 +2822,7 @@ function setDrawingLimits(newLimits) {
2921
2822
 
2922
2823
  // src/utils/index.ts
2923
2824
  function isNA(value) {
2924
- return value === null || value === void 0 || Number.isNaN(value) || isDeleted(value);
2825
+ return value === null || value === void 0 || Number.isNaN(value) || value === Infinity || value === -Infinity || isDeleted(value);
2925
2826
  }
2926
2827
  function nz(value, defaultValue = 0) {
2927
2828
  return isNA(value) ? defaultValue : value;
@@ -2930,7 +2831,7 @@ function fixnan(source) {
2930
2831
  let last;
2931
2832
  let seen = false;
2932
2833
  return source.map((v) => {
2933
- if (!isNA(v)) {
2834
+ if (!(v === null || v === void 0 || Number.isNaN(v) || isDeleted(v))) {
2934
2835
  last = v;
2935
2836
  seen = true;
2936
2837
  return v;
@@ -3654,1640 +3555,1707 @@ var format_none = 0;
3654
3555
  var format_bold = 1;
3655
3556
  var format_italic = 2;
3656
3557
 
3657
- // src/timeframe/index.ts
3658
- var timeframe_exports = {};
3659
- __export(timeframe_exports, {
3660
- from_seconds: () => from_seconds,
3661
- in_seconds: () => in_seconds,
3662
- info: () => info
3558
+ // src/math/index.ts
3559
+ var math_exports = {};
3560
+ __export(math_exports, {
3561
+ abs: () => abs,
3562
+ acos: () => acos,
3563
+ asin: () => asin,
3564
+ atan: () => atan,
3565
+ avg: () => avg,
3566
+ ceil: () => ceil,
3567
+ cos: () => cos,
3568
+ e: () => e,
3569
+ exp: () => exp,
3570
+ floor: () => floor,
3571
+ log: () => log,
3572
+ log10: () => log10,
3573
+ max: () => max3,
3574
+ min: () => min3,
3575
+ phi: () => phi,
3576
+ pi: () => pi,
3577
+ pow: () => pow,
3578
+ random: () => random,
3579
+ round: () => round,
3580
+ round_to_mintick: () => round_to_mintick,
3581
+ rphi: () => rphi,
3582
+ sign: () => sign,
3583
+ sin: () => sin,
3584
+ sqrt: () => sqrt,
3585
+ sum: () => sum,
3586
+ tan: () => tan,
3587
+ todegrees: () => todegrees,
3588
+ toradians: () => toradians
3663
3589
  });
3664
- var SECONDS_PER_MINUTE = 60;
3665
- var SECONDS_PER_DAY = 86400;
3666
- var SECONDS_PER_WEEK = 604800;
3667
- var SECONDS_PER_MONTH = 2628003;
3668
- var SECONDS_365_DAYS = 365 * SECONDS_PER_DAY;
3669
- var UNIT_SECONDS = {
3670
- S: 1,
3671
- "": SECONDS_PER_MINUTE,
3672
- D: SECONDS_PER_DAY,
3673
- W: SECONDS_PER_WEEK,
3674
- M: SECONDS_PER_MONTH
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");
3590
+ function abs(value) {
3591
+ if (value instanceof Series) {
3592
+ const bars2 = value.bars;
3593
+ const valueArray = value.toArray();
3594
+ const length2 = bars2.length;
3595
+ const result = [];
3596
+ for (let i = 0; i < length2; i++) {
3597
+ const v = valueArray[i] ?? NaN;
3598
+ result.push(Math.abs(v));
3599
+ }
3600
+ return Series.fromArray(bars2, result);
3681
3601
  }
3682
- const before = /^(\d*)([SDWMT]?)$/.exec(text2);
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];
3602
+ return Math.abs(value);
3689
3603
  }
3690
- function from_seconds(seconds) {
3691
- if (Number.isNaN(seconds)) throw new RangeError("timeframe.from_seconds() needs a number of seconds");
3692
- if (seconds >= SECONDS_365_DAYS) return "12M";
3693
- if (seconds > 0) {
3694
- if (seconds % SECONDS_PER_MONTH === 0) return `${seconds / SECONDS_PER_MONTH}M`;
3695
- if (seconds % SECONDS_PER_WEEK === 0) return `${seconds / SECONDS_PER_WEEK}W`;
3696
- if (seconds % SECONDS_PER_DAY === 0) return `${seconds / SECONDS_PER_DAY}D`;
3697
- if (seconds % SECONDS_PER_MINUTE === 0 && seconds < SECONDS_PER_DAY) return `${seconds / SECONDS_PER_MINUTE}`;
3604
+ function ceil(value) {
3605
+ if (value instanceof Series) {
3606
+ const bars2 = value.bars;
3607
+ const valueArray = value.toArray();
3608
+ const length2 = bars2.length;
3609
+ const result = [];
3610
+ for (let i = 0; i < length2; i++) {
3611
+ const v = valueArray[i] ?? NaN;
3612
+ result.push(Math.ceil(v));
3613
+ }
3614
+ return Series.fromArray(bars2, result);
3698
3615
  }
3699
- const second3 = SECOND_TIMEFRAMES.find((m) => seconds <= m);
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`;
3616
+ return Math.ceil(value);
3703
3617
  }
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
- };
3618
+ function floor(value) {
3619
+ if (value instanceof Series) {
3620
+ const bars2 = value.bars;
3621
+ const valueArray = value.toArray();
3622
+ const length2 = bars2.length;
3623
+ const result = [];
3624
+ for (let i = 0; i < length2; i++) {
3625
+ const v = valueArray[i] ?? NaN;
3626
+ result.push(Math.floor(v));
3627
+ }
3628
+ return Series.fromArray(bars2, result);
3629
+ }
3630
+ return Math.floor(value);
3722
3631
  }
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;
3736
- }
3737
- var zones = /* @__PURE__ */ new Map();
3738
- function resolveZone(timezone) {
3739
- let zone = zones.get(timezone);
3740
- if (zone) return zone;
3741
- const invalid = () => new RangeError(
3742
- `Invalid time zone "${timezone}": use UTC/GMT offset notation ("UTC-5", "GMT+0530") or an IANA name ("America/New_York")`
3743
- );
3744
- const m = OFFSET_NOTATION.exec(timezone);
3745
- if (m) {
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();
3632
+ function round(value, precision) {
3633
+ if (value instanceof Series) {
3634
+ const bars2 = value.bars;
3635
+ const valueArray = value.toArray();
3636
+ const length2 = bars2.length;
3637
+ const result = [];
3638
+ if (precision === void 0) {
3639
+ for (let i = 0; i < length2; i++) {
3640
+ const v = valueArray[i] ?? NaN;
3641
+ result.push(Math.round(v));
3642
+ }
3643
+ } else {
3644
+ const multiplier2 = Math.pow(10, precision);
3645
+ for (let i = 0; i < length2; i++) {
3646
+ const v = valueArray[i] ?? NaN;
3647
+ result.push(Math.round(v * multiplier2) / multiplier2);
3648
+ }
3769
3649
  }
3770
- zone = { kind: "iana", format: format2 };
3650
+ return Series.fromArray(bars2, result);
3771
3651
  }
3772
- zones.set(timezone, zone);
3773
- return zone;
3774
- }
3775
- function offsetAt(zone, time2) {
3776
- if (zone.kind === "fixed") return zone.offsetMs;
3777
- const wholeSecond = Math.floor(time2 / 1e3) * 1e3;
3778
- const f = {};
3779
- for (const part of zone.format.formatToParts(wholeSecond)) {
3780
- if (part.type !== "literal") f[part.type] = Number(part.value);
3652
+ if (precision === void 0) {
3653
+ return Math.round(value);
3781
3654
  }
3782
- const local = Date.UTC(f.year, f.month - 1, f.day, f.hour, f.minute, f.second);
3783
- return local - wholeSecond;
3784
- }
3785
- function zoneOffset(time2, timezone) {
3786
- return offsetAt(resolveZone(timezone), time2);
3787
- }
3788
- function zonedFields(time2, timezone) {
3789
- const local = new Date(time2 + offsetAt(resolveZone(timezone), time2));
3790
- return {
3791
- year: local.getUTCFullYear(),
3792
- month: local.getUTCMonth() + 1,
3793
- day: local.getUTCDate(),
3794
- hour: local.getUTCHours(),
3795
- minute: local.getUTCMinutes(),
3796
- second: local.getUTCSeconds(),
3797
- dayOfWeek: local.getUTCDay() + 1
3798
- };
3655
+ const multiplier = Math.pow(10, precision);
3656
+ return Math.round(value * multiplier) / multiplier;
3799
3657
  }
3800
- function zonedToUnix(timezone, year3, month3, day, hour3 = 0, minute3 = 0, second3 = 0) {
3801
- const zone = resolveZone(timezone);
3802
- const local = Date.UTC(year3, month3 - 1, day, hour3, minute3, second3);
3803
- if (zone.kind === "fixed") return local - zone.offsetMs;
3804
- const before = offsetAt(zone, local - MS_PER_DAY);
3805
- const after = offsetAt(zone, local + MS_PER_DAY);
3806
- const candidates = [local - before, local - after].filter((t2) => local - offsetAt(zone, t2) === t2);
3807
- if (candidates.length) return Math.max(...candidates);
3808
- return local - before;
3658
+ function max3(...values) {
3659
+ const hasSeries = values.some((v) => v instanceof Series);
3660
+ if (!hasSeries) {
3661
+ return Math.max(...values);
3662
+ }
3663
+ const firstSeries = values.find((v) => v instanceof Series);
3664
+ const bars2 = firstSeries.bars;
3665
+ const length2 = bars2.length;
3666
+ const valueArrays = values.map(
3667
+ (v) => v instanceof Series ? v.toArray() : null
3668
+ );
3669
+ const result = [];
3670
+ for (let i = 0; i < length2; i++) {
3671
+ const nums = values.map(
3672
+ (v, idx) => valueArrays[idx] ? valueArrays[idx][i] ?? NaN : v
3673
+ );
3674
+ result.push(Math.max(...nums));
3675
+ }
3676
+ return Series.fromArray(bars2, result);
3809
3677
  }
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;
3678
+ function min3(...values) {
3679
+ const hasSeries = values.some((v) => v instanceof Series);
3680
+ if (!hasSeries) {
3681
+ return Math.min(...values);
3682
+ }
3683
+ const firstSeries = values.find((v) => v instanceof Series);
3684
+ const bars2 = firstSeries.bars;
3685
+ const length2 = bars2.length;
3686
+ const valueArrays = values.map(
3687
+ (v) => v instanceof Series ? v.toArray() : null
3688
+ );
3689
+ const result = [];
3690
+ for (let i = 0; i < length2; i++) {
3691
+ const nums = values.map(
3692
+ (v, idx) => valueArrays[idx] ? valueArrays[idx][i] ?? NaN : v
3693
+ );
3694
+ result.push(Math.min(...nums));
3695
+ }
3696
+ return Series.fromArray(bars2, result);
3853
3697
  }
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;
3698
+ function avg(...values) {
3699
+ const hasSeries = values.some((v) => v instanceof Series);
3700
+ if (!hasSeries) {
3701
+ return values.reduce((a, b2) => a + b2, 0) / values.length;
3702
+ }
3703
+ const firstSeries = values.find((v) => v instanceof Series);
3704
+ const bars2 = firstSeries.bars;
3705
+ const length2 = bars2.length;
3706
+ const valueArrays = values.map(
3707
+ (v) => v instanceof Series ? v.toArray() : null
3708
+ );
3709
+ const result = [];
3710
+ for (let i = 0; i < length2; i++) {
3711
+ const nums = values.map(
3712
+ (v, idx) => valueArrays[idx] ? valueArrays[idx][i] ?? NaN : v
3713
+ );
3714
+ const sum2 = nums.reduce((a, b2) => a + b2, 0);
3715
+ result.push(sum2 / nums.length);
3716
+ }
3717
+ return Series.fromArray(bars2, result);
3863
3718
  }
3864
- function parseDateString(dateString) {
3865
- const text2 = dateString.trim();
3866
- let year3, month3, day;
3867
- let rest;
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")`);
3719
+ function sum(source, length2) {
3720
+ const sourceArray = source instanceof Series ? source.toArray() : source;
3721
+ const result = [];
3722
+ const len = Math.floor(length2);
3723
+ const window = [];
3724
+ for (let i = 0; i < sourceArray.length; i++) {
3725
+ const v = sourceArray[i];
3726
+ if (v !== void 0 && v !== null && !Number.isNaN(v)) {
3727
+ window.push(v);
3728
+ if (window.length > len) window.shift();
3729
+ }
3730
+ if (window.length < len) {
3731
+ result.push(NaN);
3732
+ } else {
3733
+ let total = 0;
3734
+ for (const x of window) total += x;
3735
+ result.push(total);
3736
+ }
3880
3737
  }
3881
- const [hour3 = "0", minute3 = "0", second3 = "0", millis = "0", zone] = rest;
3882
- const d = Number(day);
3883
- const h = Number(hour3);
3884
- const mi = Number(minute3);
3885
- const s = Number(second3);
3886
- const offset = zoneMinutes(zone);
3887
- const endOfDay = h === 24 && mi === 0 && s === 0 && Number(millis) === 0;
3888
- if (month3 < 1 || month3 > 12 || d < 1 || d > 31 || h > 23 && !endOfDay || mi > 59 || s > 59 || Number.isNaN(offset)) {
3889
- throw new SyntaxError(`Invalid date string "${dateString}": a field is out of range`);
3738
+ if (source instanceof Series) {
3739
+ return Series.fromArray(source.bars, result);
3890
3740
  }
3891
- const ms = Number(millis.padEnd(3, "0"));
3892
- return Date.UTC(Number(year3), month3 - 1, d, h, mi, s, ms) - offset * 6e4;
3741
+ return result;
3893
3742
  }
3894
-
3895
- // src/time/session.ts
3896
- var PERIOD = /^(\d{2})(\d{2})-(\d{2})(\d{2})$/;
3897
- var sessions = /* @__PURE__ */ new Map();
3898
- function parseSession(session2) {
3899
- let parsed = sessions.get(session2);
3900
- if (parsed) return parsed;
3901
- const invalid = () => new SyntaxError(`Invalid session "${session2}": expected "HHmm-HHmm[,HHmm-HHmm...][:days]"`);
3902
- const text2 = session2.trim() === "24x7" ? "0000-0000" : session2.replace(/\s+/g, "");
3903
- const [periodText = "", dayText, extra] = text2.split(":");
3904
- if (extra !== void 0 || periodText === "") throw invalid();
3905
- const periods = periodText.split(",").map((p) => {
3906
- const m = PERIOD.exec(p);
3907
- if (!m) throw invalid();
3908
- const [h1, m1, h2, m2] = [m[1], m[2], m[3], m[4]].map(Number);
3909
- if (h1 > 23 || h2 > 23 || m1 > 59 || m2 > 59) throw invalid();
3910
- return { start: h1 * 60 + m1, end: h2 * 60 + m2 };
3911
- });
3912
- const dayDigits = dayText ?? (periods.length > 1 ? "23456" : "1234567");
3913
- if (!/^[1-7]+$/.test(dayDigits)) throw invalid();
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;
3743
+ function sqrt(value) {
3744
+ if (value instanceof Series) {
3745
+ const bars2 = value.bars;
3746
+ const valueArray = value.toArray();
3747
+ const length2 = bars2.length;
3748
+ const result = [];
3749
+ for (let i = 0; i < length2; i++) {
3750
+ const v = valueArray[i] ?? NaN;
3751
+ result.push(Math.sqrt(v));
3752
+ }
3753
+ return Series.fromArray(bars2, result);
3754
+ }
3755
+ return Math.sqrt(value);
3919
3756
  }
3920
- function inSession(time2, session2, timezone) {
3921
- if (Number.isNaN(time2)) return false;
3922
- const { periods, days } = parseSession(session2);
3923
- const f = zonedFields(time2, timezone);
3924
- const minute3 = f.hour * 60 + f.minute;
3925
- const nextDay = f.dayOfWeek % 7 + 1;
3926
- for (const { start, end } of periods) {
3927
- if (start < end || start === 0 && end === 0) {
3928
- if (minute3 >= start && (minute3 < end || end === 0) && days[f.dayOfWeek]) return true;
3929
- } else {
3930
- if (minute3 >= start && days[nextDay]) return true;
3931
- if (minute3 < end && days[f.dayOfWeek]) return true;
3757
+ function pow(base, exponent) {
3758
+ const baseIsSeries = base instanceof Series;
3759
+ const expIsSeries = exponent instanceof Series;
3760
+ if (!baseIsSeries && !expIsSeries) {
3761
+ return Math.pow(base, exponent);
3762
+ }
3763
+ const bars2 = baseIsSeries ? base.bars : exponent.bars;
3764
+ const baseArray = baseIsSeries ? base.toArray() : null;
3765
+ const expArray = expIsSeries ? exponent.toArray() : null;
3766
+ const length2 = bars2.length;
3767
+ const result = [];
3768
+ for (let i = 0; i < length2; i++) {
3769
+ const b2 = baseArray ? baseArray[i] ?? NaN : base;
3770
+ const e2 = expArray ? expArray[i] ?? NaN : exponent;
3771
+ result.push(Math.pow(b2, e2));
3772
+ }
3773
+ return Series.fromArray(bars2, result);
3774
+ }
3775
+ function exp(value) {
3776
+ if (value instanceof Series) {
3777
+ const bars2 = value.bars;
3778
+ const valueArray = value.toArray();
3779
+ const length2 = bars2.length;
3780
+ const result = [];
3781
+ for (let i = 0; i < length2; i++) {
3782
+ const v = valueArray[i] ?? NaN;
3783
+ result.push(Math.exp(v));
3932
3784
  }
3785
+ return Series.fromArray(bars2, result);
3933
3786
  }
3934
- return false;
3787
+ return Math.exp(value);
3935
3788
  }
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);
3789
+ function log(value) {
3790
+ if (value instanceof Series) {
3791
+ const bars2 = value.bars;
3792
+ const valueArray = value.toArray();
3793
+ const length2 = bars2.length;
3794
+ const result = [];
3795
+ for (let i = 0; i < length2; i++) {
3796
+ const v = valueArray[i] ?? NaN;
3797
+ result.push(Math.log(v));
3798
+ }
3799
+ return Series.fromArray(bars2, result);
3943
3800
  }
3944
- const [month3, day, hour3, minute3, second3] = rest;
3945
- return new Date(first, month3 - 1, day, hour3 || 0, minute3 || 0, second3 || 0).getTime();
3801
+ return Math.log(value);
3946
3802
  }
3947
- function field(time2, timezone, pick) {
3948
- return Number.isNaN(time2) ? NaN : pick(zonedFields(time2, timezone));
3803
+ function log10(value) {
3804
+ if (value instanceof Series) {
3805
+ const bars2 = value.bars;
3806
+ const valueArray = value.toArray();
3807
+ const length2 = bars2.length;
3808
+ const result = [];
3809
+ for (let i = 0; i < length2; i++) {
3810
+ const v = valueArray[i] ?? NaN;
3811
+ result.push(Math.log10(v));
3812
+ }
3813
+ return Series.fromArray(bars2, result);
3814
+ }
3815
+ return Math.log10(value);
3949
3816
  }
3950
- function year(time2, timezone) {
3951
- return field(time2, timezone, (f) => f.year);
3817
+ function sin(value) {
3818
+ if (value instanceof Series) {
3819
+ const bars2 = value.bars;
3820
+ const valueArray = value.toArray();
3821
+ const length2 = bars2.length;
3822
+ const result = [];
3823
+ for (let i = 0; i < length2; i++) {
3824
+ const v = valueArray[i] ?? NaN;
3825
+ result.push(Math.sin(v));
3826
+ }
3827
+ return Series.fromArray(bars2, result);
3828
+ }
3829
+ return Math.sin(value);
3952
3830
  }
3953
- function month(time2, timezone) {
3954
- return field(time2, timezone, (f) => f.month);
3831
+ function cos(value) {
3832
+ if (value instanceof Series) {
3833
+ const bars2 = value.bars;
3834
+ const valueArray = value.toArray();
3835
+ const length2 = bars2.length;
3836
+ const result = [];
3837
+ for (let i = 0; i < length2; i++) {
3838
+ const v = valueArray[i] ?? NaN;
3839
+ result.push(Math.cos(v));
3840
+ }
3841
+ return Series.fromArray(bars2, result);
3842
+ }
3843
+ return Math.cos(value);
3955
3844
  }
3956
- function dayofmonth(time2, timezone) {
3957
- return field(time2, timezone, (f) => f.day);
3845
+ function tan(value) {
3846
+ if (value instanceof Series) {
3847
+ const bars2 = value.bars;
3848
+ const valueArray = value.toArray();
3849
+ const length2 = bars2.length;
3850
+ const result = [];
3851
+ for (let i = 0; i < length2; i++) {
3852
+ const v = valueArray[i] ?? NaN;
3853
+ result.push(Math.tan(v));
3854
+ }
3855
+ return Series.fromArray(bars2, result);
3856
+ }
3857
+ return Math.tan(value);
3958
3858
  }
3959
- function dayofweek(time2, timezone) {
3960
- return field(time2, timezone, (f) => f.dayOfWeek);
3859
+ function asin(value) {
3860
+ if (value instanceof Series) {
3861
+ const bars2 = value.bars;
3862
+ const valueArray = value.toArray();
3863
+ const length2 = bars2.length;
3864
+ const result = [];
3865
+ for (let i = 0; i < length2; i++) {
3866
+ const v = valueArray[i] ?? NaN;
3867
+ result.push(Math.asin(v));
3868
+ }
3869
+ return Series.fromArray(bars2, result);
3870
+ }
3871
+ return Math.asin(value);
3961
3872
  }
3962
- function weekofyear(time2, timezone) {
3963
- return field(time2, timezone, (f) => {
3964
- const date = Date.UTC(f.year, f.month - 1, f.day);
3965
- const mondayBased = (f.dayOfWeek + 5) % 7;
3966
- const thursday = new Date(date + (3 - mondayBased) * 864e5);
3967
- const yearStart = Date.UTC(thursday.getUTCFullYear(), 0, 1);
3968
- return 1 + Math.floor((thursday.getTime() - yearStart) / (7 * 864e5));
3969
- });
3873
+ function acos(value) {
3874
+ if (value instanceof Series) {
3875
+ const bars2 = value.bars;
3876
+ const valueArray = value.toArray();
3877
+ const length2 = bars2.length;
3878
+ const result = [];
3879
+ for (let i = 0; i < length2; i++) {
3880
+ const v = valueArray[i] ?? NaN;
3881
+ result.push(Math.acos(v));
3882
+ }
3883
+ return Series.fromArray(bars2, result);
3884
+ }
3885
+ return Math.acos(value);
3970
3886
  }
3971
- function hour(time2, timezone) {
3972
- return field(time2, timezone, (f) => f.hour);
3887
+ function atan(value) {
3888
+ if (value instanceof Series) {
3889
+ const bars2 = value.bars;
3890
+ const valueArray = value.toArray();
3891
+ const length2 = bars2.length;
3892
+ const result = [];
3893
+ for (let i = 0; i < length2; i++) {
3894
+ const v = valueArray[i] ?? NaN;
3895
+ result.push(Math.atan(v));
3896
+ }
3897
+ return Series.fromArray(bars2, result);
3898
+ }
3899
+ return Math.atan(value);
3973
3900
  }
3974
- function minute(time2, timezone) {
3975
- return field(time2, timezone, (f) => f.minute);
3901
+ function toradians(degrees) {
3902
+ if (degrees instanceof Series) {
3903
+ const bars2 = degrees.bars;
3904
+ const valueArray = degrees.toArray();
3905
+ const length2 = bars2.length;
3906
+ const result = [];
3907
+ for (let i = 0; i < length2; i++) {
3908
+ const v = valueArray[i] ?? NaN;
3909
+ result.push(v * (Math.PI / 180));
3910
+ }
3911
+ return Series.fromArray(bars2, result);
3912
+ }
3913
+ return degrees * (Math.PI / 180);
3976
3914
  }
3977
- function second(time2, timezone) {
3978
- return field(time2, timezone, (f) => f.second);
3915
+ function todegrees(radians) {
3916
+ if (radians instanceof Series) {
3917
+ const bars2 = radians.bars;
3918
+ const valueArray = radians.toArray();
3919
+ const length2 = bars2.length;
3920
+ const result = [];
3921
+ for (let i = 0; i < length2; i++) {
3922
+ const v = valueArray[i] ?? NaN;
3923
+ result.push(v * (180 / Math.PI));
3924
+ }
3925
+ return Series.fromArray(bars2, result);
3926
+ }
3927
+ return radians * (180 / Math.PI);
3979
3928
  }
3980
- function inSession2(time2, session2, timezone) {
3981
- return inSession(time2, session2, timezone);
3929
+ function random(min4, max4, _seed) {
3930
+ const rand = Math.random();
3931
+ if (min4 !== void 0 && max4 !== void 0) {
3932
+ return min4 + rand * (max4 - min4);
3933
+ }
3934
+ return rand;
3982
3935
  }
3983
-
3984
- // src/str/index.ts
3985
- var str_exports = {};
3986
- __export(str_exports, {
3987
- charAt: () => charAt,
3988
- concat: () => concat,
3989
- contains: () => contains,
3990
- endswith: () => endswith,
3991
- format: () => format,
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;
3936
+ function sign(value) {
3937
+ if (value instanceof Series) {
3938
+ const bars2 = value.bars;
3939
+ const valueArray = value.toArray();
3940
+ const length2 = bars2.length;
3941
+ const result = [];
3942
+ for (let i = 0; i < length2; i++) {
3943
+ const v = valueArray[i] ?? NaN;
3944
+ result.push(v > 0 ? 1 : v < 0 ? -1 : 0);
3945
+ }
3946
+ return Series.fromArray(bars2, result);
3947
+ }
3948
+ return value > 0 ? 1 : value < 0 ? -1 : 0;
3949
+ }
3950
+ function round_to_mintick(number2, mintick) {
3951
+ if (number2 instanceof Series) {
3952
+ const bars2 = number2.bars;
3953
+ const valueArray = number2.toArray();
3954
+ const length2 = bars2.length;
3955
+ if (mintick === void 0) {
3956
+ throw new Error(
3957
+ "math.round_to_mintick() requires mintick value. Either pass it explicitly or use createContext({ syminfo: { mintick } }) for implicit data."
3958
+ );
3959
+ }
3960
+ const result = [];
3961
+ if (mintick === 0) {
3962
+ for (let i = 0; i < length2; i++) {
3963
+ result.push(valueArray[i] ?? NaN);
4032
3964
  }
4033
- } else if (phase !== "suffix" && ("#0,.".includes(ch) || phase === "number" && ch === "E")) {
4034
- phase = "number";
4035
- number2 += ch;
4036
- continue;
4037
3965
  } else {
4038
- if (ch === "%") percent = true;
4039
- literal = ch;
3966
+ for (let i = 0; i < length2; i++) {
3967
+ const v = valueArray[i];
3968
+ if (v === void 0 || isNaN(v)) {
3969
+ result.push(NaN);
3970
+ } else {
3971
+ result.push(Math.round(v / mintick) * mintick);
3972
+ }
3973
+ }
4040
3974
  }
4041
- if (phase === "number") phase = "suffix";
4042
- if (phase === "prefix") prefix += literal;
4043
- else suffix += literal;
3975
+ return Series.fromArray(bars2, result);
4044
3976
  }
4045
- const [mantissa = "", exp2] = number2.split("E");
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;
4062
- }
4063
- function shortestDigits(x) {
4064
- const m = /^(\d+)(?:\.(\d+))?(?:e([+-]\d+))?$/.exec(String(Math.abs(x)));
4065
- const all7 = m[1] + (m[2] ?? "");
4066
- let intLen = m[1].length + Number(m[3] ?? 0);
4067
- const lead = all7.length - all7.replace(/^0+/, "").length;
4068
- intLen -= lead;
4069
- const digits = all7.slice(lead).replace(/0+$/, "");
4070
- return { digits, intLen: digits ? intLen : 0 };
3977
+ if (isNaN(number2)) {
3978
+ return NaN;
3979
+ }
3980
+ if (mintick === void 0) {
3981
+ throw new Error(
3982
+ "math.round_to_mintick() requires mintick value. Either pass it explicitly or use createContext({ syminfo: { mintick } }) for implicit data."
3983
+ );
3984
+ }
3985
+ if (mintick === 0) {
3986
+ return number2;
3987
+ }
3988
+ return Math.round(number2 / mintick) * mintick;
4071
3989
  }
4072
- function exactDigits(x) {
4073
- const abs2 = Math.abs(x);
4074
- if (abs2 === 0) return { digits: "", intLen: 0 };
4075
- const view = new DataView(new ArrayBuffer(8));
4076
- view.setFloat64(0, abs2);
4077
- const bits = view.getBigUint64(0);
4078
- const expBits = Number(bits >> 52n & 0x7ffn);
4079
- let mant = bits & 0xfffffffffffffn;
4080
- const e2 = expBits === 0 ? -1074 : expBits - 1075;
4081
- if (expBits !== 0) mant |= 1n << 52n;
4082
- let str2;
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;
3990
+ var pi = Math.PI;
3991
+ var e = Math.E;
3992
+ var phi = 1.618033988749895;
3993
+ var rphi = 0.618033988749895;
3994
+
3995
+ // src/timeframe/index.ts
3996
+ var timeframe_exports = {};
3997
+ __export(timeframe_exports, {
3998
+ from_seconds: () => from_seconds,
3999
+ in_seconds: () => in_seconds,
4000
+ info: () => info
4001
+ });
4002
+ var SECONDS_PER_MINUTE = 60;
4003
+ var SECONDS_PER_DAY = 86400;
4004
+ var SECONDS_PER_WEEK = 604800;
4005
+ var SECONDS_PER_MONTH = 2628003;
4006
+ var SECONDS_365_DAYS = 365 * SECONDS_PER_DAY;
4007
+ var UNIT_SECONDS = {
4008
+ S: 1,
4009
+ "": SECONDS_PER_MINUTE,
4010
+ D: SECONDS_PER_DAY,
4011
+ W: SECONDS_PER_WEEK,
4012
+ M: SECONDS_PER_MONTH
4013
+ };
4014
+ var SECOND_TIMEFRAMES = [1, 5, 10, 15, 30];
4015
+ function in_seconds(timeframe2) {
4016
+ const text2 = timeframe2.trim();
4017
+ if (text2 === "") {
4018
+ throw new RangeError("timeframe.in_seconds() needs a timeframe: the chart timeframe is not known here");
4090
4019
  }
4091
- const intLen = str2.length - fracDigits;
4092
- const lead = str2.length - str2.replace(/^0+/, "").length;
4093
- const digits = str2.slice(lead).replace(/0+$/, "");
4094
- return { digits, intLen: intLen - lead };
4020
+ const before = /^(\d*)([SDWMT]?)$/.exec(text2);
4021
+ const after = before ? null : /^([SDWMT])(\d+)$/.exec(text2);
4022
+ if (!before && !after) throw new RangeError(`Invalid timeframe "${timeframe2}"`);
4023
+ const [digits, unit] = before ? [before[1], before[2]] : [after[2], after[1]];
4024
+ if (unit === "T") return NaN;
4025
+ const multiplier = digits === "" ? 1 : Number(digits);
4026
+ return multiplier * UNIT_SECONDS[unit];
4095
4027
  }
4096
- function roundDigits(d, frac, mode3) {
4097
- const keep = d.intLen + frac;
4098
- if (keep >= d.digits.length) return d;
4099
- if (keep < 0) return { digits: "", intLen: 0 };
4100
- const first = d.digits.charCodeAt(keep) - 48;
4101
- let up;
4102
- if (mode3 === "halfUpShortest") up = first >= 5;
4103
- else if (first !== 5) up = first > 5;
4104
- else if (d.digits.length > keep + 1) up = true;
4105
- else up = keep > 0 && (d.digits.charCodeAt(keep - 1) - 48) % 2 === 1;
4106
- let kept = d.digits.slice(0, keep);
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;
4028
+ function from_seconds(seconds) {
4029
+ if (Number.isNaN(seconds)) throw new RangeError("timeframe.from_seconds() needs a number of seconds");
4030
+ if (seconds >= SECONDS_365_DAYS) return "12M";
4031
+ if (seconds > 0) {
4032
+ if (seconds % SECONDS_PER_MONTH === 0) return `${seconds / SECONDS_PER_MONTH}M`;
4033
+ if (seconds % SECONDS_PER_WEEK === 0) return `${seconds / SECONDS_PER_WEEK}W`;
4034
+ if (seconds % SECONDS_PER_DAY === 0) return `${seconds / SECONDS_PER_DAY}D`;
4035
+ if (seconds % SECONDS_PER_MINUTE === 0 && seconds < SECONDS_PER_DAY) return `${seconds / SECONDS_PER_MINUTE}`;
4112
4036
  }
4113
- kept = kept.replace(/0+$/, "");
4114
- return { digits: kept, intLen: kept ? intLen : 0 };
4037
+ const second3 = SECOND_TIMEFRAMES.find((m) => seconds <= m);
4038
+ if (second3 !== void 0) return `${second3}S`;
4039
+ if (seconds < SECONDS_PER_DAY) return `${Math.ceil(seconds / SECONDS_PER_MINUTE)}`;
4040
+ return `${Math.ceil(seconds / SECONDS_PER_DAY)}D`;
4115
4041
  }
4116
- function group(int, size) {
4117
- if (!size || int.length <= size) return int;
4118
- const parts = [];
4119
- for (let end = int.length; end > 0; end -= size) parts.unshift(int.slice(Math.max(0, end - size), end));
4120
- return parts.join(",");
4042
+ function info(timeframe2) {
4043
+ const text2 = timeframe2.trim();
4044
+ const m = /^(\d*)([SDWMT]?)$/.exec(text2);
4045
+ if (!m || text2 === "") throw new RangeError(`Invalid timeframe "${timeframe2}"`);
4046
+ const unit = m[2];
4047
+ const multiplier = m[1] === "" ? 1 : Number(m[1]);
4048
+ return {
4049
+ period: unit === "" ? String(multiplier) : `${multiplier}${unit}`,
4050
+ multiplier,
4051
+ isintraday: unit === "" || unit === "S" || unit === "T",
4052
+ isdaily: unit === "D",
4053
+ isweekly: unit === "W",
4054
+ ismonthly: unit === "M",
4055
+ isminutes: unit === "",
4056
+ isseconds: unit === "S",
4057
+ isticks: unit === "T",
4058
+ isdwm: unit === "D" || unit === "W" || unit === "M"
4059
+ };
4121
4060
  }
4122
- function layout(d, p) {
4123
- let int = d.intLen > 0 ? d.digits.slice(0, d.intLen).padEnd(d.intLen, "0") : "";
4124
- int = int.replace(/^0+/, "").padStart(p.minInt, "0");
4125
- let frac = d.intLen < 0 ? "0".repeat(-d.intLen) + d.digits : d.digits.slice(Math.max(0, d.intLen));
4126
- frac = frac.slice(0, p.maxFrac).replace(/0+$/, "").padEnd(p.minFrac, "0");
4127
- if (!int && !frac) int = "0";
4128
- return group(int, p.grouping) + (frac ? "." + frac : "");
4061
+
4062
+ // src/time/timezone.ts
4063
+ var MS_PER_SECOND = 1e3;
4064
+ var MS_PER_DAY = 864e5;
4065
+ var MAX_OFFSET_SECONDS = 18 * 3600;
4066
+ var OFFSET_NOTATION = /^(?:UTC|GMT)(?:([+-])(\d{1,2})(?::?(\d{2})(?::?(\d{2}))?)?)?$/;
4067
+ var REJECTED_NAMES = /* @__PURE__ */ new Set(["EST", "MST", "HST"]);
4068
+ var canonicalNames;
4069
+ function hasTimeZoneCase(name) {
4070
+ if (name.split("/").some((segment) => !/^[A-Z]/.test(segment))) return false;
4071
+ canonicalNames ??= new Map(Intl.supportedValuesOf("timeZone").map((n) => [n.toLowerCase(), n]));
4072
+ const canonical = canonicalNames.get(name.toLowerCase());
4073
+ return canonical === void 0 || canonical === name;
4129
4074
  }
4130
- function formatNumber(value, pattern, mode3) {
4131
- if (Number.isNaN(value)) return "NaN";
4132
- const p = parsePattern(pattern);
4133
- if (!Number.isFinite(value)) return (value < 0 ? "-" : "") + p.prefix + "\u221E" + p.suffix;
4134
- const x = p.percent ? value * 100 : value;
4135
- const toDigits = mode3 === "halfUpShortest" ? shortestDigits : exactDigits;
4136
- let body;
4137
- let isZero;
4138
- if (p.exponent !== null) {
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 };
4147
- }
4148
- const e2 = String(Math.abs(exponent)).padStart(p.exponent, "0");
4149
- body = layout(mant, p) + "E" + (exponent < 0 ? "-" : "") + e2;
4075
+ var zones = /* @__PURE__ */ new Map();
4076
+ function resolveZone(timezone) {
4077
+ let zone = zones.get(timezone);
4078
+ if (zone) return zone;
4079
+ const invalid = () => new RangeError(
4080
+ `Invalid time zone "${timezone}": use UTC/GMT offset notation ("UTC-5", "GMT+0530") or an IANA name ("America/New_York")`
4081
+ );
4082
+ const m = OFFSET_NOTATION.exec(timezone);
4083
+ if (m) {
4084
+ const [, sign2, h = "0", mi = "0", s] = m;
4085
+ const minutes = Number(mi);
4086
+ const seconds = s === void 0 ? 0 : Number(s);
4087
+ if (minutes > 59 || seconds > 59 || s !== void 0 && h.length !== 2) throw invalid();
4088
+ const offsetSeconds = Number(h) * 3600 + minutes * 60 + seconds;
4089
+ if (offsetSeconds > MAX_OFFSET_SECONDS) throw invalid();
4090
+ zone = { kind: "fixed", offsetMs: (sign2 === "-" ? -offsetSeconds : offsetSeconds) * MS_PER_SECOND };
4150
4091
  } 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 });
4092
+ if (REJECTED_NAMES.has(timezone) || !hasTimeZoneCase(timezone)) throw invalid();
4093
+ let format2;
4094
+ try {
4095
+ format2 = new Intl.DateTimeFormat("en-US", {
4096
+ timeZone: timezone,
4097
+ hourCycle: "h23",
4098
+ year: "numeric",
4099
+ month: "numeric",
4100
+ day: "numeric",
4101
+ hour: "numeric",
4102
+ minute: "numeric",
4103
+ second: "numeric"
4104
+ });
4105
+ } catch {
4106
+ throw invalid();
4107
+ }
4108
+ zone = { kind: "iana", format: format2 };
4154
4109
  }
4155
- const negative = x < 0 && (!isZero || !p.hasDigits);
4156
- return (negative ? "-" : "") + p.prefix + body + p.suffix;
4110
+ zones.set(timezone, zone);
4111
+ return zone;
4157
4112
  }
4158
-
4159
- // src/str/dateformat.ts
4160
- var MONTHS2 = [
4161
- "January",
4162
- "February",
4163
- "March",
4164
- "April",
4165
- "May",
4166
- "June",
4167
- "July",
4168
- "August",
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)}`;
4113
+ function offsetAt(zone, time2) {
4114
+ if (zone.kind === "fixed") return zone.offsetMs;
4115
+ const wholeSecond = Math.floor(time2 / 1e3) * 1e3;
4116
+ const f = {};
4117
+ for (const part of zone.format.formatToParts(wholeSecond)) {
4118
+ if (part.type !== "literal") f[part.type] = Number(part.value);
4182
4119
  }
4183
- const part = new Intl.DateTimeFormat("en-US", { timeZone: timezone, timeZoneName: "short" }).formatToParts(time2).find((p) => p.type === "timeZoneName");
4184
- return part?.value ?? timezone;
4120
+ const local = Date.UTC(f.year, f.month - 1, f.day, f.hour, f.minute, f.second);
4121
+ return local - wholeSecond;
4185
4122
  }
4186
- function weekOfYear(year3, month3, day) {
4187
- const date = Date.UTC(year3, month3 - 1, day);
4188
- const dow = new Date(date).getUTCDay();
4189
- const weekStart2 = date - dow * 864e5;
4190
- if (weekStart2 + 6 * 864e5 >= Date.UTC(year3 + 1, 0, 1)) return 1;
4191
- const jan1 = Date.UTC(year3, 0, 1);
4192
- const jan1Dow = new Date(jan1).getUTCDay();
4193
- return Math.floor((date - jan1 + jan1Dow * 864e5) / (7 * 864e5)) + 1;
4123
+ function zoneOffset(time2, timezone) {
4124
+ return offsetAt(resolveZone(timezone), time2);
4194
4125
  }
4195
- function formatDate(time2, pattern, timezone) {
4196
- if (Number.isNaN(time2)) return "NaN";
4197
- const f = zonedFields(time2, timezone);
4198
- const offset = zoneOffset(time2, timezone);
4199
- const ms = (time2 % 1e3 + 1e3) % 1e3;
4200
- const dayOfYear = (Date.UTC(f.year, f.month - 1, f.day) - Date.UTC(f.year, 0, 1)) / 864e5 + 1;
4201
- let out = "";
4202
- for (let i = 0; i < pattern.length; ) {
4203
- const ch = pattern[i];
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;
4214
- }
4215
- if (!/[A-Za-z]/.test(ch)) {
4216
- out += ch;
4217
- i++;
4218
- continue;
4219
- }
4220
- let n = 1;
4221
- while (pattern[i + n] === ch) n++;
4222
- i += n;
4223
- const hour12 = f.hour % 12;
4224
- switch (ch) {
4225
- case "y":
4226
- out += n === 2 ? pad(f.year % 100, 2) : pad(f.year, n);
4227
- break;
4228
- case "M":
4229
- out += n >= 4 ? MONTHS2[f.month - 1] : n === 3 ? MONTHS2[f.month - 1].slice(0, 3) : pad(f.month, n);
4230
- break;
4231
- case "d":
4232
- out += pad(f.day, n);
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;
4274
- }
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
- }
4281
- }
4282
- return out;
4126
+ function zonedFields(time2, timezone) {
4127
+ const local = new Date(time2 + offsetAt(resolveZone(timezone), time2));
4128
+ return {
4129
+ year: local.getUTCFullYear(),
4130
+ month: local.getUTCMonth() + 1,
4131
+ day: local.getUTCDate(),
4132
+ hour: local.getUTCHours(),
4133
+ minute: local.getUTCMinutes(),
4134
+ second: local.getUTCSeconds(),
4135
+ dayOfWeek: local.getUTCDay() + 1
4136
+ };
4137
+ }
4138
+ function zonedToUnix(timezone, year3, month3, day, hour3 = 0, minute3 = 0, second3 = 0) {
4139
+ const zone = resolveZone(timezone);
4140
+ const local = Date.UTC(year3, month3 - 1, day, hour3, minute3, second3);
4141
+ if (zone.kind === "fixed") return local - zone.offsetMs;
4142
+ const before = offsetAt(zone, local - MS_PER_DAY);
4143
+ const after = offsetAt(zone, local + MS_PER_DAY);
4144
+ const candidates = [local - before, local - after].filter((t2) => local - offsetAt(zone, t2) === t2);
4145
+ if (candidates.length) return Math.max(...candidates);
4146
+ return local - before;
4283
4147
  }
4284
4148
 
4285
- // src/str/messageformat.ts
4286
- var DATE_STYLES = {
4287
- short: "M/d/yy",
4288
- medium: "MMM d, yyyy",
4289
- long: "MMMM d, yyyy",
4290
- full: "EEEE, MMMM d, yyyy"
4291
- };
4292
- var TIME_STYLES = {
4293
- short: "h:mm\u202Fa",
4294
- medium: "h:mm:ss\u202Fa",
4295
- long: "h:mm:ss\u202Fa z",
4296
- full: "h:mm:ss\u202Fa z"
4149
+ // src/time/datestring.ts
4150
+ var MONTHS = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"];
4151
+ var FULL_MONTHS = [
4152
+ "january",
4153
+ "february",
4154
+ "march",
4155
+ "april",
4156
+ "may",
4157
+ "june",
4158
+ "july",
4159
+ "august",
4160
+ "september",
4161
+ "october",
4162
+ "november",
4163
+ "december"
4164
+ ];
4165
+ var ZONE_NAMES = {
4166
+ ut: 0,
4167
+ utc: 0,
4168
+ gmt: 0,
4169
+ est: -5,
4170
+ edt: -4,
4171
+ cst: -6,
4172
+ cdt: -5,
4173
+ mst: -7,
4174
+ mdt: -6,
4175
+ pst: -8,
4176
+ pdt: -7
4297
4177
  };
4298
- function number(value, pattern) {
4299
- return typeof value === "number" ? formatNumber(value, pattern, "halfEvenExact") : String(value);
4300
- }
4301
- function choice(value, spec) {
4302
- const options = spec.split("|").map((part) => {
4303
- const m = /^\s*(-?[\d.]+|-?∞)\s*([#<≤])(.*)$/.exec(part);
4304
- if (!m) throw new SyntaxError(`Invalid choice format "${spec}"`);
4305
- const limit = m[1].includes("\u221E") ? m[1].startsWith("-") ? -Infinity : Infinity : Number(m[1]);
4306
- return { limit: m[2] === "<" ? limit + Number.EPSILON * Math.max(1, Math.abs(limit)) : limit, text: m[3] };
4307
- });
4308
- let chosen = options[0];
4309
- for (const o of options) if (value >= o.limit) chosen = o;
4310
- return chosen.text;
4178
+ var TIME = String.raw`(\d{1,2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3})\d*)?)?`;
4179
+ var ZONE = String.raw`(ut|utc|gmt|[ecmp][sd]t|(?:utc|gmt)?\s*[+-]\d{1,2}(?::?\d{2})?)`;
4180
+ var NUMERIC_ZONE = String.raw`([+-]\d{2}(?::?\d{2})?)`;
4181
+ var DATE = String.raw`(\d{4})([-/])(\d{1,2})\2(\d{1,2})`;
4182
+ var WEEKDAY = String.raw`(?:[a-z]{3,9},?\s+)?`;
4183
+ var ISO_T = new RegExp(String.raw`^${DATE}t${TIME}\s*${NUMERIC_ZONE}?$`, "i");
4184
+ var ISO = new RegExp(String.raw`^${DATE}(?:\s+${TIME})?\s*${ZONE}?$`, "i");
4185
+ var DAY_FIRST = new RegExp(String.raw`^${WEEKDAY}(\d{1,2})(?:\s+|-)([a-z]+)\.?,?(?:\s+|-)(\d{4})(?:,?\s+${TIME})?\s*${ZONE}?$`, "i");
4186
+ var MONTH_FIRST = new RegExp(String.raw`^${WEEKDAY}([a-z]+)\.?\s+(\d{1,2}),?\s+(\d{4})(?:,?\s+${TIME})?\s*${ZONE}?$`, "i");
4187
+ function monthNumber(name) {
4188
+ const lower2 = name.toLowerCase();
4189
+ const i = FULL_MONTHS.findIndex((full, k) => lower2.startsWith(MONTHS[k]) && full.startsWith(lower2));
4190
+ return i + 1;
4311
4191
  }
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}"`);
4334
- }
4192
+ function zoneMinutes(zone) {
4193
+ if (!zone) return 0;
4194
+ const lower2 = zone.toLowerCase().replace(/\s+/g, "");
4195
+ const named = ZONE_NAMES[lower2];
4196
+ if (named !== void 0) return named * 60;
4197
+ const m = /^(?:utc|gmt)?([+-])(\d{1,2})(?::?(\d{2}))?$/.exec(lower2);
4198
+ if (!m) return NaN;
4199
+ const minutes = Number(m[2]) * 60 + (m[3] ? Number(m[3]) : 0);
4200
+ return m[1] === "-" ? -minutes : minutes;
4335
4201
  }
4336
- function formatMessage(pattern, args, timezone) {
4337
- let out = "";
4338
- for (let i = 0; i < pattern.length; ) {
4339
- const ch = pattern[i];
4340
- if (ch === "'") {
4341
- if (pattern[i + 1] === "'") {
4342
- out += "'";
4343
- i += 2;
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;
4202
+ function parseDateString(dateString) {
4203
+ const text2 = dateString.trim();
4204
+ let year3, month3, day;
4205
+ let rest;
4206
+ let m;
4207
+ if (m = ISO_T.exec(text2) ?? ISO.exec(text2)) {
4208
+ [year3, month3, day] = [m[1], Number(m[3]), m[4]];
4209
+ rest = m.slice(5);
4210
+ } else if (m = DAY_FIRST.exec(text2)) {
4211
+ [day, month3, year3] = [m[1], monthNumber(m[2]), m[3]];
4212
+ rest = m.slice(4);
4213
+ } else if (m = MONTH_FIRST.exec(text2)) {
4214
+ [month3, day, year3] = [monthNumber(m[1]), m[2], m[3]];
4215
+ rest = m.slice(4);
4216
+ } else {
4217
+ throw new SyntaxError(`Invalid date string "${dateString}": use RFC 2822 or ISO 8601 ("20 Feb 2020", "2020-02-20T14:48:00")`);
4371
4218
  }
4372
- return out;
4219
+ const [hour3 = "0", minute3 = "0", second3 = "0", millis = "0", zone] = rest;
4220
+ const d = Number(day);
4221
+ const h = Number(hour3);
4222
+ const mi = Number(minute3);
4223
+ const s = Number(second3);
4224
+ const offset = zoneMinutes(zone);
4225
+ const endOfDay = h === 24 && mi === 0 && s === 0 && Number(millis) === 0;
4226
+ if (month3 < 1 || month3 > 12 || d < 1 || d > 31 || h > 23 && !endOfDay || mi > 59 || s > 59 || Number.isNaN(offset)) {
4227
+ throw new SyntaxError(`Invalid date string "${dateString}": a field is out of range`);
4228
+ }
4229
+ const ms = Number(millis.padEnd(3, "0"));
4230
+ return Date.UTC(Number(year3), month3 - 1, d, h, mi, s, ms) - offset * 6e4;
4373
4231
  }
4374
4232
 
4375
- // src/str/index.ts
4376
- function length(str2) {
4377
- return str2.length;
4233
+ // src/time/session.ts
4234
+ var PERIOD = /^(\d{2})(\d{2})-(\d{2})(\d{2})$/;
4235
+ var sessions = /* @__PURE__ */ new Map();
4236
+ function parseSession(session2) {
4237
+ let parsed = sessions.get(session2);
4238
+ if (parsed) return parsed;
4239
+ const invalid = () => new SyntaxError(`Invalid session "${session2}": expected "HHmm-HHmm[,HHmm-HHmm...][:days]"`);
4240
+ const text2 = session2.trim() === "24x7" ? "0000-0000" : session2.replace(/\s+/g, "");
4241
+ const [periodText = "", dayText, extra] = text2.split(":");
4242
+ if (extra !== void 0 || periodText === "") throw invalid();
4243
+ const periods = periodText.split(",").map((p) => {
4244
+ const m = PERIOD.exec(p);
4245
+ if (!m) throw invalid();
4246
+ const [h1, m1, h2, m2] = [m[1], m[2], m[3], m[4]].map(Number);
4247
+ if (h1 > 23 || h2 > 23 || m1 > 59 || m2 > 59) throw invalid();
4248
+ return { start: h1 * 60 + m1, end: h2 * 60 + m2 };
4249
+ });
4250
+ const dayDigits = dayText ?? (periods.length > 1 ? "23456" : "1234567");
4251
+ if (!/^[1-7]+$/.test(dayDigits)) throw invalid();
4252
+ const days = new Array(8).fill(false);
4253
+ for (const d of dayDigits) days[Number(d)] = true;
4254
+ parsed = { periods, days };
4255
+ sessions.set(session2, parsed);
4256
+ return parsed;
4378
4257
  }
4379
- function tostring(value, format2) {
4380
- if (typeof value !== "number") return String(value);
4381
- if (!Number.isFinite(value)) return String(value);
4382
- if (format2 === void 0 || format2 === "") {
4383
- if (Math.abs(value) >= 1e21 && Number.isFinite(value)) {
4384
- return String(value).replace("e+", "E").replace(/\.0+E/, "E");
4385
- }
4386
- return formatNumber(value, "#.##########", "halfUpShortest");
4387
- }
4388
- switch (format2) {
4389
- case "percent":
4390
- return formatNumber(value, "0.00", "halfUpShortest") + "%";
4391
- case "volume": {
4392
- const abs2 = Math.abs(value);
4393
- for (const [size, unit] of [[1e12, "T"], [1e9, "B"], [1e6, "M"], [1e3, "K"]]) {
4394
- if (abs2 >= size) return formatNumber(value / size, "#.###", "halfUpShortest") + unit;
4395
- }
4396
- return formatNumber(value, "#", "halfUpShortest");
4258
+ function inSession(time2, session2, timezone) {
4259
+ if (Number.isNaN(time2)) return false;
4260
+ const { periods, days } = parseSession(session2);
4261
+ const f = zonedFields(time2, timezone);
4262
+ const minute3 = f.hour * 60 + f.minute;
4263
+ const nextDay = f.dayOfWeek % 7 + 1;
4264
+ for (const { start, end } of periods) {
4265
+ if (start < end || start === 0 && end === 0) {
4266
+ if (minute3 >= start && (minute3 < end || end === 0) && days[f.dayOfWeek]) return true;
4267
+ } else {
4268
+ if (minute3 >= start && days[nextDay]) return true;
4269
+ if (minute3 < end && days[f.dayOfWeek]) return true;
4397
4270
  }
4398
- case "mintick":
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");
4402
4271
  }
4272
+ return false;
4403
4273
  }
4404
- function tonumber(str2) {
4405
- const num = parseFloat(str2);
4406
- return isNaN(num) ? null : num;
4407
- }
4408
- function substring(str2, begin, end) {
4409
- return str2.substring(begin, end);
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);
4274
+
4275
+ // src/time/index.ts
4276
+ function timestamp(first, ...rest) {
4277
+ if (typeof first === "string") {
4278
+ if (rest.length === 0) return parseDateString(first);
4279
+ const [year3, month4, day2, hour4, minute4, second4] = rest;
4280
+ return zonedToUnix(first, year3, month4, day2, hour4 ?? 0, minute4 ?? 0, second4 ?? 0);
4428
4281
  }
4282
+ const [month3, day, hour3, minute3, second3] = rest;
4283
+ return new Date(first, month3 - 1, day, hour3 || 0, minute3 || 0, second3 || 0).getTime();
4429
4284
  }
4430
- function replace_all(source, target, replacement) {
4431
- return source.replaceAll(target, replacement);
4285
+ function field(time2, timezone, pick) {
4286
+ return Number.isNaN(time2) ? NaN : pick(zonedFields(time2, timezone));
4432
4287
  }
4433
- function split(str2, separator) {
4434
- return str2.split(separator);
4288
+ function year(time2, timezone) {
4289
+ return field(time2, timezone, (f) => f.year);
4435
4290
  }
4436
- function concat(...strings) {
4437
- return strings.join("");
4291
+ function month(time2, timezone) {
4292
+ return field(time2, timezone, (f) => f.month);
4438
4293
  }
4439
- function format(formatStr, ...args) {
4440
- return formatMessage(formatStr, args, "Etc/UTC");
4294
+ function dayofmonth(time2, timezone) {
4295
+ return field(time2, timezone, (f) => f.day);
4441
4296
  }
4442
- function startswith(source, str2) {
4443
- return source.startsWith(str2);
4297
+ function dayofweek(time2, timezone) {
4298
+ return field(time2, timezone, (f) => f.dayOfWeek);
4444
4299
  }
4445
- function endswith(source, str2) {
4446
- return source.endsWith(str2);
4300
+ function weekofyear(time2, timezone) {
4301
+ return field(time2, timezone, (f) => {
4302
+ const date = Date.UTC(f.year, f.month - 1, f.day);
4303
+ const mondayBased = (f.dayOfWeek + 5) % 7;
4304
+ const thursday = new Date(date + (3 - mondayBased) * 864e5);
4305
+ const yearStart = Date.UTC(thursday.getUTCFullYear(), 0, 1);
4306
+ return 1 + Math.floor((thursday.getTime() - yearStart) / (7 * 864e5));
4307
+ });
4447
4308
  }
4448
- function charAt(str2, pos2) {
4449
- return str2.charAt(pos2);
4309
+ function hour(time2, timezone) {
4310
+ return field(time2, timezone, (f) => f.hour);
4450
4311
  }
4451
- function trim(str2) {
4452
- return str2.trim();
4312
+ function minute(time2, timezone) {
4313
+ return field(time2, timezone, (f) => f.minute);
4453
4314
  }
4454
- function trimLeft(str2) {
4455
- return str2.trimStart();
4315
+ function second(time2, timezone) {
4316
+ return field(time2, timezone, (f) => f.second);
4456
4317
  }
4457
- function trimRight(str2) {
4458
- return str2.trimEnd();
4318
+ function inSession2(time2, session2, timezone) {
4319
+ return inSession(time2, session2, timezone);
4459
4320
  }
4460
- function match(source, regex) {
4461
- return new RegExp(regex).test(source);
4321
+
4322
+ // src/str/index.ts
4323
+ var str_exports = {};
4324
+ __export(str_exports, {
4325
+ charAt: () => charAt,
4326
+ concat: () => concat,
4327
+ contains: () => contains,
4328
+ endswith: () => endswith,
4329
+ format: () => format,
4330
+ format_time: () => format_time,
4331
+ length: () => length,
4332
+ lower: () => lower,
4333
+ match: () => match,
4334
+ pos: () => pos,
4335
+ repeat: () => repeat,
4336
+ replace: () => replace,
4337
+ replace_all: () => replace_all,
4338
+ split: () => split,
4339
+ startswith: () => startswith,
4340
+ substring: () => substring,
4341
+ tonumber: () => tonumber,
4342
+ tostring: () => tostring,
4343
+ trim: () => trim,
4344
+ trimLeft: () => trimLeft,
4345
+ trimRight: () => trimRight,
4346
+ upper: () => upper
4347
+ });
4348
+
4349
+ // src/str/numberformat.ts
4350
+ var patterns = /* @__PURE__ */ new Map();
4351
+ function parsePattern(pattern) {
4352
+ const cached = patterns.get(pattern);
4353
+ if (cached) return cached;
4354
+ let prefix = "";
4355
+ let suffix = "";
4356
+ let number2 = "";
4357
+ let percent = false;
4358
+ let phase = "prefix";
4359
+ for (let i = 0; i < pattern.length; i++) {
4360
+ const ch = pattern[i];
4361
+ let literal;
4362
+ if (ch === "'") {
4363
+ const end = pattern.indexOf("'", i + 1);
4364
+ if (end === i + 1) {
4365
+ literal = "'";
4366
+ i = end;
4367
+ } else {
4368
+ literal = pattern.slice(i + 1, end === -1 ? void 0 : end);
4369
+ i = end === -1 ? pattern.length : end;
4370
+ }
4371
+ } else if (phase !== "suffix" && ("#0,.".includes(ch) || phase === "number" && ch === "E")) {
4372
+ phase = "number";
4373
+ number2 += ch;
4374
+ continue;
4375
+ } else {
4376
+ if (ch === "%") percent = true;
4377
+ literal = ch;
4378
+ }
4379
+ if (phase === "number") phase = "suffix";
4380
+ if (phase === "prefix") prefix += literal;
4381
+ else suffix += literal;
4382
+ }
4383
+ const [mantissa = "", exp2] = number2.split("E");
4384
+ const [intPart = "", fracPart = ""] = mantissa.split(".");
4385
+ const lastComma = intPart.lastIndexOf(",");
4386
+ const parsed = {
4387
+ prefix,
4388
+ suffix,
4389
+ // as in Java, a pattern with a decimal point and no '0' at all ("#.##") shows one integer digit
4390
+ minInt: !mantissa.includes("0") && mantissa.includes(".") ? 1 : [...intPart].filter((c) => c === "0").length,
4391
+ minFrac: [...fracPart].filter((c) => c === "0").length,
4392
+ maxFrac: [...fracPart].filter((c) => c === "0" || c === "#").length,
4393
+ grouping: lastComma === -1 ? 0 : intPart.length - lastComma - 1,
4394
+ percent,
4395
+ exponent: exp2 === void 0 ? null : exp2.length,
4396
+ hasDigits: /[0#]/.test(mantissa)
4397
+ };
4398
+ patterns.set(pattern, parsed);
4399
+ return parsed;
4462
4400
  }
4463
- function repeat(source, count, separator = "") {
4464
- if (source == null) return null;
4465
- if (count <= 0) return "";
4466
- return Array(count).fill(source).join(separator);
4401
+ function shortestDigits(x) {
4402
+ const m = /^(\d+)(?:\.(\d+))?(?:e([+-]\d+))?$/.exec(String(Math.abs(x)));
4403
+ const all7 = m[1] + (m[2] ?? "");
4404
+ let intLen = m[1].length + Number(m[3] ?? 0);
4405
+ const lead = all7.length - all7.replace(/^0+/, "").length;
4406
+ intLen -= lead;
4407
+ const digits = all7.slice(lead).replace(/0+$/, "");
4408
+ return { digits, intLen: digits ? intLen : 0 };
4467
4409
  }
4468
- function format_time(time2, format2 = "yyyy-MM-dd'T'HH:mm:ssZ", timezone = "Etc/UTC") {
4469
- return formatDate(time2, format2, timezone);
4410
+ function exactDigits(x) {
4411
+ const abs2 = Math.abs(x);
4412
+ if (abs2 === 0) return { digits: "", intLen: 0 };
4413
+ const view = new DataView(new ArrayBuffer(8));
4414
+ view.setFloat64(0, abs2);
4415
+ const bits = view.getBigUint64(0);
4416
+ const expBits = Number(bits >> 52n & 0x7ffn);
4417
+ let mant = bits & 0xfffffffffffffn;
4418
+ const e2 = expBits === 0 ? -1074 : expBits - 1075;
4419
+ if (expBits !== 0) mant |= 1n << 52n;
4420
+ let str2;
4421
+ let fracDigits;
4422
+ if (e2 >= 0) {
4423
+ str2 = (mant << BigInt(e2)).toString();
4424
+ fracDigits = 0;
4425
+ } else {
4426
+ str2 = (mant * 5n ** BigInt(-e2)).toString();
4427
+ fracDigits = -e2;
4428
+ }
4429
+ const intLen = str2.length - fracDigits;
4430
+ const lead = str2.length - str2.replace(/^0+/, "").length;
4431
+ const digits = str2.slice(lead).replace(/0+$/, "");
4432
+ return { digits, intLen: intLen - lead };
4470
4433
  }
4471
-
4472
- // src/session/calendar.ts
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]) };
4434
+ function roundDigits(d, frac, mode3) {
4435
+ const keep = d.intLen + frac;
4436
+ if (keep >= d.digits.length) return d;
4437
+ if (keep < 0) return { digits: "", intLen: 0 };
4438
+ const first = d.digits.charCodeAt(keep) - 48;
4439
+ let up;
4440
+ if (mode3 === "halfUpShortest") up = first >= 5;
4441
+ else if (first !== 5) up = first > 5;
4442
+ else if (d.digits.length > keep + 1) up = true;
4443
+ else up = keep > 0 && (d.digits.charCodeAt(keep - 1) - 48) % 2 === 1;
4444
+ let kept = d.digits.slice(0, keep);
4445
+ let intLen = d.intLen;
4446
+ if (up) {
4447
+ const n = (BigInt(kept || "0") + 1n).toString();
4448
+ if (n.length > kept.length) intLen += 1;
4449
+ kept = n;
4450
+ }
4451
+ kept = kept.replace(/0+$/, "");
4452
+ return { digits: kept, intLen: kept ? intLen : 0 };
4486
4453
  }
4487
- function parsePeriods(text2, spec) {
4488
- if (text2.trim() === "24x7") return [{ start: 0, end: 1440, startOffset: 0, endOffset: 0 }];
4489
- return text2.split(",").map((p) => {
4490
- const [a = "", b2 = ""] = p.split("-");
4491
- const s = parseTime(a, spec);
4492
- const e2 = parseTime(b2, spec);
4493
- if (s.minutes === 0 && e2.minutes === 0 && s.offset === void 0 && e2.offset === void 0) {
4494
- return { start: 0, end: 1440, startOffset: 0, endOffset: 0 };
4495
- }
4496
- return {
4497
- start: s.minutes,
4498
- end: e2.minutes,
4499
- startOffset: s.offset ?? (e2.minutes <= s.minutes ? 1 : 0),
4500
- endOffset: e2.offset ?? 0
4501
- };
4502
- });
4454
+ function group(int, size) {
4455
+ if (!size || int.length <= size) return int;
4456
+ const parts = [];
4457
+ for (let end = int.length; end > 0; end -= size) parts.unshift(int.slice(Math.max(0, end - size), end));
4458
+ return parts.join(",");
4503
4459
  }
4504
- function parseVersion(text2, from, spec, rule) {
4505
- const [periodText = "", dayText] = text2.trim().split(":");
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 };
4460
+ function layout(d, p) {
4461
+ let int = d.intLen > 0 ? d.digits.slice(0, d.intLen).padEnd(d.intLen, "0") : "";
4462
+ int = int.replace(/^0+/, "").padStart(p.minInt, "0");
4463
+ let frac = d.intLen < 0 ? "0".repeat(-d.intLen) + d.digits : d.digits.slice(Math.max(0, d.intLen));
4464
+ frac = frac.slice(0, p.maxFrac).replace(/0+$/, "").padEnd(p.minFrac, "0");
4465
+ if (!int && !frac) int = "0";
4466
+ return group(int, p.grouping) + (frac ? "." + frac : "");
4513
4467
  }
4514
- var TradingCalendar = class {
4515
- /**
4516
- * @param timezone - Time zone of the session hours (the exchange time zone)
4517
- * @param spec - Session information (hours, corrections, holidays)
4518
- * @param rule - Days without ":days": 'symbol' (Monday to Friday) or 'pine' (PineScript session strings)
4519
- */
4520
- constructor(timezone, spec, rule = "symbol") {
4521
- this.timezone = timezone;
4522
- const [first = "", ...changes] = spec.session.split("#");
4523
- this.versions = [parseVersion(first, 0, spec.session, rule)];
4524
- for (const change3 of changes) {
4525
- const m = /^(\d{8})\/(.+)$/.exec(change3.trim());
4526
- if (!m) throw new SyntaxError(`Invalid session change in "${spec.session}"`);
4527
- this.versions.push(parseVersion(m[2], Number(m[1]), spec.session, rule));
4528
- }
4529
- for (const part of (spec.corrections ?? "").split(";").filter((p) => p.trim())) {
4530
- const i = part.lastIndexOf(":");
4531
- const text2 = part.slice(0, i).trim();
4532
- const periods = text2 === "dayoff" ? null : parsePeriods(text2, part);
4533
- for (const date of part.slice(i + 1).split(",")) this.corrections.set(Number(date), periods);
4468
+ function formatNumber(value, pattern, mode3) {
4469
+ if (Number.isNaN(value)) return "NaN";
4470
+ const p = parsePattern(pattern);
4471
+ if (!Number.isFinite(value)) return (value < 0 ? "-" : "") + p.prefix + "\u221E" + p.suffix;
4472
+ const x = p.percent ? value * 100 : value;
4473
+ const toDigits = mode3 === "halfUpShortest" ? shortestDigits : exactDigits;
4474
+ let body;
4475
+ let isZero;
4476
+ if (p.exponent !== null) {
4477
+ const rounded = roundDigits(toDigits(x), p.maxFrac, mode3);
4478
+ const intDigits = Math.max(p.minInt, 1);
4479
+ isZero = rounded.digits === "";
4480
+ let exponent = isZero ? 0 : rounded.intLen - intDigits;
4481
+ let mant = roundDigits({ digits: rounded.digits, intLen: isZero ? 0 : intDigits }, p.maxFrac, mode3);
4482
+ if (mant.intLen > intDigits) {
4483
+ exponent += 1;
4484
+ mant = { digits: mant.digits, intLen: intDigits };
4534
4485
  }
4535
- const holidays = Array.isArray(spec.holidays) ? spec.holidays : (spec.holidays ?? "").split(",");
4536
- this.holidays = new Set(holidays.filter((h) => h.trim()).map(Number));
4486
+ const e2 = String(Math.abs(exponent)).padStart(p.exponent, "0");
4487
+ body = layout(mant, p) + "E" + (exponent < 0 ? "-" : "") + e2;
4488
+ } else {
4489
+ const rounded = roundDigits(toDigits(x), p.hasDigits ? p.maxFrac : 0, mode3);
4490
+ isZero = rounded.digits === "";
4491
+ body = p.hasDigits ? layout(rounded, p) : layout(rounded, { ...p, minInt: 0, maxFrac: 0, minFrac: 0 });
4537
4492
  }
4538
- timezone;
4539
- versions;
4540
- corrections = /* @__PURE__ */ new Map();
4541
- holidays;
4542
- cache = /* @__PURE__ */ new Map();
4543
- /** Session periods [start, end) of the trading day `date`; empty when the day has no session. */
4544
- periods(date) {
4545
- let out = this.cache.get(date);
4546
- if (out) return out;
4547
- let periods = [];
4548
- const correction = this.corrections.get(date);
4549
- if (correction !== void 0) {
4550
- periods = correction ?? [];
4551
- } else if (!this.holidays.has(date)) {
4552
- const version = [...this.versions].reverse().find((v) => v.from <= date);
4553
- if (version.days[weekdayOf(date)]) periods = version.periods;
4554
- }
4555
- const y = Math.floor(date / 1e4);
4556
- const m = Math.floor(date / 100) % 100;
4557
- const d = date % 100;
4558
- out = periods.map((p) => [
4559
- zonedToUnix(this.timezone, y, m, d - p.startOffset, Math.floor(p.start / 60), p.start % 60),
4560
- zonedToUnix(this.timezone, y, m, d - p.endOffset, Math.floor(p.end / 60), p.end % 60)
4561
- ]);
4562
- this.cache.set(date, out);
4563
- return out;
4564
- }
4565
- isTradingDay(date) {
4566
- return this.periods(date).length > 0;
4567
- }
4568
- /**
4569
- * Trading day and period of a time: the period that contains it, else the last period that started
4570
- * before it. Null when no trading day is found near the time.
4571
- */
4572
- locate(time2) {
4573
- const f = zonedFields(time2, this.timezone);
4574
- const local = toDateNum(f.year, f.month, f.day);
4575
- for (let k = 0; k <= 5; k++) {
4576
- const date = addDays(local, k);
4577
- const index = this.periods(date).findIndex(([s, e2]) => s <= time2 && time2 < e2);
4578
- if (index !== -1) return { date, index, inside: true };
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 };
4588
- }
4589
- return null;
4590
- }
4591
- /** First trading day in [from, to] (dates), or null. */
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;
4600
- }
4601
- };
4602
- var weekStart = (date) => addDays(date, -((weekdayOf(date) + 5) % 7));
4603
- var monthStart = (date) => Math.floor(date / 100) * 100 + 1;
4604
- var monthEnd = (date) => addDays(monthStart(addDays(monthStart(date), 32)), -1);
4605
-
4606
- // src/session/bars.ts
4607
- function unitOf(tf) {
4608
- return { unit: tf.isdaily ? "D" : tf.isweekly ? "W" : "M", n: tf.multiplier };
4493
+ const negative = x < 0 && (!isZero || !p.hasDigits);
4494
+ return (negative ? "-" : "") + p.prefix + body + p.suffix;
4609
4495
  }
4610
- var yearOf = (date) => Math.floor(date / 1e4);
4611
- var firstMonday = (year3) => {
4612
- const jan1 = year3 * 1e4 + 101;
4613
- const monday = weekStart(jan1);
4614
- return monday === jan1 ? jan1 : addDays(monday, 7);
4615
- };
4616
- var SessionBars = class {
4617
- constructor(calendar2, chartTimeframe2) {
4618
- this.calendar = calendar2;
4619
- this.chart = info(chartTimeframe2);
4496
+
4497
+ // src/str/dateformat.ts
4498
+ var MONTHS2 = [
4499
+ "January",
4500
+ "February",
4501
+ "March",
4502
+ "April",
4503
+ "May",
4504
+ "June",
4505
+ "July",
4506
+ "August",
4507
+ "September",
4508
+ "October",
4509
+ "November",
4510
+ "December"
4511
+ ];
4512
+ var DAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
4513
+ var pad = (n, width) => String(n).padStart(width, "0");
4514
+ function zoneName(time2, timezone, offsetMs) {
4515
+ if (timezone === "Etc/UTC") return "UTC";
4516
+ if (/^(UTC|GMT)/.test(timezone)) {
4517
+ if (offsetMs === 0) return "GMT";
4518
+ const minutes = Math.abs(offsetMs) / 6e4;
4519
+ return `GMT${offsetMs < 0 ? "-" : "+"}${pad(Math.floor(minutes / 60), 2)}:${pad(minutes % 60, 2)}`;
4620
4520
  }
4621
- calendar;
4622
- chart;
4623
- yearDays = /* @__PURE__ */ new Map();
4624
- /** Trading days of a calendar year, in order. */
4625
- tradingDaysOf(year3) {
4626
- let days = this.yearDays.get(year3);
4627
- if (!days) {
4628
- days = [];
4629
- for (let date = year3 * 1e4 + 101; yearOf(date) === year3; date = addDays(date, 1)) {
4630
- if (this.calendar.isTradingDay(date)) days.push(date);
4521
+ const part = new Intl.DateTimeFormat("en-US", { timeZone: timezone, timeZoneName: "short" }).formatToParts(time2).find((p) => p.type === "timeZoneName");
4522
+ return part?.value ?? timezone;
4523
+ }
4524
+ function weekOfYear(year3, month3, day) {
4525
+ const date = Date.UTC(year3, month3 - 1, day);
4526
+ const dow = new Date(date).getUTCDay();
4527
+ const weekStart2 = date - dow * 864e5;
4528
+ if (weekStart2 + 6 * 864e5 >= Date.UTC(year3 + 1, 0, 1)) return 1;
4529
+ const jan1 = Date.UTC(year3, 0, 1);
4530
+ const jan1Dow = new Date(jan1).getUTCDay();
4531
+ return Math.floor((date - jan1 + jan1Dow * 864e5) / (7 * 864e5)) + 1;
4532
+ }
4533
+ function formatDate(time2, pattern, timezone) {
4534
+ if (Number.isNaN(time2)) return "NaN";
4535
+ const f = zonedFields(time2, timezone);
4536
+ const offset = zoneOffset(time2, timezone);
4537
+ const ms = (time2 % 1e3 + 1e3) % 1e3;
4538
+ const dayOfYear = (Date.UTC(f.year, f.month - 1, f.day) - Date.UTC(f.year, 0, 1)) / 864e5 + 1;
4539
+ let out = "";
4540
+ for (let i = 0; i < pattern.length; ) {
4541
+ const ch = pattern[i];
4542
+ if (ch === "'") {
4543
+ const end = pattern.indexOf("'", i + 1);
4544
+ if (end === i + 1) {
4545
+ out += "'";
4546
+ i += 2;
4547
+ } else {
4548
+ out += pattern.slice(i + 1, end === -1 ? void 0 : end);
4549
+ i = end === -1 ? pattern.length : end + 1;
4631
4550
  }
4632
- this.yearDays.set(year3, days);
4633
- }
4634
- return days;
4635
- }
4636
- /**
4637
- * Dates [from, to] of the `n`-`unit` period that contains `date` (for "D": its first and last trading days).
4638
- * Periods restart each calendar year.
4639
- */
4640
- periodRange(date, unit, n) {
4641
- if (unit === "D") {
4642
- if (n === 1) return [date, date];
4643
- const days = this.tradingDaysOf(yearOf(date));
4644
- let k = days.findIndex((d) => d >= date);
4645
- if (k === -1) return this.periodRange(yearOf(date) * 1e4 + 1e4 + 101, unit, n);
4646
- k -= k % n;
4647
- return [days[k], days[Math.min(k + n, days.length) - 1]];
4648
- }
4649
- if (unit === "W") {
4650
- const monday = weekStart(date);
4651
- const year4 = yearOf(monday);
4652
- const first = firstMonday(year4);
4653
- const next = firstMonday(year4 + 1);
4654
- const k = Math.round((dateUtcMs(monday) - dateUtcMs(first)) / (7 * 864e5));
4655
- const from = addDays(first, (k - k % n) * 7);
4656
- const to = addDays(from, n * 7 - 1);
4657
- return [from, to < next ? to : addDays(next, -1)];
4658
- }
4659
- const year3 = yearOf(date);
4660
- const month3 = Math.floor(date / 100) % 100;
4661
- const firstMonth = month3 - (month3 - 1) % n;
4662
- const lastMonth = Math.min(firstMonth + n - 1, 12);
4663
- return [monthStart(year3 * 1e4 + firstMonth * 100 + 1), monthEnd(year3 * 1e4 + lastMonth * 100 + 1)];
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];
4671
- }
4672
- /** PineScript `time(tf)` for a bar that opens at `time`; NaN when no trading day is found. */
4673
- timeOf(time2, timeframe2) {
4674
- const tf = info(timeframe2);
4675
- const at = this.calendar.locate(time2);
4676
- if (!at) return NaN;
4677
- if (tf.isintraday) {
4678
- if (this.chart.isdwm) return time2;
4679
- const [start] = this.calendar.periods(at.date)[at.index];
4680
- const ms = in_seconds(tf.period) * 1e3;
4681
- return start + Math.floor((time2 - start) / ms) * ms;
4682
- }
4683
- const { unit, n } = unitOf(tf);
4684
- const [from, to] = this.periodRange(at.date, unit, n);
4685
- const first = this.calendar.firstTradingDay(from, to);
4686
- return first === null ? NaN : this.dayStart(first);
4687
- }
4688
- /** PineScript `time_close(tf)` for a bar that opens at `time`. */
4689
- closeOf(time2, timeframe2) {
4690
- const tf = info(timeframe2);
4691
- const at = this.calendar.locate(time2);
4692
- if (!at) return NaN;
4693
- if (tf.isintraday) {
4694
- const [, end] = this.calendar.periods(at.date)[at.index];
4695
- if (this.chart.isdwm) return end;
4696
- return Math.min(this.timeOf(time2, timeframe2) + in_seconds(tf.period) * 1e3, end);
4697
- }
4698
- const { unit, n } = unitOf(tf);
4699
- const [from, to] = this.periodRange(at.date, unit, n);
4700
- if (this.chart.isintraday && (unit !== "D" || n > 1)) {
4701
- const [nextFrom, nextTo] = this.periodRange(addDays(to, 1), unit, n);
4702
- const first = this.calendar.firstTradingDay(nextFrom, addDays(nextTo, 31));
4703
- return first === null ? NaN : this.dayStart(first);
4551
+ continue;
4704
4552
  }
4705
- const last = this.calendar.lastTradingDay(from, to);
4706
- return last === null ? NaN : this.dayEnd(last);
4707
- }
4708
- /** Trading day of a bar: on D / W / M charts the last trading day of the chart period. */
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);
4553
+ if (!/[A-Za-z]/.test(ch)) {
4554
+ out += ch;
4555
+ i++;
4556
+ continue;
4716
4557
  }
4717
- return at.date;
4718
- }
4719
- /**
4720
- * End of the `timeframe` period that contains `time`: the intraday close, the session end of the day,
4721
- * or the session end of the last trading day of the period. Used to know whether the last loaded
4722
- * bar completes a higher-timeframe period (request.security).
4723
- */
4724
- periodEnd(time2, timeframe2) {
4725
- const tf = info(timeframe2);
4726
- const at = this.calendar.locate(time2);
4727
- if (!at) return NaN;
4728
- if (tf.isintraday) {
4729
- const [, end] = this.calendar.periods(at.date)[at.index];
4730
- return Math.min(this.timeOf(time2, timeframe2) + in_seconds(tf.period) * 1e3, end);
4558
+ let n = 1;
4559
+ while (pattern[i + n] === ch) n++;
4560
+ i += n;
4561
+ const hour12 = f.hour % 12;
4562
+ switch (ch) {
4563
+ case "y":
4564
+ out += n === 2 ? pad(f.year % 100, 2) : pad(f.year, n);
4565
+ break;
4566
+ case "M":
4567
+ out += n >= 4 ? MONTHS2[f.month - 1] : n === 3 ? MONTHS2[f.month - 1].slice(0, 3) : pad(f.month, n);
4568
+ break;
4569
+ case "d":
4570
+ out += pad(f.day, n);
4571
+ break;
4572
+ case "E":
4573
+ out += n >= 4 ? DAYS[f.dayOfWeek - 1] : DAYS[f.dayOfWeek - 1].slice(0, 3);
4574
+ break;
4575
+ case "u":
4576
+ out += pad(f.dayOfWeek === 1 ? 7 : f.dayOfWeek - 1, n);
4577
+ break;
4578
+ case "D":
4579
+ out += pad(dayOfYear, n);
4580
+ break;
4581
+ case "w":
4582
+ out += pad(weekOfYear(f.year, f.month, f.day), n);
4583
+ break;
4584
+ case "H":
4585
+ out += pad(f.hour, n);
4586
+ break;
4587
+ case "k":
4588
+ out += pad(f.hour === 0 ? 24 : f.hour, n);
4589
+ break;
4590
+ case "K":
4591
+ out += pad(hour12, n);
4592
+ break;
4593
+ case "h":
4594
+ out += pad(hour12 === 0 ? 12 : hour12, n);
4595
+ break;
4596
+ case "a":
4597
+ out += f.hour < 12 ? "AM" : "PM";
4598
+ break;
4599
+ case "m":
4600
+ out += pad(f.minute, n);
4601
+ break;
4602
+ case "s":
4603
+ out += pad(f.second, n);
4604
+ break;
4605
+ case "S":
4606
+ out += pad(ms, n);
4607
+ break;
4608
+ case "Z": {
4609
+ const minutes = Math.abs(offset) / 6e4;
4610
+ out += (offset < 0 ? "-" : "+") + pad(Math.floor(minutes / 60), 2) + pad(minutes % 60, 2);
4611
+ break;
4612
+ }
4613
+ case "z":
4614
+ out += zoneName(time2, timezone, offset);
4615
+ break;
4616
+ default:
4617
+ throw new SyntaxError(`Unsupported date pattern letter "${ch}" in "${pattern}"`);
4731
4618
  }
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
- }
4746
- /** Session start and end of the trading day of `time`, or null. */
4747
- dayBounds(time2) {
4748
- const at = this.calendar.locate(time2);
4749
- return at ? { date: at.date, start: this.dayStart(at.date), end: this.dayEnd(at.date) } : null;
4750
4619
  }
4620
+ return out;
4621
+ }
4622
+
4623
+ // src/str/messageformat.ts
4624
+ var DATE_STYLES = {
4625
+ short: "M/d/yy",
4626
+ medium: "MMM d, yyyy",
4627
+ long: "MMMM d, yyyy",
4628
+ full: "EEEE, MMMM d, yyyy"
4751
4629
  };
4752
- function sessionFlags(times, bars2, regular) {
4753
- const n = times.length;
4754
- const flag2 = () => new Array(n).fill(false);
4755
- const out = {
4756
- isfirstbar: flag2(),
4757
- islastbar: flag2(),
4758
- ismarket: flag2(),
4759
- ispremarket: flag2(),
4760
- ispostmarket: flag2(),
4761
- isfirstbar_regular: flag2(),
4762
- islastbar_regular: flag2()
4763
- };
4764
- const chart2 = bars2.chart;
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;
4630
+ var TIME_STYLES = {
4631
+ short: "h:mm\u202Fa",
4632
+ medium: "h:mm:ss\u202Fa",
4633
+ long: "h:mm:ss\u202Fa z",
4634
+ full: "h:mm:ss\u202Fa z"
4635
+ };
4636
+ function number(value, pattern) {
4637
+ return typeof value === "number" ? formatNumber(value, pattern, "halfEvenExact") : String(value);
4638
+ }
4639
+ function choice(value, spec) {
4640
+ const options = spec.split("|").map((part) => {
4641
+ const m = /^\s*(-?[\d.]+|-?∞)\s*([#<≤])(.*)$/.exec(part);
4642
+ if (!m) throw new SyntaxError(`Invalid choice format "${spec}"`);
4643
+ const limit = m[1].includes("\u221E") ? m[1].startsWith("-") ? -Infinity : Infinity : Number(m[1]);
4644
+ return { limit: m[2] === "<" ? limit + Number.EPSILON * Math.max(1, Math.abs(limit)) : limit, text: m[3] };
4645
+ });
4646
+ let chosen = options[0];
4647
+ for (const o of options) if (value >= o.limit) chosen = o;
4648
+ return chosen.text;
4649
+ }
4650
+ function formatArgument(value, type, style, timezone) {
4651
+ if (value === void 0) return "";
4652
+ if (!type) return typeof value === "number" ? number(value, "#,##0.###") : String(value);
4653
+ switch (type.trim()) {
4654
+ case "number": {
4655
+ const s = style?.trim();
4656
+ if (!s) return number(value, "#,##0.###");
4657
+ if (s === "integer") return number(value, "#,##0");
4658
+ if (s === "percent") return number(value, "#,##0%");
4659
+ if (s === "currency") return number(value, "'$'#,##0.00");
4660
+ return number(value, style);
4661
+ }
4662
+ case "date":
4663
+ case "time": {
4664
+ const styles = type.trim() === "date" ? DATE_STYLES : TIME_STYLES;
4665
+ const s = style?.trim() ?? "medium";
4666
+ return formatDate(Number(value), styles[s] ?? style, typeof timezone === "function" ? timezone() : timezone);
4667
+ }
4668
+ case "choice":
4669
+ return choice(Number(value), style ?? "");
4670
+ default:
4671
+ throw new SyntaxError(`Unknown format type "${type}"`);
4672
+ }
4673
+ }
4674
+ function formatMessage(pattern, args, timezone) {
4675
+ let out = "";
4676
+ for (let i = 0; i < pattern.length; ) {
4677
+ const ch = pattern[i];
4678
+ if (ch === "'") {
4679
+ if (pattern[i + 1] === "'") {
4680
+ out += "'";
4681
+ i += 2;
4682
+ continue;
4683
+ }
4684
+ const end = pattern.indexOf("'", i + 1);
4685
+ out += pattern.slice(i + 1, end === -1 ? void 0 : end);
4686
+ i = end === -1 ? pattern.length : end + 1;
4771
4687
  continue;
4772
4688
  }
4773
- const at = bars2.calendar.locate(t2);
4774
- if (!at) {
4775
- previousPeriod = previousRegular = "";
4689
+ if (ch !== "{") {
4690
+ out += ch;
4691
+ i++;
4776
4692
  continue;
4777
4693
  }
4778
- const close2 = bars2.closeOf(t2, chart2.period);
4779
- const [, end] = bars2.calendar.periods(at.date)[at.index];
4780
- const period = `${at.date}/${at.index}`;
4781
- out.isfirstbar[i] = period !== previousPeriod;
4782
- out.islastbar[i] = close2 >= end;
4783
- const regularPeriods = regular.calendar.periods(at.date);
4784
- const r2 = regularPeriods.findIndex(([s, e2]) => s <= t2 && t2 < e2);
4785
- const market = r2 !== -1;
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];
4694
+ let depth = 1;
4695
+ let j = i + 1;
4696
+ let inQuote = false;
4697
+ for (; j < pattern.length && depth > 0; j++) {
4698
+ const c = pattern[j];
4699
+ if (c === "'") inQuote = !inQuote;
4700
+ else if (!inQuote && c === "{") depth++;
4701
+ else if (!inQuote && c === "}") depth--;
4790
4702
  }
4791
- const regularPeriod = market ? `${at.date}/${r2}` : "";
4792
- out.isfirstbar_regular[i] = market && regularPeriod !== previousRegular;
4793
- out.islastbar_regular[i] = market && close2 >= regularPeriods[r2][1];
4794
- previousPeriod = period;
4795
- previousRegular = regularPeriod;
4703
+ const inner = pattern.slice(i + 1, j - 1);
4704
+ const [index = "", type, ...rest] = inner.split(",");
4705
+ const style = rest.length ? rest.join(",") : void 0;
4706
+ const n = Number(index.trim());
4707
+ out += n < args.length ? formatArgument(args[n], type, style, timezone) : `{${inner}}`;
4708
+ i = j;
4796
4709
  }
4797
4710
  return out;
4798
4711
  }
4799
4712
 
4800
- // src/security/resample.ts
4801
- function resample(bars2, periodStart) {
4802
- const out = [];
4803
- const group2 = [];
4804
- bars2.forEach((b2, i) => {
4805
- const start = periodStart[i];
4806
- const last = out[out.length - 1];
4807
- if (!last || last.time !== start) {
4808
- out.push({ time: start, open: b2.open, high: b2.high, low: b2.low, close: b2.close, volume: b2.volume ?? NaN });
4809
- } else {
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);
4713
+ // src/str/index.ts
4714
+ function length(str2) {
4715
+ return str2.length;
4716
+ }
4717
+ function tostring(value, format2) {
4718
+ if (typeof value !== "number") return String(value);
4719
+ if (!Number.isFinite(value)) return String(value);
4720
+ if (format2 === void 0 || format2 === "") {
4721
+ if (Math.abs(value) >= 1e21 && Number.isFinite(value)) {
4722
+ return String(value).replace("e+", "E").replace(/\.0+E/, "E");
4814
4723
  }
4815
- group2.push(out.length - 1);
4816
- });
4817
- return { bars: out, group: group2 };
4724
+ return formatNumber(value, "#.##########", "halfUpShortest");
4725
+ }
4726
+ switch (format2) {
4727
+ case "percent":
4728
+ return formatNumber(value, "0.00", "halfUpShortest") + "%";
4729
+ case "volume": {
4730
+ const abs2 = Math.abs(value);
4731
+ for (const [size, unit] of [[1e12, "T"], [1e9, "B"], [1e6, "M"], [1e3, "K"]]) {
4732
+ if (abs2 >= size) return formatNumber(value / size, "#.###", "halfUpShortest") + unit;
4733
+ }
4734
+ return formatNumber(value, "#", "halfUpShortest");
4735
+ }
4736
+ case "mintick":
4737
+ throw new Error("str.tostring(x, format.mintick) needs the symbol tick size (syminfo.mintick), which is not known here");
4738
+ default:
4739
+ return formatNumber(value, format2, "halfUpShortest");
4740
+ }
4818
4741
  }
4819
- function periodsOf(starts, dayPeriods, reaches) {
4820
- const n = starts.length;
4821
- const group2 = [];
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 };
4742
+ function tonumber(str2) {
4743
+ const num = parseFloat(str2);
4744
+ return isNaN(num) ? null : num;
4832
4745
  }
4833
- function mapToChart(values, group2, latest, lookahead, gaps) {
4834
- return group2.map((g2, i) => {
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
- });
4746
+ function substring(str2, begin, end) {
4747
+ return str2.substring(begin, end);
4843
4748
  }
4844
- function heikinAshi(bars2) {
4845
- const out = [];
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;
4749
+ function upper(str2) {
4750
+ return str2.toUpperCase();
4853
4751
  }
4854
-
4855
- // src/math/index.ts
4856
- var math_exports = {};
4857
- __export(math_exports, {
4858
- abs: () => abs,
4859
- acos: () => acos,
4860
- asin: () => asin,
4861
- atan: () => atan,
4862
- avg: () => avg,
4863
- ceil: () => ceil,
4864
- cos: () => cos,
4865
- e: () => e,
4866
- exp: () => exp,
4867
- floor: () => floor,
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);
4752
+ function lower(str2) {
4753
+ return str2.toLowerCase();
4754
+ }
4755
+ function contains(source, str2) {
4756
+ return source.includes(str2);
4757
+ }
4758
+ function pos(source, str2) {
4759
+ return source.indexOf(str2);
4760
+ }
4761
+ function replace(source, target, replacement, occurrence) {
4762
+ if (occurrence === 0) {
4763
+ return source.replace(target, replacement);
4764
+ } else {
4765
+ return source.replaceAll(target, replacement);
4898
4766
  }
4899
- return Math.abs(value);
4900
4767
  }
4901
- function ceil(value) {
4902
- if (value instanceof Series) {
4903
- const bars2 = value.bars;
4904
- const valueArray = value.toArray();
4905
- const length2 = bars2.length;
4906
- const result = [];
4907
- for (let i = 0; i < length2; i++) {
4908
- const v = valueArray[i] ?? NaN;
4909
- result.push(Math.ceil(v));
4768
+ function replace_all(source, target, replacement) {
4769
+ return source.replaceAll(target, replacement);
4770
+ }
4771
+ function split(str2, separator) {
4772
+ return str2.split(separator);
4773
+ }
4774
+ function concat(...strings) {
4775
+ return strings.join("");
4776
+ }
4777
+ function format(formatStr, ...args) {
4778
+ return formatMessage(formatStr, args, "Etc/UTC");
4779
+ }
4780
+ function startswith(source, str2) {
4781
+ return source.startsWith(str2);
4782
+ }
4783
+ function endswith(source, str2) {
4784
+ return source.endsWith(str2);
4785
+ }
4786
+ function charAt(str2, pos2) {
4787
+ return str2.charAt(pos2);
4788
+ }
4789
+ function trim(str2) {
4790
+ return str2.trim();
4791
+ }
4792
+ function trimLeft(str2) {
4793
+ return str2.trimStart();
4794
+ }
4795
+ function trimRight(str2) {
4796
+ return str2.trimEnd();
4797
+ }
4798
+ function match(source, regex) {
4799
+ return new RegExp(regex).test(source);
4800
+ }
4801
+ function repeat(source, count, separator = "") {
4802
+ if (source == null) return null;
4803
+ if (count <= 0) return "";
4804
+ return Array(count).fill(source).join(separator);
4805
+ }
4806
+ function format_time(time2, format2 = "yyyy-MM-dd'T'HH:mm:ssZ", timezone = "Etc/UTC") {
4807
+ return formatDate(time2, format2, timezone);
4808
+ }
4809
+
4810
+ // src/session/calendar.ts
4811
+ var toDateNum = (y, m, d) => y * 1e4 + m * 100 + d;
4812
+ var utcOf = (date) => Date.UTC(Math.floor(date / 1e4), Math.floor(date / 100) % 100 - 1, date % 100);
4813
+ var fromUtc = (ms) => {
4814
+ const d = new Date(ms);
4815
+ return toDateNum(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate());
4816
+ };
4817
+ var addDays = (date, n) => fromUtc(utcOf(date) + n * 864e5);
4818
+ var weekdayOf = (date) => new Date(utcOf(date)).getUTCDay() + 1;
4819
+ var dateUtcMs = utcOf;
4820
+ function parseTime(token, spec) {
4821
+ const m = /^(\d{2})(\d{2})(?:F(\d+))?$/.exec(token.trim());
4822
+ if (!m) throw new SyntaxError(`Invalid session "${spec}"`);
4823
+ return { minutes: Number(m[1]) * 60 + Number(m[2]), offset: m[3] === void 0 ? void 0 : Number(m[3]) };
4824
+ }
4825
+ function parsePeriods(text2, spec) {
4826
+ if (text2.trim() === "24x7") return [{ start: 0, end: 1440, startOffset: 0, endOffset: 0 }];
4827
+ return text2.split(",").map((p) => {
4828
+ const [a = "", b2 = ""] = p.split("-");
4829
+ const s = parseTime(a, spec);
4830
+ const e2 = parseTime(b2, spec);
4831
+ if (s.minutes === 0 && e2.minutes === 0 && s.offset === void 0 && e2.offset === void 0) {
4832
+ return { start: 0, end: 1440, startOffset: 0, endOffset: 0 };
4910
4833
  }
4911
- return Series.fromArray(bars2, result);
4912
- }
4913
- return Math.ceil(value);
4834
+ return {
4835
+ start: s.minutes,
4836
+ end: e2.minutes,
4837
+ startOffset: s.offset ?? (e2.minutes <= s.minutes ? 1 : 0),
4838
+ endOffset: e2.offset ?? 0
4839
+ };
4840
+ });
4914
4841
  }
4915
- function floor(value) {
4916
- if (value instanceof Series) {
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);
4842
+ function parseVersion(text2, from, spec, rule) {
4843
+ const [periodText = "", dayText] = text2.trim().split(":");
4844
+ const periods = parsePeriods(periodText, spec);
4845
+ const allDays = periodText.trim() === "24x7" || rule === "pine" && periods.length === 1;
4846
+ const digits = dayText ?? (allDays ? "1234567" : "23456");
4847
+ if (!/^[1-7]+$/.test(digits)) throw new SyntaxError(`Invalid session days in "${spec}"`);
4848
+ const days = new Array(8).fill(false);
4849
+ for (const d of digits) days[Number(d)] = true;
4850
+ return { from, periods, days };
4928
4851
  }
4929
- function round(value, precision) {
4930
- if (value instanceof Series) {
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
- }
4852
+ var TradingCalendar = class {
4853
+ /**
4854
+ * @param timezone - Time zone of the session hours (the exchange time zone)
4855
+ * @param spec - Session information (hours, corrections, holidays)
4856
+ * @param rule - Days without ":days": 'symbol' (Monday to Friday) or 'pine' (PineScript session strings)
4857
+ */
4858
+ constructor(timezone, spec, rule = "symbol") {
4859
+ this.timezone = timezone;
4860
+ const [first = "", ...changes] = spec.session.split("#");
4861
+ this.versions = [parseVersion(first, 0, spec.session, rule)];
4862
+ for (const change3 of changes) {
4863
+ const m = /^(\d{8})\/(.+)$/.exec(change3.trim());
4864
+ if (!m) throw new SyntaxError(`Invalid session change in "${spec.session}"`);
4865
+ this.versions.push(parseVersion(m[2], Number(m[1]), spec.session, rule));
4946
4866
  }
4947
- return Series.fromArray(bars2, result);
4867
+ for (const part of (spec.corrections ?? "").split(";").filter((p) => p.trim())) {
4868
+ const i = part.lastIndexOf(":");
4869
+ const text2 = part.slice(0, i).trim();
4870
+ const periods = text2 === "dayoff" ? null : parsePeriods(text2, part);
4871
+ for (const date of part.slice(i + 1).split(",")) this.corrections.set(Number(date), periods);
4872
+ }
4873
+ const holidays = Array.isArray(spec.holidays) ? spec.holidays : (spec.holidays ?? "").split(",");
4874
+ this.holidays = new Set(holidays.filter((h) => h.trim()).map(Number));
4948
4875
  }
4949
- if (precision === void 0) {
4950
- return Math.round(value);
4876
+ timezone;
4877
+ versions;
4878
+ corrections = /* @__PURE__ */ new Map();
4879
+ holidays;
4880
+ cache = /* @__PURE__ */ new Map();
4881
+ /** Session periods [start, end) of the trading day `date`; empty when the day has no session. */
4882
+ periods(date) {
4883
+ let out = this.cache.get(date);
4884
+ if (out) return out;
4885
+ let periods = [];
4886
+ const correction = this.corrections.get(date);
4887
+ if (correction !== void 0) {
4888
+ periods = correction ?? [];
4889
+ } else if (!this.holidays.has(date)) {
4890
+ const version = [...this.versions].reverse().find((v) => v.from <= date);
4891
+ if (version.days[weekdayOf(date)]) periods = version.periods;
4892
+ }
4893
+ const y = Math.floor(date / 1e4);
4894
+ const m = Math.floor(date / 100) % 100;
4895
+ const d = date % 100;
4896
+ out = periods.map((p) => [
4897
+ zonedToUnix(this.timezone, y, m, d - p.startOffset, Math.floor(p.start / 60), p.start % 60),
4898
+ zonedToUnix(this.timezone, y, m, d - p.endOffset, Math.floor(p.end / 60), p.end % 60)
4899
+ ]);
4900
+ this.cache.set(date, out);
4901
+ return out;
4951
4902
  }
4952
- const multiplier = Math.pow(10, precision);
4953
- return Math.round(value * multiplier) / multiplier;
4954
- }
4955
- function max3(...values) {
4956
- const hasSeries = values.some((v) => v instanceof Series);
4957
- if (!hasSeries) {
4958
- return Math.max(...values);
4903
+ isTradingDay(date) {
4904
+ return this.periods(date).length > 0;
4959
4905
  }
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));
4906
+ /**
4907
+ * Trading day and period of a time: the period that contains it, else the last period that started
4908
+ * before it. Null when no trading day is found near the time.
4909
+ */
4910
+ locate(time2) {
4911
+ const f = zonedFields(time2, this.timezone);
4912
+ const local = toDateNum(f.year, f.month, f.day);
4913
+ for (let k = 0; k <= 5; k++) {
4914
+ const date = addDays(local, k);
4915
+ const index = this.periods(date).findIndex(([s, e2]) => s <= time2 && time2 < e2);
4916
+ if (index !== -1) return { date, index, inside: true };
4917
+ }
4918
+ for (let k = 5; k >= -7; k--) {
4919
+ const date = addDays(local, k);
4920
+ const periods = this.periods(date);
4921
+ let index = -1;
4922
+ periods.forEach(([s], i) => {
4923
+ if (s <= time2) index = i;
4924
+ });
4925
+ if (index !== -1) return { date, index, inside: false };
4926
+ }
4927
+ return null;
4972
4928
  }
4973
- return Series.fromArray(bars2, result);
4974
- }
4975
- function min3(...values) {
4976
- const hasSeries = values.some((v) => v instanceof Series);
4977
- if (!hasSeries) {
4978
- return Math.min(...values);
4929
+ /** First trading day in [from, to] (dates), or null. */
4930
+ firstTradingDay(from, to) {
4931
+ for (let date = from; date <= to; date = addDays(date, 1)) if (this.isTradingDay(date)) return date;
4932
+ return null;
4979
4933
  }
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));
4934
+ /** Last trading day in [from, to] (dates), or null. */
4935
+ lastTradingDay(from, to) {
4936
+ for (let date = to; date >= from; date = addDays(date, -1)) if (this.isTradingDay(date)) return date;
4937
+ return null;
4992
4938
  }
4993
- return Series.fromArray(bars2, result);
4939
+ };
4940
+ var weekStart = (date) => addDays(date, -((weekdayOf(date) + 5) % 7));
4941
+ var monthStart = (date) => Math.floor(date / 100) * 100 + 1;
4942
+ var monthEnd = (date) => addDays(monthStart(addDays(monthStart(date), 32)), -1);
4943
+
4944
+ // src/session/bars.ts
4945
+ function unitOf(tf) {
4946
+ return { unit: tf.isdaily ? "D" : tf.isweekly ? "W" : "M", n: tf.multiplier };
4994
4947
  }
4995
- function avg(...values) {
4996
- const hasSeries = values.some((v) => v instanceof Series);
4997
- if (!hasSeries) {
4998
- return values.reduce((a, b2) => a + b2, 0) / values.length;
4999
- }
5000
- const firstSeries = values.find((v) => v instanceof Series);
5001
- const bars2 = firstSeries.bars;
5002
- const length2 = bars2.length;
5003
- const valueArrays = values.map(
5004
- (v) => v instanceof Series ? v.toArray() : null
5005
- );
5006
- const result = [];
5007
- for (let i = 0; i < length2; i++) {
5008
- const nums = values.map(
5009
- (v, idx) => valueArrays[idx] ? valueArrays[idx][i] ?? NaN : v
5010
- );
5011
- const sum2 = nums.reduce((a, b2) => a + b2, 0);
5012
- result.push(sum2 / nums.length);
4948
+ var yearOf = (date) => Math.floor(date / 1e4);
4949
+ var firstMonday = (year3) => {
4950
+ const jan1 = year3 * 1e4 + 101;
4951
+ const monday = weekStart(jan1);
4952
+ return monday === jan1 ? jan1 : addDays(monday, 7);
4953
+ };
4954
+ var SessionBars = class {
4955
+ constructor(calendar2, chartTimeframe2) {
4956
+ this.calendar = calendar2;
4957
+ this.chart = info(chartTimeframe2);
5013
4958
  }
5014
- return Series.fromArray(bars2, result);
5015
- }
5016
- function sum(source, length2) {
5017
- const sourceArray = source instanceof Series ? source.toArray() : source;
5018
- const result = [];
5019
- const len = Math.floor(length2);
5020
- const window = [];
5021
- for (let i = 0; i < sourceArray.length; i++) {
5022
- const v = sourceArray[i];
5023
- if (v !== void 0 && v !== null && !Number.isNaN(v)) {
5024
- window.push(v);
5025
- if (window.length > len) window.shift();
5026
- }
5027
- if (window.length < len) {
5028
- result.push(NaN);
5029
- } else {
5030
- let total = 0;
5031
- for (const x of window) total += x;
5032
- result.push(total);
4959
+ calendar;
4960
+ chart;
4961
+ yearDays = /* @__PURE__ */ new Map();
4962
+ /** Trading days of a calendar year, in order. */
4963
+ tradingDaysOf(year3) {
4964
+ let days = this.yearDays.get(year3);
4965
+ if (!days) {
4966
+ days = [];
4967
+ for (let date = year3 * 1e4 + 101; yearOf(date) === year3; date = addDays(date, 1)) {
4968
+ if (this.calendar.isTradingDay(date)) days.push(date);
4969
+ }
4970
+ this.yearDays.set(year3, days);
5033
4971
  }
4972
+ return days;
5034
4973
  }
5035
- if (source instanceof Series) {
5036
- return Series.fromArray(source.bars, result);
5037
- }
5038
- return result;
5039
- }
5040
- function sqrt(value) {
5041
- if (value instanceof Series) {
5042
- const bars2 = value.bars;
5043
- const valueArray = value.toArray();
5044
- const length2 = bars2.length;
5045
- const result = [];
5046
- for (let i = 0; i < length2; i++) {
5047
- const v = valueArray[i] ?? NaN;
5048
- result.push(Math.sqrt(v));
4974
+ /**
4975
+ * Dates [from, to] of the `n`-`unit` period that contains `date` (for "D": its first and last trading days).
4976
+ * Periods restart each calendar year.
4977
+ */
4978
+ periodRange(date, unit, n) {
4979
+ if (unit === "D") {
4980
+ if (n === 1) return [date, date];
4981
+ const days = this.tradingDaysOf(yearOf(date));
4982
+ let k = days.findIndex((d) => d >= date);
4983
+ if (k === -1) return this.periodRange(yearOf(date) * 1e4 + 1e4 + 101, unit, n);
4984
+ k -= k % n;
4985
+ return [days[k], days[Math.min(k + n, days.length) - 1]];
5049
4986
  }
5050
- return Series.fromArray(bars2, result);
4987
+ if (unit === "W") {
4988
+ const monday = weekStart(date);
4989
+ const year4 = yearOf(monday);
4990
+ const first = firstMonday(year4);
4991
+ const next = firstMonday(year4 + 1);
4992
+ const k = Math.round((dateUtcMs(monday) - dateUtcMs(first)) / (7 * 864e5));
4993
+ const from = addDays(first, (k - k % n) * 7);
4994
+ const to = addDays(from, n * 7 - 1);
4995
+ return [from, to < next ? to : addDays(next, -1)];
4996
+ }
4997
+ const year3 = yearOf(date);
4998
+ const month3 = Math.floor(date / 100) % 100;
4999
+ const firstMonth = month3 - (month3 - 1) % n;
5000
+ const lastMonth = Math.min(firstMonth + n - 1, 12);
5001
+ return [monthStart(year3 * 1e4 + firstMonth * 100 + 1), monthEnd(year3 * 1e4 + lastMonth * 100 + 1)];
5051
5002
  }
5052
- return Math.sqrt(value);
5053
- }
5054
- function pow(base, exponent) {
5055
- const baseIsSeries = base instanceof Series;
5056
- const expIsSeries = exponent instanceof Series;
5057
- if (!baseIsSeries && !expIsSeries) {
5058
- return Math.pow(base, exponent);
5003
+ dayStart(date) {
5004
+ return this.calendar.periods(date)[0][0];
5059
5005
  }
5060
- const bars2 = baseIsSeries ? base.bars : exponent.bars;
5061
- const baseArray = baseIsSeries ? base.toArray() : null;
5062
- const expArray = expIsSeries ? exponent.toArray() : null;
5063
- const length2 = bars2.length;
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));
5006
+ dayEnd(date) {
5007
+ const p = this.calendar.periods(date);
5008
+ return p[p.length - 1][1];
5069
5009
  }
5070
- return Series.fromArray(bars2, result);
5071
- }
5072
- function exp(value) {
5073
- if (value instanceof Series) {
5074
- const bars2 = value.bars;
5075
- const valueArray = value.toArray();
5076
- const length2 = bars2.length;
5077
- const result = [];
5078
- for (let i = 0; i < length2; i++) {
5079
- const v = valueArray[i] ?? NaN;
5080
- result.push(Math.exp(v));
5010
+ /** PineScript `time(tf)` for a bar that opens at `time`; NaN when no trading day is found. */
5011
+ timeOf(time2, timeframe2) {
5012
+ const tf = info(timeframe2);
5013
+ const at = this.calendar.locate(time2);
5014
+ if (!at) return NaN;
5015
+ if (tf.isintraday) {
5016
+ if (this.chart.isdwm) return time2;
5017
+ const [start] = this.calendar.periods(at.date)[at.index];
5018
+ const ms = in_seconds(tf.period) * 1e3;
5019
+ return start + Math.floor((time2 - start) / ms) * ms;
5081
5020
  }
5082
- return Series.fromArray(bars2, result);
5021
+ const { unit, n } = unitOf(tf);
5022
+ const [from, to] = this.periodRange(at.date, unit, n);
5023
+ const first = this.calendar.firstTradingDay(from, to);
5024
+ return first === null ? NaN : this.dayStart(first);
5083
5025
  }
5084
- return Math.exp(value);
5085
- }
5086
- function log(value) {
5087
- if (value instanceof Series) {
5088
- const bars2 = value.bars;
5089
- const valueArray = value.toArray();
5090
- const length2 = bars2.length;
5091
- const result = [];
5092
- for (let i = 0; i < length2; i++) {
5093
- const v = valueArray[i] ?? NaN;
5094
- result.push(Math.log(v));
5026
+ /** PineScript `time_close(tf)` for a bar that opens at `time`. */
5027
+ closeOf(time2, timeframe2) {
5028
+ const tf = info(timeframe2);
5029
+ const at = this.calendar.locate(time2);
5030
+ if (!at) return NaN;
5031
+ if (tf.isintraday) {
5032
+ const [, end] = this.calendar.periods(at.date)[at.index];
5033
+ if (this.chart.isdwm) return end;
5034
+ return Math.min(this.timeOf(time2, timeframe2) + in_seconds(tf.period) * 1e3, end);
5095
5035
  }
5096
- return Series.fromArray(bars2, result);
5097
- }
5098
- return Math.log(value);
5099
- }
5100
- function log10(value) {
5101
- if (value instanceof Series) {
5102
- const bars2 = value.bars;
5103
- const valueArray = value.toArray();
5104
- const length2 = bars2.length;
5105
- const result = [];
5106
- for (let i = 0; i < length2; i++) {
5107
- const v = valueArray[i] ?? NaN;
5108
- result.push(Math.log10(v));
5036
+ const { unit, n } = unitOf(tf);
5037
+ const [from, to] = this.periodRange(at.date, unit, n);
5038
+ if (this.chart.isintraday && (unit !== "D" || n > 1)) {
5039
+ const [nextFrom, nextTo] = this.periodRange(addDays(to, 1), unit, n);
5040
+ const first = this.calendar.firstTradingDay(nextFrom, addDays(nextTo, 31));
5041
+ return first === null ? NaN : this.dayStart(first);
5109
5042
  }
5110
- return Series.fromArray(bars2, result);
5043
+ const last = this.calendar.lastTradingDay(from, to);
5044
+ return last === null ? NaN : this.dayEnd(last);
5111
5045
  }
5112
- return Math.log10(value);
5113
- }
5114
- function sin(value) {
5115
- if (value instanceof Series) {
5116
- const bars2 = value.bars;
5117
- const valueArray = value.toArray();
5118
- const length2 = bars2.length;
5119
- const result = [];
5120
- for (let i = 0; i < length2; i++) {
5121
- const v = valueArray[i] ?? NaN;
5122
- result.push(Math.sin(v));
5046
+ /** Trading day of a bar: on D / W / M charts the last trading day of the chart period. */
5047
+ tradingDay(time2) {
5048
+ const at = this.calendar.locate(time2);
5049
+ if (!at) return null;
5050
+ if (this.chart.isdwm) {
5051
+ const { unit, n } = unitOf(this.chart);
5052
+ const [from, to] = this.periodRange(at.date, unit, n);
5053
+ return this.calendar.lastTradingDay(from, to);
5123
5054
  }
5124
- return Series.fromArray(bars2, result);
5055
+ return at.date;
5125
5056
  }
5126
- return Math.sin(value);
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));
5057
+ /**
5058
+ * End of the `timeframe` period that contains `time`: the intraday close, the session end of the day,
5059
+ * or the session end of the last trading day of the period. Used to know whether the last loaded
5060
+ * bar completes a higher-timeframe period (request.security).
5061
+ */
5062
+ periodEnd(time2, timeframe2) {
5063
+ const tf = info(timeframe2);
5064
+ const at = this.calendar.locate(time2);
5065
+ if (!at) return NaN;
5066
+ if (tf.isintraday) {
5067
+ const [, end] = this.calendar.periods(at.date)[at.index];
5068
+ return Math.min(this.timeOf(time2, timeframe2) + in_seconds(tf.period) * 1e3, end);
5137
5069
  }
5138
- return Series.fromArray(bars2, result);
5070
+ const { unit, n } = unitOf(tf);
5071
+ const [from, to] = this.periodRange(at.date, unit, n);
5072
+ const last = this.calendar.lastTradingDay(from, to);
5073
+ return last === null ? NaN : this.dayEnd(last);
5139
5074
  }
5140
- return Math.cos(value);
5141
- }
5142
- function tan(value) {
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);
5075
+ /** PineScript `time_tradingday`: 00:00 UTC of the trading day. */
5076
+ tradingDayTime(time2) {
5077
+ const day = this.tradingDay(time2);
5078
+ return day === null ? NaN : dateUtcMs(day);
5153
5079
  }
5154
- return Math.tan(value);
5155
- }
5156
- function asin(value) {
5157
- if (value instanceof Series) {
5158
- const bars2 = value.bars;
5159
- const valueArray = value.toArray();
5160
- const length2 = bars2.length;
5161
- const result = [];
5162
- for (let i = 0; i < length2; i++) {
5163
- const v = valueArray[i] ?? NaN;
5164
- result.push(Math.asin(v));
5165
- }
5166
- return Series.fromArray(bars2, result);
5080
+ /** True when the bar at `time` is inside the session. */
5081
+ inside(time2) {
5082
+ return this.calendar.locate(time2)?.inside ?? false;
5167
5083
  }
5168
- return Math.asin(value);
5169
- }
5170
- function acos(value) {
5171
- if (value instanceof Series) {
5172
- const bars2 = value.bars;
5173
- const valueArray = value.toArray();
5174
- const length2 = bars2.length;
5175
- const result = [];
5176
- for (let i = 0; i < length2; i++) {
5177
- const v = valueArray[i] ?? NaN;
5178
- result.push(Math.acos(v));
5179
- }
5180
- return Series.fromArray(bars2, result);
5084
+ /** Session start and end of the trading day of `time`, or null. */
5085
+ dayBounds(time2) {
5086
+ const at = this.calendar.locate(time2);
5087
+ return at ? { date: at.date, start: this.dayStart(at.date), end: this.dayEnd(at.date) } : null;
5181
5088
  }
5182
- return Math.acos(value);
5183
- }
5184
- function atan(value) {
5185
- if (value instanceof Series) {
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));
5089
+ };
5090
+ function sessionFlags(times, bars2, regular) {
5091
+ const n = times.length;
5092
+ const flag2 = () => new Array(n).fill(false);
5093
+ const out = {
5094
+ isfirstbar: flag2(),
5095
+ islastbar: flag2(),
5096
+ ismarket: flag2(),
5097
+ ispremarket: flag2(),
5098
+ ispostmarket: flag2(),
5099
+ isfirstbar_regular: flag2(),
5100
+ islastbar_regular: flag2()
5101
+ };
5102
+ const chart2 = bars2.chart;
5103
+ let previousPeriod = "";
5104
+ let previousRegular = "";
5105
+ for (let i = 0; i < n; i++) {
5106
+ const t2 = times[i];
5107
+ if (chart2.isdwm) {
5108
+ for (const k of ["isfirstbar", "islastbar", "ismarket", "isfirstbar_regular", "islastbar_regular"]) out[k][i] = true;
5109
+ continue;
5193
5110
  }
5194
- return Series.fromArray(bars2, result);
5195
- }
5196
- return Math.atan(value);
5197
- }
5198
- function toradians(degrees) {
5199
- if (degrees instanceof Series) {
5200
- const bars2 = degrees.bars;
5201
- const valueArray = degrees.toArray();
5202
- const length2 = bars2.length;
5203
- const result = [];
5204
- for (let i = 0; i < length2; i++) {
5205
- const v = valueArray[i] ?? NaN;
5206
- result.push(v * (Math.PI / 180));
5111
+ const at = bars2.calendar.locate(t2);
5112
+ if (!at) {
5113
+ previousPeriod = previousRegular = "";
5114
+ continue;
5207
5115
  }
5208
- return Series.fromArray(bars2, result);
5116
+ const close2 = bars2.closeOf(t2, chart2.period);
5117
+ const [, end] = bars2.calendar.periods(at.date)[at.index];
5118
+ const period = `${at.date}/${at.index}`;
5119
+ out.isfirstbar[i] = period !== previousPeriod;
5120
+ out.islastbar[i] = close2 >= end;
5121
+ const regularPeriods = regular.calendar.periods(at.date);
5122
+ const r2 = regularPeriods.findIndex(([s, e2]) => s <= t2 && t2 < e2);
5123
+ const market = r2 !== -1;
5124
+ out.ismarket[i] = market;
5125
+ if (!market && regularPeriods.length) {
5126
+ out.ispremarket[i] = t2 < regularPeriods[0][0];
5127
+ out.ispostmarket[i] = t2 >= regularPeriods[regularPeriods.length - 1][1];
5128
+ }
5129
+ const regularPeriod = market ? `${at.date}/${r2}` : "";
5130
+ out.isfirstbar_regular[i] = market && regularPeriod !== previousRegular;
5131
+ out.islastbar_regular[i] = market && close2 >= regularPeriods[r2][1];
5132
+ previousPeriod = period;
5133
+ previousRegular = regularPeriod;
5209
5134
  }
5210
- return degrees * (Math.PI / 180);
5135
+ return out;
5211
5136
  }
5212
- function todegrees(radians) {
5213
- if (radians instanceof Series) {
5214
- const bars2 = radians.bars;
5215
- const valueArray = radians.toArray();
5216
- const length2 = bars2.length;
5217
- const result = [];
5218
- for (let i = 0; i < length2; i++) {
5219
- const v = valueArray[i] ?? NaN;
5220
- result.push(v * (180 / Math.PI));
5137
+
5138
+ // src/security/resample.ts
5139
+ function resample(bars2, periodStart) {
5140
+ const out = [];
5141
+ const group2 = [];
5142
+ bars2.forEach((b2, i) => {
5143
+ const start = periodStart[i];
5144
+ const last = out[out.length - 1];
5145
+ if (!last || last.time !== start) {
5146
+ out.push({ time: start, open: b2.open, high: b2.high, low: b2.low, close: b2.close, volume: b2.volume ?? NaN });
5147
+ } else {
5148
+ last.high = Math.max(last.high, b2.high);
5149
+ last.low = Math.min(last.low, b2.low);
5150
+ last.close = b2.close;
5151
+ last.volume = (last.volume ?? 0) + (b2.volume ?? NaN);
5221
5152
  }
5222
- return Series.fromArray(bars2, result);
5223
- }
5224
- return radians * (180 / Math.PI);
5153
+ group2.push(out.length - 1);
5154
+ });
5155
+ return { bars: out, group: group2 };
5225
5156
  }
5226
- function random(min4, max4, _seed) {
5227
- const rand = Math.random();
5228
- if (min4 !== void 0 && max4 !== void 0) {
5229
- return min4 + rand * (max4 - min4);
5230
- }
5231
- return rand;
5157
+ function periodsOf(starts, dayPeriods, reaches) {
5158
+ const n = starts.length;
5159
+ const group2 = [];
5160
+ starts.forEach((s, i) => group2.push(i === 0 ? 0 : group2[i - 1] + (s !== starts[i - 1] ? 1 : 0)));
5161
+ const latest = [];
5162
+ starts.forEach((s, i) => {
5163
+ let done = i === 0 ? -1 : latest[i - 1];
5164
+ if (i > 0 && group2[i] !== group2[i - 1]) done = Math.max(done, group2[i] - 1);
5165
+ const ends = i < n - 1 ? starts[i + 1] !== s || dayPeriods[i + 1] !== dayPeriods[i] : true;
5166
+ if (ends && reaches[i]) done = Math.max(done, group2[i]);
5167
+ latest.push(done);
5168
+ });
5169
+ return { group: group2, latest };
5232
5170
  }
5233
- function sign(value) {
5234
- if (value instanceof Series) {
5235
- const bars2 = value.bars;
5236
- const valueArray = value.toArray();
5237
- const length2 = bars2.length;
5238
- const result = [];
5239
- for (let i = 0; i < length2; i++) {
5240
- const v = valueArray[i] ?? NaN;
5241
- result.push(v > 0 ? 1 : v < 0 ? -1 : 0);
5171
+ function mapToChart(values, group2, latest, lookahead, gaps) {
5172
+ return group2.map((g2, i) => {
5173
+ if (lookahead) {
5174
+ const first = i === 0 || group2[i - 1] !== g2;
5175
+ return gaps && !first ? NaN : values[g2] ?? NaN;
5242
5176
  }
5243
- return Series.fromArray(bars2, result);
5244
- }
5245
- return value > 0 ? 1 : value < 0 ? -1 : 0;
5177
+ const done = latest[i];
5178
+ if (done < 0 || gaps && i > 0 && latest[i - 1] === done) return NaN;
5179
+ return values[done] ?? NaN;
5180
+ });
5246
5181
  }
5247
- function round_to_mintick(number2, mintick) {
5248
- if (number2 instanceof Series) {
5249
- const bars2 = number2.bars;
5250
- const valueArray = number2.toArray();
5251
- const length2 = bars2.length;
5252
- if (mintick === void 0) {
5253
- throw new Error(
5254
- "math.round_to_mintick() requires mintick value. Either pass it explicitly or use createContext({ syminfo: { mintick } }) for implicit data."
5255
- );
5256
- }
5257
- const result = [];
5258
- if (mintick === 0) {
5259
- for (let i = 0; i < length2; i++) {
5260
- result.push(valueArray[i] ?? NaN);
5261
- }
5262
- } else {
5263
- for (let i = 0; i < length2; i++) {
5264
- const v = valueArray[i];
5265
- if (v === void 0 || isNaN(v)) {
5266
- result.push(NaN);
5267
- } else {
5268
- result.push(Math.round(v / mintick) * mintick);
5269
- }
5270
- }
5271
- }
5272
- return Series.fromArray(bars2, result);
5273
- }
5274
- if (isNaN(number2)) {
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;
5182
+ function heikinAshi(bars2) {
5183
+ const out = [];
5184
+ bars2.forEach((b2, i) => {
5185
+ const close2 = (b2.open + b2.high + b2.low + b2.close) / 4;
5186
+ const prev = out[i - 1];
5187
+ const open2 = prev ? (prev.open + prev.close) / 2 : (b2.open + b2.close) / 2;
5188
+ 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 });
5189
+ });
5190
+ return out;
5286
5191
  }
5287
- var pi = Math.PI;
5288
- var e = Math.E;
5289
- var phi = 1.618033988749895;
5290
- var rphi = 0.618033988749895;
5192
+
5193
+ // src/strategy/index.ts
5194
+ var STRATEGY_CONSTANTS = {
5195
+ long: "long",
5196
+ short: "short",
5197
+ fixed: "fixed",
5198
+ cash: "cash",
5199
+ percent_of_equity: "percent_of_equity",
5200
+ commission: { percent: "percent", cash_per_contract: "cash_per_contract", cash_per_order: "cash_per_order" },
5201
+ direction: { all: "all", long: "long", short: "short" },
5202
+ oca: { none: "none", cancel: "cancel", reduce: "reduce" }
5203
+ };
5204
+ var STRATEGY_DEFAULTS = {
5205
+ pyramiding: 0,
5206
+ calc_on_order_fills: false,
5207
+ calc_on_every_tick: false,
5208
+ backtest_fill_limits_assumption: 0,
5209
+ // v6 values; PineScript v5: fixed / 1 / 1000000 and margins 0
5210
+ default_qty_type: "percent_of_equity",
5211
+ default_qty_value: 100,
5212
+ initial_capital: 1e5,
5213
+ slippage: 0,
5214
+ commission_type: "percent",
5215
+ commission_value: 0,
5216
+ process_orders_on_close: false,
5217
+ close_entries_rule: "FIFO",
5218
+ margin_long: 100,
5219
+ margin_short: 100,
5220
+ calc_bars_count: 0,
5221
+ risk_free_rate: 2,
5222
+ use_bar_magnifier: false,
5223
+ fill_orders_on_standard_ohlc: false
5224
+ };
5225
+ var STRATEGY_NUMBER_VARIABLES = [
5226
+ "position_size",
5227
+ "position_avg_price",
5228
+ "equity",
5229
+ "initial_capital",
5230
+ "netprofit",
5231
+ "netprofit_percent",
5232
+ "openprofit",
5233
+ "openprofit_percent",
5234
+ "grossprofit",
5235
+ "grossprofit_percent",
5236
+ "grossloss",
5237
+ "grossloss_percent",
5238
+ "opentrades",
5239
+ "closedtrades",
5240
+ "wintrades",
5241
+ "losstrades",
5242
+ "eventrades",
5243
+ "avg_trade",
5244
+ "avg_trade_percent",
5245
+ "avg_winning_trade",
5246
+ "avg_winning_trade_percent",
5247
+ "avg_losing_trade",
5248
+ "avg_losing_trade_percent",
5249
+ "max_drawdown",
5250
+ "max_drawdown_percent",
5251
+ "max_runup",
5252
+ "max_runup_percent",
5253
+ "max_contracts_held_all",
5254
+ "max_contracts_held_long",
5255
+ "max_contracts_held_short",
5256
+ "margin_liquidation_price"
5257
+ ];
5258
+ var STRATEGY_TEXT_VARIABLES = ["position_entry_name", "account_currency"];
5291
5259
 
5292
5260
  // src/script/index.ts
5293
5261
  var ctxBars = new BarData([]);
@@ -5315,6 +5283,8 @@ function freshCollector(inputValues) {
5315
5283
  fillConfig: [],
5316
5284
  shapeConfig: [],
5317
5285
  markers: [],
5286
+ arrowConfig: [],
5287
+ arrows: [],
5318
5288
  barColorConfig: [],
5319
5289
  bgcolors: [],
5320
5290
  barcolors: [],
@@ -5329,9 +5299,11 @@ function slugId(title, fallback, taken) {
5329
5299
  taken.add(id);
5330
5300
  return id;
5331
5301
  }
5332
- function executeScript(body, barsInput, inputs = {}, chart2 = {}) {
5302
+ var scriptOptions = {};
5303
+ function executeScript(body, barsInput, inputs = {}, chart2 = {}, options = {}) {
5333
5304
  ctxBars.setAll(barsInput);
5334
5305
  chartCtx = { ...chart2 };
5306
+ scriptOptions = options;
5335
5307
  ctx = freshCollector(inputs);
5336
5308
  resetDrawings();
5337
5309
  try {
@@ -5350,14 +5322,17 @@ function executeScript(body, barsInput, inputs = {}, chart2 = {}) {
5350
5322
  hlineConfig: c.hlineConfig,
5351
5323
  fillConfig: c.fillConfig,
5352
5324
  shapeConfig: c.shapeConfig,
5325
+ arrowConfig: c.arrowConfig,
5353
5326
  barColorConfig: c.barColorConfig,
5354
5327
  defaultInputs: c.defaultInputs,
5355
5328
  alertConfig: c.alertConfig,
5329
+ strategyConfig: c.strategy?.properties,
5356
5330
  result: {
5357
5331
  metadata: { title: c.title, shorttitle: c.shortTitle, overlay: c.overlay, precision: c.precision },
5358
5332
  plots: c.plots,
5359
5333
  fills: c.fills.length ? c.fills : void 0,
5360
5334
  markers: c.markers.length ? c.markers : void 0,
5335
+ arrows: c.arrows.length ? c.arrows : void 0,
5361
5336
  bgcolors: c.bgcolors.length ? c.bgcolors : void 0,
5362
5337
  barcolors: c.barcolors.length ? c.barcolors : void 0,
5363
5338
  alerts: c.alerts.length ? c.alerts : void 0
@@ -5369,6 +5344,7 @@ function executeScript(body, barsInput, inputs = {}, chart2 = {}) {
5369
5344
  }
5370
5345
  function indicator(title, options = {}) {
5371
5346
  const c = collector();
5347
+ declare(c, "indicator");
5372
5348
  c.title = title;
5373
5349
  c.shortTitle = options.shorttitle;
5374
5350
  c.overlay = options.overlay ?? true;
@@ -5381,6 +5357,21 @@ function indicator(title, options = {}) {
5381
5357
  polyline: options.max_polylines_count
5382
5358
  });
5383
5359
  }
5360
+ function declare(c, kind) {
5361
+ if (c.declaration) {
5362
+ throw new Error(`${kind}(): the script already declared ${c.declaration}(); a script has one declaration.`);
5363
+ }
5364
+ c.declaration = kind;
5365
+ }
5366
+ function common(opts) {
5367
+ const out = {};
5368
+ if (opts.group !== void 0) out.group = opts.group;
5369
+ if (opts.inline !== void 0) out.inline = opts.inline;
5370
+ if (opts.tooltip !== void 0) out.tooltip = opts.tooltip;
5371
+ if (opts.confirm !== void 0) out.confirm = opts.confirm;
5372
+ if (opts.display !== void 0) out.display = opts.display;
5373
+ return out;
5374
+ }
5384
5375
  function registerInput(config, fallbackId) {
5385
5376
  const c = collector();
5386
5377
  const id = slugId(config.title, fallbackId, c.inputIds);
@@ -5391,7 +5382,7 @@ function registerInput(config, fallbackId) {
5391
5382
  }
5392
5383
  function registerNumeric(type, defval, title, opts = {}) {
5393
5384
  const v = registerInput(
5394
- { type, defval, title, min: opts.minval, max: opts.maxval, step: opts.step },
5385
+ { type, defval, title, min: opts.minval, max: opts.maxval, step: opts.step, ...common(opts) },
5395
5386
  `input_${type}`
5396
5387
  );
5397
5388
  return typeof v === "number" ? v : defval;
@@ -5403,31 +5394,37 @@ var input = {
5403
5394
  float(defval, title, opts = {}) {
5404
5395
  return registerNumeric("float", defval, title, opts);
5405
5396
  },
5406
- bool(defval, title) {
5407
- return registerInput({ type: "bool", defval, title }, "input_bool");
5397
+ bool(defval, title, opts = {}) {
5398
+ return registerInput({ type: "bool", defval, title, ...common(opts) }, "input_bool");
5408
5399
  },
5409
5400
  string(defval, title, opts = {}) {
5410
- return registerInput({ type: "string", defval, title, options: opts.options }, "input_string");
5401
+ return registerInput({ type: "string", defval, title, options: opts.options, ...common(opts) }, "input_string");
5411
5402
  },
5412
- color(defval, title) {
5413
- return registerInput({ type: "color", defval, title }, "input_color");
5403
+ color(defval, title, opts = {}) {
5404
+ return registerInput({ type: "color", defval, title, ...common(opts) }, "input_color");
5414
5405
  },
5415
5406
  /** Declares a source input and returns it as a Series. */
5416
- source(defval = "close", title) {
5417
- const name = registerInput({ type: "source", defval, title }, "input_source");
5407
+ source(defval = "close", title, opts = {}) {
5408
+ const name = registerInput({ type: "source", defval, title, ...common(opts) }, "input_source");
5418
5409
  return sourceSeries(name);
5419
5410
  },
5420
5411
  /** Timeframe string ("60", "1D", "W"). As in PineScript, "" means the chart timeframe. */
5421
5412
  timeframe(defval, title, opts = {}) {
5422
- return registerInput({ type: "timeframe", defval, title, options: opts.options }, "input_timeframe");
5413
+ return registerInput(
5414
+ { type: "timeframe", defval, title, options: opts.options, ...common(opts) },
5415
+ "input_timeframe"
5416
+ );
5423
5417
  },
5424
5418
  /** Session string ("0930-1600", "0930-1600:23456"). */
5425
5419
  session(defval, title, opts = {}) {
5426
- return registerInput({ type: "session", defval, title, options: opts.options }, "input_session");
5420
+ return registerInput(
5421
+ { type: "session", defval, title, options: opts.options, ...common(opts) },
5422
+ "input_session"
5423
+ );
5427
5424
  },
5428
5425
  /** Date and time as a UNIX time in milliseconds, e.g. `input.time(timestamp('2024-01-01'), 'Start')`. */
5429
- time(defval, title) {
5430
- const v = registerInput({ type: "time", defval, title }, "input_time");
5426
+ time(defval, title, opts = {}) {
5427
+ const v = registerInput({ type: "time", defval, title, ...common(opts) }, "input_time");
5431
5428
  return typeof v === "number" ? v : defval;
5432
5429
  }
5433
5430
  };
@@ -5481,6 +5478,8 @@ var ta2 = {
5481
5478
  const a = anchor ?? changeOf("1D");
5482
5479
  return stdev_mult === void 0 ? vwap2(source, volume, a) : vwapBands(source, volume, a, stdev_mult);
5483
5480
  }),
5481
+ /** `ta.mfi(source, length)` with the chart volume (PineScript takes 2 arguments). */
5482
+ mfi: (source, length2) => mfi2(source, length2, volume),
5484
5483
  /** `ta.pivothigh(source, leftbars, rightbars)` or `ta.pivothigh(leftbars, rightbars)` (source = high).
5485
5484
  * The value appears `rightbars` bars after the pivot bar, as in PineScript. */
5486
5485
  pivothigh: (sourceOrLeft, leftOrRight, rightbars) => typeof sourceOrLeft === "number" ? pivothigh2(high, sourceOrLeft, leftOrRight) : pivothigh2(sourceOrLeft, leftOrRight, rightbars),
@@ -5507,7 +5506,7 @@ var color = {
5507
5506
  new: new_color,
5508
5507
  when: colorWhen
5509
5508
  };
5510
- function plot(series, title, options = {}) {
5509
+ function plotImpl(series, title, options = {}) {
5511
5510
  const c = collector();
5512
5511
  const id = `plot${c.plotConfig.length}`;
5513
5512
  const perBar2 = Array.isArray(options.color) ? options.color : void 0;
@@ -5518,6 +5517,7 @@ function plot(series, title, options = {}) {
5518
5517
  color: staticColor,
5519
5518
  lineWidth: options.linewidth,
5520
5519
  style: options.style,
5520
+ linestyle: options.linestyle,
5521
5521
  display: options.display,
5522
5522
  histbase: options.histbase
5523
5523
  });
@@ -5526,13 +5526,29 @@ function plot(series, title, options = {}) {
5526
5526
  const data = [];
5527
5527
  for (let i = 0; i < b2.length; i++) {
5528
5528
  const value = values[i];
5529
- if (value === void 0 || Number.isNaN(value)) continue;
5529
+ if (value === void 0 || !Number.isFinite(value)) continue;
5530
5530
  data.push(perBar2 ? { time: b2[i].time, value, color: perBar2[i] } : { time: b2[i].time, value });
5531
5531
  }
5532
5532
  c.plots[id] = data;
5533
5533
  return { id, kind: "plot" };
5534
5534
  }
5535
- function hline(price, title, options = {}) {
5535
+ var plot = Object.assign(plotImpl, {
5536
+ style_line: "line",
5537
+ style_linebr: "linebr",
5538
+ style_stepline: "stepline",
5539
+ style_steplinebr: "steplinebr",
5540
+ style_stepline_diamond: "stepline_diamond",
5541
+ style_histogram: "histogram",
5542
+ style_columns: "columns",
5543
+ style_area: "area",
5544
+ style_areabr: "areabr",
5545
+ style_circles: "circles",
5546
+ style_cross: "cross",
5547
+ linestyle_solid: "solid",
5548
+ linestyle_dotted: "dotted",
5549
+ linestyle_dashed: "dashed"
5550
+ });
5551
+ function hlineImpl(price, title, options = {}) {
5536
5552
  const c = collector();
5537
5553
  const id = `hline${c.hlineConfig.length}`;
5538
5554
  c.hlineConfig.push({
@@ -5540,11 +5556,16 @@ function hline(price, title, options = {}) {
5540
5556
  price,
5541
5557
  title,
5542
5558
  color: options.color,
5543
- linestyle: options.linestyle,
5559
+ linestyle: options.linestyle ?? "dashed",
5544
5560
  linewidth: options.linewidth
5545
5561
  });
5546
5562
  return { id, kind: "hline" };
5547
5563
  }
5564
+ var hline = Object.assign(hlineImpl, {
5565
+ style_solid: "solid",
5566
+ style_dotted: "dotted",
5567
+ style_dashed: "dashed"
5568
+ });
5548
5569
  function perBarValues(v, n) {
5549
5570
  return v instanceof Series ? v.toArray().slice(0, n) : new Array(n).fill(v);
5550
5571
  }
@@ -5647,6 +5668,35 @@ function plotshape(condition, title, options = {}) {
5647
5668
  function plotchar(condition, title, options = {}) {
5648
5669
  emitMarkers("char", condition, title, options);
5649
5670
  }
5671
+ function plotarrow(series, title, options = {}) {
5672
+ const c = collector();
5673
+ const id = `arrow${c.arrowConfig.length}`;
5674
+ const pick = (col2, fallback, i) => col2 === void 0 ? fallback : typeof col2 === "string" ? col2 : col2[i];
5675
+ const colorup = typeof options.colorup === "string" ? options.colorup : "#00FF00";
5676
+ const colordown = typeof options.colordown === "string" ? options.colordown : "#FF0000";
5677
+ c.arrowConfig.push({
5678
+ id,
5679
+ title,
5680
+ colorup,
5681
+ colordown,
5682
+ minheight: options.minheight ?? 5,
5683
+ maxheight: options.maxheight ?? 100,
5684
+ offset: options.offset,
5685
+ display: options.display
5686
+ });
5687
+ const values = series.toArray();
5688
+ const b2 = bars();
5689
+ const off = options.offset ?? 0;
5690
+ for (let i = 0; i < b2.length; i++) {
5691
+ const v = values[i];
5692
+ if (v === void 0 || Number.isNaN(v) || v === 0) continue;
5693
+ const j = i + off;
5694
+ if (j < 0 || j >= b2.length) continue;
5695
+ const color2 = v > 0 ? pick(options.colorup, "#00FF00", i) : pick(options.colordown, "#FF0000", i);
5696
+ if (color2 === void 0) continue;
5697
+ c.arrows.push({ time: b2[j].time, id, value: v, color: color2 });
5698
+ }
5699
+ }
5650
5700
  function emitBarColors(kind, colors, options) {
5651
5701
  const c = collector();
5652
5702
  const id = `${kind}${c.barColorConfig.filter((x) => x.kind === kind).length}`;
@@ -5723,6 +5773,139 @@ function eachBar(fn) {
5723
5773
  return Series.fromArray(ctxBars, out);
5724
5774
  }
5725
5775
  var currentBar = -1;
5776
+ function strategyRun(caller) {
5777
+ const run = collector().strategy;
5778
+ if (!run) throw new Error(`${caller}: declare the script with strategy() first.`);
5779
+ return run;
5780
+ }
5781
+ function strategyEngine(caller) {
5782
+ const run = strategyRun(caller);
5783
+ if (!run.engine) {
5784
+ throw new Error(
5785
+ `${caller}: no strategy engine; pass it as executeScript(body, bars, inputs, chart, { strategyEngine }).`
5786
+ );
5787
+ }
5788
+ return run.engine;
5789
+ }
5790
+ function orderEngine(caller) {
5791
+ const engine = strategyEngine(caller);
5792
+ if (!strategyRun(caller).inLoop) throw new Error(`${caller} must be called inside strategy.eachBar().`);
5793
+ return engine;
5794
+ }
5795
+ function given(options) {
5796
+ const out = {};
5797
+ for (const [key, value] of Object.entries(options)) {
5798
+ if (value === void 0 || typeof value === "number" && Number.isNaN(value)) continue;
5799
+ out[key] = value;
5800
+ }
5801
+ return out;
5802
+ }
5803
+ function strategyVariable(name) {
5804
+ const value = strategyEngine(`strategy.${name}`).get(name);
5805
+ if (value === void 0) throw new Error(`strategy.${name} is not provided by the strategy engine.`);
5806
+ return value;
5807
+ }
5808
+ function riskRule(rule) {
5809
+ const engine = strategyEngine(`strategy.risk.${rule.rule}()`);
5810
+ if (!engine.risk) throw new Error(`strategy.risk.${rule.rule}() is not provided by the strategy engine.`);
5811
+ engine.risk(rule);
5812
+ }
5813
+ function declareStrategy(title, options = {}) {
5814
+ const c = collector();
5815
+ declare(c, "strategy");
5816
+ c.title = title;
5817
+ c.shortTitle = options.shorttitle;
5818
+ c.overlay = options.overlay ?? false;
5819
+ c.precision = options.precision;
5820
+ c.format = options.format;
5821
+ setDrawingLimits({
5822
+ line: options.max_lines_count,
5823
+ label: options.max_labels_count,
5824
+ box: options.max_boxes_count,
5825
+ polyline: options.max_polylines_count
5826
+ });
5827
+ const properties = { ...STRATEGY_DEFAULTS };
5828
+ const target = properties;
5829
+ for (const key of [...Object.keys(STRATEGY_DEFAULTS), "currency"]) {
5830
+ const value = options[key];
5831
+ if (value !== void 0) target[key] = value;
5832
+ }
5833
+ const factory = scriptOptions.strategyEngine;
5834
+ c.strategy = {
5835
+ properties,
5836
+ engine: factory?.({ properties, bars: ctxBars.bars, chart: chartCtx }),
5837
+ looped: false,
5838
+ inLoop: false
5839
+ };
5840
+ }
5841
+ function strategyEachBar(fn) {
5842
+ const run = strategyRun("strategy.eachBar()");
5843
+ const engine = strategyEngine("strategy.eachBar()");
5844
+ if (run.looped) throw new Error("strategy.eachBar() runs once per script run.");
5845
+ run.looped = true;
5846
+ return eachBar((c) => {
5847
+ engine.processBar(c.i);
5848
+ run.inLoop = true;
5849
+ try {
5850
+ return fn(c);
5851
+ } finally {
5852
+ run.inLoop = false;
5853
+ engine.processClose(c.i);
5854
+ }
5855
+ });
5856
+ }
5857
+ var strategyMembers = {
5858
+ ...STRATEGY_CONSTANTS,
5859
+ eachBar: strategyEachBar,
5860
+ entry(id, direction, options = {}) {
5861
+ orderEngine("strategy.entry()").entry(id, direction, given(options));
5862
+ },
5863
+ order(id, direction, options = {}) {
5864
+ orderEngine("strategy.order()").order(id, direction, given(options));
5865
+ },
5866
+ exit(id, options = {}) {
5867
+ orderEngine("strategy.exit()").exit(id, given(options));
5868
+ },
5869
+ close(id, options = {}) {
5870
+ orderEngine("strategy.close()").close(id, given(options));
5871
+ },
5872
+ close_all(options = {}) {
5873
+ orderEngine("strategy.close_all()").close_all(given(options));
5874
+ },
5875
+ cancel(id) {
5876
+ orderEngine("strategy.cancel()").cancel(id);
5877
+ },
5878
+ cancel_all() {
5879
+ orderEngine("strategy.cancel_all()").cancel_all();
5880
+ },
5881
+ opentrade(index) {
5882
+ return strategyEngine("strategy.opentrade()").openTrade(index);
5883
+ },
5884
+ closedtrade(index) {
5885
+ return strategyEngine("strategy.closedtrade()").closedTrade(index);
5886
+ },
5887
+ default_entry_qty(fill_price) {
5888
+ const engine = strategyEngine("strategy.default_entry_qty()");
5889
+ if (!engine.defaultEntryQty) throw new Error("strategy.default_entry_qty() is not provided by the strategy engine.");
5890
+ return engine.defaultEntryQty(fill_price);
5891
+ },
5892
+ risk: {
5893
+ allow_entry_in: (direction) => riskRule({ rule: "allow_entry_in", direction }),
5894
+ max_cons_loss_days: (count, alert_message) => riskRule(given({ rule: "max_cons_loss_days", count, alert_message })),
5895
+ max_drawdown: (value, type, alert_message) => riskRule(given({ rule: "max_drawdown", value, type, alert_message })),
5896
+ max_intraday_filled_orders: (count, alert_message) => riskRule(given({ rule: "max_intraday_filled_orders", count, alert_message })),
5897
+ max_intraday_loss: (value, type, alert_message) => riskRule(given({ rule: "max_intraday_loss", value, type, alert_message })),
5898
+ max_position_size: (contracts) => riskRule({ rule: "max_position_size", contracts })
5899
+ }
5900
+ };
5901
+ var variableGetters = {};
5902
+ for (const name of [...STRATEGY_NUMBER_VARIABLES, ...STRATEGY_TEXT_VARIABLES]) {
5903
+ variableGetters[name] = { get: () => strategyVariable(name), enumerable: true };
5904
+ }
5905
+ var strategy = Object.defineProperties(
5906
+ Object.assign((title, options) => declareStrategy(title, options), strategyMembers),
5907
+ variableGetters
5908
+ );
5726
5909
  var chartCtx = {};
5727
5910
  function chartTimeframe() {
5728
5911
  collector();
@@ -5782,7 +5965,24 @@ var timeframe = {
5782
5965
  return in_seconds(tf === void 0 || tf === "" ? chartTimeframe().period : tf);
5783
5966
  }
5784
5967
  };
5968
+ function symbolProperty(key) {
5969
+ collector();
5970
+ const value = chartCtx[key];
5971
+ if (value === void 0) {
5972
+ throw new Error(`syminfo.${key} is not known: pass it as executeScript(body, bars, inputs, { ${key} }).`);
5973
+ }
5974
+ return value;
5975
+ }
5785
5976
  var syminfo = {
5977
+ get mintick() {
5978
+ return symbolProperty("mintick");
5979
+ },
5980
+ get pointvalue() {
5981
+ return symbolProperty("pointvalue");
5982
+ },
5983
+ get mincontract() {
5984
+ return symbolProperty("mincontract");
5985
+ },
5786
5986
  get timezone() {
5787
5987
  return exchangeTimezone();
5788
5988
  },
@@ -5898,6 +6098,37 @@ function flag(key) {
5898
6098
  const values = sessionFlags(ctxBars.bars.map(barTime), bars2, regular)[key];
5899
6099
  return Series.fromArray(ctxBars, values.map((v) => v ? 1 : 0));
5900
6100
  }
6101
+ function barFlag(test) {
6102
+ const n = ctxBars.bars.length;
6103
+ return Series.fromArray(ctxBars, Array.from({ length: n }, (_, i) => test(i, n) ? 1 : 0));
6104
+ }
6105
+ var lastRealtime = (i, n) => i === n - 1 && chartCtx.realtime === true;
6106
+ var barstate = {
6107
+ get isfirst() {
6108
+ return barFlag((i) => i === 0);
6109
+ },
6110
+ get islast() {
6111
+ return barFlag((i, n) => i === n - 1);
6112
+ },
6113
+ get isconfirmed() {
6114
+ return barFlag((i, n) => i < n - 1 || chartCtx.lastBarConfirmed === true);
6115
+ },
6116
+ get isrealtime() {
6117
+ return barFlag(lastRealtime);
6118
+ },
6119
+ get ishistory() {
6120
+ return barFlag((i, n) => !lastRealtime(i, n));
6121
+ },
6122
+ get isnew() {
6123
+ return barFlag((i, n) => !lastRealtime(i, n) || chartCtx.lastBarNew !== false);
6124
+ },
6125
+ get islastconfirmedhistory() {
6126
+ return barFlag((i, n) => {
6127
+ const lastConfirmed = chartCtx.lastBarConfirmed === true && chartCtx.realtime !== true;
6128
+ return i === (lastConfirmed ? n - 1 : n - 2);
6129
+ });
6130
+ }
6131
+ };
5901
6132
  var session = {
5902
6133
  regular: "regular",
5903
6134
  extended: "extended",
@@ -6051,12 +6282,21 @@ function alertcondition(condition, title, message) {
6051
6282
  const last = condition.length() ? condition.last() : NaN;
6052
6283
  c.alerts.push({ id, title, message, triggered: !isNA(last) && last !== 0 });
6053
6284
  }
6285
+ var math = {
6286
+ ...math_exports,
6287
+ round_to_mintick: ((number2, mintick) => {
6288
+ const tick = mintick ?? syminfo.mintick;
6289
+ return number2 instanceof Series ? round_to_mintick(number2, tick) : round_to_mintick(number2, tick);
6290
+ })
6291
+ };
6054
6292
  export {
6055
6293
  BarData,
6294
+ STRATEGY_DEFAULTS,
6056
6295
  Series,
6057
6296
  alertcondition,
6058
6297
  barcolor,
6059
6298
  barmerge,
6299
+ barstate,
6060
6300
  bgcolor,
6061
6301
  box,
6062
6302
  chart,
@@ -6082,7 +6322,7 @@ export {
6082
6322
  line,
6083
6323
  linefill,
6084
6324
  low,
6085
- math_exports as math,
6325
+ math,
6086
6326
  minute2 as minute,
6087
6327
  month2 as month,
6088
6328
  isNA as na,
@@ -6090,6 +6330,7 @@ export {
6090
6330
  ohlc4,
6091
6331
  open,
6092
6332
  plot,
6333
+ plotarrow,
6093
6334
  plotchar,
6094
6335
  plotshape,
6095
6336
  polyline,
@@ -6098,6 +6339,7 @@ export {
6098
6339
  seriesOf,
6099
6340
  session,
6100
6341
  str,
6342
+ strategy,
6101
6343
  syminfo,
6102
6344
  ta2 as ta,
6103
6345
  text,