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/dist/esm/ta/index.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { eq, ge, gt, le, lt } from '../compare/index.js';
|
|
11
11
|
import { runningSum, runningSumSeries, runningVariance, runningVarianceSeries } from './running-sum.js';
|
|
12
|
-
import { checkSumLength, checkWindowLength } from './limits.js';
|
|
12
|
+
import { checkPositiveLength, checkSumLength, checkWindowLength } from './limits.js';
|
|
13
13
|
/**
|
|
14
14
|
* Simple Moving Average - returns the moving average (sum of last y values divided by y).
|
|
15
15
|
*
|
|
@@ -64,6 +64,7 @@ export function sma(source, length) {
|
|
|
64
64
|
* ```
|
|
65
65
|
*/
|
|
66
66
|
export function ema(source, length) {
|
|
67
|
+
checkPositiveLength('ema', length, 0);
|
|
67
68
|
const result = [];
|
|
68
69
|
const len = Math.floor(length);
|
|
69
70
|
const multiplier = 2 / (len + 1);
|
|
@@ -101,32 +102,20 @@ export function ema(source, length) {
|
|
|
101
102
|
}
|
|
102
103
|
return result;
|
|
103
104
|
}
|
|
104
|
-
/**
|
|
105
|
-
* Relative Strength Index - momentum oscillator measuring speed and magnitude of price changes.
|
|
106
|
-
*
|
|
107
|
-
* @param source - Series of values to process
|
|
108
|
-
* @param length - Number of bars (length)
|
|
109
|
-
* @returns RSI series (values range from 0 to 100)
|
|
110
|
-
*
|
|
111
|
-
* @remarks
|
|
112
|
-
* - RSI values above 70 typically indicate overbought conditions
|
|
113
|
-
* - RSI values below 30 typically indicate oversold conditions
|
|
114
|
-
* - Uses `ta.rma()` (Relative Moving Average) for smoothing, matching PineScript v6
|
|
115
|
-
* - Formula: RSI = 100 - (100 / (1 + RS)), where RS = Average Gain / Average Loss
|
|
116
|
-
* - As in PineScript (`down == 0 ? 100 : up == 0 ? 0 : ...`): 100 when the average loss is 0, else 0 when the
|
|
117
|
-
* average gain is 0, both with the 1e-10 tolerance of the comparison operators
|
|
118
|
-
* - Average Gain and Average Loss are calculated using RMA (alpha = 1 / length)
|
|
119
|
-
* - `na` values in the source series are ignored
|
|
120
|
-
*
|
|
121
|
-
* @example
|
|
122
|
-
* ```typescript
|
|
123
|
-
* const rsi14 = ta.rsi(closePrices, 14);
|
|
124
|
-
* // Identify overbought/oversold conditions
|
|
125
|
-
* const overbought = rsi14.map(v => v > 70);
|
|
126
|
-
* const oversold = rsi14.map(v => v < 30);
|
|
127
|
-
* ```
|
|
128
|
-
*/
|
|
129
105
|
export function rsi(source, length) {
|
|
106
|
+
if (typeof length !== 'number') {
|
|
107
|
+
return Array.from(source, (xv, i) => {
|
|
108
|
+
const x = xv ?? NaN;
|
|
109
|
+
const y = length[i] ?? NaN;
|
|
110
|
+
if (eq(y, 0))
|
|
111
|
+
return 100;
|
|
112
|
+
if (eq(x, 0))
|
|
113
|
+
return 0;
|
|
114
|
+
const r = 100 - 100 / (1 + x / y);
|
|
115
|
+
return Number.isFinite(r) ? r : NaN;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
checkPositiveLength('rsi', length, 0, 'y');
|
|
130
119
|
const result = [];
|
|
131
120
|
// Calculate price changes
|
|
132
121
|
const changes = [];
|
|
@@ -463,6 +452,7 @@ export function crossunder(series1, series2) {
|
|
|
463
452
|
* ```
|
|
464
453
|
*/
|
|
465
454
|
export function change(source, length = 1) {
|
|
455
|
+
checkPositiveLength('change', length, 0);
|
|
466
456
|
const result = [];
|
|
467
457
|
for (let i = 0; i < source.length; i++) {
|
|
468
458
|
if (i < length) {
|
|
@@ -560,6 +550,7 @@ export function tr(handle_na = false, high, low, close) {
|
|
|
560
550
|
* ```
|
|
561
551
|
*/
|
|
562
552
|
export function atr(length, high, low, close) {
|
|
553
|
+
checkPositiveLength('atr->rma', length, 0);
|
|
563
554
|
if (!high || !low || !close) {
|
|
564
555
|
throw new Error('ta.atr() requires high, low, and close series. ' +
|
|
565
556
|
'Either pass them explicitly or use createContext({ chart: { high, low, close } }) for implicit data.');
|
|
@@ -684,6 +675,7 @@ export function supertrend(factor, atrPeriod, high, low, close, wicks = false) {
|
|
|
684
675
|
* ```
|
|
685
676
|
*/
|
|
686
677
|
export function rma(source, length) {
|
|
678
|
+
checkPositiveLength('rma', length, 0);
|
|
687
679
|
const result = [];
|
|
688
680
|
// Floor the length to match PineScript's auto-truncation of float to int
|
|
689
681
|
const len = Math.floor(length);
|
|
@@ -763,6 +755,8 @@ export function wma(source, length) {
|
|
|
763
755
|
const result = [];
|
|
764
756
|
// Floor the length to match PineScript's auto-truncation of float to int
|
|
765
757
|
const fixed = typeof length === 'number' ? Math.floor(length) : NaN;
|
|
758
|
+
if (typeof length === 'number')
|
|
759
|
+
checkPositiveLength('wma', fixed, 0);
|
|
766
760
|
// PineScript: na on a bar with an na source (also +/-Infinity) and until `len` non-na values were received;
|
|
767
761
|
// otherwise the last `len` bars, each na replaced by the previous non-na value
|
|
768
762
|
const filled = [];
|
|
@@ -778,6 +772,8 @@ export function wma(source, length) {
|
|
|
778
772
|
filled.push(last);
|
|
779
773
|
// a series length: the window of this bar's length (the result of ta.wma with that fixed length)
|
|
780
774
|
const len = typeof length === 'number' ? fixed : Math.floor(length[i]);
|
|
775
|
+
if (typeof length !== 'number')
|
|
776
|
+
checkPositiveLength('wma', len, i);
|
|
781
777
|
if (isNa || !(len >= 1) || count < len) {
|
|
782
778
|
result.push(NaN);
|
|
783
779
|
continue;
|
|
@@ -937,6 +933,7 @@ function monotonic(source, length, step) {
|
|
|
937
933
|
* ```
|
|
938
934
|
*/
|
|
939
935
|
export function rising(source, length) {
|
|
936
|
+
checkPositiveLength('rising', length, 0);
|
|
940
937
|
return monotonic(source, length, gt);
|
|
941
938
|
}
|
|
942
939
|
/**
|
|
@@ -961,6 +958,7 @@ export function rising(source, length) {
|
|
|
961
958
|
* ```
|
|
962
959
|
*/
|
|
963
960
|
export function falling(source, length) {
|
|
961
|
+
checkPositiveLength('falling', length, 0);
|
|
964
962
|
return monotonic(source, length, lt);
|
|
965
963
|
}
|
|
966
964
|
/**
|
|
@@ -985,6 +983,7 @@ export function falling(source, length) {
|
|
|
985
983
|
* ```
|
|
986
984
|
*/
|
|
987
985
|
export function roc(source, length) {
|
|
986
|
+
checkPositiveLength('roc', length, 0);
|
|
988
987
|
const result = [];
|
|
989
988
|
for (let i = 0; i < source.length; i++) {
|
|
990
989
|
if (i < length) {
|
|
@@ -1024,6 +1023,7 @@ export function roc(source, length) {
|
|
|
1024
1023
|
* ```
|
|
1025
1024
|
*/
|
|
1026
1025
|
export function mom(source, length) {
|
|
1026
|
+
checkPositiveLength('mom', length, 0);
|
|
1027
1027
|
const result = [];
|
|
1028
1028
|
for (let i = 0; i < source.length; i++) {
|
|
1029
1029
|
if (i < length) {
|
|
@@ -1062,6 +1062,7 @@ export function mom(source, length) {
|
|
|
1062
1062
|
* ```
|
|
1063
1063
|
*/
|
|
1064
1064
|
export function dev(source, length) {
|
|
1065
|
+
checkPositiveLength('dev', length, 0);
|
|
1065
1066
|
const len = Math.floor(length);
|
|
1066
1067
|
return sma(source, len).map((mean, i) => {
|
|
1067
1068
|
if (i < len - 1 || Number.isNaN(mean))
|
|
@@ -1136,6 +1137,7 @@ function varianceOf(source, length, biased, name) {
|
|
|
1136
1137
|
* ```
|
|
1137
1138
|
*/
|
|
1138
1139
|
export function median(source, length) {
|
|
1140
|
+
checkPositiveLength('median', length, 0);
|
|
1139
1141
|
const len = Math.floor(length);
|
|
1140
1142
|
const n = source.length;
|
|
1141
1143
|
const out = new Array(n).fill(NaN);
|
|
@@ -1224,6 +1226,7 @@ export function swma(source) {
|
|
|
1224
1226
|
* ```
|
|
1225
1227
|
*/
|
|
1226
1228
|
export function vwma(source, length, volume) {
|
|
1229
|
+
checkPositiveLength('vwma->sma', length, 0);
|
|
1227
1230
|
if (!volume) {
|
|
1228
1231
|
throw new Error('ta.vwma() requires volume series. ' +
|
|
1229
1232
|
'Either pass it explicitly or use createContext({ chart: { ..., volume } }) for implicit data.');
|
|
@@ -1271,6 +1274,7 @@ export function vwma(source, length, volume) {
|
|
|
1271
1274
|
* ```
|
|
1272
1275
|
*/
|
|
1273
1276
|
export function linreg(source, length, offset = 0) {
|
|
1277
|
+
checkPositiveLength('linreg', length, 0);
|
|
1274
1278
|
const result = [];
|
|
1275
1279
|
// Floor the length to match PineScript's auto-truncation of float to int
|
|
1276
1280
|
const len = Math.floor(length);
|
|
@@ -1338,6 +1342,7 @@ export function linreg(source, length, offset = 0) {
|
|
|
1338
1342
|
* ```
|
|
1339
1343
|
*/
|
|
1340
1344
|
export function correlation(source1, source2, length) {
|
|
1345
|
+
checkPositiveLength('correlation', length, 0);
|
|
1341
1346
|
// PineScript: from compensated running sums, cov = sma(x * y) - sma(x) * sma(y), r = cov / sqrt(var(x) * var(y))
|
|
1342
1347
|
// (biased variances); each running sum skips its own na values
|
|
1343
1348
|
const product = Array.from({ length: source1.length }, (_, i) => {
|
|
@@ -1377,8 +1382,8 @@ export function correlation(source1, source2, length) {
|
|
|
1377
1382
|
*
|
|
1378
1383
|
* PineScript rules:
|
|
1379
1384
|
* - percentrank = count(source[k] <= source, k = 1..length) * 100 / length (in this order: the PineScript bits)
|
|
1380
|
-
* - a value from bar `length` on
|
|
1381
|
-
*
|
|
1385
|
+
* - a value from bar `length` on; an `na` value in the window counts as not `<=` the current value, and an `na`
|
|
1386
|
+
* current value gives 0 (#177)
|
|
1382
1387
|
* - the comparison uses the 1e-10 tolerance
|
|
1383
1388
|
*
|
|
1384
1389
|
* @example
|
|
@@ -1389,14 +1394,15 @@ export function correlation(source1, source2, length) {
|
|
|
1389
1394
|
* ```
|
|
1390
1395
|
*/
|
|
1391
1396
|
export function percentrank(source, length) {
|
|
1397
|
+
checkPositiveLength('percentrank', length, 0);
|
|
1392
1398
|
const result = [];
|
|
1393
1399
|
for (let i = 0; i < source.length; i++) {
|
|
1394
1400
|
const currentValue = source[i];
|
|
1395
|
-
if (i < length
|
|
1401
|
+
if (i < length) {
|
|
1396
1402
|
result.push(NaN);
|
|
1397
1403
|
continue;
|
|
1398
1404
|
}
|
|
1399
|
-
// le() is false for an na value in the window
|
|
1405
|
+
// le() is false for an na value in the window, and for all of them when the current value is na (0)
|
|
1400
1406
|
let countLessOrEqual = 0;
|
|
1401
1407
|
for (let j = 1; j <= length; j++) {
|
|
1402
1408
|
if (le(source[i - j], currentValue))
|
|
@@ -1435,6 +1441,7 @@ export function percentrank(source, length) {
|
|
|
1435
1441
|
* \`\`\`
|
|
1436
1442
|
*/
|
|
1437
1443
|
export function cci(source, length) {
|
|
1444
|
+
checkPositiveLength('cci', length, 0);
|
|
1438
1445
|
const smaValues = sma(source, length);
|
|
1439
1446
|
const devValues = dev(source, length);
|
|
1440
1447
|
let last = 0;
|
|
@@ -1472,6 +1479,7 @@ export function cci(source, length) {
|
|
|
1472
1479
|
* \`\`\`
|
|
1473
1480
|
*/
|
|
1474
1481
|
export function stoch(source, high, low, length) {
|
|
1482
|
+
checkPositiveLength('stoch->highest', length, 0);
|
|
1475
1483
|
const result = [];
|
|
1476
1484
|
const lowestValues = lowest(low, length);
|
|
1477
1485
|
const highestValues = highest(high, length);
|
|
@@ -1521,6 +1529,7 @@ export function stoch(source, high, low, length) {
|
|
|
1521
1529
|
* ```
|
|
1522
1530
|
*/
|
|
1523
1531
|
export function mfi(source, length, volume) {
|
|
1532
|
+
checkPositiveLength('mfi', length, 0);
|
|
1524
1533
|
if (!volume) {
|
|
1525
1534
|
throw new Error('ta.mfi() requires volume series. ' +
|
|
1526
1535
|
'Either pass it explicitly or use createContext({ chart: { ..., volume } }) for implicit data.');
|
|
@@ -1576,6 +1585,7 @@ export function mfi(source, length, volume) {
|
|
|
1576
1585
|
* ```
|
|
1577
1586
|
*/
|
|
1578
1587
|
export function hma(source, length) {
|
|
1588
|
+
checkPositiveLength('hma', length, 0);
|
|
1579
1589
|
const halfLength = Math.floor(length / 2);
|
|
1580
1590
|
const sqrtLength = Math.floor(Math.sqrt(length));
|
|
1581
1591
|
const wmaHalf = wma(source, halfLength);
|
|
@@ -1933,6 +1943,7 @@ export function dmi(diLength, adxSmoothing, high, low, close) {
|
|
|
1933
1943
|
* ```
|
|
1934
1944
|
*/
|
|
1935
1945
|
export function tsi(source, shortLength, longLength) {
|
|
1946
|
+
checkPositiveLength('tsi->ema', shortLength, 0);
|
|
1936
1947
|
const momentum = [];
|
|
1937
1948
|
// Calculate momentum (price change)
|
|
1938
1949
|
for (let i = 0; i < source.length; i++) {
|
|
@@ -1978,6 +1989,7 @@ export function tsi(source, shortLength, longLength) {
|
|
|
1978
1989
|
* ```
|
|
1979
1990
|
*/
|
|
1980
1991
|
export function cmo(source, length) {
|
|
1992
|
+
checkPositiveLength('cmo', length, 0);
|
|
1981
1993
|
// PineScript definition: mom = ta.change(src), sm1 = math.sum(mom >= 0 ? mom : 0, length),
|
|
1982
1994
|
// sm2 = math.sum(mom >= 0 ? 0 : -mom, length), cmo = 100 * (sm1 - sm2) / (sm1 + sm2), with the running sums of
|
|
1983
1995
|
// math.sum (bit for bit). A comparison with na is false: an na change adds 0 to sm1 and na (skipped) to sm2.
|
|
@@ -2018,6 +2030,7 @@ export function cmo(source, length) {
|
|
|
2018
2030
|
* ```
|
|
2019
2031
|
*/
|
|
2020
2032
|
export function kc(source, length, mult, useTrueRange = true, high, low, close) {
|
|
2033
|
+
checkPositiveLength('kc', length, 0);
|
|
2021
2034
|
// Calculate middle band (EMA of source)
|
|
2022
2035
|
const middle = ema(source, length);
|
|
2023
2036
|
// Calculate range
|
|
@@ -2072,6 +2085,7 @@ export function kc(source, length, mult, useTrueRange = true, high, low, close)
|
|
|
2072
2085
|
* ```
|
|
2073
2086
|
*/
|
|
2074
2087
|
export function bbw(source, length, mult) {
|
|
2088
|
+
checkPositiveLength('bbw', length, 0);
|
|
2075
2089
|
const [basis, upper, lower] = bb(source, length, mult);
|
|
2076
2090
|
const result = [];
|
|
2077
2091
|
for (let i = 0; i < source.length; i++) {
|
|
@@ -2113,6 +2127,7 @@ export function bbw(source, length, mult) {
|
|
|
2113
2127
|
* ```
|
|
2114
2128
|
*/
|
|
2115
2129
|
export function wpr(high, low, close, length = 14) {
|
|
2130
|
+
checkPositiveLength('wpr', length, 0);
|
|
2116
2131
|
const highs = highest(high, length);
|
|
2117
2132
|
const lows = lowest(low, length);
|
|
2118
2133
|
return Array.from({ length: close.length }, (_, i) => {
|
|
@@ -2177,6 +2192,7 @@ export function vwap(source, volume, anchor, stdev_mult) {
|
|
|
2177
2192
|
* ```
|
|
2178
2193
|
*/
|
|
2179
2194
|
export function alma(source, length = 9, offset = 0.85, sigma = 6, floor = false) {
|
|
2195
|
+
checkPositiveLength('alma', length, 0);
|
|
2180
2196
|
const result = [];
|
|
2181
2197
|
const m = floor ? Math.floor(offset * (length - 1)) : offset * (length - 1);
|
|
2182
2198
|
const s = length / sigma;
|
|
@@ -2255,6 +2271,7 @@ export function kcw(source, length = 20, mult = 2, useTrueRange = true, high, lo
|
|
|
2255
2271
|
* values), and a bar whose own value is `na` still gets a result.
|
|
2256
2272
|
*/
|
|
2257
2273
|
export function range(source, length) {
|
|
2274
|
+
checkPositiveLength('range', length, 0);
|
|
2258
2275
|
return source.map((_, i) => {
|
|
2259
2276
|
const values = lastValues(source, i, length);
|
|
2260
2277
|
return values ? Math.max(...values) - Math.min(...values) : NaN;
|
|
@@ -2337,6 +2354,7 @@ export function min(source) {
|
|
|
2337
2354
|
* ```
|
|
2338
2355
|
*/
|
|
2339
2356
|
export function cog(source, length = 10) {
|
|
2357
|
+
checkPositiveLength('cog', length, 0);
|
|
2340
2358
|
const len = Math.floor(length);
|
|
2341
2359
|
return runningSum(source, len).map((sum, i) => {
|
|
2342
2360
|
if (i < len - 1 || Number.isNaN(sum) || sum === 0)
|
|
@@ -2371,6 +2389,7 @@ export function cog(source, length = 10) {
|
|
|
2371
2389
|
* - If no mode exists, returns the smallest value
|
|
2372
2390
|
*/
|
|
2373
2391
|
export function mode(source, length) {
|
|
2392
|
+
checkPositiveLength('mode', length, 0);
|
|
2374
2393
|
const result = [];
|
|
2375
2394
|
const len = Math.floor(length);
|
|
2376
2395
|
const seen = []; // non-na values so far
|
|
@@ -2438,6 +2457,7 @@ export function mode(source, length) {
|
|
|
2438
2457
|
* `na` values are before all numbers
|
|
2439
2458
|
*/
|
|
2440
2459
|
export function percentile_linear_interpolation(source, length, percentage) {
|
|
2460
|
+
checkPositiveLength('percentile_linear_interpolation', length, 0);
|
|
2441
2461
|
return sortedWindow(source, length, (s) => {
|
|
2442
2462
|
const pos = (percentage / 100) * length - 0.5;
|
|
2443
2463
|
if (pos <= 0)
|
|
@@ -2504,6 +2524,7 @@ function sortedWindow(source, length, fn) {
|
|
|
2504
2524
|
* - `na` values stay in the window, sorted from bar to bar as in `ta.percentile_linear_interpolation`
|
|
2505
2525
|
*/
|
|
2506
2526
|
export function percentile_nearest_rank(source, length, percentage) {
|
|
2527
|
+
checkPositiveLength('percentile_nearest_rank', length, 0);
|
|
2507
2528
|
const rank = Math.min(length, Math.max(1, Math.ceil((percentage / 100) * length)));
|
|
2508
2529
|
return sortedWindow(source, length, (s) => s[rank - 1]);
|
|
2509
2530
|
}
|
|
@@ -2539,6 +2560,7 @@ export function percentile_nearest_rank(source, length, percentage) {
|
|
|
2539
2560
|
* where the `na` was
|
|
2540
2561
|
*/
|
|
2541
2562
|
export function rci(source, length) {
|
|
2563
|
+
checkPositiveLength('rci', length, 0);
|
|
2542
2564
|
const len = Math.floor(length);
|
|
2543
2565
|
const result = [];
|
|
2544
2566
|
// PineScript keeps the values in a ring of `length + 1` slots indexed by the bar index, filled with 0 at the start
|
|
@@ -2604,187 +2626,135 @@ export function rci(source, length) {
|
|
|
2604
2626
|
return result;
|
|
2605
2627
|
}
|
|
2606
2628
|
/**
|
|
2607
|
-
* Pivot Point Levels
|
|
2629
|
+
* Pivot Point Levels (PineScript `ta.pivot_point_levels`).
|
|
2608
2630
|
*
|
|
2609
|
-
*
|
|
2610
|
-
* Returns an array containing: [P, R1, S1, R2, S2, R3, S3, R4, S4, R5, S5]
|
|
2631
|
+
* Returns 11 series: [P, R1, S1, R2, S2, R3, S3, R4, S4, R5, S5] (one value per bar in each).
|
|
2611
2632
|
*
|
|
2612
2633
|
* @param type - Calculation type: "Traditional", "Fibonacci", "Woodie", "Classic", "DM", "Camarilla"
|
|
2613
|
-
* @param anchor - Condition that
|
|
2614
|
-
* @param developing -
|
|
2615
|
-
*
|
|
2616
|
-
* @param
|
|
2617
|
-
* @param
|
|
2618
|
-
* @param
|
|
2619
|
-
* @
|
|
2634
|
+
* @param anchor - Condition that starts a new period (`timeframe.change("W")`...)
|
|
2635
|
+
* @param developing - false: the levels of the previous period, constant until the next anchor; true: the levels of
|
|
2636
|
+
* the current period so far, recalculated on each bar
|
|
2637
|
+
* @param high - High price series
|
|
2638
|
+
* @param low - Low price series
|
|
2639
|
+
* @param close - Close price series
|
|
2640
|
+
* @param open - Open price series (Woodie and DM)
|
|
2641
|
+
* @returns 11 series of levels
|
|
2620
2642
|
*
|
|
2621
2643
|
* @example
|
|
2622
2644
|
* ```typescript
|
|
2623
2645
|
* const weekChange = [false, false, false, false, true, false, ...]; // Weekly anchor
|
|
2624
|
-
* const
|
|
2625
|
-
* //
|
|
2646
|
+
* const levels = ta.pivot_point_levels("Traditional", weekChange, false, high, low, close, open);
|
|
2647
|
+
* // levels[0]![i] is P on bar i, levels[5]![i] is R3
|
|
2626
2648
|
* ```
|
|
2627
2649
|
*
|
|
2628
2650
|
* @remarks
|
|
2629
|
-
*
|
|
2630
|
-
* -
|
|
2631
|
-
*
|
|
2651
|
+
* As in PineScript (#177):
|
|
2652
|
+
* - a period runs from an anchor bar to the bar before the next anchor; the bars before the first anchor are a
|
|
2653
|
+
* period too (from bar 0). The fixed levels use the high and low of the previous period and the close of the bar
|
|
2654
|
+
* before the anchor (na with an anchor on bar 0), and are na until the first anchor; the developing levels use
|
|
2655
|
+
* the current period's high and low and the bar's close, from bar 0
|
|
2656
|
+
* - 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),
|
|
2657
|
+
* R5 = P * 4 + (H - 4 * L), S5 = P * 4 - (4 * H - L)
|
|
2658
|
+
* - Fibonacci: P +- 0.382 / 0.618 / 1 * (H - L); R4 to S5 na
|
|
2659
|
+
* - Classic: R3 / S3 = P +- 2 * (H - L), R4 / S4 = P +- 3 * (H - L); R5 / S5 na
|
|
2660
|
+
* - Woodie: P = (H + L + 2 * open of the current period) / 4, R3 = H + 2 * (P - L), S3 = L - 2 * (H - P), R4 / S4 =
|
|
2661
|
+
* R3 + (H - L) / S3 - (H - L); R5 / S5 na. `developing` true throws (RE10128)
|
|
2662
|
+
* - 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,
|
|
2663
|
+
* R1 = x / 2 - L, S1 = x / 2 - H; the other levels na
|
|
2664
|
+
* - Camarilla: C +- (H - L) * 1.1 / 12, / 6, / 4, / 2 for R1 to S4, R5 = (H / L) * C, S5 = 2 * C - R5
|
|
2632
2665
|
*/
|
|
2633
2666
|
export function pivot_point_levels(type, anchor, developing = false, high, low, close, open) {
|
|
2634
|
-
// For simplicity, we need to handle the case where type is a string array
|
|
2635
|
-
// But according to the docs, type is "series string", meaning it can change per bar
|
|
2636
|
-
// For this implementation, we'll support constant type strings
|
|
2637
2667
|
const typeStr = typeof type === 'string' ? type : String(type[0]);
|
|
2638
|
-
const isDeveloping = typeof developing === 'boolean' ? developing : developing[0];
|
|
2639
|
-
// Woodie cannot be developing
|
|
2668
|
+
const isDeveloping = typeof developing === 'boolean' ? developing : Boolean(developing[0]);
|
|
2640
2669
|
if (typeStr === 'Woodie' && isDeveloping) {
|
|
2641
|
-
throw new Error('ta.pivot_point_levels
|
|
2642
|
-
}
|
|
2643
|
-
|
|
2644
|
-
const
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
lastAnchorIndex = i;
|
|
2662
|
-
// Store OHLC at anchor point (these will be used for calculations)
|
|
2663
|
-
lastH = high ? high[i] : NaN;
|
|
2664
|
-
lastL = low ? low[i] : NaN;
|
|
2665
|
-
lastC = close ? close[i] : NaN;
|
|
2666
|
-
lastO = open ? open[i] : NaN;
|
|
2667
|
-
}
|
|
2668
|
-
// Calculate data to use
|
|
2669
|
-
let h, l, c, o;
|
|
2670
|
-
if (isDeveloping && lastAnchorIndex >= 0) {
|
|
2671
|
-
// Developing: use max/min/last since anchor
|
|
2672
|
-
h = high ? Math.max(...high.slice(lastAnchorIndex, i + 1).filter(v => !isNaN(v))) : NaN;
|
|
2673
|
-
l = low ? Math.min(...low.slice(lastAnchorIndex, i + 1).filter(v => !isNaN(v))) : NaN;
|
|
2674
|
-
c = close ? close[i] : NaN;
|
|
2675
|
-
o = open && lastAnchorIndex >= 0 ? open[lastAnchorIndex] : NaN;
|
|
2676
|
-
}
|
|
2677
|
-
else {
|
|
2678
|
-
// Not developing: use last anchor values
|
|
2679
|
-
h = lastH;
|
|
2680
|
-
l = lastL;
|
|
2681
|
-
c = lastC;
|
|
2682
|
-
o = lastO;
|
|
2683
|
-
}
|
|
2684
|
-
// Calculate pivot levels based on type
|
|
2685
|
-
const levels = calculatePivotLevels(typeStr, h, l, c, o);
|
|
2686
|
-
// Push to results
|
|
2687
|
-
for (let j = 0; j < 11; j++) {
|
|
2688
|
-
results[j].push(levels[j]);
|
|
2670
|
+
throw new Error('Error on bar 0: The `developing` parameter of the `ta.pivot_point_levels()` cannot be `true` when `type` is "Woodie".');
|
|
2671
|
+
}
|
|
2672
|
+
const n = anchor.length;
|
|
2673
|
+
for (const [s, name] of [[high, 'High'], [low, 'Low'], [close, 'Close'], [open, 'Open']]) {
|
|
2674
|
+
if (s && s.length !== n)
|
|
2675
|
+
throw new Error(`${name} series length mismatch`);
|
|
2676
|
+
}
|
|
2677
|
+
const at = (s, i) => (s ? (s[i] ?? NaN) : NaN);
|
|
2678
|
+
const results = Array.from({ length: 11 }, () => new Array(n));
|
|
2679
|
+
// the current period (from bar 0 until the first anchor) and the previous one
|
|
2680
|
+
let curH = NaN, curL = NaN, curO = NaN;
|
|
2681
|
+
let prevH = NaN, prevL = NaN, prevC = NaN, prevO = NaN;
|
|
2682
|
+
let anchored = false;
|
|
2683
|
+
for (let i = 0; i < n; i++) {
|
|
2684
|
+
const h = at(high, i), l = at(low, i);
|
|
2685
|
+
if (i === 0) {
|
|
2686
|
+
// the first period starts on bar 0: an anchor there makes bar 0 its own previous period
|
|
2687
|
+
curH = h;
|
|
2688
|
+
curL = l;
|
|
2689
|
+
curO = at(open, i);
|
|
2689
2690
|
}
|
|
2691
|
+
if (anchor[i]) {
|
|
2692
|
+
prevH = curH;
|
|
2693
|
+
prevL = curL;
|
|
2694
|
+
prevC = i > 0 ? at(close, i - 1) : NaN;
|
|
2695
|
+
prevO = curO;
|
|
2696
|
+
curH = h;
|
|
2697
|
+
curL = l;
|
|
2698
|
+
curO = at(open, i);
|
|
2699
|
+
anchored = true;
|
|
2700
|
+
}
|
|
2701
|
+
else if (i > 0) {
|
|
2702
|
+
if (h > curH || Number.isNaN(curH))
|
|
2703
|
+
curH = h;
|
|
2704
|
+
if (l < curL || Number.isNaN(curL))
|
|
2705
|
+
curL = l;
|
|
2706
|
+
}
|
|
2707
|
+
const levels = isDeveloping
|
|
2708
|
+
? pivotLevels(typeStr, curH, curL, at(close, i), curO, at(close, i))
|
|
2709
|
+
: anchored
|
|
2710
|
+
? pivotLevels(typeStr, prevH, prevL, prevC, prevO, curO)
|
|
2711
|
+
: NA_LEVELS;
|
|
2712
|
+
for (let k = 0; k < 11; k++)
|
|
2713
|
+
results[k][i] = levels[k];
|
|
2690
2714
|
}
|
|
2691
2715
|
return results;
|
|
2692
2716
|
}
|
|
2717
|
+
const NA_LEVELS = new Array(11).fill(NaN);
|
|
2693
2718
|
/**
|
|
2694
|
-
*
|
|
2719
|
+
* The 11 levels of one bar, in PineScript's operation order (bit for bit). `o` is the open of the period (DM),
|
|
2720
|
+
* `wo` the close term of Woodie (the open of the current period, or the bar's close while developing).
|
|
2695
2721
|
*/
|
|
2696
|
-
function
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
return Array(11).fill(NaN);
|
|
2700
|
-
}
|
|
2701
|
-
const levels = Array(11).fill(NaN);
|
|
2702
|
-
// Calculate pivot point (P)
|
|
2703
|
-
let P;
|
|
2722
|
+
function pivotLevels(type, h, l, c, o, wo) {
|
|
2723
|
+
const N = NaN;
|
|
2724
|
+
const r = h - l;
|
|
2704
2725
|
switch (type) {
|
|
2705
|
-
case 'Traditional':
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
case '
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
switch (type) {
|
|
2725
|
-
case 'Traditional':
|
|
2726
|
-
case 'Classic':
|
|
2727
|
-
levels[1] = 2 * P - l; // R1
|
|
2728
|
-
levels[2] = 2 * P - h; // S1
|
|
2729
|
-
levels[3] = P + (h - l); // R2
|
|
2730
|
-
levels[4] = P - (h - l); // S2
|
|
2731
|
-
levels[5] = h + 2 * (P - l); // R3
|
|
2732
|
-
levels[6] = l - 2 * (h - P); // S3
|
|
2733
|
-
levels[7] = levels[5] + (h - l); // R4
|
|
2734
|
-
levels[8] = levels[6] - (h - l); // S4
|
|
2735
|
-
levels[9] = levels[7] + (h - l); // R5
|
|
2736
|
-
levels[10] = levels[8] - (h - l); // S5
|
|
2737
|
-
break;
|
|
2738
|
-
case 'Fibonacci':
|
|
2739
|
-
levels[1] = P + 0.382 * (h - l); // R1
|
|
2740
|
-
levels[2] = P - 0.382 * (h - l); // S1
|
|
2741
|
-
levels[3] = P + 0.618 * (h - l); // R2
|
|
2742
|
-
levels[4] = P - 0.618 * (h - l); // S2
|
|
2743
|
-
levels[5] = P + (h - l); // R3
|
|
2744
|
-
levels[6] = P - (h - l); // S3
|
|
2745
|
-
levels[7] = levels[5] + 0.618 * (h - l); // R4
|
|
2746
|
-
levels[8] = levels[6] - 0.618 * (h - l); // S4
|
|
2747
|
-
levels[9] = levels[7] + 0.382 * (h - l); // R5
|
|
2748
|
-
levels[10] = levels[8] - 0.382 * (h - l); // S5
|
|
2749
|
-
break;
|
|
2750
|
-
case 'Woodie':
|
|
2751
|
-
levels[1] = 2 * P - l; // R1
|
|
2752
|
-
levels[2] = 2 * P - h; // S1
|
|
2753
|
-
levels[3] = P + (h - l); // R2
|
|
2754
|
-
levels[4] = P - (h - l); // S2
|
|
2755
|
-
levels[5] = h + 2 * (P - l); // R3
|
|
2756
|
-
levels[6] = l - 2 * (h - P); // S3
|
|
2757
|
-
levels[7] = levels[5] + (h - l); // R4
|
|
2758
|
-
levels[8] = levels[6] - (h - l); // S4
|
|
2759
|
-
levels[9] = levels[7] + (h - l); // R5
|
|
2760
|
-
levels[10] = levels[8] - (h - l); // S5
|
|
2761
|
-
break;
|
|
2726
|
+
case 'Traditional': {
|
|
2727
|
+
const p = (h + l + c) / 3;
|
|
2728
|
+
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),
|
|
2729
|
+
p * 3 - (3 * h - l), p * 4 + (h - 4 * l), p * 4 - (4 * h - l)];
|
|
2730
|
+
}
|
|
2731
|
+
case 'Fibonacci': {
|
|
2732
|
+
const p = (h + l + c) / 3;
|
|
2733
|
+
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];
|
|
2734
|
+
}
|
|
2735
|
+
case 'Classic': {
|
|
2736
|
+
const p = (h + l + c) / 3;
|
|
2737
|
+
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];
|
|
2738
|
+
}
|
|
2739
|
+
case 'Woodie': {
|
|
2740
|
+
const p = (h + l + 2 * wo) / 4;
|
|
2741
|
+
const r3 = h + 2 * (p - l);
|
|
2742
|
+
const s3 = l - 2 * (h - p);
|
|
2743
|
+
return [p, 2 * p - l, 2 * p - h, p + r, p - r, r3, s3, r3 + r, s3 - r, N, N];
|
|
2744
|
+
}
|
|
2762
2745
|
case 'DM': {
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
const newP = x / (isNaN(o) ? 4 : 5);
|
|
2766
|
-
levels[0] = newP;
|
|
2767
|
-
levels[1] = x / 2 - l; // R1
|
|
2768
|
-
levels[2] = x / 2 - h; // S1
|
|
2769
|
-
// R2-S5 remain NaN
|
|
2770
|
-
break;
|
|
2746
|
+
const x = c < o ? h + 2 * l + c : c > o ? 2 * h + l + c : h + l + 2 * c;
|
|
2747
|
+
return [x / 4, x / 2 - l, x / 2 - h, N, N, N, N, N, N, N, N];
|
|
2771
2748
|
}
|
|
2772
2749
|
case 'Camarilla': {
|
|
2773
|
-
const
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
levels[4] = c - range * 1.1 / 6; // S2
|
|
2778
|
-
levels[5] = c + range * 1.1 / 4; // R3
|
|
2779
|
-
levels[6] = c - range * 1.1 / 4; // S3
|
|
2780
|
-
levels[7] = c + range * 1.1 / 2; // R4
|
|
2781
|
-
levels[8] = c - range * 1.1 / 2; // S4
|
|
2782
|
-
levels[9] = h; // R5 (high)
|
|
2783
|
-
levels[10] = l; // S5 (low)
|
|
2784
|
-
break;
|
|
2750
|
+
const p = (h + l + c) / 3;
|
|
2751
|
+
const r5 = (h / l) * c;
|
|
2752
|
+
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,
|
|
2753
|
+
c - (r * 1.1) / 4, c + (r * 1.1) / 2, c - (r * 1.1) / 2, r5, 2 * c - r5];
|
|
2785
2754
|
}
|
|
2755
|
+
default:
|
|
2756
|
+
return NA_LEVELS;
|
|
2786
2757
|
}
|
|
2787
|
-
return levels;
|
|
2788
2758
|
}
|
|
2789
2759
|
/**
|
|
2790
2760
|
* Ichimoku Kinko Hyo (Ichimoku Cloud) - Japanese charting technique for trend identification.
|