oakscriptjs 0.8.0 → 0.8.2

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
  /**
@@ -625,26 +625,86 @@ __export(ta_series_exports, {
625
625
  zigzag: () => zigzag2
626
626
  });
627
627
 
628
- // src/ta/index.ts
629
- function sma(source, length2) {
630
- const result = [];
628
+ // src/ta/running-sum.ts
629
+ var view = new DataView(new ArrayBuffer(8));
630
+ function exponentOf(x) {
631
+ view.setFloat64(0, x);
632
+ const e2 = view.getUint16(0) >> 4 & 2047;
633
+ return e2 === 0 ? -1074 : e2 - 1023;
634
+ }
635
+ function compensationLost(x, c) {
636
+ if (c === 0 || x === 0) return false;
637
+ const ulp = 2 ** (exponentOf(x) - 52);
638
+ const q = c / ulp;
639
+ const mantissa = x / ulp;
640
+ const f = Math.floor(q);
641
+ const d = q - f;
642
+ const applied = d > 0.5 ? f + 1 : d < 0.5 ? f : (mantissa - f) % 2 === 0 ? f : f + 1;
643
+ return Math.abs(applied) < Math.abs(q);
644
+ }
645
+ function isNa(v) {
646
+ return v === void 0 || v === null || !Number.isFinite(v);
647
+ }
648
+ function runningSum(source, length2) {
631
649
  const len = Math.floor(length2);
632
- const window = [];
650
+ const out = new Array(source.length).fill(NaN);
651
+ if (!(len >= 1)) return out;
652
+ const values = [];
653
+ const stored = [];
654
+ let s = 0;
655
+ let c = 0;
656
+ let previous = NaN;
657
+ const kahanAdd = (v) => {
658
+ const y = v - c;
659
+ const t2 = s + y;
660
+ c = t2 - s - y;
661
+ s = t2;
662
+ return y;
663
+ };
633
664
  for (let i = 0; i < source.length; i++) {
634
665
  const v = source[i];
635
- if (v !== void 0 && v !== null && !Number.isNaN(v)) {
636
- window.push(v);
637
- if (window.length > len) window.shift();
666
+ if (isNa(v)) {
667
+ out[i] = previous;
668
+ continue;
638
669
  }
639
- if (window.length < len) {
640
- result.push(NaN);
670
+ const x = v;
671
+ const c0 = c;
672
+ const n = values.length;
673
+ if (n >= len) kahanAdd(-stored[n - len]);
674
+ values.push(x);
675
+ if (compensationLost(x, c0)) {
676
+ let fresh = 0;
677
+ for (let k = values.length - 1; k >= Math.max(0, values.length - len); k--) fresh += values[k];
678
+ s = fresh;
679
+ c = 0;
680
+ stored.push(x);
641
681
  } else {
642
- let sum2 = 0;
643
- for (const x of window) sum2 += x;
644
- result.push(sum2 / len);
682
+ stored.push(kahanAdd(x));
645
683
  }
684
+ previous = values.length >= len ? s : NaN;
685
+ out[i] = previous;
646
686
  }
647
- return result;
687
+ return out;
688
+ }
689
+ function runningVariance(source, length2, biased) {
690
+ const len = Math.floor(length2);
691
+ const squares = Array.from({ length: source.length }, (_, i) => {
692
+ const v = source[i];
693
+ return isNa(v) ? NaN : v * v;
694
+ });
695
+ const sums = runningSum(source, len);
696
+ const sumSquares = runningSum(squares, len);
697
+ return sums.map((sum2, i) => {
698
+ const mean = sum2 / len;
699
+ const sq = sumSquares[i];
700
+ return biased ? sq / len - mean * mean : sq / (len - 1) - mean * sum2 / (len - 1);
701
+ });
702
+ }
703
+
704
+ // src/ta/index.ts
705
+ function sma(source, length2) {
706
+ const len = Math.floor(length2);
707
+ return runningSum(source, len).map((sum2) => sum2 / len);
648
708
  }
649
709
  function strictWindowMean(source, length2) {
650
710
  const len = Math.floor(length2);
@@ -664,7 +724,7 @@ function ema(source, length2) {
664
724
  let initSum = 0;
665
725
  for (let i = 0; i < source.length; i++) {
666
726
  const val = source[i];
667
- if (val !== void 0 && !isNaN(val)) {
727
+ if (val !== void 0 && Number.isFinite(val)) {
668
728
  initSum += val;
669
729
  validCount++;
670
730
  if (validCount === len) {
@@ -682,7 +742,7 @@ function ema(source, length2) {
682
742
  result.push(emaValue);
683
743
  } else {
684
744
  const val = source[i];
685
- if (val !== void 0 && !isNaN(val)) {
745
+ if (val !== void 0 && Number.isFinite(val)) {
686
746
  emaValue = (val - emaValue) * multiplier + emaValue;
687
747
  result.push(emaValue);
688
748
  } else {
@@ -739,14 +799,7 @@ function bb(series, length2, mult) {
739
799
  return [basis, upper2, lower2];
740
800
  }
741
801
  function stdev(source, length2, biased = true) {
742
- const len = Math.floor(length2);
743
- return source.map((_, i) => {
744
- const values = lastValues(source, i, len);
745
- if (!values) return NaN;
746
- const mean = values.reduce((a, b2) => a + b2, 0) / len;
747
- const squares = values.reduce((a, b2) => a + (b2 - mean) * (b2 - mean), 0);
748
- return Math.sqrt(squares / (biased ? len : len - 1));
749
- });
802
+ return variance(source, length2, biased).map((v) => Number.isNaN(v) ? NaN : v > 0 ? Math.sqrt(v) : 0);
750
803
  }
751
804
  function lastValues(source, i, length2) {
752
805
  const values = [];
@@ -900,13 +953,12 @@ function supertrend(factor, atrPeriod, high2, low2, close2, wicks = false) {
900
953
  function rma(source, length2) {
901
954
  const result = [];
902
955
  const len = Math.floor(length2);
903
- const alpha = 1 / len;
904
956
  let firstValidIndex = -1;
905
957
  let validCount = 0;
906
958
  let initSum = 0;
907
959
  for (let i = 0; i < source.length; i++) {
908
960
  const val = source[i];
909
- if (val !== void 0 && !isNaN(val)) {
961
+ if (val !== void 0 && Number.isFinite(val)) {
910
962
  initSum += val;
911
963
  validCount++;
912
964
  if (validCount === len) {
@@ -924,8 +976,8 @@ function rma(source, length2) {
924
976
  result.push(rmaValue);
925
977
  } else {
926
978
  const val = source[i];
927
- if (val !== void 0 && !isNaN(val)) {
928
- rmaValue = alpha * val + (1 - alpha) * rmaValue;
979
+ if (val !== void 0 && Number.isFinite(val)) {
980
+ rmaValue = (val + (len - 1) * rmaValue) / len;
929
981
  result.push(rmaValue);
930
982
  } else {
931
983
  result.push(NaN);
@@ -939,18 +991,22 @@ function wma(source, length2) {
939
991
  const len = Math.floor(length2);
940
992
  const filled = [];
941
993
  let last = NaN;
994
+ let count = 0;
942
995
  for (let i = 0; i < source.length; i++) {
943
996
  const v = source[i];
944
- const isNa = v === void 0 || v === null || Number.isNaN(v);
945
- if (!isNa) last = v;
997
+ const isNa2 = v === void 0 || v === null || !Number.isFinite(v);
998
+ if (!isNa2) {
999
+ last = v;
1000
+ count++;
1001
+ }
946
1002
  filled.push(last);
947
- if (isNa || i < len - 1) {
1003
+ if (isNa2 || count < len) {
948
1004
  result.push(NaN);
949
1005
  continue;
950
1006
  }
951
1007
  let sum2 = 0;
952
1008
  let weightSum = 0;
953
- for (let j = 0; j < len; j++) {
1009
+ for (let j = len - 1; j >= 0; j--) {
954
1010
  const weight = len - j;
955
1011
  sum2 += filled[i - j] * weight;
956
1012
  weightSum += weight;
@@ -976,7 +1032,7 @@ function lowest(source, length2) {
976
1032
  function cum(source) {
977
1033
  let sum2 = 0;
978
1034
  return source.map((v) => {
979
- if (Number.isNaN(v)) return NaN;
1035
+ if (!Number.isFinite(v)) return NaN;
980
1036
  sum2 += v;
981
1037
  return sum2;
982
1038
  });
@@ -994,41 +1050,24 @@ function cross(source1, source2) {
994
1050
  }
995
1051
  return result;
996
1052
  }
997
- function rising(source, length2) {
1053
+ function monotonic(source, length2, step) {
998
1054
  const result = [];
1055
+ const values = [];
999
1056
  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
- }
1057
+ const v = source[i];
1058
+ if (!Number.isNaN(v)) values.push(v);
1059
+ const n = values.length;
1060
+ let ok = n > length2;
1061
+ for (let j = 1; ok && j <= length2; j++) ok = step(values[n - j], values[n - j - 1]);
1062
+ result.push(ok);
1012
1063
  }
1013
1064
  return result;
1014
1065
  }
1066
+ function rising(source, length2) {
1067
+ return monotonic(source, length2, gt);
1068
+ }
1015
1069
  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;
1070
+ return monotonic(source, length2, lt);
1032
1071
  }
1033
1072
  function roc(source, length2) {
1034
1073
  const result = [];
@@ -1081,53 +1120,19 @@ function dev(source, length2) {
1081
1120
  return result;
1082
1121
  }
1083
1122
  function variance(source, length2, biased = true) {
1084
- const result = [];
1085
1123
  const len = Math.floor(length2);
1086
- const window = [];
1087
- for (let i = 0; i < source.length; i++) {
1088
- const v = source[i];
1089
- if (v !== void 0 && v !== null && !Number.isNaN(v)) {
1090
- window.push(v);
1091
- if (window.length > len) window.shift();
1092
- }
1093
- const divisor = biased ? len : len - 1;
1094
- if (window.length < len || divisor <= 0) {
1095
- result.push(NaN);
1096
- continue;
1097
- }
1098
- const mean = window.reduce((a, x) => a + x, 0) / len;
1099
- let sumSquares = 0;
1100
- for (const x of window) sumSquares += (x - mean) * (x - mean);
1101
- result.push(sumSquares / divisor);
1102
- }
1103
- return result;
1124
+ if ((biased ? len : len - 1) <= 0) return source.map(() => NaN);
1125
+ return runningVariance(source, len, biased);
1104
1126
  }
1105
1127
  function median(source, length2) {
1106
- const result = [];
1107
- for (let i = 0; i < source.length; i++) {
1108
- if (i < length2 - 1) {
1109
- result.push(NaN);
1110
- } else {
1111
- const values = [];
1112
- for (let j = 0; j < length2; j++) {
1113
- if (!isNaN(source[i - j])) {
1114
- values.push(source[i - j]);
1115
- }
1116
- }
1117
- if (values.length === 0) {
1118
- result.push(NaN);
1119
- } else {
1120
- values.sort((a, b2) => a - b2);
1121
- const mid = Math.floor(values.length / 2);
1122
- if (values.length % 2 === 0) {
1123
- result.push((values[mid - 1] + values[mid]) / 2);
1124
- } else {
1125
- result.push(values[mid]);
1126
- }
1127
- }
1128
- }
1129
- }
1130
- return result;
1128
+ const len = Math.floor(length2);
1129
+ return source.map((_, i) => {
1130
+ const values = lastValues(source, i, len);
1131
+ if (!values) return NaN;
1132
+ values.sort((a, b2) => a - b2);
1133
+ const mid = Math.floor(len / 2);
1134
+ return len % 2 === 0 ? (values[mid - 1] + values[mid]) / 2 : values[mid];
1135
+ });
1131
1136
  }
1132
1137
  function swma(source) {
1133
1138
  const result = [];
@@ -1252,33 +1257,16 @@ function correlation(source1, source2, length2) {
1252
1257
  function percentrank(source, length2) {
1253
1258
  const result = [];
1254
1259
  for (let i = 0; i < source.length; i++) {
1255
- if (i < length2) {
1260
+ const currentValue = source[i];
1261
+ if (i < length2 || Number.isNaN(currentValue)) {
1256
1262
  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
- }
1263
+ continue;
1264
+ }
1265
+ let countLessOrEqual = 0;
1266
+ for (let j = 1; j <= length2; j++) {
1267
+ if (le(source[i - j], currentValue)) countLessOrEqual++;
1281
1268
  }
1269
+ result.push(countLessOrEqual / length2 * 100);
1282
1270
  }
1283
1271
  return result;
1284
1272
  }
@@ -1329,12 +1317,8 @@ function mfi(source, length2, volume2) {
1329
1317
  upperFlow.push(le(change3, 0) ? 0 : flow);
1330
1318
  lowerFlow.push(ge(change3, 0) ? 0 : flow);
1331
1319
  }
1332
- const sumAt = (flow, i) => {
1333
- const values = lastValues(flow, i, Math.floor(length2));
1334
- return values ? values.reduce((a, b2) => a + b2, 0) : NaN;
1335
- };
1336
- const upper2 = upperFlow.map((_, i) => sumAt(upperFlow, i));
1337
- const lower2 = lowerFlow.map((_, i) => sumAt(lowerFlow, i));
1320
+ const upper2 = runningSum(upperFlow, length2);
1321
+ const lower2 = runningSum(lowerFlow, length2);
1338
1322
  return upper2.map((u, i) => {
1339
1323
  const l = lower2[i];
1340
1324
  if (Number.isNaN(u) || Number.isNaN(l)) return NaN;
@@ -1805,63 +1789,36 @@ function mode(source, length2) {
1805
1789
  return result;
1806
1790
  }
1807
1791
  function percentile_linear_interpolation(source, length2, percentage) {
1792
+ return sortedWindow(source, length2, (s) => {
1793
+ const pos2 = percentage / 100 * length2 - 0.5;
1794
+ if (pos2 <= 0) return s[0];
1795
+ if (pos2 >= length2 - 1) return s[length2 - 1];
1796
+ const lo = Math.floor(pos2);
1797
+ return s[lo] + (pos2 - lo) * (s[lo + 1] - s[lo]);
1798
+ });
1799
+ }
1800
+ function sortedWindow(source, length2, fn) {
1808
1801
  const result = [];
1802
+ const values = [];
1803
+ const bars2 = [];
1809
1804
  for (let i = 0; i < source.length; i++) {
1810
- if (i < length2 - 1) {
1811
- result.push(NaN);
1812
- continue;
1813
- }
1814
- const values = [];
1815
- for (let j = 0; j < length2; j++) {
1816
- const value = source[i - j];
1817
- values.push(value);
1818
- }
1819
- if (values.some((v) => isNaN(v))) {
1820
- result.push(NaN);
1821
- continue;
1822
- }
1823
- const sorted = [...values].sort((a, b2) => a - b2);
1824
- const position = percentage / 100 * (sorted.length - 1);
1825
- const lowerIndex = Math.floor(position);
1826
- const upperIndex = Math.ceil(position);
1827
- if (lowerIndex === upperIndex) {
1828
- result.push(sorted[lowerIndex]);
1829
- } else {
1830
- const fraction = position - lowerIndex;
1831
- const interpolated = sorted[lowerIndex] + fraction * (sorted[upperIndex] - sorted[lowerIndex]);
1832
- result.push(interpolated);
1805
+ const v = source[i];
1806
+ let k = 0;
1807
+ while (k < values.length && !(values[k] >= v)) k++;
1808
+ values.splice(k, 0, v);
1809
+ bars2.splice(k, 0, i);
1810
+ if (i >= length2) {
1811
+ const old = bars2.indexOf(i - length2);
1812
+ values.splice(old, 1);
1813
+ bars2.splice(old, 1);
1833
1814
  }
1815
+ result.push(i < length2 - 1 ? NaN : fn(values));
1834
1816
  }
1835
1817
  return result;
1836
1818
  }
1837
1819
  function percentile_nearest_rank(source, length2, percentage) {
1838
- const result = [];
1839
- for (let i = 0; i < source.length; i++) {
1840
- if (i < length2 - 1) {
1841
- result.push(NaN);
1842
- continue;
1843
- }
1844
- const values = [];
1845
- for (let j = 0; j < length2; j++) {
1846
- const value = source[i - j];
1847
- if (!isNaN(value)) {
1848
- values.push(value);
1849
- }
1850
- }
1851
- if (values.length === 0) {
1852
- result.push(NaN);
1853
- continue;
1854
- }
1855
- const sorted = [...values].sort((a, b2) => a - b2);
1856
- if (percentage >= 100) {
1857
- result.push(sorted[sorted.length - 1]);
1858
- continue;
1859
- }
1860
- const rank = Math.ceil(percentage / 100 * sorted.length);
1861
- const index = Math.max(0, rank - 1);
1862
- result.push(sorted[index]);
1863
- }
1864
- return result;
1820
+ const rank = Math.min(length2, Math.max(1, Math.ceil(percentage / 100 * length2)));
1821
+ return sortedWindow(source, length2, (s) => s[rank - 1]);
1865
1822
  }
1866
1823
  function rci(source, length2) {
1867
1824
  const result = [];
@@ -2727,11 +2684,13 @@ __export(color_exports, {
2727
2684
  white: () => white,
2728
2685
  yellow: () => yellow
2729
2686
  });
2687
+ var channel = (v) => v === null || v === void 0 || Number.isNaN(v) ? 0 : Math.max(0, Math.min(255, Math.trunc(v)));
2688
+ var alphaOf = (transp) => transp === null || Number.isNaN(transp) ? 0 : 1 - Math.max(0, Math.min(100, transp)) / 100;
2730
2689
  function rgb(red2, green2, blue2, transp) {
2731
- const r2 = Math.max(0, Math.min(255, red2));
2732
- const g2 = Math.max(0, Math.min(255, green2));
2733
- const b2 = Math.max(0, Math.min(255, blue2));
2734
- const a = transp !== void 0 ? 1 - transp / 100 : 1;
2690
+ const r2 = channel(red2);
2691
+ const g2 = channel(green2);
2692
+ const b2 = channel(blue2);
2693
+ const a = transp !== void 0 ? alphaOf(transp) : 1;
2735
2694
  if (a === 1) {
2736
2695
  return `rgb(${r2}, ${g2}, ${b2})`;
2737
2696
  }
@@ -2758,7 +2717,8 @@ function b(clr) {
2758
2717
  return parseColor(clr).b;
2759
2718
  }
2760
2719
  function t(clr) {
2761
- return parseColor(clr).t;
2720
+ const alpha = Math.round((1 - parseColor(clr).t / 100) * 255);
2721
+ return Math.round((1 - alpha / 255) * 100);
2762
2722
  }
2763
2723
  function parseColor(clr) {
2764
2724
  if (typeof clr === "string") {
@@ -2811,13 +2771,12 @@ function from_gradient(value, bottom_value, top_value, bottom_color, top_color)
2811
2771
  };
2812
2772
  const c1 = rgba(bottom_color);
2813
2773
  const c2 = rgba(top_color);
2814
- const w1 = c1.a * (1 - k);
2815
- const w2 = c2.a * k;
2816
- const a = w1 + w2;
2774
+ const a = c1.a * (1 - k) + c2.a * k;
2817
2775
  if (a === 0) return transparent;
2818
- const mix = (x1, x2) => Math.floor((x1 * w1 + x2 * w2) / a);
2776
+ const mix = (x1, x2) => Math.floor((x1 / 255 * c1.a * (1 - k) + x2 / 255 * c2.a * k) / (a / 255));
2819
2777
  const [r2, g2, b2] = [mix(c1.r, c2.r), mix(c1.g, c2.g), mix(c1.b, c2.b)];
2820
- return a === 255 ? `rgb(${r2}, ${g2}, ${b2})` : `rgba(${r2}, ${g2}, ${b2}, ${a / 255})`;
2778
+ const alpha = Math.floor(a);
2779
+ return alpha === 255 ? `rgb(${r2}, ${g2}, ${b2})` : `rgba(${r2}, ${g2}, ${b2}, ${alpha / 255})`;
2821
2780
  }
2822
2781
 
2823
2782
  // src/drawing/registry.ts
@@ -2881,7 +2840,7 @@ function setDrawingLimits(newLimits) {
2881
2840
 
2882
2841
  // src/utils/index.ts
2883
2842
  function isNA(value) {
2884
- return value === null || value === void 0 || Number.isNaN(value) || isDeleted(value);
2843
+ return value === null || value === void 0 || Number.isNaN(value) || value === Infinity || value === -Infinity || isDeleted(value);
2885
2844
  }
2886
2845
  function nz(value, defaultValue = 0) {
2887
2846
  return isNA(value) ? defaultValue : value;
@@ -2890,7 +2849,7 @@ function fixnan(source) {
2890
2849
  let last;
2891
2850
  let seen = false;
2892
2851
  return source.map((v) => {
2893
- if (!isNA(v)) {
2852
+ if (!(v === null || v === void 0 || Number.isNaN(v) || isDeleted(v))) {
2894
2853
  last = v;
2895
2854
  seen = true;
2896
2855
  return v;
@@ -3777,23 +3736,7 @@ function avg(...values) {
3777
3736
  }
3778
3737
  function sum(source, length2) {
3779
3738
  const sourceArray = source instanceof Series ? source.toArray() : source;
3780
- const result = [];
3781
- const len = Math.floor(length2);
3782
- const window = [];
3783
- for (let i = 0; i < sourceArray.length; i++) {
3784
- const v = sourceArray[i];
3785
- if (v !== void 0 && v !== null && !Number.isNaN(v)) {
3786
- window.push(v);
3787
- if (window.length > len) window.shift();
3788
- }
3789
- if (window.length < len) {
3790
- result.push(NaN);
3791
- } else {
3792
- let total = 0;
3793
- for (const x of window) total += x;
3794
- result.push(total);
3795
- }
3796
- }
3739
+ const result = runningSum(sourceArray, length2);
3797
3740
  if (source instanceof Series) {
3798
3741
  return Series.fromArray(source.bars, result);
3799
3742
  }
@@ -4469,9 +4412,9 @@ function shortestDigits(x) {
4469
4412
  function exactDigits(x) {
4470
4413
  const abs2 = Math.abs(x);
4471
4414
  if (abs2 === 0) return { digits: "", intLen: 0 };
4472
- const view = new DataView(new ArrayBuffer(8));
4473
- view.setFloat64(0, abs2);
4474
- const bits = view.getBigUint64(0);
4415
+ const view2 = new DataView(new ArrayBuffer(8));
4416
+ view2.setFloat64(0, abs2);
4417
+ const bits = view2.getBigUint64(0);
4475
4418
  const expBits = Number(bits >> 52n & 0x7ffn);
4476
4419
  let mant = bits & 0xfffffffffffffn;
4477
4420
  const e2 = expBits === 0 ? -1074 : expBits - 1075;
@@ -5265,9 +5208,10 @@ var STRATEGY_DEFAULTS = {
5265
5208
  calc_on_order_fills: false,
5266
5209
  calc_on_every_tick: false,
5267
5210
  backtest_fill_limits_assumption: 0,
5268
- default_qty_type: "fixed",
5269
- default_qty_value: 1,
5270
- initial_capital: 1e6,
5211
+ // v6 values; PineScript v5: fixed / 1 / 1000000 and margins 0
5212
+ default_qty_type: "percent_of_equity",
5213
+ default_qty_value: 100,
5214
+ initial_capital: 1e5,
5271
5215
  slippage: 0,
5272
5216
  commission_type: "percent",
5273
5217
  commission_value: 0,
@@ -5341,6 +5285,8 @@ function freshCollector(inputValues) {
5341
5285
  fillConfig: [],
5342
5286
  shapeConfig: [],
5343
5287
  markers: [],
5288
+ arrowConfig: [],
5289
+ arrows: [],
5344
5290
  barColorConfig: [],
5345
5291
  bgcolors: [],
5346
5292
  barcolors: [],
@@ -5378,6 +5324,7 @@ function executeScript(body, barsInput, inputs = {}, chart2 = {}, options = {})
5378
5324
  hlineConfig: c.hlineConfig,
5379
5325
  fillConfig: c.fillConfig,
5380
5326
  shapeConfig: c.shapeConfig,
5327
+ arrowConfig: c.arrowConfig,
5381
5328
  barColorConfig: c.barColorConfig,
5382
5329
  defaultInputs: c.defaultInputs,
5383
5330
  alertConfig: c.alertConfig,
@@ -5387,6 +5334,7 @@ function executeScript(body, barsInput, inputs = {}, chart2 = {}, options = {})
5387
5334
  plots: c.plots,
5388
5335
  fills: c.fills.length ? c.fills : void 0,
5389
5336
  markers: c.markers.length ? c.markers : void 0,
5337
+ arrows: c.arrows.length ? c.arrows : void 0,
5390
5338
  bgcolors: c.bgcolors.length ? c.bgcolors : void 0,
5391
5339
  barcolors: c.barcolors.length ? c.barcolors : void 0,
5392
5340
  alerts: c.alerts.length ? c.alerts : void 0
@@ -5417,6 +5365,15 @@ function declare(c, kind) {
5417
5365
  }
5418
5366
  c.declaration = kind;
5419
5367
  }
5368
+ function common(opts) {
5369
+ const out = {};
5370
+ if (opts.group !== void 0) out.group = opts.group;
5371
+ if (opts.inline !== void 0) out.inline = opts.inline;
5372
+ if (opts.tooltip !== void 0) out.tooltip = opts.tooltip;
5373
+ if (opts.confirm !== void 0) out.confirm = opts.confirm;
5374
+ if (opts.display !== void 0) out.display = opts.display;
5375
+ return out;
5376
+ }
5420
5377
  function registerInput(config, fallbackId) {
5421
5378
  const c = collector();
5422
5379
  const id = slugId(config.title, fallbackId, c.inputIds);
@@ -5427,7 +5384,7 @@ function registerInput(config, fallbackId) {
5427
5384
  }
5428
5385
  function registerNumeric(type, defval, title, opts = {}) {
5429
5386
  const v = registerInput(
5430
- { type, defval, title, min: opts.minval, max: opts.maxval, step: opts.step },
5387
+ { type, defval, title, min: opts.minval, max: opts.maxval, step: opts.step, ...common(opts) },
5431
5388
  `input_${type}`
5432
5389
  );
5433
5390
  return typeof v === "number" ? v : defval;
@@ -5439,31 +5396,37 @@ var input = {
5439
5396
  float(defval, title, opts = {}) {
5440
5397
  return registerNumeric("float", defval, title, opts);
5441
5398
  },
5442
- bool(defval, title) {
5443
- return registerInput({ type: "bool", defval, title }, "input_bool");
5399
+ bool(defval, title, opts = {}) {
5400
+ return registerInput({ type: "bool", defval, title, ...common(opts) }, "input_bool");
5444
5401
  },
5445
5402
  string(defval, title, opts = {}) {
5446
- return registerInput({ type: "string", defval, title, options: opts.options }, "input_string");
5403
+ return registerInput({ type: "string", defval, title, options: opts.options, ...common(opts) }, "input_string");
5447
5404
  },
5448
- color(defval, title) {
5449
- return registerInput({ type: "color", defval, title }, "input_color");
5405
+ color(defval, title, opts = {}) {
5406
+ return registerInput({ type: "color", defval, title, ...common(opts) }, "input_color");
5450
5407
  },
5451
5408
  /** Declares a source input and returns it as a Series. */
