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.
@@ -26,6 +26,7 @@ __export(index_exports, {
26
26
  alertcondition: () => alertcondition,
27
27
  barcolor: () => barcolor,
28
28
  barmerge: () => barmerge,
29
+ barstate: () => barstate,
29
30
  bgcolor: () => bgcolor,
30
31
  box: () => box,
31
32
  chart: () => chart,
@@ -59,6 +60,7 @@ __export(index_exports, {
59
60
  ohlc4: () => ohlc4,
60
61
  open: () => open,
61
62
  plot: () => plot,
63
+ plotarrow: () => plotarrow,
62
64
  plotchar: () => plotchar,
63
65
  plotshape: () => plotshape,
64
66
  polyline: () => polyline,
@@ -338,7 +340,7 @@ var Series = class _Series {
338
340
  return new _Series(this.dataSource, (bar, i, data) => {
339
341
  const a = this.extractor(bar, i, data);
340
342
  const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
341
- return b2 !== 0 ? a / b2 : NaN;
343
+ return a / b2;
342
344
  });
343
345
  }
344
346
  /**
@@ -704,26 +706,86 @@ __export(ta_series_exports, {
704
706
  zigzag: () => zigzag2
705
707
  });
706
708
 
707
- // src/ta/index.ts
708
- function sma(source, length2) {
709
- const result = [];
709
+ // src/ta/running-sum.ts
710
+ var view = new DataView(new ArrayBuffer(8));
711
+ function exponentOf(x) {
712
+ view.setFloat64(0, x);
713
+ const e2 = view.getUint16(0) >> 4 & 2047;
714
+ return e2 === 0 ? -1074 : e2 - 1023;
715
+ }
716
+ function compensationLost(x, c) {
717
+ if (c === 0 || x === 0) return false;
718
+ const ulp = 2 ** (exponentOf(x) - 52);
719
+ const q = c / ulp;
720
+ const mantissa = x / ulp;
721
+ const f = Math.floor(q);
722
+ const d = q - f;
723
+ const applied = d > 0.5 ? f + 1 : d < 0.5 ? f : (mantissa - f) % 2 === 0 ? f : f + 1;
724
+ return Math.abs(applied) < Math.abs(q);
725
+ }
726
+ function isNa(v) {
727
+ return v === void 0 || v === null || !Number.isFinite(v);
728
+ }
729
+ function runningSum(source, length2) {
710
730
  const len = Math.floor(length2);
711
- const window = [];
731
+ const out = new Array(source.length).fill(NaN);
732
+ if (!(len >= 1)) return out;
733
+ const values = [];
734
+ const stored = [];
735
+ let s = 0;
736
+ let c = 0;
737
+ let previous = NaN;
738
+ const kahanAdd = (v) => {
739
+ const y = v - c;
740
+ const t2 = s + y;
741
+ c = t2 - s - y;
742
+ s = t2;
743
+ return y;
744
+ };
712
745
  for (let i = 0; i < source.length; i++) {
713
746
  const v = source[i];
714
- if (v !== void 0 && v !== null && !Number.isNaN(v)) {
715
- window.push(v);
716
- if (window.length > len) window.shift();
747
+ if (isNa(v)) {
748
+ out[i] = previous;
749
+ continue;
717
750
  }
718
- if (window.length < len) {
719
- result.push(NaN);
751
+ const x = v;
752
+ const c0 = c;
753
+ const n = values.length;
754
+ if (n >= len) kahanAdd(-stored[n - len]);
755
+ values.push(x);
756
+ if (compensationLost(x, c0)) {
757
+ let fresh = 0;
758
+ for (let k = values.length - 1; k >= Math.max(0, values.length - len); k--) fresh += values[k];
759
+ s = fresh;
760
+ c = 0;
761
+ stored.push(x);
720
762
  } else {
721
- let sum2 = 0;
722
- for (const x of window) sum2 += x;
723
- result.push(sum2 / len);
763
+ stored.push(kahanAdd(x));
724
764
  }
765
+ previous = values.length >= len ? s : NaN;
766
+ out[i] = previous;
725
767
  }
726
- return result;
768
+ return out;
769
+ }
770
+ function runningVariance(source, length2, biased) {
771
+ const len = Math.floor(length2);
772
+ const squares = Array.from({ length: source.length }, (_, i) => {
773
+ const v = source[i];
774
+ return isNa(v) ? NaN : v * v;
775
+ });
776
+ const sums = runningSum(source, len);
777
+ const sumSquares = runningSum(squares, len);
778
+ return sums.map((sum2, i) => {
779
+ const mean = sum2 / len;
780
+ const sq = sumSquares[i];
781
+ return biased ? sq / len - mean * mean : sq / (len - 1) - mean * sum2 / (len - 1);
782
+ });
783
+ }
784
+
785
+ // src/ta/index.ts
786
+ function sma(source, length2) {
787
+ const len = Math.floor(length2);
788
+ return runningSum(source, len).map((sum2) => sum2 / len);
727
789
  }
728
790
  function strictWindowMean(source, length2) {
729
791
  const len = Math.floor(length2);
@@ -743,7 +805,7 @@ function ema(source, length2) {
743
805
  let initSum = 0;
744
806
  for (let i = 0; i < source.length; i++) {
745
807
  const val = source[i];
746
- if (val !== void 0 && !isNaN(val)) {
808
+ if (val !== void 0 && Number.isFinite(val)) {
747
809
  initSum += val;
748
810
  validCount++;
749
811
  if (validCount === len) {
@@ -761,7 +823,7 @@ function ema(source, length2) {
761
823
  result.push(emaValue);
762
824
  } else {
763
825
  const val = source[i];
764
- if (val !== void 0 && !isNaN(val)) {
826
+ if (val !== void 0 && Number.isFinite(val)) {
765
827
  emaValue = (val - emaValue) * multiplier + emaValue;
766
828
  result.push(emaValue);
767
829
  } else {
@@ -818,14 +880,7 @@ function bb(series, length2, mult) {
818
880
  return [basis, upper2, lower2];
819
881
  }
820
882
  function stdev(source, length2, biased = true) {
821
- const len = Math.floor(length2);
822
- return source.map((_, i) => {
823
- const values = lastValues(source, i, len);
824
- if (!values) return NaN;
825
- const mean = values.reduce((a, b2) => a + b2, 0) / len;
826
- const squares = values.reduce((a, b2) => a + (b2 - mean) * (b2 - mean), 0);
827
- return Math.sqrt(squares / (biased ? len : len - 1));
828
- });
883
+ return variance(source, length2, biased).map((v) => Number.isNaN(v) ? NaN : v > 0 ? Math.sqrt(v) : 0);
829
884
  }
830
885
  function lastValues(source, i, length2) {
831
886
  const values = [];
@@ -979,13 +1034,12 @@ function supertrend(factor, atrPeriod, high2, low2, close2, wicks = false) {
979
1034
  function rma(source, length2) {
980
1035
  const result = [];
981
1036
  const len = Math.floor(length2);
982
- const alpha = 1 / len;
983
1037
  let firstValidIndex = -1;
984
1038
  let validCount = 0;
985
1039
  let initSum = 0;
986
1040
  for (let i = 0; i < source.length; i++) {
987
1041
  const val = source[i];
988
- if (val !== void 0 && !isNaN(val)) {
1042
+ if (val !== void 0 && Number.isFinite(val)) {
989
1043
  initSum += val;
990
1044
  validCount++;
991
1045
  if (validCount === len) {
@@ -1003,8 +1057,8 @@ function rma(source, length2) {
1003
1057
  result.push(rmaValue);
1004
1058
  } else {
1005
1059
  const val = source[i];
1006
- if (val !== void 0 && !isNaN(val)) {
1007
- rmaValue = alpha * val + (1 - alpha) * rmaValue;
1060
+ if (val !== void 0 && Number.isFinite(val)) {
1061
+ rmaValue = (val + (len - 1) * rmaValue) / len;
1008
1062
  result.push(rmaValue);
1009
1063
  } else {
1010
1064
  result.push(NaN);
@@ -1018,18 +1072,22 @@ function wma(source, length2) {
1018
1072
  const len = Math.floor(length2);
1019
1073
  const filled = [];
1020
1074
  let last = NaN;
1075
+ let count = 0;
1021
1076
  for (let i = 0; i < source.length; i++) {
1022
1077
  const v = source[i];
1023
- const isNa = v === void 0 || v === null || Number.isNaN(v);
1024
- if (!isNa) last = v;
1078
+ const isNa2 = v === void 0 || v === null || !Number.isFinite(v);
1079
+ if (!isNa2) {
1080
+ last = v;
1081
+ count++;
1082
+ }
1025
1083
  filled.push(last);
1026
- if (isNa || i < len - 1) {
1084
+ if (isNa2 || count < len) {
1027
1085
  result.push(NaN);
1028
1086
  continue;
1029
1087
  }
1030
1088
  let sum2 = 0;
1031
1089
  let weightSum = 0;
1032
- for (let j = 0; j < len; j++) {
1090
+ for (let j = len - 1; j >= 0; j--) {
1033
1091
  const weight = len - j;
1034
1092
  sum2 += filled[i - j] * weight;
1035
1093
  weightSum += weight;
@@ -1055,7 +1113,7 @@ function lowest(source, length2) {
1055
1113
  function cum(source) {
1056
1114
  let sum2 = 0;
1057
1115
  return source.map((v) => {
1058
- if (Number.isNaN(v)) return NaN;
1116
+ if (!Number.isFinite(v)) return NaN;
1059
1117
  sum2 += v;
1060
1118
  return sum2;
1061
1119
  });
@@ -1073,41 +1131,24 @@ function cross(source1, source2) {
1073
1131
  }
1074
1132
  return result;
1075
1133
  }
1076
- function rising(source, length2) {
1134
+ function monotonic(source, length2, step) {
1077
1135
  const result = [];
1136
+ const values = [];
1078
1137
  for (let i = 0; i < source.length; i++) {
1079
- if (i < length2) {
1080
- result.push(false);
1081
- } else {
1082
- let isRising = true;
1083
- for (let j = 1; j <= length2; j++) {
1084
- if (source[i - j + 1] <= source[i - j]) {
1085
- isRising = false;
1086
- break;
1087
- }
1088
- }
1089
- result.push(isRising);
1090
- }
1138
+ const v = source[i];
1139
+ if (!Number.isNaN(v)) values.push(v);
1140
+ const n = values.length;
1141
+ let ok = n > length2;
1142
+ for (let j = 1; ok && j <= length2; j++) ok = step(values[n - j], values[n - j - 1]);
1143
+ result.push(ok);
1091
1144
  }
1092
1145
  return result;
1093
1146
  }
1147
+ function rising(source, length2) {
1148
+ return monotonic(source, length2, gt);
1149
+ }
1094
1150
  function falling(source, length2) {
1095
- const result = [];
1096
- for (let i = 0; i < source.length; i++) {
1097
- if (i < length2) {
1098
- result.push(false);
1099
- } else {
1100
- let isFalling = true;
1101
- for (let j = 1; j <= length2; j++) {
1102
- if (source[i - j + 1] >= source[i - j]) {
1103
- isFalling = false;
1104
- break;
1105
- }
1106
- }
1107
- result.push(isFalling);
1108
- }
1109
- }
1110
- return result;
1151
+ return monotonic(source, length2, lt);
1111
1152
  }
1112
1153
  function roc(source, length2) {
1113
1154
  const result = [];
@@ -1160,53 +1201,19 @@ function dev(source, length2) {
1160
1201
  return result;
1161
1202
  }
1162
1203
  function variance(source, length2, biased = true) {
1163
- const result = [];
1164
1204
  const len = Math.floor(length2);
1165
- const window = [];
1166
- for (let i = 0; i < source.length; i++) {
1167
- const v = source[i];
1168
- if (v !== void 0 && v !== null && !Number.isNaN(v)) {
1169
- window.push(v);
1170
- if (window.length > len) window.shift();
1171
- }
1172
- const divisor = biased ? len : len - 1;
1173
- if (window.length < len || divisor <= 0) {
1174
- result.push(NaN);
1175
- continue;
1176
- }
1177
- const mean = window.reduce((a, x) => a + x, 0) / len;
1178
- let sumSquares = 0;
1179
- for (const x of window) sumSquares += (x - mean) * (x - mean);
1180
- result.push(sumSquares / divisor);
1181
- }
1182
- return result;
1205
+ if ((biased ? len : len - 1) <= 0) return source.map(() => NaN);
1206
+ return runningVariance(source, len, biased);
1183
1207
  }
1184
1208
  function median(source, length2) {
1185
- const result = [];
1186
- for (let i = 0; i < source.length; i++) {
1187
- if (i < length2 - 1) {
1188
- result.push(NaN);
1189
- } else {
1190
- const values = [];
1191
- for (let j = 0; j < length2; j++) {
1192
- if (!isNaN(source[i - j])) {
1193
- values.push(source[i - j]);
1194
- }
1195
- }
1196
- if (values.length === 0) {
1197
- result.push(NaN);
1198
- } else {
1199
- values.sort((a, b2) => a - b2);
1200
- const mid = Math.floor(values.length / 2);
1201
- if (values.length % 2 === 0) {
1202
- result.push((values[mid - 1] + values[mid]) / 2);
1203
- } else {
1204
- result.push(values[mid]);
1205
- }
1206
- }
1207
- }
1208
- }
1209
- return result;
1209
+ const len = Math.floor(length2);
1210
+ return source.map((_, i) => {
1211
+ const values = lastValues(source, i, len);
1212
+ if (!values) return NaN;
1213
+ values.sort((a, b2) => a - b2);
1214
+ const mid = Math.floor(len / 2);
1215
+ return len % 2 === 0 ? (values[mid - 1] + values[mid]) / 2 : values[mid];
1216
+ });
1210
1217
  }
1211
1218
  function swma(source) {
1212
1219
  const result = [];
@@ -1331,33 +1338,16 @@ function correlation(source1, source2, length2) {
1331
1338
  function percentrank(source, length2) {
1332
1339
  const result = [];
1333
1340
  for (let i = 0; i < source.length; i++) {
1334
- if (i < length2) {
1341
+ const currentValue = source[i];
1342
+ if (i < length2 || Number.isNaN(currentValue)) {
1335
1343
  result.push(NaN);
1336
- } else {
1337
- if (isNaN(source[i])) {
1338
- result.push(NaN);
1339
- continue;
1340
- }
1341
- let hasNaN = false;
1342
- for (let j = 1; j <= length2; j++) {
1343
- if (isNaN(source[i - j])) {
1344
- hasNaN = true;
1345
- break;
1346
- }
1347
- }
1348
- if (hasNaN) {
1349
- result.push(NaN);
1350
- } else {
1351
- const currentValue = source[i];
1352
- let countLessOrEqual = 0;
1353
- for (let j = 1; j <= length2; j++) {
1354
- if (source[i - j] <= currentValue) {
1355
- countLessOrEqual++;
1356
- }
1357
- }
1358
- result.push(countLessOrEqual / length2 * 100);
1359
- }
1344
+ continue;
1345
+ }
1346
+ let countLessOrEqual = 0;
1347
+ for (let j = 1; j <= length2; j++) {
1348
+ if (le(source[i - j], currentValue)) countLessOrEqual++;
1360
1349
  }
1350
+ result.push(countLessOrEqual / length2 * 100);
1361
1351
  }
1362
1352
  return result;
1363
1353
  }
@@ -1408,12 +1398,8 @@ function mfi(source, length2, volume2) {
1408
1398
  upperFlow.push(le(change3, 0) ? 0 : flow);
1409
1399
  lowerFlow.push(ge(change3, 0) ? 0 : flow);
1410
1400
  }
1411
- const sumAt = (flow, i) => {
1412
- const values = lastValues(flow, i, Math.floor(length2));
1413
- return values ? values.reduce((a, b2) => a + b2, 0) : NaN;
1414
- };
1415
- const upper2 = upperFlow.map((_, i) => sumAt(upperFlow, i));
1416
- const lower2 = lowerFlow.map((_, i) => sumAt(lowerFlow, i));
1401
+ const upper2 = runningSum(upperFlow, length2);
1402
+ const lower2 = runningSum(lowerFlow, length2);
1417
1403
  return upper2.map((u, i) => {
1418
1404
  const l = lower2[i];
1419
1405
  if (Number.isNaN(u) || Number.isNaN(l)) return NaN;
@@ -1884,63 +1870,36 @@ function mode(source, length2) {
1884
1870
  return result;
1885
1871
  }
1886
1872
  function percentile_linear_interpolation(source, length2, percentage) {
1873
+ return sortedWindow(source, length2, (s) => {
1874
+ const pos2 = percentage / 100 * length2 - 0.5;
1875
+ if (pos2 <= 0) return s[0];
1876
+ if (pos2 >= length2 - 1) return s[length2 - 1];
1877
+ const lo = Math.floor(pos2);
1878
+ return s[lo] + (pos2 - lo) * (s[lo + 1] - s[lo]);
1879
+ });
1880
+ }
1881
+ function sortedWindow(source, length2, fn) {
1887
1882
  const result = [];
1883
+ const values = [];
1884
+ const bars2 = [];
1888
1885
  for (let i = 0; i < source.length; i++) {
1889
- if (i < length2 - 1) {
1890
- result.push(NaN);
1891
- continue;
1892
- }
1893
- const values = [];
1894
- for (let j = 0; j < length2; j++) {
1895
- const value = source[i - j];
1896
- values.push(value);
1897
- }
1898
- if (values.some((v) => isNaN(v))) {
1899
- result.push(NaN);
1900
- continue;
1901
- }
1902
- const sorted = [...values].sort((a, b2) => a - b2);
1903
- const position = percentage / 100 * (sorted.length - 1);
1904
- const lowerIndex = Math.floor(position);
1905
- const upperIndex = Math.ceil(position);
1906
- if (lowerIndex === upperIndex) {
1907
- result.push(sorted[lowerIndex]);
1908
- } else {
1909
- const fraction = position - lowerIndex;
1910
- const interpolated = sorted[lowerIndex] + fraction * (sorted[upperIndex] - sorted[lowerIndex]);
1911
- result.push(interpolated);
1886
+ const v = source[i];
1887
+ let k = 0;
1888
+ while (k < values.length && !(values[k] >= v)) k++;
1889
+ values.splice(k, 0, v);
1890
+ bars2.splice(k, 0, i);
1891
+ if (i >= length2) {
1892
+ const old = bars2.indexOf(i - length2);
1893
+ values.splice(old, 1);
1894
+ bars2.splice(old, 1);
1912
1895
  }
1896
+ result.push(i < length2 - 1 ? NaN : fn(values));
1913
1897
  }
1914
1898
  return result;
1915
1899
  }
1916
1900
  function percentile_nearest_rank(source, length2, percentage) {
1917
- const result = [];
1918
- for (let i = 0; i < source.length; i++) {
1919
- if (i < length2 - 1) {
1920
- result.push(NaN);
1921
- continue;
1922
- }
1923
- const values = [];
1924
- for (let j = 0; j < length2; j++) {
1925
- const value = source[i - j];
1926
- if (!isNaN(value)) {
1927
- values.push(value);
1928
- }
1929
- }
1930
- if (values.length === 0) {
1931
- result.push(NaN);
1932
- continue;
1933
- }
1934
- const sorted = [...values].sort((a, b2) => a - b2);
1935
- if (percentage >= 100) {
1936
- result.push(sorted[sorted.length - 1]);
1937
- continue;
1938
- }
1939
- const rank = Math.ceil(percentage / 100 * sorted.length);
1940
- const index = Math.max(0, rank - 1);
1941
- result.push(sorted[index]);
1942
- }
1943
- return result;
1901
+ const rank = Math.min(length2, Math.max(1, Math.ceil(percentage / 100 * length2)));
1902
+ return sortedWindow(source, length2, (s) => s[rank - 1]);
1944
1903
  }
1945
1904
  function rci(source, length2) {
1946
1905
  const result = [];
@@ -2806,11 +2765,13 @@ __export(color_exports, {
2806
2765
  white: () => white,
2807
2766
  yellow: () => yellow
2808
2767
  });
2768
+ var channel = (v) => v === null || v === void 0 || Number.isNaN(v) ? 0 : Math.max(0, Math.min(255, Math.trunc(v)));
2769
+ var alphaOf = (transp) => transp === null || Number.isNaN(transp) ? 0 : 1 - Math.max(0, Math.min(100, transp)) / 100;
2809
2770
  function rgb(red2, green2, blue2, transp) {
2810
- const r2 = Math.max(0, Math.min(255, red2));
2811
- const g2 = Math.max(0, Math.min(255, green2));
2812
- const b2 = Math.max(0, Math.min(255, blue2));
2813
- const a = transp !== void 0 ? 1 - transp / 100 : 1;
2771
+ const r2 = channel(red2);
2772
+ const g2 = channel(green2);
2773
+ const b2 = channel(blue2);
2774
+ const a = transp !== void 0 ? alphaOf(transp) : 1;
2814
2775
  if (a === 1) {
2815
2776
  return `rgb(${r2}, ${g2}, ${b2})`;
2816
2777
  }
@@ -2837,7 +2798,8 @@ function b(clr) {
2837
2798
  return parseColor(clr).b;
2838
2799
  }
2839
2800
  function t(clr) {
2840
- return parseColor(clr).t;
2801
+ const alpha = Math.round((1 - parseColor(clr).t / 100) * 255);
2802
+ return Math.round((1 - alpha / 255) * 100);
2841
2803
  }
2842
2804
  function parseColor(clr) {
2843
2805
  if (typeof clr === "string") {
@@ -2890,13 +2852,12 @@ function from_gradient(value, bottom_value, top_value, bottom_color, top_color)
2890
2852
  };
2891
2853
  const c1 = rgba(bottom_color);
2892
2854
  const c2 = rgba(top_color);
2893
- const w1 = c1.a * (1 - k);
2894
- const w2 = c2.a * k;
2895
- const a = w1 + w2;
2855
+ const a = c1.a * (1 - k) + c2.a * k;
2896
2856
  if (a === 0) return transparent;
2897
- const mix = (x1, x2) => Math.floor((x1 * w1 + x2 * w2) / a);
2857
+ const mix = (x1, x2) => Math.floor((x1 / 255 * c1.a * (1 - k) + x2 / 255 * c2.a * k) / (a / 255));
2898
2858
  const [r2, g2, b2] = [mix(c1.r, c2.r), mix(c1.g, c2.g), mix(c1.b, c2.b)];
2899
- return a === 255 ? `rgb(${r2}, ${g2}, ${b2})` : `rgba(${r2}, ${g2}, ${b2}, ${a / 255})`;
2859
+ const alpha = Math.floor(a);
2860
+ return alpha === 255 ? `rgb(${r2}, ${g2}, ${b2})` : `rgba(${r2}, ${g2}, ${b2}, ${alpha / 255})`;
2900
2861
  }
2901
2862
 
2902
2863
  // src/drawing/registry.ts
@@ -2960,7 +2921,7 @@ function setDrawingLimits(newLimits) {
2960
2921
 
2961
2922
  // src/utils/index.ts
2962
2923
  function isNA(value) {
2963
- return value === null || value === void 0 || Number.isNaN(value) || isDeleted(value);
2924
+ return value === null || value === void 0 || Number.isNaN(value) || value === Infinity || value === -Infinity || isDeleted(value);
2964
2925
  }
2965
2926
  function nz(value, defaultValue = 0) {
2966
2927
  return isNA(value) ? defaultValue : value;
@@ -2969,7 +2930,7 @@ function fixnan(source) {
2969
2930
  let last;
2970
2931
  let seen = false;
2971
2932
  return source.map((v) => {
2972
- if (!isNA(v)) {
2933
+ if (!(v === null || v === void 0 || Number.isNaN(v) || isDeleted(v))) {
2973
2934
  last = v;
2974
2935
  seen = true;
2975
2936
  return v;
@@ -3856,23 +3817,7 @@ function avg(...values) {
3856
3817
  }
3857
3818
  function sum(source, length2) {
3858
3819
  const sourceArray = source instanceof Series ? source.toArray() : source;
3859
- const result = [];
3860
- const len = Math.floor(length2);
3861
- const window = [];
3862
- for (let i = 0; i < sourceArray.length; i++) {
3863
- const v = sourceArray[i];
3864
- if (v !== void 0 && v !== null && !Number.isNaN(v)) {
3865
- window.push(v);
3866
- if (window.length > len) window.shift();
3867
- }
3868
- if (window.length < len) {
3869
- result.push(NaN);
3870
- } else {
3871
- let total = 0;
3872
- for (const x of window) total += x;
3873
- result.push(total);
3874
- }
3875
- }
3820
+ const result = runningSum(sourceArray, length2);
3876
3821
  if (source instanceof Series) {
3877
3822
  return Series.fromArray(source.bars, result);
3878
3823
  }
@@ -4548,9 +4493,9 @@ function shortestDigits(x) {
4548
4493
  function exactDigits(x) {
4549
4494
  const abs2 = Math.abs(x);
4550
4495
  if (abs2 === 0) return { digits: "", intLen: 0 };
4551
- const view = new DataView(new ArrayBuffer(8));
4552
- view.setFloat64(0, abs2);
4553
- const bits = view.getBigUint64(0);
4496
+ const view2 = new DataView(new ArrayBuffer(8));
4497
+ view2.setFloat64(0, abs2);
4498
+ const bits = view2.getBigUint64(0);
4554
4499
  const expBits = Number(bits >> 52n & 0x7ffn);
4555
4500
  let mant = bits & 0xfffffffffffffn;
4556
4501
  const e2 = expBits === 0 ? -1074 : expBits - 1075;
@@ -5344,9 +5289,10 @@ var STRATEGY_DEFAULTS = {
5344
5289
  calc_on_order_fills: false,
5345
5290
  calc_on_every_tick: false,
5346
5291
  backtest_fill_limits_assumption: 0,
5347
- default_qty_type: "fixed",
5348
- default_qty_value: 1,
5349
- initial_capital: 1e6,
5292
+ // v6 values; PineScript v5: fixed / 1 / 1000000 and margins 0
5293
+ default_qty_type: "percent_of_equity",
5294
+ default_qty_value: 100,
5295
+ initial_capital: 1e5,
5350
5296
  slippage: 0,
5351
5297
  commission_type: "percent",
5352
5298
  commission_value: 0,
@@ -5420,6 +5366,8 @@ function freshCollector(inputValues) {
5420
5366
  fillConfig: [],
5421
5367
  shapeConfig: [],
5422
5368
  markers: [],
5369
+ arrowConfig: [],
5370
+ arrows: [],
5423
5371
  barColorConfig: [],
5424
5372
  bgcolors: [],
5425
5373
  barcolors: [],
@@ -5457,6 +5405,7 @@ function executeScript(body, barsInput, inputs = {}, chart2 = {}, options = {})
5457
5405
  hlineConfig: c.hlineConfig,
5458
5406
  fillConfig: c.fillConfig,
5459
5407
  shapeConfig: c.shapeConfig,
5408
+ arrowConfig: c.arrowConfig,
5460
5409
  barColorConfig: c.barColorConfig,
5461
5410
  defaultInputs: c.defaultInputs,
5462
5411
  alertConfig: c.alertConfig,
@@ -5466,6 +5415,7 @@ function executeScript(body, barsInput, inputs = {}, chart2 = {}, options = {})
5466
5415
  plots: c.plots,
5467
5416
  fills: c.fills.length ? c.fills : void 0,
5468
5417
  markers: c.markers.length ? c.markers : void 0,
5418
+ arrows: c.arrows.length ? c.arrows : void 0,
5469
5419
  bgcolors: c.bgcolors.length ? c.bgcolors : void 0,
5470
5420
  barcolors: c.barcolors.length ? c.barcolors : void 0,
5471
5421
  alerts: c.alerts.length ? c.alerts : void 0
@@ -5496,6 +5446,15 @@ function declare(c, kind) {
5496
5446
  }
5497
5447
  c.declaration = kind;
5498
5448
  }
5449
+ function common(opts) {
5450
+ const out = {};
5451
+ if (opts.group !== void 0) out.group = opts.group;
5452
+ if (opts.inline !== void 0) out.inline = opts.inline;
5453
+ if (opts.tooltip !== void 0) out.tooltip = opts.tooltip;
5454
+ if (opts.confirm !== void 0) out.confirm = opts.confirm;
5455
+ if (opts.display !== void 0) out.display = opts.display;
5456
+ return out;
5457
+ }
5499
5458
  function registerInput(config, fallbackId) {
5500
5459
  const c = collector();
5501
5460
  const id = slugId(config.title, fallbackId, c.inputIds);
@@ -5506,7 +5465,7 @@ function registerInput(config, fallbackId) {
5506
5465
  }
5507
5466
  function registerNumeric(type, defval, title, opts = {}) {
5508
5467
  const v = registerInput(
5509
- { type, defval, title, min: opts.minval, max: opts.maxval, step: opts.step },
5468
+ { type, defval, title, min: opts.minval, max: opts.maxval, step: opts.step, ...common(opts) },
5510
5469
  `input_${type}`
5511
5470
  );
5512
5471
  return typeof v === "number" ? v : defval;
@@ -5518,31 +5477,37 @@ var input = {
5518
5477
  float(defval, title, opts = {}) {
5519
5478
  return registerNumeric("float", defval, title, opts);
5520
5479
  },
5521
- bool(defval, title) {
5522
- return registerInput({ type: "bool", defval, title }, "input_bool");
5480
+ bool(defval, title, opts = {}) {
5481
+ return registerInput({ type: "bool", defval, title, ...common(opts) }, "input_bool");
5523
5482
  },
5524
5483
  string(defval, title, opts = {}) {
5525
- return registerInput({ type: "string", defval, title, options: opts.options }, "input_string");
5484
+ return registerInput({ type: "string", defval, title, options: opts.options, ...common(opts) }, "input_string");
5526
5485
  },
5527
- color(defval, title) {
5528
- return registerInput({ type: "color", defval, title }, "input_color");
5486
+ color(defval, title, opts = {}) {
5487
+ return registerInput({ type: "color", defval, title, ...common(opts) }, "input_color");
5529
5488
  },
5530
5489
  /** Declares a source input and returns it as a Series. */
5531
- source(defval = "close", title) {
5532
- const name = registerInput({ type: "source", defval, title }, "input_source");
5490
+ source(defval = "close", title, opts = {}) {
5491
+ const name = registerInput({ type: "source", defval, title, ...common(opts) }, "input_source");
5533
5492
  return sourceSeries(name);
5534
5493
  },
5535
5494
  /** Timeframe string ("60", "1D", "W"). As in PineScript, "" means the chart timeframe. */
5536
5495
  timeframe(defval, title, opts = {}) {
5537
- return registerInput({ type: "timeframe", defval, title, options: opts.options }, "input_timeframe");
5496
+ return registerInput(
5497
+ { type: "timeframe", defval, title, options: opts.options, ...common(opts) },
5498
+ "input_timeframe"
5499
+ );
5538
5500
  },
5539
5501
  /** Session string ("0930-1600", "0930-1600:23456"). */
5540
5502
  session(defval, title, opts = {}) {
5541
- return registerInput({ type: "session", defval, title, options: opts.options }, "input_session");
5503
+ return registerInput(
5504
+ { type: "session", defval, title, options: opts.options, ...common(opts) },
5505
+ "input_session"
5506
+ );
5542
5507
  },
5543
5508
  /** Date and time as a UNIX time in milliseconds, e.g. `input.time(timestamp('2024-01-01'), 'Start')`. */
5544
- time(defval, title) {
5545
- const v = registerInput({ type: "time", defval, title }, "input_time");
5509
+ time(defval, title, opts = {}) {
5510
+ const v = registerInput({ type: "time", defval, title, ...common(opts) }, "input_time");
5546
5511
  return typeof v === "number" ? v : defval;
5547
5512
  }
5548
5513
  };
@@ -5596,6 +5561,8 @@ var ta2 = {
5596
5561
  const a = anchor ?? changeOf("1D");
5597
5562
  return stdev_mult === void 0 ? vwap2(source, volume, a) : vwapBands(source, volume, a, stdev_mult);
5598
5563
  }),
5564
+ /** `ta.mfi(source, length)` with the chart volume (PineScript takes 2 arguments). */
5565
+ mfi: (source, length2) => mfi2(source, length2, volume),
5599
5566
  /** `ta.pivothigh(source, leftbars, rightbars)` or `ta.pivothigh(leftbars, rightbars)` (source = high).
5600
5567
  * The value appears `rightbars` bars after the pivot bar, as in PineScript. */
5601
5568
  pivothigh: (sourceOrLeft, leftOrRight, rightbars) => typeof sourceOrLeft === "number" ? pivothigh2(high, sourceOrLeft, leftOrRight) : pivothigh2(sourceOrLeft, leftOrRight, rightbars),
@@ -5622,7 +5589,7 @@ var color = {
5622
5589
  new: new_color,
5623
5590
  when: colorWhen
5624
5591
  };
5625
- function plot(series, title, options = {}) {
5592
+ function plotImpl(series, title, options = {}) {
5626
5593
  const c = collector();
5627
5594
  const id = `plot${c.plotConfig.length}`;
5628
5595
  const perBar2 = Array.isArray(options.color) ? options.color : void 0;
@@ -5633,21 +5600,39 @@ function plot(series, title, options = {}) {
5633
5600
  color: staticColor,
5634
5601
  lineWidth: options.linewidth,
5635
5602
  style: options.style,
5603
+ linestyle: options.linestyle,
5636
5604
  display: options.display,
5637
- histbase: options.histbase
5605
+ histbase: options.histbase,
5606
+ forceOverlay: options.force_overlay
5638
5607
  });
5639
5608
  const values = series.toArray();
5640
5609
  const b2 = bars();
5641
5610
  const data = [];
5642
5611
  for (let i = 0; i < b2.length; i++) {
5643
5612
  const value = values[i];
5644
- if (value === void 0 || Number.isNaN(value)) continue;
5613
+ if (value === void 0 || !Number.isFinite(value)) continue;
5645
5614
  data.push(perBar2 ? { time: b2[i].time, value, color: perBar2[i] } : { time: b2[i].time, value });
5646
5615
  }
5647
5616
  c.plots[id] = data;
5648
5617
  return { id, kind: "plot" };
5649
5618
  }
5650
- function hline(price, title, options = {}) {
5619
+ var plot = Object.assign(plotImpl, {
5620
+ style_line: "line",
5621
+ style_linebr: "linebr",
5622
+ style_stepline: "stepline",
5623
+ style_steplinebr: "steplinebr",
5624
+ style_stepline_diamond: "stepline_diamond",
5625
+ style_histogram: "histogram",
5626
+ style_columns: "columns",
5627
+ style_area: "area",
5628
+ style_areabr: "areabr",
5629
+ style_circles: "circles",
5630
+ style_cross: "cross",
5631
+ linestyle_solid: "solid",
5632
+ linestyle_dotted: "dotted",
5633
+ linestyle_dashed: "dashed"
5634
+ });
5635
+ function hlineImpl(price, title, options = {}) {
5651
5636
  const c = collector();
5652
5637
  const id = `hline${c.hlineConfig.length}`;
5653
5638
  c.hlineConfig.push({
@@ -5655,11 +5640,16 @@ function hline(price, title, options = {}) {
5655
5640
  price,
5656
5641
  title,
5657
5642
  color: options.color,
5658
- linestyle: options.linestyle,
5643
+ linestyle: options.linestyle ?? "dashed",
5659
5644
  linewidth: options.linewidth
5660
5645
  });
5661
5646
  return { id, kind: "hline" };
5662
5647
  }
5648
+ var hline = Object.assign(hlineImpl, {
5649
+ style_solid: "solid",
5650
+ style_dotted: "dotted",
5651
+ style_dashed: "dashed"
5652
+ });
5663
5653
  function perBarValues(v, n) {
5664
5654
  return v instanceof Series ? v.toArray().slice(0, n) : new Array(n).fill(v);
5665
5655
  }
@@ -5731,7 +5721,8 @@ function emitMarkers(kind, condition, title, options) {
5731
5721
  text: options.text,
5732
5722
  textcolor: options.textcolor,
5733
5723
  size: options.size,
5734
- offset: options.offset
5724
+ offset: options.offset,
5725
+ forceOverlay: options.force_overlay
5735
5726
  });
5736
5727
  const values = condition.toArray();
5737
5728
  const b2 = bars();
@@ -5762,10 +5753,40 @@ function plotshape(condition, title, options = {}) {
5762
5753
  function plotchar(condition, title, options = {}) {
5763
5754
  emitMarkers("char", condition, title, options);
5764
5755
  }
5756
+ function plotarrow(series, title, options = {}) {
5757
+ const c = collector();
5758
+ const id = `arrow${c.arrowConfig.length}`;
5759
+ const pick = (col2, fallback, i) => col2 === void 0 ? fallback : typeof col2 === "string" ? col2 : col2[i];
5760
+ const colorup = typeof options.colorup === "string" ? options.colorup : "#00FF00";
5761
+ const colordown = typeof options.colordown === "string" ? options.colordown : "#FF0000";
5762
+ c.arrowConfig.push({
5763
+ id,
5764
+ title,
5765
+ colorup,
5766
+ colordown,
5767
+ minheight: options.minheight ?? 5,
5768
+ maxheight: options.maxheight ?? 100,
5769
+ offset: options.offset,
5770
+ display: options.display,
5771
+ forceOverlay: options.force_overlay
5772
+ });
5773
+ const values = series.toArray();
5774
+ const b2 = bars();
5775
+ const off = options.offset ?? 0;
5776
+ for (let i = 0; i < b2.length; i++) {
5777
+ const v = values[i];
5778
+ if (v === void 0 || Number.isNaN(v) || v === 0) continue;
5779
+ const j = i + off;
5780
+ if (j < 0 || j >= b2.length) continue;
5781
+ const color2 = v > 0 ? pick(options.colorup, "#00FF00", i) : pick(options.colordown, "#FF0000", i);
5782
+ if (color2 === void 0) continue;
5783
+ c.arrows.push({ time: b2[j].time, id, value: v, color: color2 });
5784
+ }
5785
+ }
5765
5786
  function emitBarColors(kind, colors, options) {
5766
5787
  const c = collector();
5767
5788
  const id = `${kind}${c.barColorConfig.filter((x) => x.kind === kind).length}`;
5768
- c.barColorConfig.push({ id, kind, title: options.title, offset: options.offset });
5789
+ c.barColorConfig.push({ id, kind, title: options.title, offset: options.offset, forceOverlay: options.force_overlay });
5769
5790
  const b2 = bars();
5770
5791
  const off = options.offset ?? 0;
5771
5792
  const target = kind === "bgcolor" ? c.bgcolors : c.barcolors;
@@ -6163,6 +6184,37 @@ function flag(key) {
6163
6184
  const values = sessionFlags(ctxBars.bars.map(barTime), bars2, regular)[key];
6164
6185
  return Series.fromArray(ctxBars, values.map((v) => v ? 1 : 0));
6165
6186
  }
6187
+ function barFlag(test) {
6188
+ const n = ctxBars.bars.length;
6189
+ return Series.fromArray(ctxBars, Array.from({ length: n }, (_, i) => test(i, n) ? 1 : 0));
6190
+ }
6191
+ var lastRealtime = (i, n) => i === n - 1 && chartCtx.realtime === true;
6192
+ var barstate = {
6193
+ get isfirst() {
6194
+ return barFlag((i) => i === 0);
6195
+ },
6196
+ get islast() {
6197
+ return barFlag((i, n) => i === n - 1);
6198
+ },
6199
+ get isconfirmed() {
6200
+ return barFlag((i, n) => i < n - 1 || chartCtx.lastBarConfirmed === true);
6201
+ },
6202
+ get isrealtime() {
6203
+ return barFlag(lastRealtime);
6204
+ },
6205
+ get ishistory() {
6206
+ return barFlag((i, n) => !lastRealtime(i, n));
6207
+ },
6208
+ get isnew() {
6209
+ return barFlag((i, n) => !lastRealtime(i, n) || chartCtx.lastBarNew !== false);
6210
+ },
6211
+ get islastconfirmedhistory() {
6212
+ return barFlag((i, n) => {
6213
+ const lastConfirmed = chartCtx.lastBarConfirmed === true && chartCtx.realtime !== true;
6214
+ return i === (lastConfirmed ? n - 1 : n - 2);
6215
+ });
6216
+ }
6217
+ };
6166
6218
  var session = {
6167
6219
  regular: "regular",
6168
6220
  extended: "extended",