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.
- package/README.md +1 -1
- package/dist/array/index.d.ts.map +1 -1
- package/dist/callsite/index.d.ts +1 -0
- package/dist/callsite/index.d.ts.map +1 -1
- package/dist/color/index.d.ts +4 -4
- package/dist/color/index.d.ts.map +1 -1
- package/dist/index.cjs +197 -232
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +197 -232
- package/dist/math/index.d.ts.map +1 -1
- package/dist/runtime/index.cjs +1 -1
- package/dist/runtime/index.mjs +1 -1
- package/dist/runtime/types.d.ts +21 -1
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/script/index.cjs +293 -241
- package/dist/script/index.d.ts +71 -16
- package/dist/script/index.d.ts.map +1 -1
- package/dist/script/index.mjs +293 -241
- package/dist/strategy/index.d.ts.map +1 -1
- package/dist/ta/index.d.ts.map +1 -1
- package/dist/ta/running-sum.d.ts +3 -0
- package/dist/ta/running-sum.d.ts.map +1 -0
- package/dist/types/metadata.d.ts +10 -1
- package/dist/types/metadata.d.ts.map +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -234,26 +234,86 @@ function ge(a, b2) {
|
|
|
234
234
|
return valid(a, b2) && b2 - a <= EPSILON;
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
// src/ta/
|
|
238
|
-
|
|
239
|
-
|
|
237
|
+
// src/ta/running-sum.ts
|
|
238
|
+
var view = new DataView(new ArrayBuffer(8));
|
|
239
|
+
function exponentOf(x) {
|
|
240
|
+
view.setFloat64(0, x);
|
|
241
|
+
const e2 = view.getUint16(0) >> 4 & 2047;
|
|
242
|
+
return e2 === 0 ? -1074 : e2 - 1023;
|
|
243
|
+
}
|
|
244
|
+
function compensationLost(x, c) {
|
|
245
|
+
if (c === 0 || x === 0) return false;
|
|
246
|
+
const ulp = 2 ** (exponentOf(x) - 52);
|
|
247
|
+
const q = c / ulp;
|
|
248
|
+
const mantissa = x / ulp;
|
|
249
|
+
const f = Math.floor(q);
|
|
250
|
+
const d = q - f;
|
|
251
|
+
const applied = d > 0.5 ? f + 1 : d < 0.5 ? f : (mantissa - f) % 2 === 0 ? f : f + 1;
|
|
252
|
+
return Math.abs(applied) < Math.abs(q);
|
|
253
|
+
}
|
|
254
|
+
function isNa(v) {
|
|
255
|
+
return v === void 0 || v === null || !Number.isFinite(v);
|
|
256
|
+
}
|
|
257
|
+
function runningSum(source, length2) {
|
|
240
258
|
const len = Math.floor(length2);
|
|
241
|
-
const
|
|
259
|
+
const out = new Array(source.length).fill(NaN);
|
|
260
|
+
if (!(len >= 1)) return out;
|
|
261
|
+
const values2 = [];
|
|
262
|
+
const stored = [];
|
|
263
|
+
let s = 0;
|
|
264
|
+
let c = 0;
|
|
265
|
+
let previous = NaN;
|
|
266
|
+
const kahanAdd = (v) => {
|
|
267
|
+
const y = v - c;
|
|
268
|
+
const t2 = s + y;
|
|
269
|
+
c = t2 - s - y;
|
|
270
|
+
s = t2;
|
|
271
|
+
return y;
|
|
272
|
+
};
|
|
242
273
|
for (let i = 0; i < source.length; i++) {
|
|
243
274
|
const v = source[i];
|
|
244
|
-
if (
|
|
245
|
-
|
|
246
|
-
|
|
275
|
+
if (isNa(v)) {
|
|
276
|
+
out[i] = previous;
|
|
277
|
+
continue;
|
|
247
278
|
}
|
|
248
|
-
|
|
249
|
-
|
|
279
|
+
const x = v;
|
|
280
|
+
const c0 = c;
|
|
281
|
+
const n = values2.length;
|
|
282
|
+
if (n >= len) kahanAdd(-stored[n - len]);
|
|
283
|
+
values2.push(x);
|
|
284
|
+
if (compensationLost(x, c0)) {
|
|
285
|
+
let fresh = 0;
|
|
286
|
+
for (let k = values2.length - 1; k >= Math.max(0, values2.length - len); k--) fresh += values2[k];
|
|
287
|
+
s = fresh;
|
|
288
|
+
c = 0;
|
|
289
|
+
stored.push(x);
|
|
250
290
|
} else {
|
|
251
|
-
|
|
252
|
-
for (const x of window) sum4 += x;
|
|
253
|
-
result.push(sum4 / len);
|
|
291
|
+
stored.push(kahanAdd(x));
|
|
254
292
|
}
|
|
293
|
+
previous = values2.length >= len ? s : NaN;
|
|
294
|
+
out[i] = previous;
|
|
255
295
|
}
|
|
256
|
-
return
|
|
296
|
+
return out;
|
|
297
|
+
}
|
|
298
|
+
function runningVariance(source, length2, biased) {
|
|
299
|
+
const len = Math.floor(length2);
|
|
300
|
+
const squares = Array.from({ length: source.length }, (_, i) => {
|
|
301
|
+
const v = source[i];
|
|
302
|
+
return isNa(v) ? NaN : v * v;
|
|
303
|
+
});
|
|
304
|
+
const sums = runningSum(source, len);
|
|
305
|
+
const sumSquares = runningSum(squares, len);
|
|
306
|
+
return sums.map((sum4, i) => {
|
|
307
|
+
const mean = sum4 / len;
|
|
308
|
+
const sq = sumSquares[i];
|
|
309
|
+
return biased ? sq / len - mean * mean : sq / (len - 1) - mean * sum4 / (len - 1);
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// src/ta/index.ts
|
|
314
|
+
function sma(source, length2) {
|
|
315
|
+
const len = Math.floor(length2);
|
|
316
|
+
return runningSum(source, len).map((sum4) => sum4 / len);
|
|
257
317
|
}
|
|
258
318
|
function strictWindowMean(source, length2) {
|
|
259
319
|
const len = Math.floor(length2);
|
|
@@ -273,7 +333,7 @@ function ema(source, length2) {
|
|
|
273
333
|
let initSum = 0;
|
|
274
334
|
for (let i = 0; i < source.length; i++) {
|
|
275
335
|
const val = source[i];
|
|
276
|
-
if (val !== void 0 &&
|
|
336
|
+
if (val !== void 0 && Number.isFinite(val)) {
|
|
277
337
|
initSum += val;
|
|
278
338
|
validCount++;
|
|
279
339
|
if (validCount === len) {
|
|
@@ -291,7 +351,7 @@ function ema(source, length2) {
|
|
|
291
351
|
result.push(emaValue);
|
|
292
352
|
} else {
|
|
293
353
|
const val = source[i];
|
|
294
|
-
if (val !== void 0 &&
|
|
354
|
+
if (val !== void 0 && Number.isFinite(val)) {
|
|
295
355
|
emaValue = (val - emaValue) * multiplier + emaValue;
|
|
296
356
|
result.push(emaValue);
|
|
297
357
|
} else {
|
|
@@ -348,14 +408,7 @@ function bb(series, length2, mult2) {
|
|
|
348
408
|
return [basis, upper2, lower2];
|
|
349
409
|
}
|
|
350
410
|
function stdev(source, length2, biased = true) {
|
|
351
|
-
|
|
352
|
-
return source.map((_, i) => {
|
|
353
|
-
const values2 = lastValues(source, i, len);
|
|
354
|
-
if (!values2) return NaN;
|
|
355
|
-
const mean = values2.reduce((a, b2) => a + b2, 0) / len;
|
|
356
|
-
const squares = values2.reduce((a, b2) => a + (b2 - mean) * (b2 - mean), 0);
|
|
357
|
-
return Math.sqrt(squares / (biased ? len : len - 1));
|
|
358
|
-
});
|
|
411
|
+
return variance(source, length2, biased).map((v) => Number.isNaN(v) ? NaN : v > 0 ? Math.sqrt(v) : 0);
|
|
359
412
|
}
|
|
360
413
|
function lastValues(source, i, length2) {
|
|
361
414
|
const values2 = [];
|
|
@@ -509,13 +562,12 @@ function supertrend(factor, atrPeriod, high, low, close, wicks = false) {
|
|
|
509
562
|
function rma(source, length2) {
|
|
510
563
|
const result = [];
|
|
511
564
|
const len = Math.floor(length2);
|
|
512
|
-
const alpha = 1 / len;
|
|
513
565
|
let firstValidIndex = -1;
|
|
514
566
|
let validCount = 0;
|
|
515
567
|
let initSum = 0;
|
|
516
568
|
for (let i = 0; i < source.length; i++) {
|
|
517
569
|
const val = source[i];
|
|
518
|
-
if (val !== void 0 &&
|
|
570
|
+
if (val !== void 0 && Number.isFinite(val)) {
|
|
519
571
|
initSum += val;
|
|
520
572
|
validCount++;
|
|
521
573
|
if (validCount === len) {
|
|
@@ -533,8 +585,8 @@ function rma(source, length2) {
|
|
|
533
585
|
result.push(rmaValue);
|
|
534
586
|
} else {
|
|
535
587
|
const val = source[i];
|
|
536
|
-
if (val !== void 0 &&
|
|
537
|
-
rmaValue =
|
|
588
|
+
if (val !== void 0 && Number.isFinite(val)) {
|
|
589
|
+
rmaValue = (val + (len - 1) * rmaValue) / len;
|
|
538
590
|
result.push(rmaValue);
|
|
539
591
|
} else {
|
|
540
592
|
result.push(NaN);
|
|
@@ -548,18 +600,22 @@ function wma(source, length2) {
|
|
|
548
600
|
const len = Math.floor(length2);
|
|
549
601
|
const filled = [];
|
|
550
602
|
let last2 = NaN;
|
|
603
|
+
let count = 0;
|
|
551
604
|
for (let i = 0; i < source.length; i++) {
|
|
552
605
|
const v = source[i];
|
|
553
|
-
const
|
|
554
|
-
if (!
|
|
606
|
+
const isNa2 = v === void 0 || v === null || !Number.isFinite(v);
|
|
607
|
+
if (!isNa2) {
|
|
608
|
+
last2 = v;
|
|
609
|
+
count++;
|
|
610
|
+
}
|
|
555
611
|
filled.push(last2);
|
|
556
|
-
if (
|
|
612
|
+
if (isNa2 || count < len) {
|
|
557
613
|
result.push(NaN);
|
|
558
614
|
continue;
|
|
559
615
|
}
|
|
560
616
|
let sum4 = 0;
|
|
561
617
|
let weightSum = 0;
|
|
562
|
-
for (let j =
|
|
618
|
+
for (let j = len - 1; j >= 0; j--) {
|
|
563
619
|
const weight = len - j;
|
|
564
620
|
sum4 += filled[i - j] * weight;
|
|
565
621
|
weightSum += weight;
|
|
@@ -585,7 +641,7 @@ function lowest(source, length2) {
|
|
|
585
641
|
function cum(source) {
|
|
586
642
|
let sum4 = 0;
|
|
587
643
|
return source.map((v) => {
|
|
588
|
-
if (Number.
|
|
644
|
+
if (!Number.isFinite(v)) return NaN;
|
|
589
645
|
sum4 += v;
|
|
590
646
|
return sum4;
|
|
591
647
|
});
|
|
@@ -603,41 +659,24 @@ function cross(source1, source2) {
|
|
|
603
659
|
}
|
|
604
660
|
return result;
|
|
605
661
|
}
|
|
606
|
-
function
|
|
662
|
+
function monotonic(source, length2, step) {
|
|
607
663
|
const result = [];
|
|
664
|
+
const values2 = [];
|
|
608
665
|
for (let i = 0; i < source.length; i++) {
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
isRising = false;
|
|
616
|
-
break;
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
result.push(isRising);
|
|
620
|
-
}
|
|
666
|
+
const v = source[i];
|
|
667
|
+
if (!Number.isNaN(v)) values2.push(v);
|
|
668
|
+
const n = values2.length;
|
|
669
|
+
let ok = n > length2;
|
|
670
|
+
for (let j = 1; ok && j <= length2; j++) ok = step(values2[n - j], values2[n - j - 1]);
|
|
671
|
+
result.push(ok);
|
|
621
672
|
}
|
|
622
673
|
return result;
|
|
623
674
|
}
|
|
675
|
+
function rising(source, length2) {
|
|
676
|
+
return monotonic(source, length2, gt);
|
|
677
|
+
}
|
|
624
678
|
function falling(source, length2) {
|
|
625
|
-
|
|
626
|
-
for (let i = 0; i < source.length; i++) {
|
|
627
|
-
if (i < length2) {
|
|
628
|
-
result.push(false);
|
|
629
|
-
} else {
|
|
630
|
-
let isFalling = true;
|
|
631
|
-
for (let j = 1; j <= length2; j++) {
|
|
632
|
-
if (source[i - j + 1] >= source[i - j]) {
|
|
633
|
-
isFalling = false;
|
|
634
|
-
break;
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
result.push(isFalling);
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
return result;
|
|
679
|
+
return monotonic(source, length2, lt);
|
|
641
680
|
}
|
|
642
681
|
function roc(source, length2) {
|
|
643
682
|
const result = [];
|
|
@@ -690,53 +729,19 @@ function dev(source, length2) {
|
|
|
690
729
|
return result;
|
|
691
730
|
}
|
|
692
731
|
function variance(source, length2, biased = true) {
|
|
693
|
-
const result = [];
|
|
694
732
|
const len = Math.floor(length2);
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
const v = source[i];
|
|
698
|
-
if (v !== void 0 && v !== null && !Number.isNaN(v)) {
|
|
699
|
-
window.push(v);
|
|
700
|
-
if (window.length > len) window.shift();
|
|
701
|
-
}
|
|
702
|
-
const divisor = biased ? len : len - 1;
|
|
703
|
-
if (window.length < len || divisor <= 0) {
|
|
704
|
-
result.push(NaN);
|
|
705
|
-
continue;
|
|
706
|
-
}
|
|
707
|
-
const mean = window.reduce((a, x) => a + x, 0) / len;
|
|
708
|
-
let sumSquares = 0;
|
|
709
|
-
for (const x of window) sumSquares += (x - mean) * (x - mean);
|
|
710
|
-
result.push(sumSquares / divisor);
|
|
711
|
-
}
|
|
712
|
-
return result;
|
|
733
|
+
if ((biased ? len : len - 1) <= 0) return source.map(() => NaN);
|
|
734
|
+
return runningVariance(source, len, biased);
|
|
713
735
|
}
|
|
714
736
|
function median(source, length2) {
|
|
715
|
-
const
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
values2.push(source[i - j]);
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
if (values2.length === 0) {
|
|
727
|
-
result.push(NaN);
|
|
728
|
-
} else {
|
|
729
|
-
values2.sort((a, b2) => a - b2);
|
|
730
|
-
const mid = Math.floor(values2.length / 2);
|
|
731
|
-
if (values2.length % 2 === 0) {
|
|
732
|
-
result.push((values2[mid - 1] + values2[mid]) / 2);
|
|
733
|
-
} else {
|
|
734
|
-
result.push(values2[mid]);
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
return result;
|
|
737
|
+
const len = Math.floor(length2);
|
|
738
|
+
return source.map((_, i) => {
|
|
739
|
+
const values2 = lastValues(source, i, len);
|
|
740
|
+
if (!values2) return NaN;
|
|
741
|
+
values2.sort((a, b2) => a - b2);
|
|
742
|
+
const mid = Math.floor(len / 2);
|
|
743
|
+
return len % 2 === 0 ? (values2[mid - 1] + values2[mid]) / 2 : values2[mid];
|
|
744
|
+
});
|
|
740
745
|
}
|
|
741
746
|
function swma(source) {
|
|
742
747
|
const result = [];
|
|
@@ -861,33 +866,16 @@ function correlation(source1, source2, length2) {
|
|
|
861
866
|
function percentrank(source, length2) {
|
|
862
867
|
const result = [];
|
|
863
868
|
for (let i = 0; i < source.length; i++) {
|
|
864
|
-
|
|
869
|
+
const currentValue = source[i];
|
|
870
|
+
if (i < length2 || Number.isNaN(currentValue)) {
|
|
865
871
|
result.push(NaN);
|
|
866
|
-
|
|
867
|
-
if (isNaN(source[i])) {
|
|
868
|
-
result.push(NaN);
|
|
869
|
-
continue;
|
|
870
|
-
}
|
|
871
|
-
let hasNaN = false;
|
|
872
|
-
for (let j = 1; j <= length2; j++) {
|
|
873
|
-
if (isNaN(source[i - j])) {
|
|
874
|
-
hasNaN = true;
|
|
875
|
-
break;
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
if (hasNaN) {
|
|
879
|
-
result.push(NaN);
|
|
880
|
-
} else {
|
|
881
|
-
const currentValue = source[i];
|
|
882
|
-
let countLessOrEqual = 0;
|
|
883
|
-
for (let j = 1; j <= length2; j++) {
|
|
884
|
-
if (source[i - j] <= currentValue) {
|
|
885
|
-
countLessOrEqual++;
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
result.push(countLessOrEqual / length2 * 100);
|
|
889
|
-
}
|
|
872
|
+
continue;
|
|
890
873
|
}
|
|
874
|
+
let countLessOrEqual = 0;
|
|
875
|
+
for (let j = 1; j <= length2; j++) {
|
|
876
|
+
if (le(source[i - j], currentValue)) countLessOrEqual++;
|
|
877
|
+
}
|
|
878
|
+
result.push(countLessOrEqual / length2 * 100);
|
|
891
879
|
}
|
|
892
880
|
return result;
|
|
893
881
|
}
|
|
@@ -938,12 +926,8 @@ function mfi(source, length2, volume) {
|
|
|
938
926
|
upperFlow.push(le(change3, 0) ? 0 : flow);
|
|
939
927
|
lowerFlow.push(ge(change3, 0) ? 0 : flow);
|
|
940
928
|
}
|
|
941
|
-
const
|
|
942
|
-
|
|
943
|
-
return values2 ? values2.reduce((a, b2) => a + b2, 0) : NaN;
|
|
944
|
-
};
|
|
945
|
-
const upper2 = upperFlow.map((_, i) => sumAt(upperFlow, i));
|
|
946
|
-
const lower2 = lowerFlow.map((_, i) => sumAt(lowerFlow, i));
|
|
929
|
+
const upper2 = runningSum(upperFlow, length2);
|
|
930
|
+
const lower2 = runningSum(lowerFlow, length2);
|
|
947
931
|
return upper2.map((u, i) => {
|
|
948
932
|
const l = lower2[i];
|
|
949
933
|
if (Number.isNaN(u) || Number.isNaN(l)) return NaN;
|
|
@@ -1414,63 +1398,36 @@ function mode(source, length2) {
|
|
|
1414
1398
|
return result;
|
|
1415
1399
|
}
|
|
1416
1400
|
function percentile_linear_interpolation(source, length2, percentage) {
|
|
1401
|
+
return sortedWindow(source, length2, (s) => {
|
|
1402
|
+
const pos2 = percentage / 100 * length2 - 0.5;
|
|
1403
|
+
if (pos2 <= 0) return s[0];
|
|
1404
|
+
if (pos2 >= length2 - 1) return s[length2 - 1];
|
|
1405
|
+
const lo = Math.floor(pos2);
|
|
1406
|
+
return s[lo] + (pos2 - lo) * (s[lo + 1] - s[lo]);
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
1409
|
+
function sortedWindow(source, length2, fn) {
|
|
1417
1410
|
const result = [];
|
|
1411
|
+
const values2 = [];
|
|
1412
|
+
const bars = [];
|
|
1418
1413
|
for (let i = 0; i < source.length; i++) {
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
const
|
|
1426
|
-
values2.
|
|
1427
|
-
|
|
1428
|
-
if (values2.some((v) => isNaN(v))) {
|
|
1429
|
-
result.push(NaN);
|
|
1430
|
-
continue;
|
|
1431
|
-
}
|
|
1432
|
-
const sorted = [...values2].sort((a, b2) => a - b2);
|
|
1433
|
-
const position = percentage / 100 * (sorted.length - 1);
|
|
1434
|
-
const lowerIndex = Math.floor(position);
|
|
1435
|
-
const upperIndex = Math.ceil(position);
|
|
1436
|
-
if (lowerIndex === upperIndex) {
|
|
1437
|
-
result.push(sorted[lowerIndex]);
|
|
1438
|
-
} else {
|
|
1439
|
-
const fraction = position - lowerIndex;
|
|
1440
|
-
const interpolated = sorted[lowerIndex] + fraction * (sorted[upperIndex] - sorted[lowerIndex]);
|
|
1441
|
-
result.push(interpolated);
|
|
1414
|
+
const v = source[i];
|
|
1415
|
+
let k = 0;
|
|
1416
|
+
while (k < values2.length && !(values2[k] >= v)) k++;
|
|
1417
|
+
values2.splice(k, 0, v);
|
|
1418
|
+
bars.splice(k, 0, i);
|
|
1419
|
+
if (i >= length2) {
|
|
1420
|
+
const old = bars.indexOf(i - length2);
|
|
1421
|
+
values2.splice(old, 1);
|
|
1422
|
+
bars.splice(old, 1);
|
|
1442
1423
|
}
|
|
1424
|
+
result.push(i < length2 - 1 ? NaN : fn(values2));
|
|
1443
1425
|
}
|
|
1444
1426
|
return result;
|
|
1445
1427
|
}
|
|
1446
1428
|
function percentile_nearest_rank(source, length2, percentage) {
|
|
1447
|
-
const
|
|
1448
|
-
|
|
1449
|
-
if (i < length2 - 1) {
|
|
1450
|
-
result.push(NaN);
|
|
1451
|
-
continue;
|
|
1452
|
-
}
|
|
1453
|
-
const values2 = [];
|
|
1454
|
-
for (let j = 0; j < length2; j++) {
|
|
1455
|
-
const value = source[i - j];
|
|
1456
|
-
if (!isNaN(value)) {
|
|
1457
|
-
values2.push(value);
|
|
1458
|
-
}
|
|
1459
|
-
}
|
|
1460
|
-
if (values2.length === 0) {
|
|
1461
|
-
result.push(NaN);
|
|
1462
|
-
continue;
|
|
1463
|
-
}
|
|
1464
|
-
const sorted = [...values2].sort((a, b2) => a - b2);
|
|
1465
|
-
if (percentage >= 100) {
|
|
1466
|
-
result.push(sorted[sorted.length - 1]);
|
|
1467
|
-
continue;
|
|
1468
|
-
}
|
|
1469
|
-
const rank2 = Math.ceil(percentage / 100 * sorted.length);
|
|
1470
|
-
const index = Math.max(0, rank2 - 1);
|
|
1471
|
-
result.push(sorted[index]);
|
|
1472
|
-
}
|
|
1473
|
-
return result;
|
|
1429
|
+
const rank2 = Math.min(length2, Math.max(1, Math.ceil(percentage / 100 * length2)));
|
|
1430
|
+
return sortedWindow(source, length2, (s) => s[rank2 - 1]);
|
|
1474
1431
|
}
|
|
1475
1432
|
function rci(source, length2) {
|
|
1476
1433
|
const result = [];
|
|
@@ -2188,7 +2145,7 @@ var Series = class _Series {
|
|
|
2188
2145
|
return new _Series(this.dataSource, (bar, i, data) => {
|
|
2189
2146
|
const a = this.extractor(bar, i, data);
|
|
2190
2147
|
const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
|
|
2191
|
-
return
|
|
2148
|
+
return a / b2;
|
|
2192
2149
|
});
|
|
2193
2150
|
}
|
|
2194
2151
|
/**
|
|
@@ -2611,23 +2568,7 @@ function avg(...values2) {
|
|
|
2611
2568
|
}
|
|
2612
2569
|
function sum(source, length2) {
|
|
2613
2570
|
const sourceArray = source instanceof Series ? source.toArray() : source;
|
|
2614
|
-
const result =
|
|
2615
|
-
const len = Math.floor(length2);
|
|
2616
|
-
const window = [];
|
|
2617
|
-
for (let i = 0; i < sourceArray.length; i++) {
|
|
2618
|
-
const v = sourceArray[i];
|
|
2619
|
-
if (v !== void 0 && v !== null && !Number.isNaN(v)) {
|
|
2620
|
-
window.push(v);
|
|
2621
|
-
if (window.length > len) window.shift();
|
|
2622
|
-
}
|
|
2623
|
-
if (window.length < len) {
|
|
2624
|
-
result.push(NaN);
|
|
2625
|
-
} else {
|
|
2626
|
-
let total = 0;
|
|
2627
|
-
for (const x of window) total += x;
|
|
2628
|
-
result.push(total);
|
|
2629
|
-
}
|
|
2630
|
-
}
|
|
2571
|
+
const result = runningSum(sourceArray, length2);
|
|
2631
2572
|
if (source instanceof Series) {
|
|
2632
2573
|
return Series.fromArray(source.bars, result);
|
|
2633
2574
|
}
|
|
@@ -3195,15 +3136,27 @@ function percentile_linear_interpolation2(id, percentage) {
|
|
|
3195
3136
|
if (id.length === 0) {
|
|
3196
3137
|
return NaN;
|
|
3197
3138
|
}
|
|
3198
|
-
const
|
|
3199
|
-
|
|
3139
|
+
const s = sortedNaLast(id);
|
|
3140
|
+
const n = s.length;
|
|
3141
|
+
const pos2 = percentage / 100 * n - 0.5;
|
|
3142
|
+
if (pos2 <= 0) return s[0];
|
|
3143
|
+
if (pos2 >= n - 1) return s[n - 1];
|
|
3144
|
+
const lo = Math.floor(pos2);
|
|
3145
|
+
const f = pos2 - lo;
|
|
3146
|
+
if (f === 0) return s[lo];
|
|
3147
|
+
return Number.isNaN(s[n - 1]) ? NaN : s[lo] + f * (s[lo + 1] - s[lo]);
|
|
3148
|
+
}
|
|
3149
|
+
function sortedNaLast(id) {
|
|
3150
|
+
const numbers = id.filter((v) => !Number.isNaN(v)).sort((a, b2) => a - b2);
|
|
3151
|
+
return [...numbers, ...Array(id.length - numbers.length).fill(NaN)];
|
|
3200
3152
|
}
|
|
3201
3153
|
function percentile_nearest_rank2(id, percentage) {
|
|
3202
3154
|
if (id.length === 0) {
|
|
3203
3155
|
return NaN;
|
|
3204
3156
|
}
|
|
3205
|
-
const
|
|
3206
|
-
|
|
3157
|
+
const s = sortedNaLast(id);
|
|
3158
|
+
const rank2 = Math.min(s.length, Math.max(1, Math.ceil(percentage / 100 * s.length)));
|
|
3159
|
+
return s[rank2 - 1];
|
|
3207
3160
|
}
|
|
3208
3161
|
function percentrank2(id, index) {
|
|
3209
3162
|
if (id.length === 0 || index < 0 || index >= id.length) {
|
|
@@ -3400,9 +3353,9 @@ function shortestDigits(x) {
|
|
|
3400
3353
|
function exactDigits(x) {
|
|
3401
3354
|
const abs3 = Math.abs(x);
|
|
3402
3355
|
if (abs3 === 0) return { digits: "", intLen: 0 };
|
|
3403
|
-
const
|
|
3404
|
-
|
|
3405
|
-
const bits =
|
|
3356
|
+
const view2 = new DataView(new ArrayBuffer(8));
|
|
3357
|
+
view2.setFloat64(0, abs3);
|
|
3358
|
+
const bits = view2.getBigUint64(0);
|
|
3406
3359
|
const expBits = Number(bits >> 52n & 0x7ffn);
|
|
3407
3360
|
let mant = bits & 0xfffffffffffffn;
|
|
3408
3361
|
const e2 = expBits === 0 ? -1074 : expBits - 1075;
|
|
@@ -3914,11 +3867,13 @@ __export(color_exports, {
|
|
|
3914
3867
|
white: () => white,
|
|
3915
3868
|
yellow: () => yellow
|
|
3916
3869
|
});
|
|
3870
|
+
var channel = (v) => v === null || v === void 0 || Number.isNaN(v) ? 0 : Math.max(0, Math.min(255, Math.trunc(v)));
|
|
3871
|
+
var alphaOf = (transp) => transp === null || Number.isNaN(transp) ? 0 : 1 - Math.max(0, Math.min(100, transp)) / 100;
|
|
3917
3872
|
function rgb(red2, green2, blue2, transp) {
|
|
3918
|
-
const r2 =
|
|
3919
|
-
const g2 =
|
|
3920
|
-
const b2 =
|
|
3921
|
-
const a = transp !== void 0 ?
|
|
3873
|
+
const r2 = channel(red2);
|
|
3874
|
+
const g2 = channel(green2);
|
|
3875
|
+
const b2 = channel(blue2);
|
|
3876
|
+
const a = transp !== void 0 ? alphaOf(transp) : 1;
|
|
3922
3877
|
if (a === 1) {
|
|
3923
3878
|
return `rgb(${r2}, ${g2}, ${b2})`;
|
|
3924
3879
|
}
|
|
@@ -3945,7 +3900,8 @@ function b(clr) {
|
|
|
3945
3900
|
return parseColor(clr).b;
|
|
3946
3901
|
}
|
|
3947
3902
|
function t(clr) {
|
|
3948
|
-
|
|
3903
|
+
const alpha = Math.round((1 - parseColor(clr).t / 100) * 255);
|
|
3904
|
+
return Math.round((1 - alpha / 255) * 100);
|
|
3949
3905
|
}
|
|
3950
3906
|
function parseColor(clr) {
|
|
3951
3907
|
if (typeof clr === "string") {
|
|
@@ -3998,13 +3954,12 @@ function from_gradient(value, bottom_value, top_value, bottom_color, top_color)
|
|
|
3998
3954
|
};
|
|
3999
3955
|
const c1 = rgba(bottom_color);
|
|
4000
3956
|
const c2 = rgba(top_color);
|
|
4001
|
-
const
|
|
4002
|
-
const w2 = c2.a * k;
|
|
4003
|
-
const a = w1 + w2;
|
|
3957
|
+
const a = c1.a * (1 - k) + c2.a * k;
|
|
4004
3958
|
if (a === 0) return transparent;
|
|
4005
|
-
const mix = (x1, x2) => Math.floor((x1 *
|
|
3959
|
+
const mix = (x1, x2) => Math.floor((x1 / 255 * c1.a * (1 - k) + x2 / 255 * c2.a * k) / (a / 255));
|
|
4006
3960
|
const [r2, g2, b2] = [mix(c1.r, c2.r), mix(c1.g, c2.g), mix(c1.b, c2.b)];
|
|
4007
|
-
|
|
3961
|
+
const alpha = Math.floor(a);
|
|
3962
|
+
return alpha === 255 ? `rgb(${r2}, ${g2}, ${b2})` : `rgba(${r2}, ${g2}, ${b2}, ${alpha / 255})`;
|
|
4008
3963
|
}
|
|
4009
3964
|
|
|
4010
3965
|
// src/time/index.ts
|
|
@@ -6215,6 +6170,7 @@ var format_italic = 2;
|
|
|
6215
6170
|
// src/callsite/index.ts
|
|
6216
6171
|
var callsite_exports = {};
|
|
6217
6172
|
__export(callsite_exports, {
|
|
6173
|
+
barssince: () => barssince2,
|
|
6218
6174
|
cross: () => cross2,
|
|
6219
6175
|
crossover: () => crossover2,
|
|
6220
6176
|
crossunder: () => crossunder2,
|
|
@@ -6246,6 +6202,14 @@ function crossover2() {
|
|
|
6246
6202
|
function crossunder2() {
|
|
6247
6203
|
return twoSeriesSite((a, b2, pa, pb) => a < b2 && pa >= pb);
|
|
6248
6204
|
}
|
|
6205
|
+
function barssince2() {
|
|
6206
|
+
let count = NaN;
|
|
6207
|
+
return (condition) => {
|
|
6208
|
+
if (condition && !Number.isNaN(condition)) count = 0;
|
|
6209
|
+
else if (!Number.isNaN(count)) count++;
|
|
6210
|
+
return count;
|
|
6211
|
+
};
|
|
6212
|
+
}
|
|
6249
6213
|
function cross2() {
|
|
6250
6214
|
return twoSeriesSite((a, b2, pa, pb) => a > b2 && pa <= pb || a < b2 && pa >= pb);
|
|
6251
6215
|
}
|
|
@@ -6256,7 +6220,7 @@ __export(ta_series_exports, {
|
|
|
6256
6220
|
accdist: () => accdist2,
|
|
6257
6221
|
alma: () => alma2,
|
|
6258
6222
|
atr: () => atr2,
|
|
6259
|
-
barssince: () =>
|
|
6223
|
+
barssince: () => barssince3,
|
|
6260
6224
|
bb: () => bb2,
|
|
6261
6225
|
bbw: () => bbw2,
|
|
6262
6226
|
cci: () => cci2,
|
|
@@ -6644,7 +6608,7 @@ function pivotlow2(source, leftbars, rightbars) {
|
|
|
6644
6608
|
const result = pivotlow(source.toArray(), leftbars, rightbars);
|
|
6645
6609
|
return Series.fromArray(bars, result);
|
|
6646
6610
|
}
|
|
6647
|
-
function
|
|
6611
|
+
function barssince3(condition) {
|
|
6648
6612
|
const bars = condition.bars;
|
|
6649
6613
|
const boolValues = condition.toArray().map((v) => v === 1);
|
|
6650
6614
|
const result = barssince(boolValues);
|
|
@@ -6796,7 +6760,7 @@ var ta = {
|
|
|
6796
6760
|
hma: hma2,
|
|
6797
6761
|
pivothigh: pivothigh2,
|
|
6798
6762
|
pivotlow: pivotlow2,
|
|
6799
|
-
barssince:
|
|
6763
|
+
barssince: barssince3,
|
|
6800
6764
|
valuewhen: valuewhen2,
|
|
6801
6765
|
dmi: dmi2,
|
|
6802
6766
|
tsi: tsi2,
|
|
@@ -6828,7 +6792,7 @@ var ta = {
|
|
|
6828
6792
|
|
|
6829
6793
|
// src/utils/index.ts
|
|
6830
6794
|
function isNA(value) {
|
|
6831
|
-
return value === null || value === void 0 || Number.isNaN(value) || isDeleted(value);
|
|
6795
|
+
return value === null || value === void 0 || Number.isNaN(value) || value === Infinity || value === -Infinity || isDeleted(value);
|
|
6832
6796
|
}
|
|
6833
6797
|
function nz(value, defaultValue = 0) {
|
|
6834
6798
|
return isNA(value) ? defaultValue : value;
|
|
@@ -6837,7 +6801,7 @@ function fixnan(source) {
|
|
|
6837
6801
|
let last2;
|
|
6838
6802
|
let seen = false;
|
|
6839
6803
|
return source.map((v) => {
|
|
6840
|
-
if (!
|
|
6804
|
+
if (!(v === null || v === void 0 || Number.isNaN(v) || isDeleted(v))) {
|
|
6841
6805
|
last2 = v;
|
|
6842
6806
|
seen = true;
|
|
6843
6807
|
return v;
|
|
@@ -6853,7 +6817,7 @@ function at(source, i, offset = 0) {
|
|
|
6853
6817
|
return j >= 0 && j < source.length ? source[j] ?? NaN : NaN;
|
|
6854
6818
|
}
|
|
6855
6819
|
function div(a, b2) {
|
|
6856
|
-
return
|
|
6820
|
+
return a / b2;
|
|
6857
6821
|
}
|
|
6858
6822
|
function ohlcFromBars(bars) {
|
|
6859
6823
|
return {
|
|
@@ -7487,7 +7451,7 @@ function hline(price, title, color, linestyle, linewidth) {
|
|
|
7487
7451
|
const options = {
|
|
7488
7452
|
color,
|
|
7489
7453
|
lineWidth: linewidth,
|
|
7490
|
-
lineStyle: getLineStyle(linestyle)
|
|
7454
|
+
lineStyle: getLineStyle(linestyle ?? "dashed")
|
|
7491
7455
|
};
|
|
7492
7456
|
const seriesHandle = context.chart.addSeries("line", options);
|
|
7493
7457
|
const data = context.ohlcv.time.map((time) => ({
|
|
@@ -7734,9 +7698,10 @@ var STRATEGY_DEFAULTS = {
|
|
|
7734
7698
|
calc_on_order_fills: false,
|
|
7735
7699
|
calc_on_every_tick: false,
|
|
7736
7700
|
backtest_fill_limits_assumption: 0,
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7701
|
+
// v6 values; PineScript v5: fixed / 1 / 1000000 and margins 0
|
|
7702
|
+
default_qty_type: "percent_of_equity",
|
|
7703
|
+
default_qty_value: 100,
|
|
7704
|
+
initial_capital: 1e5,
|
|
7740
7705
|
slippage: 0,
|
|
7741
7706
|
commission_type: "percent",
|
|
7742
7707
|
commission_value: 0,
|
|
@@ -7992,7 +7957,7 @@ var SimpleInputAdapter = class {
|
|
|
7992
7957
|
};
|
|
7993
7958
|
|
|
7994
7959
|
// src/index.ts
|
|
7995
|
-
var VERSION = "0.8.
|
|
7960
|
+
var VERSION = "0.8.2";
|
|
7996
7961
|
var info2 = {
|
|
7997
7962
|
name: "OakScriptJS",
|
|
7998
7963
|
version: VERSION,
|