5452
- source(defval = "close", title) {
5453
- const name = registerInput({ type: "source", defval, title }, "input_source");
5409
+ source(defval = "close", title, opts = {}) {
5410
+ const name = registerInput({ type: "source", defval, title, ...common(opts) }, "input_source");
5454
5411
  return sourceSeries(name);
5455
5412
  },
5456
5413
  /** Timeframe string ("60", "1D", "W"). As in PineScript, "" means the chart timeframe. */
5457
5414
  timeframe(defval, title, opts = {}) {
5458
- return registerInput({ type: "timeframe", defval, title, options: opts.options }, "input_timeframe");
5415
+ return registerInput(
5416
+ { type: "timeframe", defval, title, options: opts.options, ...common(opts) },
5417
+ "input_timeframe"
5418
+ );
5459
5419
  },
5460
5420
  /** Session string ("0930-1600", "0930-1600:23456"). */
5461
5421
  session(defval, title, opts = {}) {
5462
- return registerInput({ type: "session", defval, title, options: opts.options }, "input_session");
5422
+ return registerInput(
5423
+ { type: "session", defval, title, options: opts.options, ...common(opts) },
5424
+ "input_session"
5425
+ );
5463
5426
  },
5464
5427
  /** Date and time as a UNIX time in milliseconds, e.g. `input.time(timestamp('2024-01-01'), 'Start')`. */
5465
- time(defval, title) {
5466
- const v = registerInput({ type: "time", defval, title }, "input_time");
5428
+ time(defval, title, opts = {}) {
5429
+ const v = registerInput({ type: "time", defval, title, ...common(opts) }, "input_time");
5467
5430
  return typeof v === "number" ? v : defval;
5468
5431
  }
5469
5432
  };
@@ -5517,6 +5480,8 @@ var ta2 = {
5517
5480
  const a = anchor ?? changeOf("1D");
5518
5481
  return stdev_mult === void 0 ? vwap2(source, volume, a) : vwapBands(source, volume, a, stdev_mult);
5519
5482
  }),
