oakscriptjs 0.11.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/array/index.d.ts +8 -2
- package/dist/cjs/array/index.d.ts.map +1 -1
- package/dist/cjs/array/index.js +2 -1
- package/dist/cjs/array/index.js.map +2 -2
- package/dist/cjs/box/index.js +6 -6
- package/dist/cjs/box/index.js.map +2 -2
- package/dist/cjs/callsite/index.js +1 -1
- package/dist/cjs/callsite/index.js.map +2 -2
- package/dist/cjs/drawing/registry.d.ts +15 -6
- package/dist/cjs/drawing/registry.d.ts.map +1 -1
- package/dist/cjs/drawing/registry.js +16 -2
- package/dist/cjs/drawing/registry.js.map +2 -2
- package/dist/cjs/index.d.ts +3 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +6 -1
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/input.d.ts +9 -1
- package/dist/cjs/input.d.ts.map +1 -1
- package/dist/cjs/input.js +16 -0
- package/dist/cjs/input.js.map +2 -2
- package/dist/cjs/label/index.js +3 -3
- package/dist/cjs/label/index.js.map +2 -2
- package/dist/cjs/line/index.d.ts +10 -27
- package/dist/cjs/line/index.d.ts.map +1 -1
- package/dist/cjs/line/index.js +10 -27
- package/dist/cjs/line/index.js.map +2 -2
- package/dist/cjs/linefill/index.d.ts +3 -0
- package/dist/cjs/linefill/index.d.ts.map +1 -1
- package/dist/cjs/linefill/index.js +15 -1
- package/dist/cjs/linefill/index.js.map +3 -3
- package/dist/cjs/runtime/adapters/SimpleInputAdapter.js +1 -1
- package/dist/cjs/runtime/adapters/SimpleInputAdapter.js.map +2 -2
- package/dist/cjs/runtime/index.d.ts +1 -1
- package/dist/cjs/runtime/index.d.ts.map +1 -1
- package/dist/cjs/runtime/index.js +1 -0
- package/dist/cjs/runtime/index.js.map +2 -2
- package/dist/cjs/runtime/inputs.d.ts +9 -0
- package/dist/cjs/runtime/inputs.d.ts.map +1 -1
- package/dist/cjs/runtime/inputs.js +8 -0
- package/dist/cjs/runtime/inputs.js.map +2 -2
- package/dist/cjs/runtime/types.d.ts +1 -1
- package/dist/cjs/runtime/types.d.ts.map +1 -1
- package/dist/cjs/runtime/types.js.map +1 -1
- package/dist/cjs/script/index.d.ts +65 -12
- package/dist/cjs/script/index.d.ts.map +1 -1
- package/dist/cjs/script/index.js +168 -19
- package/dist/cjs/script/index.js.map +3 -3
- package/dist/cjs/security/other.d.ts +92 -0
- package/dist/cjs/security/other.d.ts.map +1 -0
- package/dist/cjs/security/other.js +164 -0
- package/dist/cjs/security/other.js.map +7 -0
- package/dist/cjs/session/bars.d.ts +10 -1
- package/dist/cjs/session/bars.d.ts.map +1 -1
- package/dist/cjs/session/bars.js +16 -2
- package/dist/cjs/session/bars.js.map +2 -2
- package/dist/cjs/session/calendar.d.ts +4 -1
- package/dist/cjs/session/calendar.d.ts.map +1 -1
- package/dist/cjs/session/calendar.js +11 -7
- package/dist/cjs/session/calendar.js.map +2 -2
- package/dist/cjs/session/context.d.ts +2 -1
- package/dist/cjs/session/context.d.ts.map +1 -1
- package/dist/cjs/session/context.js +2 -1
- package/dist/cjs/session/context.js.map +2 -2
- package/dist/cjs/str/floatingdecimal.d.ts +31 -0
- package/dist/cjs/str/floatingdecimal.d.ts.map +1 -0
- package/dist/cjs/str/floatingdecimal.js +298 -0
- package/dist/cjs/str/floatingdecimal.js.map +7 -0
- package/dist/cjs/str/index.d.ts +4 -3
- package/dist/cjs/str/index.d.ts.map +1 -1
- package/dist/cjs/str/index.js +1 -1
- package/dist/cjs/str/index.js.map +2 -2
- package/dist/cjs/str/numberformat.d.ts +6 -4
- package/dist/cjs/str/numberformat.d.ts.map +1 -1
- package/dist/cjs/str/numberformat.js +3 -2
- package/dist/cjs/str/numberformat.js.map +2 -2
- package/dist/cjs/ta/index.d.ts +34 -17
- package/dist/cjs/ta/index.d.ts.map +1 -1
- package/dist/cjs/ta/index.js +132 -116
- package/dist/cjs/ta/index.js.map +2 -2
- package/dist/cjs/ta/limits.d.ts +11 -0
- package/dist/cjs/ta/limits.d.ts.map +1 -1
- package/dist/cjs/ta/limits.js +15 -1
- package/dist/cjs/ta/limits.js.map +2 -2
- package/dist/cjs/ta/running-sum.js +1 -1
- package/dist/cjs/ta/running-sum.js.map +2 -2
- package/dist/cjs/ta-series.d.ts +1 -1
- package/dist/cjs/ta-series.d.ts.map +1 -1
- package/dist/cjs/ta-series.js +1 -1
- package/dist/cjs/ta-series.js.map +2 -2
- package/dist/cjs/table/index.d.ts +3 -1
- package/dist/cjs/table/index.d.ts.map +1 -1
- package/dist/cjs/table/index.js +1 -0
- package/dist/cjs/table/index.js.map +3 -3
- package/dist/cjs/time/session.d.ts +9 -0
- package/dist/cjs/time/session.d.ts.map +1 -1
- package/dist/cjs/time/session.js +42 -14
- package/dist/cjs/time/session.js.map +3 -3
- package/dist/cjs/time/timezone.d.ts +6 -1
- package/dist/cjs/time/timezone.d.ts.map +1 -1
- package/dist/cjs/time/timezone.js +2 -2
- package/dist/cjs/time/timezone.js.map +2 -2
- package/dist/cjs/types/metadata.d.ts +1 -1
- package/dist/cjs/types/metadata.d.ts.map +1 -1
- package/dist/cjs/types/metadata.js.map +1 -1
- package/dist/esm/array/index.d.ts +8 -2
- package/dist/esm/array/index.d.ts.map +1 -1
- package/dist/esm/array/index.js +12 -3
- package/dist/esm/array/index.js.map +1 -1
- package/dist/esm/box/index.js +6 -6
- package/dist/esm/box/index.js.map +1 -1
- package/dist/esm/callsite/index.js +1 -1
- package/dist/esm/callsite/index.js.map +1 -1
- package/dist/esm/drawing/registry.d.ts +15 -6
- package/dist/esm/drawing/registry.d.ts.map +1 -1
- package/dist/esm/drawing/registry.js +30 -7
- package/dist/esm/drawing/registry.js.map +1 -1
- package/dist/esm/index.d.ts +3 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +4 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/input.d.ts +9 -1
- package/dist/esm/input.d.ts.map +1 -1
- package/dist/esm/input.js +16 -0
- package/dist/esm/input.js.map +1 -1
- package/dist/esm/label/index.js +3 -3
- package/dist/esm/label/index.js.map +1 -1
- package/dist/esm/line/index.d.ts +10 -27
- package/dist/esm/line/index.d.ts.map +1 -1
- package/dist/esm/line/index.js +20 -64
- package/dist/esm/line/index.js.map +1 -1
- package/dist/esm/linefill/index.d.ts +3 -0
- package/dist/esm/linefill/index.d.ts.map +1 -1
- package/dist/esm/linefill/index.js +20 -1
- package/dist/esm/linefill/index.js.map +1 -1
- package/dist/esm/runtime/adapters/SimpleInputAdapter.js +1 -1
- package/dist/esm/runtime/adapters/SimpleInputAdapter.js.map +1 -1
- package/dist/esm/runtime/index.d.ts +1 -1
- package/dist/esm/runtime/index.d.ts.map +1 -1
- package/dist/esm/runtime/index.js +1 -1
- package/dist/esm/runtime/index.js.map +1 -1
- package/dist/esm/runtime/inputs.d.ts +9 -0
- package/dist/esm/runtime/inputs.d.ts.map +1 -1
- package/dist/esm/runtime/inputs.js +15 -0
- package/dist/esm/runtime/inputs.js.map +1 -1
- package/dist/esm/runtime/types.d.ts +1 -1
- package/dist/esm/runtime/types.d.ts.map +1 -1
- package/dist/esm/script/index.d.ts +65 -12
- package/dist/esm/script/index.d.ts.map +1 -1
- package/dist/esm/script/index.js +217 -29
- package/dist/esm/script/index.js.map +1 -1
- package/dist/esm/security/other.d.ts +92 -0
- package/dist/esm/security/other.d.ts.map +1 -0
- package/dist/esm/security/other.js +211 -0
- package/dist/esm/security/other.js.map +1 -0
- package/dist/esm/session/bars.d.ts +10 -1
- package/dist/esm/session/bars.d.ts.map +1 -1
- package/dist/esm/session/bars.js +26 -1
- package/dist/esm/session/bars.js.map +1 -1
- package/dist/esm/session/calendar.d.ts +4 -1
- package/dist/esm/session/calendar.d.ts.map +1 -1
- package/dist/esm/session/calendar.js +19 -7
- package/dist/esm/session/calendar.js.map +1 -1
- package/dist/esm/session/context.d.ts +2 -1
- package/dist/esm/session/context.d.ts.map +1 -1
- package/dist/esm/session/context.js +5 -3
- package/dist/esm/session/context.js.map +1 -1
- package/dist/esm/str/floatingdecimal.d.ts +31 -0
- package/dist/esm/str/floatingdecimal.d.ts.map +1 -0
- package/dist/esm/str/floatingdecimal.js +272 -0
- package/dist/esm/str/floatingdecimal.js.map +1 -0
- package/dist/esm/str/index.d.ts +4 -3
- package/dist/esm/str/index.d.ts.map +1 -1
- package/dist/esm/str/index.js +6 -5
- package/dist/esm/str/index.js.map +1 -1
- package/dist/esm/str/numberformat.d.ts +6 -4
- package/dist/esm/str/numberformat.d.ts.map +1 -1
- package/dist/esm/str/numberformat.js +9 -5
- package/dist/esm/str/numberformat.js.map +1 -1
- package/dist/esm/ta/index.d.ts +34 -17
- package/dist/esm/ta/index.d.ts.map +1 -1
- package/dist/esm/ta/index.js +155 -185
- package/dist/esm/ta/index.js.map +1 -1
- package/dist/esm/ta/limits.d.ts +11 -0
- package/dist/esm/ta/limits.d.ts.map +1 -1
- package/dist/esm/ta/limits.js +27 -2
- package/dist/esm/ta/limits.js.map +1 -1
- package/dist/esm/ta/running-sum.js +1 -1
- package/dist/esm/ta/running-sum.js.map +1 -1
- package/dist/esm/ta-series.d.ts +1 -1
- package/dist/esm/ta-series.d.ts.map +1 -1
- package/dist/esm/ta-series.js +2 -1
- package/dist/esm/ta-series.js.map +1 -1
- package/dist/esm/table/index.d.ts +3 -1
- package/dist/esm/table/index.d.ts.map +1 -1
- package/dist/esm/table/index.js +6 -1
- package/dist/esm/table/index.js.map +1 -1
- package/dist/esm/time/session.d.ts +9 -0
- package/dist/esm/time/session.d.ts.map +1 -1
- package/dist/esm/time/session.js +53 -15
- package/dist/esm/time/session.js.map +1 -1
- package/dist/esm/time/timezone.d.ts +6 -1
- package/dist/esm/time/timezone.d.ts.map +1 -1
- package/dist/esm/time/timezone.js +8 -2
- package/dist/esm/time/timezone.js.map +1 -1
- package/dist/esm/types/metadata.d.ts +1 -1
- package/dist/esm/types/metadata.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/array/index.ts +11 -3
- package/src/box/index.ts +6 -6
- package/src/callsite/index.ts +1 -1
- package/src/drawing/registry.ts +30 -7
- package/src/index.ts +11 -1
- package/src/input.ts +18 -1
- package/src/label/index.ts +3 -3
- package/src/line/index.ts +20 -68
- package/src/linefill/index.ts +20 -1
- package/src/runtime/adapters/SimpleInputAdapter.ts +1 -1
- package/src/runtime/index.ts +1 -0
- package/src/runtime/inputs.ts +16 -0
- package/src/runtime/types.ts +1 -1
- package/src/script/index.ts +292 -30
- package/src/security/other.ts +269 -0
- package/src/session/bars.ts +24 -1
- package/src/session/calendar.ts +23 -7
- package/src/session/context.ts +5 -3
- package/src/str/floatingdecimal.ts +268 -0
- package/src/str/index.ts +6 -5
- package/src/str/numberformat.ts +11 -6
- package/src/ta/index.ts +157 -183
- package/src/ta/limits.ts +28 -1
- package/src/ta/running-sum.ts +1 -1
- package/src/ta-series.ts +3 -2
- package/src/table/index.ts +4 -1
- package/src/time/session.ts +58 -16
- package/src/time/timezone.ts +9 -2
- package/src/types/metadata.ts +1 -1
package/src/ta/index.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import type { series_float, series_bool, series_int, int, Source, simple_int, simple_float, simple_bool } from '../types/index.js';
|
|
12
12
|
import { eq, ge, gt, le, lt } from '../compare/index.js';
|
|
13
13
|
import { runningSum, runningSumSeries, runningVariance, runningVarianceSeries } from './running-sum.js';
|
|
14
|
-
import { checkSumLength, checkWindowLength } from './limits.js';
|
|
14
|
+
import { checkPositiveLength, checkSumLength, checkWindowLength } from './limits.js';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Simple Moving Average - returns the moving average (sum of last y values divided by y).
|
|
@@ -68,6 +68,7 @@ export function sma(source: Source, length: simple_int | ArrayLike<number>): ser
|
|
|
68
68
|
* ```
|
|
69
69
|
*/
|
|
70
70
|
export function ema(source: Source, length: simple_int): series_float {
|
|
71
|
+
checkPositiveLength('ema', length, 0);
|
|
71
72
|
const result: series_float = [];
|
|
72
73
|
const len = Math.floor(length);
|
|
73
74
|
const multiplier = 2 / (len + 1);
|
|
@@ -133,7 +134,25 @@ export function ema(source: Source, length: simple_int): series_float {
|
|
|
133
134
|
* const oversold = rsi14.map(v => v < 30);
|
|
134
135
|
* ```
|
|
135
136
|
*/
|
|
136
|
-
export function rsi(source: Source, length: simple_int): series_float
|
|
137
|
+
export function rsi(source: Source, length: simple_int): series_float;
|
|
138
|
+
/**
|
|
139
|
+
* PineScript v4 `rsi(x, y)` with two series (#180): `x` and `y` are the averages of the upward and downward changes,
|
|
140
|
+
* already computed. As in PineScript: 100 when `y` is within 1e-10 of zero (also with an na `x`), else 0 when `x` is,
|
|
141
|
+
* else `100 - 100 / (1 + x / y)`, na when that divides by zero (`x == -y`). Versions 5 and 6 have the length form only.
|
|
142
|
+
*/
|
|
143
|
+
export function rsi(x: Source, y: Source): series_float;
|
|
144
|
+
export function rsi(source: Source, length: simple_int | Source): series_float {
|
|
145
|
+
if (typeof length !== 'number') {
|
|
146
|
+
return Array.from(source, (xv, i) => {
|
|
147
|
+
const x = xv ?? NaN;
|
|
148
|
+
const y = length[i] ?? NaN;
|
|
149
|
+
if (eq(y, 0)) return 100;
|
|
150
|
+
if (eq(x, 0)) return 0;
|
|
151
|
+
const r = 100 - 100 / (1 + x / y);
|
|
152
|
+
return Number.isFinite(r) ? r : NaN;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
checkPositiveLength('rsi', length, 0, 'y');
|
|
137
156
|
const result: series_float = [];
|
|
138
157
|
|
|
139
158
|
// Calculate price changes
|
|
@@ -506,6 +525,7 @@ export function crossunder(series1: Source, series2: Source): series_bool {
|
|
|
506
525
|
* ```
|
|
507
526
|
*/
|
|
508
527
|
export function change(source: Source, length: simple_int = 1): series_float {
|
|
528
|
+
checkPositiveLength('change', length, 0);
|
|
509
529
|
const result: series_float = [];
|
|
510
530
|
|
|
511
531
|
for (let i = 0; i < source.length; i++) {
|
|
@@ -618,6 +638,7 @@ export function tr(
|
|
|
618
638
|
* ```
|
|
619
639
|
*/
|
|
620
640
|
export function atr(length: simple_int, high?: Source, low?: Source, close?: Source): series_float {
|
|
641
|
+
checkPositiveLength('atr->rma', length, 0);
|
|
621
642
|
if (!high || !low || !close) {
|
|
622
643
|
throw new Error(
|
|
623
644
|
'ta.atr() requires high, low, and close series. ' +
|
|
@@ -763,6 +784,7 @@ export function supertrend(
|
|
|
763
784
|
* ```
|
|
764
785
|
*/
|
|
765
786
|
export function rma(source: Source, length: simple_int): series_float {
|
|
787
|
+
checkPositiveLength('rma', length, 0);
|
|
766
788
|
const result: series_float = [];
|
|
767
789
|
// Floor the length to match PineScript's auto-truncation of float to int
|
|
768
790
|
const len = Math.floor(length);
|
|
@@ -846,6 +868,7 @@ export function wma(source: Source, length: simple_int | ArrayLike<number>): ser
|
|
|
846
868
|
const result: series_float = [];
|
|
847
869
|
// Floor the length to match PineScript's auto-truncation of float to int
|
|
848
870
|
const fixed = typeof length === 'number' ? Math.floor(length) : NaN;
|
|
871
|
+
if (typeof length === 'number') checkPositiveLength('wma', fixed, 0);
|
|
849
872
|
// PineScript: na on a bar with an na source (also +/-Infinity) and until `len` non-na values were received;
|
|
850
873
|
// otherwise the last `len` bars, each na replaced by the previous non-na value
|
|
851
874
|
const filled: number[] = [];
|
|
@@ -861,6 +884,7 @@ export function wma(source: Source, length: simple_int | ArrayLike<number>): ser
|
|
|
861
884
|
filled.push(last);
|
|
862
885
|
// a series length: the window of this bar's length (the result of ta.wma with that fixed length)
|
|
863
886
|
const len = typeof length === 'number' ? fixed : Math.floor(length[i]!);
|
|
887
|
+
if (typeof length !== 'number') checkPositiveLength('wma', len, i);
|
|
864
888
|
if (isNa || !(len >= 1) || count < len) {
|
|
865
889
|
result.push(NaN);
|
|
866
890
|
continue;
|
|
@@ -1022,6 +1046,7 @@ function monotonic(source: Source, length: simple_int, step: (newer: number, old
|
|
|
1022
1046
|
* ```
|
|
1023
1047
|
*/
|
|
1024
1048
|
export function rising(source: Source, length: simple_int): series_bool {
|
|
1049
|
+
checkPositiveLength('rising', length, 0);
|
|
1025
1050
|
return monotonic(source, length, gt);
|
|
1026
1051
|
}
|
|
1027
1052
|
|
|
@@ -1047,6 +1072,7 @@ export function rising(source: Source, length: simple_int): series_bool {
|
|
|
1047
1072
|
* ```
|
|
1048
1073
|
*/
|
|
1049
1074
|
export function falling(source: Source, length: simple_int): series_bool {
|
|
1075
|
+
checkPositiveLength('falling', length, 0);
|
|
1050
1076
|
return monotonic(source, length, lt);
|
|
1051
1077
|
}
|
|
1052
1078
|
|
|
@@ -1072,6 +1098,7 @@ export function falling(source: Source, length: simple_int): series_bool {
|
|
|
1072
1098
|
* ```
|
|
1073
1099
|
*/
|
|
1074
1100
|
export function roc(source: Source, length: simple_int): series_float {
|
|
1101
|
+
checkPositiveLength('roc', length, 0);
|
|
1075
1102
|
const result: series_float = [];
|
|
1076
1103
|
|
|
1077
1104
|
for (let i = 0; i < source.length; i++) {
|
|
@@ -1112,6 +1139,7 @@ export function roc(source: Source, length: simple_int): series_float {
|
|
|
1112
1139
|
* ```
|
|
1113
1140
|
*/
|
|
1114
1141
|
export function mom(source: Source, length: simple_int): series_float {
|
|
1142
|
+
checkPositiveLength('mom', length, 0);
|
|
1115
1143
|
const result: series_float = [];
|
|
1116
1144
|
|
|
1117
1145
|
for (let i = 0; i < source.length; i++) {
|
|
@@ -1151,6 +1179,7 @@ export function mom(source: Source, length: simple_int): series_float {
|
|
|
1151
1179
|
* ```
|
|
1152
1180
|
*/
|
|
1153
1181
|
export function dev(source: Source, length: simple_int): series_float {
|
|
1182
|
+
checkPositiveLength('dev', length, 0);
|
|
1154
1183
|
const len = Math.floor(length);
|
|
1155
1184
|
return sma(source, len).map((mean, i) => {
|
|
1156
1185
|
if (i < len - 1 || Number.isNaN(mean)) return NaN;
|
|
@@ -1234,6 +1263,7 @@ function varianceOf(
|
|
|
1234
1263
|
* ```
|
|
1235
1264
|
*/
|
|
1236
1265
|
export function median(source: Source, length: simple_int): series_float {
|
|
1266
|
+
checkPositiveLength('median', length, 0);
|
|
1237
1267
|
const len = Math.floor(length);
|
|
1238
1268
|
const n = source.length;
|
|
1239
1269
|
const out: series_float = new Array<number>(n).fill(NaN);
|
|
@@ -1321,6 +1351,7 @@ export function swma(source: Source): series_float {
|
|
|
1321
1351
|
* ```
|
|
1322
1352
|
*/
|
|
1323
1353
|
export function vwma(source: Source, length: simple_int, volume?: Source): series_float {
|
|
1354
|
+
checkPositiveLength('vwma->sma', length, 0);
|
|
1324
1355
|
if (!volume) {
|
|
1325
1356
|
throw new Error(
|
|
1326
1357
|
'ta.vwma() requires volume series. ' +
|
|
@@ -1374,6 +1405,7 @@ export function vwma(source: Source, length: simple_int, volume?: Source): serie
|
|
|
1374
1405
|
* ```
|
|
1375
1406
|
*/
|
|
1376
1407
|
export function linreg(source: Source, length: simple_int, offset: simple_int = 0): series_float {
|
|
1408
|
+
checkPositiveLength('linreg', length, 0);
|
|
1377
1409
|
const result: series_float = [];
|
|
1378
1410
|
// Floor the length to match PineScript's auto-truncation of float to int
|
|
1379
1411
|
const len = Math.floor(length);
|
|
@@ -1443,6 +1475,7 @@ export function linreg(source: Source, length: simple_int, offset: simple_int =
|
|
|
1443
1475
|
* ```
|
|
1444
1476
|
*/
|
|
1445
1477
|
export function correlation(source1: Source, source2: Source, length: simple_int): series_float {
|
|
1478
|
+
checkPositiveLength('correlation', length, 0);
|
|
1446
1479
|
// PineScript: from compensated running sums, cov = sma(x * y) - sma(x) * sma(y), r = cov / sqrt(var(x) * var(y))
|
|
1447
1480
|
// (biased variances); each running sum skips its own na values
|
|
1448
1481
|
const product = Array.from({ length: source1.length }, (_, i) => {
|
|
@@ -1481,8 +1514,8 @@ export function correlation(source1: Source, source2: Source, length: simple_int
|
|
|
1481
1514
|
*
|
|
1482
1515
|
* PineScript rules:
|
|
1483
1516
|
* - percentrank = count(source[k] <= source, k = 1..length) * 100 / length (in this order: the PineScript bits)
|
|
1484
|
-
* - a value from bar `length` on
|
|
1485
|
-
*
|
|
1517
|
+
* - a value from bar `length` on; an `na` value in the window counts as not `<=` the current value, and an `na`
|
|
1518
|
+
* current value gives 0 (#177)
|
|
1486
1519
|
* - the comparison uses the 1e-10 tolerance
|
|
1487
1520
|
*
|
|
1488
1521
|
* @example
|
|
@@ -1493,15 +1526,16 @@ export function correlation(source1: Source, source2: Source, length: simple_int
|
|
|
1493
1526
|
* ```
|
|
1494
1527
|
*/
|
|
1495
1528
|
export function percentrank(source: Source, length: simple_int): series_float {
|
|
1529
|
+
checkPositiveLength('percentrank', length, 0);
|
|
1496
1530
|
const result: series_float = [];
|
|
1497
1531
|
|
|
1498
1532
|
for (let i = 0; i < source.length; i++) {
|
|
1499
1533
|
const currentValue = source[i]!;
|
|
1500
|
-
if (i < length
|
|
1534
|
+
if (i < length) {
|
|
1501
1535
|
result.push(NaN);
|
|
1502
1536
|
continue;
|
|
1503
1537
|
}
|
|
1504
|
-
// le() is false for an na value in the window
|
|
1538
|
+
// le() is false for an na value in the window, and for all of them when the current value is na (0)
|
|
1505
1539
|
let countLessOrEqual = 0;
|
|
1506
1540
|
for (let j = 1; j <= length; j++) {
|
|
1507
1541
|
if (le(source[i - j]!, currentValue)) countLessOrEqual++;
|
|
@@ -1541,6 +1575,7 @@ export function percentrank(source: Source, length: simple_int): series_float {
|
|
|
1541
1575
|
* \`\`\`
|
|
1542
1576
|
*/
|
|
1543
1577
|
export function cci(source: Source, length: simple_int): series_float {
|
|
1578
|
+
checkPositiveLength('cci', length, 0);
|
|
1544
1579
|
const smaValues = sma(source, length);
|
|
1545
1580
|
const devValues = dev(source, length);
|
|
1546
1581
|
let last = 0;
|
|
@@ -1577,6 +1612,7 @@ export function cci(source: Source, length: simple_int): series_float {
|
|
|
1577
1612
|
* \`\`\`
|
|
1578
1613
|
*/
|
|
1579
1614
|
export function stoch(source: Source, high: Source, low: Source, length: simple_int): series_float {
|
|
1615
|
+
checkPositiveLength('stoch->highest', length, 0);
|
|
1580
1616
|
const result: series_float = [];
|
|
1581
1617
|
const lowestValues = lowest(low, length);
|
|
1582
1618
|
const highestValues = highest(high, length);
|
|
@@ -1629,6 +1665,7 @@ export function stoch(source: Source, high: Source, low: Source, length: simple_
|
|
|
1629
1665
|
* ```
|
|
1630
1666
|
*/
|
|
1631
1667
|
export function mfi(source: Source, length: simple_int, volume?: Source): series_float {
|
|
1668
|
+
checkPositiveLength('mfi', length, 0);
|
|
1632
1669
|
if (!volume) {
|
|
1633
1670
|
throw new Error(
|
|
1634
1671
|
'ta.mfi() requires volume series. ' +
|
|
@@ -1687,6 +1724,7 @@ export function mfi(source: Source, length: simple_int, volume?: Source): series
|
|
|
1687
1724
|
* ```
|
|
1688
1725
|
*/
|
|
1689
1726
|
export function hma(source: Source, length: simple_int): series_float {
|
|
1727
|
+
checkPositiveLength('hma', length, 0);
|
|
1690
1728
|
const halfLength = Math.floor(length / 2);
|
|
1691
1729
|
const sqrtLength = Math.floor(Math.sqrt(length));
|
|
1692
1730
|
|
|
@@ -2093,6 +2131,7 @@ export function dmi(
|
|
|
2093
2131
|
* ```
|
|
2094
2132
|
*/
|
|
2095
2133
|
export function tsi(source: Source, shortLength: simple_int, longLength: simple_int): series_float {
|
|
2134
|
+
checkPositiveLength('tsi->ema', shortLength, 0);
|
|
2096
2135
|
const momentum: series_float = [];
|
|
2097
2136
|
|
|
2098
2137
|
// Calculate momentum (price change)
|
|
@@ -2142,6 +2181,7 @@ export function tsi(source: Source, shortLength: simple_int, longLength: simple_
|
|
|
2142
2181
|
* ```
|
|
2143
2182
|
*/
|
|
2144
2183
|
export function cmo(source: Source, length: simple_int): series_float {
|
|
2184
|
+
checkPositiveLength('cmo', length, 0);
|
|
2145
2185
|
// PineScript definition: mom = ta.change(src), sm1 = math.sum(mom >= 0 ? mom : 0, length),
|
|
2146
2186
|
// sm2 = math.sum(mom >= 0 ? 0 : -mom, length), cmo = 100 * (sm1 - sm2) / (sm1 + sm2), with the running sums of
|
|
2147
2187
|
// math.sum (bit for bit). A comparison with na is false: an na change adds 0 to sm1 and na (skipped) to sm2.
|
|
@@ -2191,6 +2231,7 @@ export function kc(
|
|
|
2191
2231
|
low?: Source,
|
|
2192
2232
|
close?: Source
|
|
2193
2233
|
): [series_float, series_float, series_float] {
|
|
2234
|
+
checkPositiveLength('kc', length, 0);
|
|
2194
2235
|
// Calculate middle band (EMA of source)
|
|
2195
2236
|
const middle = ema(source, length);
|
|
2196
2237
|
|
|
@@ -2250,6 +2291,7 @@ export function kc(
|
|
|
2250
2291
|
* ```
|
|
2251
2292
|
*/
|
|
2252
2293
|
export function bbw(source: Source, length: simple_int, mult: simple_float): series_float {
|
|
2294
|
+
checkPositiveLength('bbw', length, 0);
|
|
2253
2295
|
const [basis, upper, lower] = bb(source, length, mult);
|
|
2254
2296
|
const result: series_float = [];
|
|
2255
2297
|
|
|
@@ -2293,6 +2335,7 @@ export function bbw(source: Source, length: simple_int, mult: simple_float): ser
|
|
|
2293
2335
|
* ```
|
|
2294
2336
|
*/
|
|
2295
2337
|
export function wpr(high: Source, low: Source, close: Source, length: simple_int = 14): series_float {
|
|
2338
|
+
checkPositiveLength('wpr', length, 0);
|
|
2296
2339
|
const highs = highest(high, length);
|
|
2297
2340
|
const lows = lowest(low, length);
|
|
2298
2341
|
return Array.from({ length: close.length }, (_, i) => {
|
|
@@ -2393,6 +2436,7 @@ export function alma(
|
|
|
2393
2436
|
sigma: simple_float = 6,
|
|
2394
2437
|
floor: boolean = false
|
|
2395
2438
|
): series_float {
|
|
2439
|
+
checkPositiveLength('alma', length, 0);
|
|
2396
2440
|
const result: series_float = [];
|
|
2397
2441
|
const m = floor ? Math.floor(offset * (length - 1)) : offset * (length - 1);
|
|
2398
2442
|
const s = length / sigma;
|
|
@@ -2489,6 +2533,7 @@ export function kcw(
|
|
|
2489
2533
|
* values), and a bar whose own value is `na` still gets a result.
|
|
2490
2534
|
*/
|
|
2491
2535
|
export function range(source: Source, length: simple_int): series_float {
|
|
2536
|
+
checkPositiveLength('range', length, 0);
|
|
2492
2537
|
return source.map((_, i) => {
|
|
2493
2538
|
const values = lastValues(source, i, length);
|
|
2494
2539
|
return values ? Math.max(...values) - Math.min(...values) : NaN;
|
|
@@ -2574,6 +2619,7 @@ export function min(source: Source): series_float {
|
|
|
2574
2619
|
* ```
|
|
2575
2620
|
*/
|
|
2576
2621
|
export function cog(source: Source, length: simple_int = 10): series_float {
|
|
2622
|
+
checkPositiveLength('cog', length, 0);
|
|
2577
2623
|
const len = Math.floor(length);
|
|
2578
2624
|
return runningSum(source, len).map((sum, i) => {
|
|
2579
2625
|
if (i < len - 1 || Number.isNaN(sum) || sum === 0) return NaN;
|
|
@@ -2607,6 +2653,7 @@ export function cog(source: Source, length: simple_int = 10): series_float {
|
|
|
2607
2653
|
* - If no mode exists, returns the smallest value
|
|
2608
2654
|
*/
|
|
2609
2655
|
export function mode(source: Source, length: simple_int): series_float {
|
|
2656
|
+
checkPositiveLength('mode', length, 0);
|
|
2610
2657
|
const result: series_float = [];
|
|
2611
2658
|
const len = Math.floor(length);
|
|
2612
2659
|
const seen: number[] = []; // non-na values so far
|
|
@@ -2684,6 +2731,7 @@ export function percentile_linear_interpolation(
|
|
|
2684
2731
|
length: simple_int,
|
|
2685
2732
|
percentage: number
|
|
2686
2733
|
): series_float {
|
|
2734
|
+
checkPositiveLength('percentile_linear_interpolation', length, 0);
|
|
2687
2735
|
return sortedWindow(source, length, (s) => {
|
|
2688
2736
|
const pos = (percentage / 100) * length - 0.5;
|
|
2689
2737
|
if (pos <= 0) return s[0]!;
|
|
@@ -2753,6 +2801,7 @@ export function percentile_nearest_rank(
|
|
|
2753
2801
|
length: simple_int,
|
|
2754
2802
|
percentage: number
|
|
2755
2803
|
): series_float {
|
|
2804
|
+
checkPositiveLength('percentile_nearest_rank', length, 0);
|
|
2756
2805
|
const rank = Math.min(length, Math.max(1, Math.ceil((percentage / 100) * length)));
|
|
2757
2806
|
return sortedWindow(source, length, (s) => s[rank - 1]!);
|
|
2758
2807
|
}
|
|
@@ -2789,6 +2838,7 @@ export function percentile_nearest_rank(
|
|
|
2789
2838
|
* where the `na` was
|
|
2790
2839
|
*/
|
|
2791
2840
|
export function rci(source: Source, length: simple_int): series_float {
|
|
2841
|
+
checkPositiveLength('rci', length, 0);
|
|
2792
2842
|
const len = Math.floor(length);
|
|
2793
2843
|
const result: series_float = [];
|
|
2794
2844
|
// PineScript keeps the values in a ring of `length + 1` slots indexed by the bar index, filled with 0 at the start
|
|
@@ -2852,31 +2902,42 @@ export function rci(source: Source, length: simple_int): series_float {
|
|
|
2852
2902
|
}
|
|
2853
2903
|
|
|
2854
2904
|
/**
|
|
2855
|
-
* Pivot Point Levels
|
|
2905
|
+
* Pivot Point Levels (PineScript `ta.pivot_point_levels`).
|
|
2856
2906
|
*
|
|
2857
|
-
*
|
|
2858
|
-
* Returns an array containing: [P, R1, S1, R2, S2, R3, S3, R4, S4, R5, S5]
|
|
2907
|
+
* Returns 11 series: [P, R1, S1, R2, S2, R3, S3, R4, S4, R5, S5] (one value per bar in each).
|
|
2859
2908
|
*
|
|
2860
2909
|
* @param type - Calculation type: "Traditional", "Fibonacci", "Woodie", "Classic", "DM", "Camarilla"
|
|
2861
|
-
* @param anchor - Condition that
|
|
2862
|
-
* @param developing -
|
|
2863
|
-
*
|
|
2864
|
-
* @param
|
|
2865
|
-
* @param
|
|
2866
|
-
* @param
|
|
2867
|
-
* @
|
|
2910
|
+
* @param anchor - Condition that starts a new period (`timeframe.change("W")`...)
|
|
2911
|
+
* @param developing - false: the levels of the previous period, constant until the next anchor; true: the levels of
|
|
2912
|
+
* the current period so far, recalculated on each bar
|
|
2913
|
+
* @param high - High price series
|
|
2914
|
+
* @param low - Low price series
|
|
2915
|
+
* @param close - Close price series
|
|
2916
|
+
* @param open - Open price series (Woodie and DM)
|
|
2917
|
+
* @returns 11 series of levels
|
|
2868
2918
|
*
|
|
2869
2919
|
* @example
|
|
2870
2920
|
* ```typescript
|
|
2871
2921
|
* const weekChange = [false, false, false, false, true, false, ...]; // Weekly anchor
|
|
2872
|
-
* const
|
|
2873
|
-
* //
|
|
2922
|
+
* const levels = ta.pivot_point_levels("Traditional", weekChange, false, high, low, close, open);
|
|
2923
|
+
* // levels[0]![i] is P on bar i, levels[5]![i] is R3
|
|
2874
2924
|
* ```
|
|
2875
2925
|
*
|
|
2876
2926
|
* @remarks
|
|
2877
|
-
*
|
|
2878
|
-
* -
|
|
2879
|
-
*
|
|
2927
|
+
* As in PineScript (#177):
|
|
2928
|
+
* - a period runs from an anchor bar to the bar before the next anchor; the bars before the first anchor are a
|
|
2929
|
+
* period too (from bar 0). The fixed levels use the high and low of the previous period and the close of the bar
|
|
2930
|
+
* before the anchor (na with an anchor on bar 0), and are na until the first anchor; the developing levels use
|
|
2931
|
+
* the current period's high and low and the bar's close, from bar 0
|
|
2932
|
+
* - Traditional: R3 = P * 2 + (H - 2 * L), S3 = P * 2 - (2 * H - L), R4 = P * 3 + (H - 3 * L), S4 = P * 3 - (3 * H - L),
|
|
2933
|
+
* R5 = P * 4 + (H - 4 * L), S5 = P * 4 - (4 * H - L)
|
|
2934
|
+
* - Fibonacci: P +- 0.382 / 0.618 / 1 * (H - L); R4 to S5 na
|
|
2935
|
+
* - Classic: R3 / S3 = P +- 2 * (H - L), R4 / S4 = P +- 3 * (H - L); R5 / S5 na
|
|
2936
|
+
* - Woodie: P = (H + L + 2 * open of the current period) / 4, R3 = H + 2 * (P - L), S3 = L - 2 * (H - P), R4 / S4 =
|
|
2937
|
+
* R3 + (H - L) / S3 - (H - L); R5 / S5 na. `developing` true throws (RE10128)
|
|
2938
|
+
* - DM: x = H + 2 * L + C (C < open of the period), 2 * H + L + C (C > O) or H + L + 2 * C; P = x / 4,
|
|
2939
|
+
* R1 = x / 2 - L, S1 = x / 2 - H; the other levels na
|
|
2940
|
+
* - Camarilla: C +- (H - L) * 1.1 / 12, / 6, / 4, / 2 for R1 to S4, R5 = (H / L) * C, S5 = 2 * C - R5
|
|
2880
2941
|
*/
|
|
2881
2942
|
export function pivot_point_levels(
|
|
2882
2943
|
type: series_float | string,
|
|
@@ -2887,183 +2948,96 @@ export function pivot_point_levels(
|
|
|
2887
2948
|
close?: Source,
|
|
2888
2949
|
open?: Source
|
|
2889
2950
|
): series_float[] {
|
|
2890
|
-
// For simplicity, we need to handle the case where type is a string array
|
|
2891
|
-
// But according to the docs, type is "series string", meaning it can change per bar
|
|
2892
|
-
// For this implementation, we'll support constant type strings
|
|
2893
|
-
|
|
2894
2951
|
const typeStr = typeof type === 'string' ? type : String(type[0]);
|
|
2895
|
-
const isDeveloping = typeof developing === 'boolean' ? developing : developing[0];
|
|
2896
|
-
|
|
2897
|
-
// Woodie cannot be developing
|
|
2952
|
+
const isDeveloping = typeof developing === 'boolean' ? developing : Boolean(developing[0]);
|
|
2898
2953
|
if (typeStr === 'Woodie' && isDeveloping) {
|
|
2899
|
-
throw new Error(
|
|
2954
|
+
throw new Error(
|
|
2955
|
+
'Error on bar 0: The `developing` parameter of the `ta.pivot_point_levels()` cannot be `true` when `type` is "Woodie".'
|
|
2956
|
+
);
|
|
2900
2957
|
}
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
h = lastH;
|
|
2939
|
-
l = lastL;
|
|
2940
|
-
c = lastC;
|
|
2941
|
-
o = lastO;
|
|
2942
|
-
}
|
|
2943
|
-
|
|
2944
|
-
// Calculate pivot levels based on type
|
|
2945
|
-
const levels = calculatePivotLevels(typeStr, h, l, c, o);
|
|
2946
|
-
|
|
2947
|
-
// Push to results
|
|
2948
|
-
for (let j = 0; j < 11; j++) {
|
|
2949
|
-
results[j]!.push(levels[j]!);
|
|
2950
|
-
}
|
|
2958
|
+
const n = anchor.length;
|
|
2959
|
+
for (const [s, name] of [[high, 'High'], [low, 'Low'], [close, 'Close'], [open, 'Open']] as const) {
|
|
2960
|
+
if (s && s.length !== n) throw new Error(`${name} series length mismatch`);
|
|
2961
|
+
}
|
|
2962
|
+
const at = (s: Source | undefined, i: number): number => (s ? (s[i] ?? NaN) : NaN);
|
|
2963
|
+
const results: series_float[] = Array.from({ length: 11 }, () => new Array<number>(n));
|
|
2964
|
+
// the current period (from bar 0 until the first anchor) and the previous one
|
|
2965
|
+
let curH = NaN, curL = NaN, curO = NaN;
|
|
2966
|
+
let prevH = NaN, prevL = NaN, prevC = NaN, prevO = NaN;
|
|
2967
|
+
let anchored = false;
|
|
2968
|
+
for (let i = 0; i < n; i++) {
|
|
2969
|
+
const h = at(high, i), l = at(low, i);
|
|
2970
|
+
if (i === 0) {
|
|
2971
|
+
// the first period starts on bar 0: an anchor there makes bar 0 its own previous period
|
|
2972
|
+
curH = h;
|
|
2973
|
+
curL = l;
|
|
2974
|
+
curO = at(open, i);
|
|
2975
|
+
}
|
|
2976
|
+
if (anchor[i]) {
|
|
2977
|
+
prevH = curH;
|
|
2978
|
+
prevL = curL;
|
|
2979
|
+
prevC = i > 0 ? at(close, i - 1) : NaN;
|
|
2980
|
+
prevO = curO;
|
|
2981
|
+
curH = h;
|
|
2982
|
+
curL = l;
|
|
2983
|
+
curO = at(open, i);
|
|
2984
|
+
anchored = true;
|
|
2985
|
+
} else if (i > 0) {
|
|
2986
|
+
if (h > curH || Number.isNaN(curH)) curH = h;
|
|
2987
|
+
if (l < curL || Number.isNaN(curL)) curL = l;
|
|
2988
|
+
}
|
|
2989
|
+
const levels = isDeveloping
|
|
2990
|
+
? pivotLevels(typeStr, curH, curL, at(close, i), curO, at(close, i))
|
|
2991
|
+
: anchored
|
|
2992
|
+
? pivotLevels(typeStr, prevH, prevL, prevC, prevO, curO)
|
|
2993
|
+
: NA_LEVELS;
|
|
2994
|
+
for (let k = 0; k < 11; k++) results[k]![i] = levels[k]!;
|
|
2951
2995
|
}
|
|
2952
|
-
|
|
2953
2996
|
return results;
|
|
2954
2997
|
}
|
|
2955
2998
|
|
|
2999
|
+
const NA_LEVELS: readonly number[] = new Array<number>(11).fill(NaN);
|
|
3000
|
+
|
|
2956
3001
|
/**
|
|
2957
|
-
*
|
|
3002
|
+
* The 11 levels of one bar, in PineScript's operation order (bit for bit). `o` is the open of the period (DM),
|
|
3003
|
+
* `wo` the close term of Woodie (the open of the current period, or the bar's close while developing).
|
|
2958
3004
|
*/
|
|
2959
|
-
function
|
|
2960
|
-
|
|
2961
|
-
h
|
|
2962
|
-
l: number,
|
|
2963
|
-
c: number,
|
|
2964
|
-
o: number
|
|
2965
|
-
): number[] {
|
|
2966
|
-
// Return NaN array if data is insufficient
|
|
2967
|
-
if (isNaN(h) || isNaN(l) || isNaN(c)) {
|
|
2968
|
-
return Array(11).fill(NaN);
|
|
2969
|
-
}
|
|
2970
|
-
|
|
2971
|
-
const levels: number[] = Array(11).fill(NaN);
|
|
2972
|
-
|
|
2973
|
-
// Calculate pivot point (P)
|
|
2974
|
-
let P: number;
|
|
2975
|
-
|
|
2976
|
-
switch (type) {
|
|
2977
|
-
case 'Traditional':
|
|
2978
|
-
case 'Fibonacci':
|
|
2979
|
-
case 'Classic':
|
|
2980
|
-
P = (h + l + c) / 3;
|
|
2981
|
-
break;
|
|
2982
|
-
case 'Woodie':
|
|
2983
|
-
P = (h + l + 2 * c) / 4;
|
|
2984
|
-
break;
|
|
2985
|
-
case 'DM':
|
|
2986
|
-
P = (h + l + c) / 3;
|
|
2987
|
-
break;
|
|
2988
|
-
case 'Camarilla':
|
|
2989
|
-
P = (h + l + c) / 3;
|
|
2990
|
-
break;
|
|
2991
|
-
default:
|
|
2992
|
-
P = (h + l + c) / 3;
|
|
2993
|
-
}
|
|
2994
|
-
|
|
2995
|
-
levels[0] = P; // P is at index 0
|
|
2996
|
-
|
|
2997
|
-
// Calculate resistance and support levels based on type
|
|
3005
|
+
function pivotLevels(type: string, h: number, l: number, c: number, o: number, wo: number): readonly number[] {
|
|
3006
|
+
const N = NaN;
|
|
3007
|
+
const r = h - l;
|
|
2998
3008
|
switch (type) {
|
|
2999
|
-
case 'Traditional':
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
levels[5] = P + (h - l); // R3
|
|
3019
|
-
levels[6] = P - (h - l); // S3
|
|
3020
|
-
levels[7] = levels[5] + 0.618 * (h - l); // R4
|
|
3021
|
-
levels[8] = levels[6] - 0.618 * (h - l); // S4
|
|
3022
|
-
levels[9] = levels[7] + 0.382 * (h - l); // R5
|
|
3023
|
-
levels[10] = levels[8] - 0.382 * (h - l); // S5
|
|
3024
|
-
break;
|
|
3025
|
-
|
|
3026
|
-
case 'Woodie':
|
|
3027
|
-
levels[1] = 2 * P - l; // R1
|
|
3028
|
-
levels[2] = 2 * P - h; // S1
|
|
3029
|
-
levels[3] = P + (h - l); // R2
|
|
3030
|
-
levels[4] = P - (h - l); // S2
|
|
3031
|
-
levels[5] = h + 2 * (P - l); // R3
|
|
3032
|
-
levels[6] = l - 2 * (h - P); // S3
|
|
3033
|
-
levels[7] = levels[5] + (h - l); // R4
|
|
3034
|
-
levels[8] = levels[6] - (h - l); // S4
|
|
3035
|
-
levels[9] = levels[7] + (h - l); // R5
|
|
3036
|
-
levels[10] = levels[8] - (h - l); // S5
|
|
3037
|
-
break;
|
|
3038
|
-
|
|
3009
|
+
case 'Traditional': {
|
|
3010
|
+
const p = (h + l + c) / 3;
|
|
3011
|
+
return [p, 2 * p - l, 2 * p - h, p + r, p - r, p * 2 + (h - 2 * l), p * 2 - (2 * h - l), p * 3 + (h - 3 * l),
|
|
3012
|
+
p * 3 - (3 * h - l), p * 4 + (h - 4 * l), p * 4 - (4 * h - l)];
|
|
3013
|
+
}
|
|
3014
|
+
case 'Fibonacci': {
|
|
3015
|
+
const p = (h + l + c) / 3;
|
|
3016
|
+
return [p, p + 0.382 * r, p - 0.382 * r, p + 0.618 * r, p - 0.618 * r, p + 1 * r, p - 1 * r, N, N, N, N];
|
|
3017
|
+
}
|
|
3018
|
+
case 'Classic': {
|
|
3019
|
+
const p = (h + l + c) / 3;
|
|
3020
|
+
return [p, 2 * p - l, 2 * p - h, p + r, p - r, p + 2 * r, p - 2 * r, p + 3 * r, p - 3 * r, N, N];
|
|
3021
|
+
}
|
|
3022
|
+
case 'Woodie': {
|
|
3023
|
+
const p = (h + l + 2 * wo) / 4;
|
|
3024
|
+
const r3 = h + 2 * (p - l);
|
|
3025
|
+
const s3 = l - 2 * (h - p);
|
|
3026
|
+
return [p, 2 * p - l, 2 * p - h, p + r, p - r, r3, s3, r3 + r, s3 - r, N, N];
|
|
3027
|
+
}
|
|
3039
3028
|
case 'DM': {
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
const newP = x / (isNaN(o) ? 4 : 5);
|
|
3043
|
-
levels[0] = newP;
|
|
3044
|
-
levels[1] = x / 2 - l; // R1
|
|
3045
|
-
levels[2] = x / 2 - h; // S1
|
|
3046
|
-
// R2-S5 remain NaN
|
|
3047
|
-
break;
|
|
3029
|
+
const x = c < o ? h + 2 * l + c : c > o ? 2 * h + l + c : h + l + 2 * c;
|
|
3030
|
+
return [x / 4, x / 2 - l, x / 2 - h, N, N, N, N, N, N, N, N];
|
|
3048
3031
|
}
|
|
3049
|
-
|
|
3050
3032
|
case 'Camarilla': {
|
|
3051
|
-
const
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
levels[4] = c - range * 1.1 / 6; // S2
|
|
3056
|
-
levels[5] = c + range * 1.1 / 4; // R3
|
|
3057
|
-
levels[6] = c - range * 1.1 / 4; // S3
|
|
3058
|
-
levels[7] = c + range * 1.1 / 2; // R4
|
|
3059
|
-
levels[8] = c - range * 1.1 / 2; // S4
|
|
3060
|
-
levels[9] = h; // R5 (high)
|
|
3061
|
-
levels[10] = l; // S5 (low)
|
|
3062
|
-
break;
|
|
3033
|
+
const p = (h + l + c) / 3;
|
|
3034
|
+
const r5 = (h / l) * c;
|
|
3035
|
+
return [p, c + (r * 1.1) / 12, c - (r * 1.1) / 12, c + (r * 1.1) / 6, c - (r * 1.1) / 6, c + (r * 1.1) / 4,
|
|
3036
|
+
c - (r * 1.1) / 4, c + (r * 1.1) / 2, c - (r * 1.1) / 2, r5, 2 * c - r5];
|
|
3063
3037
|
}
|
|
3038
|
+
default:
|
|
3039
|
+
return NA_LEVELS;
|
|
3064
3040
|
}
|
|
3065
|
-
|
|
3066
|
-
return levels;
|
|
3067
3041
|
}
|
|
3068
3042
|
|
|
3069
3043
|
/**
|
package/src/ta/limits.ts
CHANGED
|
@@ -37,11 +37,38 @@ export function windowError(name: string, length: number, bar?: number, max = MA
|
|
|
37
37
|
/** Throws RE10004 when the (truncated) length of a window function is above the limit. */
|
|
38
38
|
export function checkWindowLength(name: string, length: number, bar?: number, max = MAX_WINDOW_LENGTH): void {
|
|
39
39
|
const len = Math.trunc(length);
|
|
40
|
+
if (len <= 0) throw new Error(lengthError(name, len, bar));
|
|
40
41
|
if (len > max) throw new Error(windowError(name, len, bar, max));
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
/** Throws RE10004 for a function of {@link SUM_FUNCTIONS} ("ta.sma", ...) with a length above 5,000. */
|
|
44
45
|
export function checkSumLength(name: string, length: number, bar?: number): void {
|
|
45
46
|
const fn = SUM_FUNCTIONS[name];
|
|
46
|
-
if (fn
|
|
47
|
+
if (fn === undefined) return;
|
|
48
|
+
// RE10001 names 'bb' itself, RE10004 its inner 'sma'
|
|
49
|
+
checkPositiveLength(name === 'ta.bb' ? 'bb' : fn, length, bar);
|
|
50
|
+
checkWindowLength(fn, length, bar, MAX_SUM_LENGTH);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* PineScript's runtime error RE10001 text for a length that is 0 or negative. `name` is the function, or a call path
|
|
55
|
+
* "atr->rma" (printed 'atr'->'rma'); the value prints as a float ("0.0", "-1.0").
|
|
56
|
+
*/
|
|
57
|
+
export function lengthError(name: string, value: number, bar?: number, arg = 'length'): string {
|
|
58
|
+
const fn = name.split('->').map((part) => `'${part}'`).join('->');
|
|
59
|
+
const text = Number.isInteger(value) ? value.toFixed(1) : String(value);
|
|
60
|
+
return (
|
|
61
|
+
(bar === undefined ? '' : `Error on bar ${bar}: `) +
|
|
62
|
+
`Invalid value of the '${arg}' argument (${text}) in the ${fn} function. It must be > 0.`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Throws RE10001 when the (truncated) length is 0 or negative, as PineScript does for every window function on the
|
|
68
|
+
* bar of the call (#175): `ta.sma(close, 0)` stops on bar 0, a series length that becomes 0 on the bar where it
|
|
69
|
+
* does. `ta.hma(src, 1)` stops in its inner `wma(src, 0)`. An na length is not checked here.
|
|
70
|
+
*/
|
|
71
|
+
export function checkPositiveLength(name: string, length: number, bar?: number, arg = 'length'): void {
|
|
72
|
+
const len = Math.trunc(length);
|
|
73
|
+
if (len <= 0) throw new Error(lengthError(name, len, bar, arg));
|
|
47
74
|
}
|