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.mjs
CHANGED
|
@@ -118,26 +118,86 @@ function ge(a, b2) {
|
|
|
118
118
|
return valid(a, b2) && b2 - a <= EPSILON;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
// src/ta/
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
// src/ta/running-sum.ts
|
|
122
|
+
var view = new DataView(new ArrayBuffer(8));
|
|
123
|
+
function exponentOf(x) {
|
|
124
|
+
view.setFloat64(0, x);
|
|
125
|
+
const e2 = view.getUint16(0) >> 4 & 2047;
|
|
126
|
+
return e2 === 0 ? -1074 : e2 - 1023;
|
|
127
|
+
}
|
|
128
|
+
function compensationLost(x, c) {
|
|
129
|
+
if (c === 0 || x === 0) return false;
|
|
130
|
+
const ulp = 2 ** (exponentOf(x) - 52);
|
|
131
|
+
const q = c / ulp;
|
|
132
|
+
const mantissa = x / ulp;
|
|
133
|
+
const f = Math.floor(q);
|
|
134
|
+
const d = q - f;
|
|
135
|
+
const applied = d > 0.5 ? f + 1 : d < 0.5 ? f : (mantissa - f) % 2 === 0 ? f : f + 1;
|
|
136
|
+
return Math.abs(applied) < Math.abs(q);
|
|
137
|
+
}
|
|
138
|
+
function isNa(v) {
|
|
139
|
+
return v === void 0 || v === null || !Number.isFinite(v);
|
|
140
|
+
}
|
|
141
|
+
function runningSum(source, length2) {
|
|
124
142
|
const len = Math.floor(length2);
|
|
125
|
-
const
|
|
143
|
+
const out = new Array(source.length).fill(NaN);
|
|
144
|
+
if (!(len >= 1)) return out;
|
|
145
|
+
const values2 = [];
|
|
146
|
+
const stored = [];
|
|
147
|
+
let s = 0;
|
|
148
|
+
let c = 0;
|
|
149
|
+
let previous = NaN;
|
|
150
|
+
const kahanAdd = (v) => {
|
|
151
|
+
const y = v - c;
|
|
152
|
+
const t2 = s + y;
|
|
153
|
+
c = t2 - s - y;
|
|
154
|
+
s = t2;
|
|
155
|
+
return y;
|
|
156
|
+
};
|
|
126
157
|
for (let i = 0; i < source.length; i++) {
|
|
127
158
|
const v = source[i];
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
|
|
159
|
+
if (isNa(v)) {
|
|
160
|
+
out[i] = previous;
|
|
161
|
+
continue;
|
|
131
162
|
}
|
|
132
|
-
|
|
133
|
-
|
|
163
|
+
const x = v;
|
|
164
|
+
const c0 = c;
|
|
165
|
+
const n = values2.length;
|
|
166
|
+
if (n >= len) kahanAdd(-stored[n - len]);
|
|
167
|
+
values2.push(x);
|
|
168
|
+
if (compensationLost(x, c0)) {
|
|
169
|
+
let fresh = 0;
|
|
170
|
+
for (let k = values2.length - 1; k >= Math.max(0, values2.length - len); k--) fresh += values2[k];
|
|
171
|
+
s = fresh;
|
|
172
|
+
c = 0;
|
|
173
|
+
stored.push(x);
|
|
134
174
|
} else {
|
|
135
|
-
|
|
136
|
-
for (const x of window) sum4 += x;
|
|
137
|
-
result.push(sum4 / len);
|
|
175
|
+
stored.push(kahanAdd(x));
|
|
138
176
|
}
|
|
177
|
+
previous = values2.length >= len ? s : NaN;
|
|
178
|
+
out[i] = previous;
|
|
139
179
|
}
|
|
140
|
-
return
|
|
180
|
+
return out;
|
|
181
|
+
}
|
|
182
|
+
function runningVariance(source, length2, biased) {
|
|
183
|
+
const len = Math.floor(length2);
|
|
184
|
+
const squares = Array.from({ length: source.length }, (_, i) => {
|
|
185
|
+
const v = source[i];
|
|
186
|
+
return isNa(v) ? NaN : v * v;
|
|
187
|
+
});
|
|
188
|
+
const sums = runningSum(source, len);
|
|
189
|
+
const sumSquares = runningSum(squares, len);
|
|
190
|
+
return sums.map((sum4, i) => {
|
|
191
|
+
const mean = sum4 / len;
|
|
192
|
+
const sq = sumSquares[i];
|
|
193
|
+
return biased ? sq / len - mean * mean : sq / (len - 1) - mean * sum4 / (len - 1);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// src/ta/index.ts
|
|
198
|
+
function sma(source, length2) {
|
|
199
|
+
const len = Math.floor(length2);
|
|
200
|
+
return runningSum(source, len).map((sum4) => sum4 / len);
|
|
141
201
|
}
|
|
142
202
|
function strictWindowMean(source, length2) {
|
|
143
203
|
const len = Math.floor(length2);
|
|
@@ -157,7 +217,7 @@ function ema(source, length2) {
|
|
|
157
217
|
let initSum = 0;
|
|
158
218
|
for (let i = 0; i < source.length; i++) {
|
|
159
219
|
const val = source[i];
|
|
160
|
-
if (val !== void 0 &&
|
|
220
|
+
if (val !== void 0 && Number.isFinite(val)) {
|
|
161
221
|
initSum += val;
|
|
162
222
|
validCount++;
|
|
163
223
|
if (validCount === len) {
|
|
@@ -175,7 +235,7 @@ function ema(source, length2) {
|
|
|
175
235
|
result.push(emaValue);
|
|
176
236
|
} else {
|
|
177
237
|
const val = source[i];
|
|
178
|
-
if (val !== void 0 &&
|
|
238
|
+
if (val !== void 0 && Number.isFinite(val)) {
|
|
179
239
|
emaValue = (val - emaValue) * multiplier + emaValue;
|
|
180
240
|
result.push(emaValue);
|
|
181
241
|
} else {
|
|
@@ -232,14 +292,7 @@ function bb(series, length2, mult2) {
|
|
|
232
292
|
return [basis, upper2, lower2];
|
|
233
293
|
}
|
|
234
294
|
function stdev(source, length2, biased = true) {
|
|
235
|
-
|
|
236
|
-
return source.map((_, i) => {
|
|
237
|
-
const values2 = lastValues(source, i, len);
|
|
238
|
-
if (!values2) return NaN;
|
|
239
|
-
const mean = values2.reduce((a, b2) => a + b2, 0) / len;
|
|
240
|
-
const squares = values2.reduce((a, b2) => a + (b2 - mean) * (b2 - mean), 0);
|
|
241
|
-
return Math.sqrt(squares / (biased ? len : len - 1));
|
|
242
|
-
});
|
|
295
|
+
return variance(source, length2, biased).map((v) => Number.isNaN(v) ? NaN : v > 0 ? Math.sqrt(v) : 0);
|
|
243
296
|
}
|
|
244
297
|
function lastValues(source, i, length2) {
|
|
245
298
|
const values2 = [];
|
|
@@ -393,13 +446,12 @@ function supertrend(factor, atrPeriod, high, low, close, wicks = false) {
|
|
|
393
446
|
function rma(source, length2) {
|
|
394
447
|
const result = [];
|
|
395
448
|
const len = Math.floor(length2);
|
|
396
|
-
const alpha = 1 / len;
|
|
397
449
|
let firstValidIndex = -1;
|
|
398
450
|
let validCount = 0;
|
|
399
451
|
let initSum = 0;
|
|
400
452
|
for (let i = 0; i < source.length; i++) {
|
|
401
453
|
const val = source[i];
|
|
402
|
-
if (val !== void 0 &&
|
|
454
|
+
if (val !== void 0 && Number.isFinite(val)) {
|
|
403
455
|
initSum += val;
|
|
404
456
|
validCount++;
|
|
405
457
|
if (validCount === len) {
|
|
@@ -417,8 +469,8 @@ function rma(source, length2) {
|
|
|
417
469
|
result.push(rmaValue);
|
|
418
470
|
} else {
|
|
419
471
|
const val = source[i];
|
|
420
|
-
if (val !== void 0 &&
|
|
421
|
-
rmaValue =
|
|
472
|
+
if (val !== void 0 && Number.isFinite(val)) {
|
|
473
|
+
rmaValue = (val + (len - 1) * rmaValue) / len;
|
|
422
474
|
result.push(rmaValue);
|
|
423
475
|
} else {
|
|
424
476
|
result.push(NaN);
|
|
@@ -432,18 +484,22 @@ function wma(source, length2) {
|
|
|
432
484
|
const len = Math.floor(length2);
|
|
433
485
|
const filled = [];
|
|
434
486
|
let last2 = NaN;
|
|
487
|
+
let count = 0;
|
|
435
488
|
for (let i = 0; i < source.length; i++) {
|
|
436
489
|
const v = source[i];
|
|
437
|
-
const
|
|
438
|
-
if (!
|
|
490
|
+
const isNa2 = v === void 0 || v === null || !Number.isFinite(v);
|
|
491
|
+
if (!isNa2) {
|
|
492
|
+
last2 = v;
|
|
493
|
+
count++;
|
|
494
|
+
}
|
|
439
495
|
filled.push(last2);
|
|
440
|
-
if (
|
|
496
|
+
if (isNa2 || count < len) {
|
|
441
497
|
result.push(NaN);
|
|
442
498
|
continue;
|
|
443
499
|
}
|
|
444
500
|
let sum4 = 0;
|
|
445
501
|
let weightSum = 0;
|
|
446
|
-
for (let j =
|
|
502
|
+
for (let j = len - 1; j >= 0; j--) {
|
|
447
503
|
const weight = len - j;
|
|
448
504
|
sum4 += filled[i - j] * weight;
|
|
449
505
|
weightSum += weight;
|
|
@@ -469,7 +525,7 @@ function lowest(source, length2) {
|
|
|
469
525
|
function cum(source) {
|
|
470
526
|
let sum4 = 0;
|
|
471
527
|
return source.map((v) => {
|
|
472
|
-
if (Number.
|
|
528
|
+
if (!Number.isFinite(v)) return NaN;
|
|
473
529
|
sum4 += v;
|
|
474
530
|
return sum4;
|
|
475
531
|
});
|
|
@@ -487,41 +543,24 @@ function cross(source1, source2) {
|
|
|
487
543
|
}
|
|
488
544
|
return result;
|
|
489
545
|
}
|
|
490
|
-
function
|
|
546
|
+
function monotonic(source, length2, step) {
|
|
491
547
|
const result = [];
|
|
548
|
+
const values2 = [];
|
|
492
549
|
for (let i = 0; i < source.length; i++) {
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
isRising = false;
|
|
500
|
-
break;
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
result.push(isRising);
|
|
504
|
-
}
|
|
550
|
+
const v = source[i];
|
|
551
|
+
if (!Number.isNaN(v)) values2.push(v);
|
|
552
|
+
const n = values2.length;
|
|
553
|
+
let ok = n > length2;
|
|
554
|
+
for (let j = 1; ok && j <= length2; j++) ok = step(values2[n - j], values2[n - j - 1]);
|
|
555
|
+
result.push(ok);
|
|
505
556
|
}
|
|
506
557
|
return result;
|
|
507
558
|
}
|
|
559
|
+
function rising(source, length2) {
|
|
560
|
+
return monotonic(source, length2, gt);
|
|
561
|
+
}
|
|
508
562
|
function falling(source, length2) {
|
|
509
|
-
|
|
510
|
-
for (let i = 0; i < source.length; i++) {
|
|
511
|
-
if (i < length2) {
|
|
512
|
-
result.push(false);
|
|
513
|
-
} else {
|
|
514
|
-
let isFalling = true;
|
|
515
|
-
for (let j = 1; j <= length2; j++) {
|
|
516
|
-
if (source[i - j + 1] >= source[i - j]) {
|
|
517
|
-
isFalling = false;
|
|
518
|
-
break;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
result.push(isFalling);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
return result;
|
|
563
|
+
return monotonic(source, length2, lt);
|
|
525
564
|
}
|
|
526
565
|
function roc(source, length2) {
|
|
527
566
|
const result = [];
|
|
@@ -574,53 +613,19 @@ function dev(source, length2) {
|
|
|
574
613
|
return result;
|
|
575
614
|
}
|
|
576
615
|
function variance(source, length2, biased = true) {
|
|
577
|
-
const result = [];
|
|
578
616
|
const len = Math.floor(length2);
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
const v = source[i];
|
|
582
|
-
if (v !== void 0 && v !== null && !Number.isNaN(v)) {
|
|
583
|
-
window.push(v);
|
|
584
|
-
if (window.length > len) window.shift();
|
|
585
|
-
}
|
|
586
|
-
const divisor = biased ? len : len - 1;
|
|
587
|
-
if (window.length < len || divisor <= 0) {
|
|
588
|
-
result.push(NaN);
|
|
589
|
-
continue;
|
|
590
|
-
}
|
|
591
|
-
const mean = window.reduce((a, x) => a + x, 0) / len;
|
|
592
|
-
let sumSquares = 0;
|
|
593
|
-
for (const x of window) sumSquares += (x - mean) * (x - mean);
|
|
594
|
-
result.push(sumSquares / divisor);
|
|
595
|
-
}
|
|
596
|
-
return result;
|
|
617
|
+
if ((biased ? len : len - 1) <= 0) return source.map(() => NaN);
|
|
618
|
+
return runningVariance(source, len, biased);
|
|
597
619
|
}
|
|
598
620
|
function median(source, length2) {
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
values2.push(source[i - j]);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
if (values2.length === 0) {
|
|
611
|
-
result.push(NaN);
|
|
612
|
-
} else {
|
|
613
|
-
values2.sort((a, b2) => a - b2);
|
|
614
|
-
const mid = Math.floor(values2.length / 2);
|
|
615
|
-
if (values2.length % 2 === 0) {
|
|
616
|
-
result.push((values2[mid - 1] + values2[mid]) / 2);
|
|
617
|
-
} else {
|
|
618
|
-
result.push(values2[mid]);
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
return result;
|
|
621
|
+
const len = Math.floor(length2);
|
|
622
|
+
return source.map((_, i) => {
|
|
623
|
+
const values2 = lastValues(source, i, len);
|
|
624
|
+
if (!values2) return NaN;
|
|
625
|
+
values2.sort((a, b2) => a - b2);
|
|
626
|
+
const mid = Math.floor(len / 2);
|
|
627
|
+
return len % 2 === 0 ? (values2[mid - 1] + values2[mid]) / 2 : values2[mid];
|
|
628
|
+
});
|
|
624
629
|
}
|
|
625
630
|
function swma(source) {
|
|
626
631
|
const result = [];
|
|
@@ -745,33 +750,16 @@ function correlation(source1, source2, length2) {
|
|
|
745
750
|
function percentrank(source, length2) {
|
|
746
751
|
const result = [];
|
|
747
752
|
for (let i = 0; i < source.length; i++) {
|
|
748
|
-
|
|
753
|
+
const currentValue = source[i];
|
|
754
|
+
if (i < length2 || Number.isNaN(currentValue)) {
|
|
749
755
|
result.push(NaN);
|
|
750
|
-
|
|
751
|
-
if (isNaN(source[i])) {
|
|
752
|
-
result.push(NaN);
|
|
753
|
-
continue;
|
|
754
|
-
}
|
|
755
|
-
let hasNaN = false;
|
|
756
|
-
for (let j = 1; j <= length2; j++) {
|
|
757
|
-
if (isNaN(source[i - j])) {
|
|
758
|
-
hasNaN = true;
|
|
759
|
-
break;
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
if (hasNaN) {
|
|
763
|
-
result.push(NaN);
|
|
764
|
-
} else {
|
|
765
|
-
const currentValue = source[i];
|
|
766
|
-
let countLessOrEqual = 0;
|
|
767
|
-
for (let j = 1; j <= length2; j++) {
|
|
768
|
-
if (source[i - j] <= currentValue) {
|
|
769
|
-
countLessOrEqual++;
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
result.push(countLessOrEqual / length2 * 100);
|
|
773
|
-
}
|
|
756
|
+
continue;
|
|
774
757
|
}
|
|
758
|
+
let countLessOrEqual = 0;
|
|
759
|
+
for (let j = 1; j <= length2; j++) {
|
|
760
|
+
if (le(source[i - j], currentValue)) countLessOrEqual++;
|
|
761
|
+
}
|
|
762
|
+
result.push(countLessOrEqual / length2 * 100);
|
|
775
763
|
}
|
|
776
764
|
return result;
|
|
777
765
|
}
|
|
@@ -822,12 +810,8 @@ function mfi(source, length2, volume) {
|
|
|
822
810
|
upperFlow.push(le(change3, 0) ? 0 : flow);
|
|
823
811
|
lowerFlow.push(ge(change3, 0) ? 0 : flow);
|
|
824
812
|
}
|
|
825
|
-
const
|
|
826
|
-
|
|
827
|
-
return values2 ? values2.reduce((a, b2) => a + b2, 0) : NaN;
|
|
828
|
-
};
|
|
829
|
-
const upper2 = upperFlow.map((_, i) => sumAt(upperFlow, i));
|
|
830
|
-
const lower2 = lowerFlow.map((_, i) => sumAt(lowerFlow, i));
|
|
813
|
+
const upper2 = runningSum(upperFlow, length2);
|
|
814
|
+
const lower2 = runningSum(lowerFlow, length2);
|
|
831
815
|
return upper2.map((u, i) => {
|
|
832
816
|
const l = lower2[i];
|
|
833
817
|
if (Number.isNaN(u) || Number.isNaN(l)) return NaN;
|
|
@@ -1298,63 +1282,36 @@ function mode(source, length2) {
|
|
|
1298
1282
|
return result;
|
|
1299
1283
|
}
|
|
1300
1284
|
function percentile_linear_interpolation(source, length2, percentage) {
|
|
1285
|
+
return sortedWindow(source, length2, (s) => {
|
|
1286
|
+
const pos2 = percentage / 100 * length2 - 0.5;
|
|
1287
|
+
if (pos2 <= 0) return s[0];
|
|
1288
|
+
if (pos2 >= length2 - 1) return s[length2 - 1];
|
|
1289
|
+
const lo = Math.floor(pos2);
|
|
1290
|
+
return s[lo] + (pos2 - lo) * (s[lo + 1] - s[lo]);
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
function sortedWindow(source, length2, fn) {
|
|
1301
1294
|
const result = [];
|
|
1295
|
+
const values2 = [];
|
|
1296
|
+
const bars = [];
|
|
1302
1297
|
for (let i = 0; i < source.length; i++) {
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
const
|
|
1310
|
-
values2.
|
|
1311
|
-
|
|
1312
|
-
if (values2.some((v) => isNaN(v))) {
|
|
1313
|
-
result.push(NaN);
|
|
1314
|
-
continue;
|
|
1315
|
-
}
|
|
1316
|
-
const sorted = [...values2].sort((a, b2) => a - b2);
|
|
1317
|
-
const position = percentage / 100 * (sorted.length - 1);
|
|
1318
|
-
const lowerIndex = Math.floor(position);
|
|
1319
|
-
const upperIndex = Math.ceil(position);
|
|
1320
|
-
if (lowerIndex === upperIndex) {
|
|
1321
|
-
result.push(sorted[lowerIndex]);
|
|
1322
|
-
} else {
|
|
1323
|
-
const fraction = position - lowerIndex;
|
|
1324
|
-
const interpolated = sorted[lowerIndex] + fraction * (sorted[upperIndex] - sorted[lowerIndex]);
|
|
1325
|
-
result.push(interpolated);
|
|
1298
|
+
const v = source[i];
|
|
1299
|
+
let k = 0;
|
|
1300
|
+
while (k < values2.length && !(values2[k] >= v)) k++;
|
|
1301
|
+
values2.splice(k, 0, v);
|
|
1302
|
+
bars.splice(k, 0, i);
|
|
1303
|
+
if (i >= length2) {
|
|
1304
|
+
const old = bars.indexOf(i - length2);
|
|
1305
|
+
values2.splice(old, 1);
|
|
1306
|
+
bars.splice(old, 1);
|
|
1326
1307
|
}
|
|
1308
|
+
result.push(i < length2 - 1 ? NaN : fn(values2));
|
|
1327
1309
|
}
|
|
1328
1310
|
return result;
|
|
1329
1311
|
}
|
|
1330
1312
|
function percentile_nearest_rank(source, length2, percentage) {
|
|
1331
|
-
const
|
|
1332
|
-
|
|
1333
|
-
if (i < length2 - 1) {
|
|
1334
|
-
result.push(NaN);
|
|
1335
|
-
continue;
|
|
1336
|
-
}
|
|
1337
|
-
const values2 = [];
|
|
1338
|
-
for (let j = 0; j < length2; j++) {
|
|
1339
|
-
const value = source[i - j];
|
|
1340
|
-
if (!isNaN(value)) {
|
|
1341
|
-
values2.push(value);
|
|
1342
|
-
}
|
|
1343
|
-
}
|
|
1344
|
-
if (values2.length === 0) {
|
|
1345
|
-
result.push(NaN);
|
|
1346
|
-
continue;
|
|
1347
|
-
}
|
|
1348
|
-
const sorted = [...values2].sort((a, b2) => a - b2);
|
|
1349
|
-
if (percentage >= 100) {
|
|
1350
|
-
result.push(sorted[sorted.length - 1]);
|
|
1351
|
-
continue;
|
|
1352
|
-
}
|
|
1353
|
-
const rank2 = Math.ceil(percentage / 100 * sorted.length);
|
|
1354
|
-
const index = Math.max(0, rank2 - 1);
|
|
1355
|
-
result.push(sorted[index]);
|
|
1356
|
-
}
|
|
1357
|
-
return result;
|
|
1313
|
+
const rank2 = Math.min(length2, Math.max(1, Math.ceil(percentage / 100 * length2)));
|
|
1314
|
+
return sortedWindow(source, length2, (s) => s[rank2 - 1]);
|
|
1358
1315
|
}
|
|
1359
1316
|
function rci(source, length2) {
|
|
1360
1317
|
const result = [];
|
|
@@ -2072,7 +2029,7 @@ var Series = class _Series {
|
|
|
2072
2029
|
return new _Series(this.dataSource, (bar, i, data) => {
|
|
2073
2030
|
const a = this.extractor(bar, i, data);
|
|
2074
2031
|
const b2 = typeof other === "number" ? other : other.extractor(bar, i, data);
|
|
2075
|
-
return
|
|
2032
|
+
return a / b2;
|
|
2076
2033
|
});
|
|
2077
2034
|
}
|
|
2078
2035
|
/**
|
|
@@ -2495,23 +2452,7 @@ function avg(...values2) {
|
|
|
2495
2452
|
}
|
|
2496
2453
|
function sum(source, length2) {
|
|
2497
2454
|
const sourceArray = source instanceof Series ? source.toArray() : source;
|
|
2498
|
-
const result =
|
|
2499
|
-
const len = Math.floor(length2);
|
|
2500
|
-
const window = [];
|
|
2501
|
-
for (let i = 0; i < sourceArray.length; i++) {
|
|
2502
|
-
const v = sourceArray[i];
|
|
2503
|
-
if (v !== void 0 && v !== null && !Number.isNaN(v)) {
|
|
2504
|
-
window.push(v);
|
|
2505
|
-
if (window.length > len) window.shift();
|
|
2506
|
-
}
|
|
2507
|
-
if (window.length < len) {
|
|
2508
|
-
result.push(NaN);
|
|
2509
|
-
} else {
|
|
2510
|
-
let total = 0;
|
|
2511
|
-
for (const x of window) total += x;
|
|
2512
|
-
result.push(total);
|
|
2513
|
-
}
|
|
2514
|
-
}
|
|
2455
|
+
const result = runningSum(sourceArray, length2);
|
|
2515
2456
|
if (source instanceof Series) {
|
|
2516
2457
|
return Series.fromArray(source.bars, result);
|
|
2517
2458
|
}
|
|
@@ -3079,15 +3020,27 @@ function percentile_linear_interpolation2(id, percentage) {
|
|
|
3079
3020
|
if (id.length === 0) {
|
|
3080
3021
|
return NaN;
|
|
3081
3022
|
}
|
|
3082
|
-
const
|
|
3083
|
-
|
|
3023
|
+
const s = sortedNaLast(id);
|
|
3024
|
+
const n = s.length;
|
|
3025
|
+
const pos2 = percentage / 100 * n - 0.5;
|
|
3026
|
+
if (pos2 <= 0) return s[0];
|
|
3027
|
+
if (pos2 >= n - 1) return s[n - 1];
|
|
3028
|
+
const lo = Math.floor(pos2);
|
|
3029
|
+
const f = pos2 - lo;
|
|
3030
|
+
if (f === 0) return s[lo];
|
|
3031
|
+
return Number.isNaN(s[n - 1]) ? NaN : s[lo] + f * (s[lo + 1] - s[lo]);
|
|
3032
|
+
}
|
|
3033
|
+
function sortedNaLast(id) {
|
|
3034
|
+
const numbers = id.filter((v) => !Number.isNaN(v)).sort((a, b2) => a - b2);
|
|
3035
|
+
return [...numbers, ...Array(id.length - numbers.length).fill(NaN)];
|
|
3084
3036
|
}
|
|
3085
3037
|
function percentile_nearest_rank2(id, percentage) {
|
|
3086
3038
|
if (id.length === 0) {
|
|
3087
3039
|
return NaN;
|
|
3088
3040
|
}
|
|
3089
|
-
const
|
|
3090
|
-
|
|
3041
|
+
const s = sortedNaLast(id);
|
|
3042
|
+
const rank2 = Math.min(s.length, Math.max(1, Math.ceil(percentage / 100 * s.length)));
|
|
3043
|
+
return s[rank2 - 1];
|
|
3091
3044
|
}
|
|
3092
3045
|
function percentrank2(id, index) {
|
|
3093
3046
|
if (id.length === 0 || index < 0 || index >= id.length) {
|
|
@@ -3284,9 +3237,9 @@ function shortestDigits(x) {
|
|
|
3284
3237
|
function exactDigits(x) {
|
|
3285
3238
|
const abs3 = Math.abs(x);
|
|
3286
3239
|
if (abs3 === 0) return { digits: "", intLen: 0 };
|
|
3287
|
-
const
|
|
3288
|
-
|
|
3289
|
-
const bits =
|
|
3240
|
+
const view2 = new DataView(new ArrayBuffer(8));
|
|
3241
|
+
view2.setFloat64(0, abs3);
|
|
3242
|
+
const bits = view2.getBigUint64(0);
|
|
3290
3243
|
const expBits = Number(bits >> 52n & 0x7ffn);
|
|
3291
3244
|
let mant = bits & 0xfffffffffffffn;
|
|
3292
3245
|
const e2 = expBits === 0 ? -1074 : expBits - 1075;
|
|
@@ -3798,11 +3751,13 @@ __export(color_exports, {
|
|
|
3798
3751
|
white: () => white,
|
|
3799
3752
|
yellow: () => yellow
|
|
3800
3753
|
});
|
|
3754
|
+
var channel = (v) => v === null || v === void 0 || Number.isNaN(v) ? 0 : Math.max(0, Math.min(255, Math.trunc(v)));
|
|
3755
|
+
var alphaOf = (transp) => transp === null || Number.isNaN(transp) ? 0 : 1 - Math.max(0, Math.min(100, transp)) / 100;
|
|
3801
3756
|
function rgb(red2, green2, blue2, transp) {
|
|
3802
|
-
const r2 =
|
|
3803
|
-
const g2 =
|
|
3804
|
-
const b2 =
|
|
3805
|
-
const a = transp !== void 0 ?
|
|
3757
|
+
const r2 = channel(red2);
|
|
3758
|
+
const g2 = channel(green2);
|
|
3759
|
+
const b2 = channel(blue2);
|
|
3760
|
+
const a = transp !== void 0 ? alphaOf(transp) : 1;
|
|
3806
3761
|
if (a === 1) {
|
|
3807
3762
|
return `rgb(${r2}, ${g2}, ${b2})`;
|
|
3808
3763
|
}
|
|
@@ -3829,7 +3784,8 @@ function b(clr) {
|
|
|
3829
3784
|
return parseColor(clr).b;
|
|
3830
3785
|
}
|
|
3831
3786
|
function t(clr) {
|
|
3832
|
-
|
|
3787
|
+
const alpha = Math.round((1 - parseColor(clr).t / 100) * 255);
|
|
3788
|
+
return Math.round((1 - alpha / 255) * 100);
|
|
3833
3789
|
}
|
|
3834
3790
|
function parseColor(clr) {
|
|
3835
3791
|
if (typeof clr === "string") {
|
|
@@ -3882,13 +3838,12 @@ function from_gradient(value, bottom_value, top_value, bottom_color, top_color)
|
|
|
3882
3838
|
};
|
|
3883
3839
|
const c1 = rgba(bottom_color);
|
|
3884
3840
|
const c2 = rgba(top_color);
|
|
3885
|
-
const
|
|
3886
|
-
const w2 = c2.a * k;
|
|
3887
|
-
const a = w1 + w2;
|
|
3841
|
+
const a = c1.a * (1 - k) + c2.a * k;
|
|
3888
3842
|
if (a === 0) return transparent;
|
|
3889
|
-
const mix = (x1, x2) => Math.floor((x1 *
|
|
3843
|
+
const mix = (x1, x2) => Math.floor((x1 / 255 * c1.a * (1 - k) + x2 / 255 * c2.a * k) / (a / 255));
|
|
3890
3844
|
const [r2, g2, b2] = [mix(c1.r, c2.r), mix(c1.g, c2.g), mix(c1.b, c2.b)];
|
|
3891
|
-
|
|
3845
|
+
const alpha = Math.floor(a);
|
|
3846
|
+
return alpha === 255 ? `rgb(${r2}, ${g2}, ${b2})` : `rgba(${r2}, ${g2}, ${b2}, ${alpha / 255})`;
|
|
3892
3847
|
}
|
|
3893
3848
|
|
|
3894
3849
|
// src/time/index.ts
|
|
@@ -6099,6 +6054,7 @@ var format_italic = 2;
|
|
|
6099
6054
|
// src/callsite/index.ts
|
|
6100
6055
|
var callsite_exports = {};
|
|
6101
6056
|
__export(callsite_exports, {
|
|
6057
|
+
barssince: () => barssince2,
|
|
6102
6058
|
cross: () => cross2,
|
|
6103
6059
|
crossover: () => crossover2,
|
|
6104
6060
|
crossunder: () => crossunder2,
|
|
@@ -6130,6 +6086,14 @@ function crossover2() {
|
|
|
6130
6086
|
function crossunder2() {
|
|
6131
6087
|
return twoSeriesSite((a, b2, pa, pb) => a < b2 && pa >= pb);
|
|
6132
6088
|
}
|
|
6089
|
+
function barssince2() {
|
|
6090
|
+
let count = NaN;
|
|
6091
|
+
return (condition) => {
|
|
6092
|
+
if (condition && !Number.isNaN(condition)) count = 0;
|
|
6093
|
+
else if (!Number.isNaN(count)) count++;
|
|
6094
|
+
return count;
|
|
6095
|
+
};
|
|
6096
|
+
}
|
|
6133
6097
|
function cross2() {
|
|
6134
6098
|
return twoSeriesSite((a, b2, pa, pb) => a > b2 && pa <= pb || a < b2 && pa >= pb);
|
|
6135
6099
|
}
|
|
@@ -6140,7 +6104,7 @@ __export(ta_series_exports, {
|
|
|
6140
6104
|
accdist: () => accdist2,
|
|
6141
6105
|
alma: () => alma2,
|
|
6142
6106
|
atr: () => atr2,
|
|
6143
|
-
barssince: () =>
|
|
6107
|
+
barssince: () => barssince3,
|
|
6144
6108
|
bb: () => bb2,
|
|
6145
6109
|
bbw: () => bbw2,
|
|
6146
6110
|
cci: () => cci2,
|
|
@@ -6528,7 +6492,7 @@ function pivotlow2(source, leftbars, rightbars) {
|
|
|
6528
6492
|
const result = pivotlow(source.toArray(), leftbars, rightbars);
|
|
6529
6493
|
return Series.fromArray(bars, result);
|
|
6530
6494
|
}
|
|
6531
|
-
function
|
|
6495
|
+
function barssince3(condition) {
|
|
6532
6496
|
const bars = condition.bars;
|
|
6533
6497
|
const boolValues = condition.toArray().map((v) => v === 1);
|
|
6534
6498
|
const result = barssince(boolValues);
|
|
@@ -6680,7 +6644,7 @@ var ta = {
|
|
|
6680
6644
|
hma: hma2,
|
|
6681
6645
|
pivothigh: pivothigh2,
|
|
6682
6646
|
pivotlow: pivotlow2,
|
|
6683
|
-
barssince:
|
|
6647
|
+
barssince: barssince3,
|
|
6684
6648
|
valuewhen: valuewhen2,
|
|
6685
6649
|
dmi: dmi2,
|
|
6686
6650
|
tsi: tsi2,
|
|
@@ -6712,7 +6676,7 @@ var ta = {
|
|
|
6712
6676
|
|
|
6713
6677
|
// src/utils/index.ts
|
|
6714
6678
|
function isNA(value) {
|
|
6715
|
-
return value === null || value === void 0 || Number.isNaN(value) || isDeleted(value);
|
|
6679
|
+
return value === null || value === void 0 || Number.isNaN(value) || value === Infinity || value === -Infinity || isDeleted(value);
|
|
6716
6680
|
}
|
|
6717
6681
|
function nz(value, defaultValue = 0) {
|
|
6718
6682
|
return isNA(value) ? defaultValue : value;
|
|
@@ -6721,7 +6685,7 @@ function fixnan(source) {
|
|
|
6721
6685
|
let last2;
|
|
6722
6686
|
let seen = false;
|
|
6723
6687
|
return source.map((v) => {
|
|
6724
|
-
if (!
|
|
6688
|
+
if (!(v === null || v === void 0 || Number.isNaN(v) || isDeleted(v))) {
|
|
6725
6689
|
last2 = v;
|
|
6726
6690
|
seen = true;
|
|
6727
6691
|
return v;
|
|
@@ -6737,7 +6701,7 @@ function at(source, i, offset = 0) {
|
|
|
6737
6701
|
return j >= 0 && j < source.length ? source[j] ?? NaN : NaN;
|
|
6738
6702
|
}
|
|
6739
6703
|
function div(a, b2) {
|
|
6740
|
-
return
|
|
6704
|
+
return a / b2;
|
|
6741
6705
|
}
|
|
6742
6706
|
function ohlcFromBars(bars) {
|
|
6743
6707
|
return {
|
|
@@ -7371,7 +7335,7 @@ function hline(price, title, color, linestyle, linewidth) {
|
|
|
7371
7335
|
const options = {
|
|
7372
7336
|
color,
|
|
7373
7337
|
lineWidth: linewidth,
|
|
7374
|
-
lineStyle: getLineStyle(linestyle)
|
|
7338
|
+
lineStyle: getLineStyle(linestyle ?? "dashed")
|
|
7375
7339
|
};
|
|
7376
7340
|
const seriesHandle = context.chart.addSeries("line", options);
|
|
7377
7341
|
const data = context.ohlcv.time.map((time) => ({
|
|
@@ -7618,9 +7582,10 @@ var STRATEGY_DEFAULTS = {
|
|
|
7618
7582
|
calc_on_order_fills: false,
|
|
7619
7583
|
calc_on_every_tick: false,
|
|
7620
7584
|
backtest_fill_limits_assumption: 0,
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7585
|
+
// v6 values; PineScript v5: fixed / 1 / 1000000 and margins 0
|
|
7586
|
+
default_qty_type: "percent_of_equity",
|
|
7587
|
+
default_qty_value: 100,
|
|
7588
|
+
initial_capital: 1e5,
|
|
7624
7589
|
slippage: 0,
|
|
7625
7590
|
commission_type: "percent",
|
|
7626
7591
|
commission_value: 0,
|
|
@@ -7876,7 +7841,7 @@ var SimpleInputAdapter = class {
|
|
|
7876
7841
|
};
|
|
7877
7842
|
|
|
7878
7843
|
// src/index.ts
|
|
7879
|
-
var VERSION = "0.8.
|
|
7844
|
+
var VERSION = "0.8.2";
|
|
7880
7845
|
var info2 = {
|
|
7881
7846
|
name: "OakScriptJS",
|
|
7882
7847
|
version: VERSION,
|