5483
+ /** `ta.mfi(source, length)` with the chart volume (PineScript takes 2 arguments). */
5484
+ mfi: (source, length2) => mfi2(source, length2, volume),
5520
5485
  /** `ta.pivothigh(source, leftbars, rightbars)` or `ta.pivothigh(leftbars, rightbars)` (source = high).
5521
5486
  * The value appears `rightbars` bars after the pivot bar, as in PineScript. */
5522
5487
  pivothigh: (sourceOrLeft, leftOrRight, rightbars) => typeof sourceOrLeft === "number" ? pivothigh2(high, sourceOrLeft, leftOrRight) : pivothigh2(sourceOrLeft, leftOrRight, rightbars),
@@ -5543,7 +5508,7 @@ var color = {
5543
5508
  new: new_color,
5544
5509
  when: colorWhen
5545
5510
  };
5546
- function plot(series, title, options = {}) {
5511
+ function plotImpl(series, title, options = {}) {
5547
5512
  const c = collector();
5548
5513
  const id = `plot${c.plotConfig.length}`;
5549
5514
  const perBar2 = Array.isArray(options.color) ? options.color : void 0;
@@ -5554,21 +5519,39 @@ function plot(series, title, options = {}) {
5554
5519
  color: staticColor,
5555
5520
  lineWidth: options.linewidth,
5556
5521
  style: options.style,
5522
+ linestyle: options.linestyle,
5557
5523
  display: options.display,
5558
- histbase: options.histbase
5524
+ histbase: options.histbase,
5525
+ forceOverlay: options.force_overlay
5559
5526
  });
5560
5527
  const values = series.toArray();
5561
5528
  const b2 = bars();
5562
5529
  const data = [];
5563
5530
  for (let i = 0; i < b2.length; i++) {
5564
5531
  const value = values[i];
5565
- if (value === void 0 || Number.isNaN(value)) continue;
5532
+ if (value === void 0 || !Number.isFinite(value)) continue;
5566
5533
  data.push(perBar2 ? { time: b2[i].time, value, color: perBar2[i] } : { time: b2[i].time, value });
5567
5534
  }
5568
5535
  c.plots[id] = data;
5569
5536
  return { id, kind: "plot" };
5570
5537
  }
5571
- function hline(price, title, options = {}) {
5538
+ var plot = Object.assign(plotImpl, {
5539
+ style_line: "line",
5540
+ style_linebr: "linebr",
5541
+ style_stepline: "stepline",
5542
+ style_steplinebr: "steplinebr",
5543
+ style_stepline_diamond: "stepline_diamond",
5544
+ style_histogram: "histogram",
5545
+ style_columns: "columns",
5546
+ style_area: "area",
5547
+ style_areabr: "areabr",
5548
+ style_circles: "circles",
5549
+ style_cross: "cross",
5550
+ linestyle_solid: "solid",
5551
+ linestyle_dotted: "dotted",
5552
+ linestyle_dashed: "dashed"
5553
+ });
5554
+ function hlineImpl(price, title, options = {}) {
5572
5555
  const c = collector();
5573
5556
  const id = `hline${c.hlineConfig.length}`;
5574
5557
  c.hlineConfig.push({
@@ -5576,11 +5559,16 @@ function hline(price, title, options = {}) {
5576
5559
  price,
5577
5560
  title,
5578
5561
  color: options.color,
5579
- linestyle: options.linestyle,
5562
+ linestyle: options.linestyle ?? "dashed",
5580
5563
  linewidth: options.linewidth
5581
5564
  });
5582
5565
  return { id, kind: "hline" };
5583
5566
  }
5567
+ var hline = Object.assign(hlineImpl, {
5568
+ style_solid: "solid",
5569
+ style_dotted: "dotted",
5570
+ style_dashed: "dashed"
5571
+ });
5584
5572
  function perBarValues(v, n) {
5585
5573
  return v instanceof Series ? v.toArray().slice(0, n) : new Array(n).fill(v);
5586
5574
  }
@@ -5652,7 +5640,8 @@ function emitMarkers(kind, condition, title, options) {
5652
5640
  text: options.text,
5653
5641
  textcolor: options.textcolor,
5654
5642
  size: options.size,
5655
- offset: options.offset
5643
+ offset: options.offset,
5644
+ forceOverlay: options.force_overlay
5656
5645
  });
5657
5646
  const values = condition.toArray();
5658
5647
  const b2 = bars();
@@ -5683,10 +5672,40 @@ function plotshape(condition, title, options = {}) {
5683
5672
  function plotchar(condition, title, options = {}) {
5684
5673
  emitMarkers("char", condition, title, options);
5685
5674
  }
5675
+ function plotarrow(series, title, options = {}) {
5676
+ const c = collector();
5677
+ const id = `arrow${c.arrowConfig.length}`;
5678
+ const pick = (col2, fallback, i) => col2 === void 0 ? fallback : typeof col2 === "string" ? col2 : col2[i];
5679
+ const colorup = typeof options.colorup === "string" ? options.colorup : "#00FF00";
5680
+ const colordown = typeof options.colordown === "string" ? options.colordown : "#FF0000";
5681
+ c.arrowConfig.push({
5682
+ id,
5683
+ title,
5684
+ colorup,
5685
+ colordown,
5686
+ minheight: options.minheight ?? 5,
5687
+ maxheight: options.maxheight ?? 100,
5688
+ offset: options.offset,
5689
+ display: options.display,
5690
+ forceOverlay: options.force_overlay
5691
+ });
5692
+ const values = series.toArray();
5693
+ const b2 = bars();
5694
+ const off = options.offset ?? 0;
5695
+ for (let i = 0; i < b2.length; i++) {
5696
+ const v = values[i];
5697
+ if (v === void 0 || Number.isNaN(v) || v === 0) continue;
5698
+ const j = i + off;
5699
+ if (j < 0 || j >= b2.length) continue;
5700
+ const color2 = v > 0 ? pick(options.colorup, "#00FF00", i) : pick(options.colordown, "#FF0000", i);
5701
+ if (color2 === void 0) continue;
5702
+ c.arrows.push({ time: b2[j].time, id, value: v, color: color2 });
5703
+ }
5704
+ }
5686
5705
  function emitBarColors(kind, colors, options) {
5687
5706
  const c = collector();
5688
5707
  const id = `${kind}${c.barColorConfig.filter((x) => x.kind === kind).length}`;
5689
- c.barColorConfig.push({ id, kind, title: options.title, offset: options.offset });
5708
+ c.barColorConfig.push({ id, kind, title: options.title, offset: options.offset, forceOverlay: options.force_overlay });
5690
5709
  const b2 = bars();
5691
5710
  const off = options.offset ?? 0;
5692
5711
  const target = kind === "bgcolor" ? c.bgcolors : c.barcolors;
@@ -6084,6 +6103,37 @@ function flag(key) {
6084
6103
  const values = sessionFlags(ctxBars.bars.map(barTime), bars2, regular)[key];
6085
6104
  return Series.fromArray(ctxBars, values.map((v) => v ? 1 : 0));
6086
6105
  }
6106
+ function barFlag(test) {
6107
+ const n = ctxBars.bars.length;
6108
+ return Series.fromArray(ctxBars, Array.from({ length: n }, (_, i) => test(i, n) ? 1 : 0));
6109
+ }
6110
+ var lastRealtime = (i, n) => i === n - 1 && chartCtx.realtime === true;
6111
+ var barstate = {
6112
+ get isfirst() {
6113
+ return barFlag((i) => i === 0);
6114
+ },
6115
+ get islast() {
6116
+ return barFlag((i, n) => i === n - 1);
6117
+ },
6118
+ get isconfirmed() {
6119
+ return barFlag((i, n) => i < n - 1 || chartCtx.lastBarConfirmed === true);
6120
+ },
6121
+ get isrealtime() {
6122
+ return barFlag(lastRealtime);
6123
+ },
6124
+ get ishistory() {
6125
+ return barFlag((i, n) => !lastRealtime(i, n));
6126
+ },
6127
+ get isnew() {
6128
+ return barFlag((i, n) => !lastRealtime(i, n) || chartCtx.lastBarNew !== false);
6129
+ },
6130
+ get islastconfirmedhistory() {
6131
+ return barFlag((i, n) => {
6132
+ const lastConfirmed = chartCtx.lastBarConfirmed === true && chartCtx.realtime !== true;
6133
+ return i === (lastConfirmed ? n - 1 : n - 2);
6134
+ });
6135
+ }
6136
+ };
6087
6137
  var session = {
6088
6138
  regular: "regular",
6089
6139
  extended: "extended",
@@ -6251,6 +6301,7 @@ export {
6251
6301
  alertcondition,
6252
6302
  barcolor,
6253
6303
  barmerge,
6304
+ barstate,
6254
6305
  bgcolor,
6255
6306
  box,
6256
6307
  chart,
@@ -6284,6 +6335,7 @@ export {
6284
6335
  ohlc4,
6285
6336
  open,
6286
6337
  plot,
6338
+ plotarrow,
6287
6339
  plotchar,
6288
6340
  plotshape,
6289
6341
  polyline,