oakscriptjs 0.11.4 → 0.11.6
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/index.d.ts +2 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/input.d.ts +19 -3
- package/dist/cjs/input.d.ts.map +1 -1
- package/dist/cjs/input.js +24 -1
- package/dist/cjs/input.js.map +2 -2
- package/dist/cjs/lib/zigzag/zigzag.d.ts +8 -3
- package/dist/cjs/lib/zigzag/zigzag.d.ts.map +1 -1
- package/dist/cjs/lib/zigzag/zigzag.js +16 -3
- package/dist/cjs/lib/zigzag/zigzag.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 +4 -3
- 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 +50 -4
- package/dist/cjs/script/index.d.ts.map +1 -1
- package/dist/cjs/script/index.js +60 -4
- package/dist/cjs/script/index.js.map +3 -3
- package/dist/cjs/security/other.d.ts +2 -1
- package/dist/cjs/security/other.d.ts.map +1 -1
- package/dist/cjs/security/other.js +1 -1
- package/dist/cjs/security/other.js.map +2 -2
- package/dist/cjs/ta/index.d.ts +1 -0
- package/dist/cjs/ta/index.d.ts.map +1 -1
- package/dist/cjs/ta/index.js +1 -1
- package/dist/cjs/ta/index.js.map +2 -2
- package/dist/cjs/time/index.d.ts +2 -0
- package/dist/cjs/time/index.d.ts.map +1 -1
- package/dist/cjs/time/index.js +1 -1
- package/dist/cjs/time/index.js.map +2 -2
- package/dist/cjs/types/index.d.ts +1 -0
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/index.js.map +2 -2
- package/dist/cjs/utils/index.d.ts +5 -3
- package/dist/cjs/utils/index.d.ts.map +1 -1
- package/dist/cjs/utils/index.js +6 -0
- package/dist/cjs/utils/index.js.map +2 -2
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/input.d.ts +19 -3
- package/dist/esm/input.d.ts.map +1 -1
- package/dist/esm/input.js +24 -1
- package/dist/esm/input.js.map +1 -1
- package/dist/esm/lib/zigzag/zigzag.d.ts +8 -3
- package/dist/esm/lib/zigzag/zigzag.d.ts.map +1 -1
- package/dist/esm/lib/zigzag/zigzag.js +19 -4
- package/dist/esm/lib/zigzag/zigzag.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 +4 -3
- package/dist/esm/runtime/types.d.ts.map +1 -1
- package/dist/esm/script/index.d.ts +50 -4
- package/dist/esm/script/index.d.ts.map +1 -1
- package/dist/esm/script/index.js +73 -2
- package/dist/esm/script/index.js.map +1 -1
- package/dist/esm/security/other.d.ts +2 -1
- package/dist/esm/security/other.d.ts.map +1 -1
- package/dist/esm/security/other.js +4 -2
- package/dist/esm/security/other.js.map +1 -1
- package/dist/esm/ta/index.d.ts +1 -0
- package/dist/esm/ta/index.d.ts.map +1 -1
- package/dist/esm/ta/index.js +3 -1
- package/dist/esm/ta/index.js.map +1 -1
- package/dist/esm/time/index.d.ts +2 -0
- package/dist/esm/time/index.d.ts.map +1 -1
- package/dist/esm/time/index.js +4 -1
- package/dist/esm/time/index.js.map +1 -1
- package/dist/esm/types/index.d.ts +1 -0
- package/dist/esm/types/index.d.ts.map +1 -1
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm/utils/index.d.ts +5 -3
- package/dist/esm/utils/index.d.ts.map +1 -1
- package/dist/esm/utils/index.js +5 -1
- package/dist/esm/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +2 -1
- package/src/input.ts +28 -4
- package/src/lib/zigzag/zigzag.ts +20 -6
- package/src/runtime/index.ts +1 -0
- package/src/runtime/inputs.ts +16 -0
- package/src/runtime/types.ts +4 -3
- package/src/script/index.ts +111 -5
- package/src/security/other.ts +5 -2
- package/src/ta/index.ts +3 -1
- package/src/time/index.ts +4 -1
- package/src/types/index.ts +1 -0
- package/src/utils/index.ts +8 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAErF,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAG9C;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAI5F;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,GAAG,GAAG,YAAY,CAEzD;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CASxC;AAED;;GAEG;AACH,wBAAgB,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,YAAY,GAAE,GAAO,GAAG,GAAG,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAY1C;AAED;;;GAGG;AACH,wBAAgB,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,GAAE,GAAO,GAAG,KAAK,CAM5E;AAED;;;GAGG;AACH,wBAAgB,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,GAAG,KAAK,CAE7C;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,GAAG,KAAK,CAEjE;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,GAAG,KAAK,CAE9D;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,GAAE,KAAS,EAAE,MAAM,GAAE,KAAS,GAAG,KAAK,CAE3G;AAKD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAO9C;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,CAEjD;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,CAE/C;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,CAEhD;AAID
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/utils/index.js
CHANGED
|
@@ -143,7 +143,8 @@ export function getOpen(ohlc) {
|
|
|
143
143
|
* Extract a specific source from OHLC data or bar array
|
|
144
144
|
*
|
|
145
145
|
* @param data - Bar array or OHLC data
|
|
146
|
-
* @param source - Source type: 'close', 'open', 'high', 'low', 'hl2', 'hlc3', 'ohlc4'
|
|
146
|
+
* @param source - Source type: 'close', 'open', 'high', 'low', 'hl2', 'hlc3', 'ohlc4', 'hlcc4', 'volume' (NaN for a
|
|
147
|
+
* bar without volume)
|
|
147
148
|
* @returns Series of the requested source
|
|
148
149
|
*
|
|
149
150
|
* @example
|
|
@@ -167,6 +168,7 @@ export function getSource(data, source = 'close') {
|
|
|
167
168
|
case 'hlc3': return ohlc.high.map((h, i) => (h + ohlc.low[i] + ohlc.close[i]) / 3);
|
|
168
169
|
case 'ohlc4': return ohlc.open.map((o, i) => (o + ohlc.high[i] + ohlc.low[i] + ohlc.close[i]) / 4);
|
|
169
170
|
case 'hlcc4': return ohlc.high.map((h, i) => (h + ohlc.low[i] + ohlc.close[i] + ohlc.close[i]) / 4);
|
|
171
|
+
case 'volume': return ohlc.volume ?? ohlc.close.map(() => NaN);
|
|
170
172
|
}
|
|
171
173
|
}
|
|
172
174
|
else {
|
|
@@ -180,6 +182,7 @@ export function getSource(data, source = 'close') {
|
|
|
180
182
|
case 'hlc3': return bars.map(b => (b.high + b.low + b.close) / 3);
|
|
181
183
|
case 'ohlc4': return bars.map(b => (b.open + b.high + b.low + b.close) / 4);
|
|
182
184
|
case 'hlcc4': return bars.map(b => (b.high + b.low + b.close + b.close) / 4);
|
|
185
|
+
case 'volume': return bars.map(b => b.volume ?? NaN);
|
|
183
186
|
}
|
|
184
187
|
}
|
|
185
188
|
}
|
|
@@ -213,6 +216,7 @@ export function getSourceSeries(bars, source = 'close') {
|
|
|
213
216
|
case 'hlc3': return high.add(low).add(close).div(3);
|
|
214
217
|
case 'ohlc4': return open.add(high).add(low).add(close).div(4);
|
|
215
218
|
case 'hlcc4': return high.add(low).add(close).add(close).div(4);
|
|
219
|
+
case 'volume': return Series.fromBars(bars, 'volume');
|
|
216
220
|
default: return close;
|
|
217
221
|
}
|
|
218
222
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -179,6 +179,7 @@ export {
|
|
|
179
179
|
input_float,
|
|
180
180
|
input_bool,
|
|
181
181
|
input_string,
|
|
182
|
+
input_text_area,
|
|
182
183
|
input_source,
|
|
183
184
|
input_timeframe,
|
|
184
185
|
input_session,
|
|
@@ -218,7 +219,7 @@ export type { LightweightSeriesDefinitions } from './runtime/adapters/Lightweigh
|
|
|
218
219
|
export { SimpleInputAdapter } from './runtime/adapters/SimpleInputAdapter.js';
|
|
219
220
|
|
|
220
221
|
// Version
|
|
221
|
-
export const VERSION = '0.11.
|
|
222
|
+
export const VERSION = '0.11.6';
|
|
222
223
|
|
|
223
224
|
/**
|
|
224
225
|
* Library information
|
package/src/input.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
export interface InputValue<T> {
|
|
11
11
|
/** Input type identifier */
|
|
12
|
-
type: 'int' | 'float' | 'source' | 'bool' | 'string' | 'timeframe' | 'session' | 'time' | 'symbol';
|
|
12
|
+
type: 'int' | 'float' | 'source' | 'bool' | 'string' | 'text_area' | 'timeframe' | 'session' | 'time' | 'symbol';
|
|
13
13
|
/** Default value */
|
|
14
14
|
defaultValue: T;
|
|
15
15
|
/** Current value (initially equals defaultValue) */
|
|
@@ -89,9 +89,9 @@ export interface TimeInputOptions {
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
/**
|
|
92
|
-
* Source type for price data
|
|
92
|
+
* Source type for price data (PineScript `input.source` built-in sources, `volume` included)
|
|
93
93
|
*/
|
|
94
|
-
export type SourceType = 'open' | 'high' | 'low' | 'close' | 'hl2' | 'hlc3' | 'ohlc4' | 'hlcc4';
|
|
94
|
+
export type SourceType = 'open' | 'high' | 'low' | 'close' | 'hl2' | 'hlc3' | 'ohlc4' | 'hlcc4' | 'volume';
|
|
95
95
|
|
|
96
96
|
/**
|
|
97
97
|
* Input helper functions for creating indicator parameters
|
|
@@ -163,7 +163,7 @@ export const input = {
|
|
|
163
163
|
defaultValue,
|
|
164
164
|
value: defaultValue,
|
|
165
165
|
title: options.title,
|
|
166
|
-
options: ['open', 'high', 'low', 'close', 'hl2', 'hlc3', 'ohlc4', 'hlcc4'],
|
|
166
|
+
options: ['open', 'high', 'low', 'close', 'hl2', 'hlc3', 'ohlc4', 'hlcc4', 'volume'],
|
|
167
167
|
};
|
|
168
168
|
},
|
|
169
169
|
|
|
@@ -210,6 +210,30 @@ export const input = {
|
|
|
210
210
|
};
|
|
211
211
|
},
|
|
212
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Create a multi-line text input parameter (PineScript `input.text_area`, #184)
|
|
215
|
+
* @param defaultValue - Default text; lines are separated by "
|
|
216
|
+
"
|
|
217
|
+
* @param options - Additional options (title)
|
|
218
|
+
* @returns Input value object
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* ```typescript
|
|
222
|
+
* const list = input.text_area('AAPL, MSFT
|
|
223
|
+
BTCUSD', { title: 'Symbol list' });
|
|
224
|
+
* console.log(list.value); // 'AAPL, MSFT
|
|
225
|
+
BTCUSD'
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
text_area(defaultValue: string, options: TimeInputOptions = {}): InputValue<string> {
|
|
229
|
+
return {
|
|
230
|
+
type: 'text_area' as const,
|
|
231
|
+
defaultValue,
|
|
232
|
+
value: defaultValue,
|
|
233
|
+
title: options.title,
|
|
234
|
+
};
|
|
235
|
+
},
|
|
236
|
+
|
|
213
237
|
/**
|
|
214
238
|
* Create a timeframe input parameter (PineScript `input.timeframe`)
|
|
215
239
|
* @param defaultValue - Default timeframe string ("60", "1D", "W"); "" means the chart timeframe
|
package/src/lib/zigzag/zigzag.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { Bar } from '../../types/index.js';
|
|
11
|
+
import { RunningSum, isNa } from '../../ta/running-sum.js';
|
|
11
12
|
|
|
12
13
|
// ============ Types ============
|
|
13
14
|
|
|
@@ -44,9 +45,9 @@ export interface ZigZagPoint {
|
|
|
44
45
|
export interface ZigZagPivot {
|
|
45
46
|
/** True if this is a pivot high, false for pivot low */
|
|
46
47
|
isHigh: boolean;
|
|
47
|
-
/** Cumulative volume from start to end */
|
|
48
|
+
/** Cumulative volume from start to end: the sum of `volume[depth]` over the bars that built the pivot */
|
|
48
49
|
volume: number;
|
|
49
|
-
/** Starting point of this segment */
|
|
50
|
+
/** Starting point of this segment (the first pivot starts on its own end point) */
|
|
50
51
|
start: ZigZagPoint;
|
|
51
52
|
/** Ending point (the pivot) of this segment */
|
|
52
53
|
end: ZigZagPoint;
|
|
@@ -83,7 +84,11 @@ export class ZigZag {
|
|
|
83
84
|
private highBuffer: number[] = [];
|
|
84
85
|
private lowBuffer: number[] = [];
|
|
85
86
|
private timeBuffer: number[] = [];
|
|
87
|
+
private volumeBuffer: number[] = [];
|
|
86
88
|
private barCount: number = 0;
|
|
89
|
+
/** math.sum(volume, max(depth, 1)) of the current bar, for the extension */
|
|
90
|
+
private remVol: number = NaN;
|
|
91
|
+
private readonly remVolSum = new RunningSum();
|
|
87
92
|
|
|
88
93
|
constructor(settings?: Partial<ZigZagSettings>) {
|
|
89
94
|
this.settings = { ...defaultSettings, ...settings };
|
|
@@ -99,10 +104,17 @@ export class ZigZag {
|
|
|
99
104
|
this.highBuffer.push(bar.high);
|
|
100
105
|
this.lowBuffer.push(bar.low);
|
|
101
106
|
this.timeBuffer.push(bar.time);
|
|
107
|
+
const volume = bar.volume ?? NaN;
|
|
108
|
+
this.volumeBuffer.push(volume);
|
|
102
109
|
this.barCount++;
|
|
103
110
|
|
|
104
111
|
const depth = Math.max(2, Math.floor(this.settings.depth / 2));
|
|
105
|
-
|
|
112
|
+
// PineScript: sumVol += nz(volume[depth]); the extension adds math.sum(volume, max(depth, 1)) (#184)
|
|
113
|
+
const pastVolume = this.volumeBuffer[this.volumeBuffer.length - 1 - depth];
|
|
114
|
+
this.sumVol += pastVolume === undefined || Number.isNaN(pastVolume) ? 0 : pastVolume;
|
|
115
|
+
const sumLength = Math.max(depth, 1);
|
|
116
|
+
this.remVol = isNa(volume) ? this.remVolSum.stepNa(sumLength) : this.remVolSum.step(volume, sumLength);
|
|
117
|
+
this.remVolSum.commit();
|
|
106
118
|
|
|
107
119
|
// Need enough bars for pivot detection (depth bars before and after)
|
|
108
120
|
if (this.barCount < depth * 2 + 1) return false;
|
|
@@ -128,7 +140,8 @@ export class ZigZag {
|
|
|
128
140
|
}
|
|
129
141
|
|
|
130
142
|
/**
|
|
131
|
-
* Get extension line to current bar (if extendLast enabled)
|
|
143
|
+
* Get extension line to current bar (if extendLast enabled). Call it after {@link update} of `currentBar`: its
|
|
144
|
+
* volume is the cumulative volume plus the volume of the last max(depth, 1) bars (na before that many bars).
|
|
132
145
|
*/
|
|
133
146
|
getExtension(currentBar: Bar, barIndex: number): ZigZagPivot | null {
|
|
134
147
|
if (!this.settings.extendLast) return null;
|
|
@@ -142,7 +155,7 @@ export class ZigZag {
|
|
|
142
155
|
|
|
143
156
|
return {
|
|
144
157
|
isHigh,
|
|
145
|
-
volume: this.sumVol,
|
|
158
|
+
volume: this.sumVol + this.remVol,
|
|
146
159
|
start: last.end,
|
|
147
160
|
end: { time: currentBar.time, barIndex, price },
|
|
148
161
|
};
|
|
@@ -250,7 +263,8 @@ export class ZigZag {
|
|
|
250
263
|
: point.price < last.end.price;
|
|
251
264
|
|
|
252
265
|
if (isMoreExtreme) {
|
|
253
|
-
// Update the existing pivot to the new extreme
|
|
266
|
+
// Update the existing pivot to the new extreme; the first pivot moves its start with its end (#184)
|
|
267
|
+
if (this.pivots.length === 1) last.start = point;
|
|
254
268
|
last.end = point;
|
|
255
269
|
last.volume += this.sumVol;
|
|
256
270
|
this.sumVol = 0;
|
package/src/runtime/index.ts
CHANGED
package/src/runtime/inputs.ts
CHANGED
|
@@ -245,6 +245,22 @@ function registerOnce(config: InputConfig): unknown {
|
|
|
245
245
|
return context.inputs.getValue(config.id);
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Register a multi-line text input (PineScript `input.text_area`, #184)
|
|
250
|
+
* First call registers with defval, subsequent calls return current value
|
|
251
|
+
* @param defval - Default text; lines are separated by "
|
|
252
|
+
"
|
|
253
|
+
* @param title - Display title (optional)
|
|
254
|
+
* @returns Current text
|
|
255
|
+
*/
|
|
256
|
+
export function input_text_area(defval: string, title?: string): string {
|
|
257
|
+
if (!getContext()) {
|
|
258
|
+
return defval;
|
|
259
|
+
}
|
|
260
|
+
const value = registerOnce({ id: generateInputId(title, defval, 'text_area'), type: 'text_area', defval, title });
|
|
261
|
+
return typeof value === 'string' ? value : defval;
|
|
262
|
+
}
|
|
263
|
+
|
|
248
264
|
/**
|
|
249
265
|
* Register a timeframe input (PineScript `input.timeframe`)
|
|
250
266
|
* First call registers with defval, subsequent calls return current value
|
package/src/runtime/types.ts
CHANGED
|
@@ -70,9 +70,10 @@ export interface InputConfig {
|
|
|
70
70
|
id: string;
|
|
71
71
|
/**
|
|
72
72
|
* Type of input. `timeframe` and `session` values are strings ("60", "1D", "0930-1600:23456";
|
|
73
|
-
* an empty timeframe means the chart timeframe), `time` values are UNIX times in milliseconds.
|
|
73
|
+
* an empty timeframe means the chart timeframe), `time` values are UNIX times in milliseconds. A `text_area`
|
|
74
|
+
* value is a string that can hold several lines.
|
|
74
75
|
*/
|
|
75
|
-
type: 'int' | 'float' | 'bool' | 'string' | 'source' | 'color' | 'timeframe' | 'session' | 'time' | 'symbol';
|
|
76
|
+
type: 'int' | 'float' | 'bool' | 'string' | 'text_area' | 'source' | 'color' | 'timeframe' | 'session' | 'time' | 'symbol';
|
|
76
77
|
/** Default value */
|
|
77
78
|
defval: unknown;
|
|
78
79
|
/** Display title */
|
|
@@ -95,7 +96,7 @@ export interface InputConfig {
|
|
|
95
96
|
confirm?: boolean;
|
|
96
97
|
/**
|
|
97
98
|
* Where the input value is shown (PineScript `display`); not set means the PineScript default: 'none' for
|
|
98
|
-
* bool, color and
|
|
99
|
+
* bool, color, time and text_area inputs, 'all' for the others
|
|
99
100
|
*/
|
|
100
101
|
display?: 'all' | 'none' | 'data_window' | 'status_line';
|
|
101
102
|
/**
|
package/src/script/index.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* Execution model: the host calls {@link executeScript} with the script body,
|
|
15
15
|
* the bars and the current input values. Declaration calls (indicator, input.*,
|
|
16
|
-
* plot, hline, fill, alertcondition) run as the body executes and are collected
|
|
16
|
+
* plot, hline, fill, alertcondition, alert) run as the body executes and are collected
|
|
17
17
|
* into a {@link ScriptRunResult}: the declarative configs (inputConfig,
|
|
18
18
|
* plotConfig, hlineConfig, fillConfig) plus an IndicatorResult with the plot
|
|
19
19
|
* data. Re-running the body with new bars or inputs is PineScript's
|
|
@@ -136,6 +136,11 @@ export interface ScriptRunResult {
|
|
|
136
136
|
barColorConfig: BarColorConfig[];
|
|
137
137
|
/** plotcandle() / plotbar() declarations */
|
|
138
138
|
candleConfig: CandleConfig[];
|
|
139
|
+
/**
|
|
140
|
+
* The plot(), plotshape(), plotchar(), plotarrow(), plotcandle() and plotbar() declarations in the order the
|
|
141
|
+
* script made them (the id of each in its own config). PineScript numbers a script's outputs in this order.
|
|
142
|
+
*/
|
|
143
|
+
outputs: ScriptOutput[];
|
|
139
144
|
defaultInputs: Record<string, unknown>;
|
|
140
145
|
alertConfig: AlertConditionConfig[];
|
|
141
146
|
/** Strategy properties (declared values, else the PineScript defaults) when the script declares strategy(). */
|
|
@@ -143,9 +148,13 @@ export interface ScriptRunResult {
|
|
|
143
148
|
/**
|
|
144
149
|
* The renderable output: plots keyed by plotConfig ids, plot-pair fills, markers, arrows, background and bar
|
|
145
150
|
* colours, candles and bars, and the drawings (labels, lines, boxes, linefills, polylines, tables) alive after the
|
|
146
|
-
* last bar.
|
|
151
|
+
* last bar. `outputValues`: per plotshape() / plotchar() / plotarrow() id, the value of its series on each bar where
|
|
152
|
+
* it is not na (a condition gives 1 or 0), at the bar it was computed on (the offset not applied).
|
|
147
153
|
*/
|
|
148
|
-
result: IndicatorResult & { alerts?: AlertState[] };
|
|
154
|
+
result: IndicatorResult & { alerts?: AlertState[]; alertCalls?: AlertCall[]; outputValues?: Record<string, TimeValue[]> };
|
|
155
|
+
/** The script called alert() during the run (PineScript `hasAlertFunction` is known at compile time: a host that
|
|
156
|
+
* needs it before any bar runs reads the source). */
|
|
157
|
+
hasAlertFunction: boolean;
|
|
149
158
|
}
|
|
150
159
|
|
|
151
160
|
export interface AlertConditionConfig {
|
|
@@ -164,6 +173,24 @@ export interface AlertState {
|
|
|
164
173
|
times: number[];
|
|
165
174
|
}
|
|
166
175
|
|
|
176
|
+
/** How often an alert() call may trigger the alert (PineScript `alert.freq_*`). */
|
|
177
|
+
export type AlertFrequency = 'all' | 'once_per_bar' | 'once_per_bar_close';
|
|
178
|
+
|
|
179
|
+
/** One alert() call: the time of the bar it ran on (as given in the input bars), its message and frequency. */
|
|
180
|
+
export interface AlertCall {
|
|
181
|
+
time: number;
|
|
182
|
+
message: string;
|
|
183
|
+
freq: AlertFrequency;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** One output declaration of a script: plot(), plotshape() ('shape'), plotchar() ('char'), plotarrow() ('arrow'),
|
|
187
|
+
* plotcandle() ('candle') or plotbar() ('bar'), with its id in plotConfig / shapeConfig / arrowConfig / candleConfig. */
|
|
188
|
+
export interface ScriptOutput {
|
|
189
|
+
kind: 'plot' | 'shape' | 'char' | 'arrow' | 'candle' | 'bar';
|
|
190
|
+
id: string;
|
|
191
|
+
title?: string;
|
|
192
|
+
}
|
|
193
|
+
|
|
167
194
|
/** Handle returned by plot()/hline() so fill() can reference them. */
|
|
168
195
|
export interface PlotHandle {
|
|
169
196
|
id: string;
|
|
@@ -188,6 +215,7 @@ interface Collector {
|
|
|
188
215
|
fillConfig: FillConfig[];
|
|
189
216
|
shapeConfig: ShapeConfig[];
|
|
190
217
|
markers: MarkerData[];
|
|
218
|
+
outputValues: Record<string, TimeValue[]>;
|
|
191
219
|
arrowConfig: ArrowConfig[];
|
|
192
220
|
arrows: ArrowData[];
|
|
193
221
|
barColorConfig: BarColorConfig[];
|
|
@@ -196,8 +224,11 @@ interface Collector {
|
|
|
196
224
|
candleConfig: CandleConfig[];
|
|
197
225
|
plotCandles: Record<string, PlotCandleData[]>;
|
|
198
226
|
plotBars: Record<string, PlotBarData[]>;
|
|
227
|
+
outputs: ScriptOutput[];
|
|
199
228
|
alertConfig: AlertConditionConfig[];
|
|
200
229
|
alerts: AlertState[];
|
|
230
|
+
alertCalls: AlertCall[];
|
|
231
|
+
hasAlertFunction: boolean;
|
|
201
232
|
strategy?: StrategyRun;
|
|
202
233
|
}
|
|
203
234
|
|
|
@@ -242,6 +273,7 @@ function freshCollector(inputValues: Record<string, unknown>): Collector {
|
|
|
242
273
|
fillConfig: [],
|
|
243
274
|
shapeConfig: [],
|
|
244
275
|
markers: [],
|
|
276
|
+
outputValues: {},
|
|
245
277
|
arrowConfig: [],
|
|
246
278
|
arrows: [],
|
|
247
279
|
barColorConfig: [],
|
|
@@ -250,8 +282,11 @@ function freshCollector(inputValues: Record<string, unknown>): Collector {
|
|
|
250
282
|
candleConfig: [],
|
|
251
283
|
plotCandles: {},
|
|
252
284
|
plotBars: {},
|
|
285
|
+
outputs: [],
|
|
253
286
|
alertConfig: [],
|
|
254
287
|
alerts: [],
|
|
288
|
+
alertCalls: [],
|
|
289
|
+
hasAlertFunction: false,
|
|
255
290
|
};
|
|
256
291
|
}
|
|
257
292
|
|
|
@@ -326,6 +361,7 @@ export function executeScript(
|
|
|
326
361
|
arrowConfig: c.arrowConfig,
|
|
327
362
|
barColorConfig: c.barColorConfig,
|
|
328
363
|
candleConfig: c.candleConfig,
|
|
364
|
+
outputs: c.outputs,
|
|
329
365
|
defaultInputs: c.defaultInputs,
|
|
330
366
|
alertConfig: c.alertConfig,
|
|
331
367
|
strategyConfig: c.strategy?.properties,
|
|
@@ -334,6 +370,7 @@ export function executeScript(
|
|
|
334
370
|
plots: c.plots,
|
|
335
371
|
fills: c.fills.length ? c.fills : undefined,
|
|
336
372
|
markers: c.markers.length ? c.markers : undefined,
|
|
373
|
+
outputValues: Object.keys(c.outputValues).length ? c.outputValues : undefined,
|
|
337
374
|
arrows: c.arrows.length ? c.arrows : undefined,
|
|
338
375
|
bgColors: c.bgColors.length ? c.bgColors : undefined,
|
|
339
376
|
barColors: c.barColors.length ? c.barColors : undefined,
|
|
@@ -341,7 +378,9 @@ export function executeScript(
|
|
|
341
378
|
plotBars: Object.keys(c.plotBars).length ? c.plotBars : undefined,
|
|
342
379
|
...drawingOutputs(ctxBars.bars, chartCtx.timeUnit),
|
|
343
380
|
alerts: c.alerts.length ? c.alerts : undefined,
|
|
381
|
+
alertCalls: c.alertCalls.length ? c.alertCalls : undefined,
|
|
344
382
|
},
|
|
383
|
+
hasAlertFunction: c.hasAlertFunction,
|
|
345
384
|
};
|
|
346
385
|
} finally {
|
|
347
386
|
ctx = null;
|
|
@@ -459,6 +498,11 @@ export const input = {
|
|
|
459
498
|
string(defval: string, title?: string, opts: StringInputOptions = {}): string {
|
|
460
499
|
return registerInput<string>({ type: 'string', defval, title, options: opts.options, ...common(opts) }, 'input_string');
|
|
461
500
|
},
|
|
501
|
+
/** Multi-line text ("
|
|
502
|
+
" between the lines), e.g. a list a script parses (#184). */
|
|
503
|
+
text_area(defval: string, title?: string, opts: InputOptions = {}): string {
|
|
504
|
+
return registerInput<string>({ type: 'text_area', defval, title, ...common(opts) }, 'input_text_area');
|
|
505
|
+
},
|
|
462
506
|
/**
|
|
463
507
|
* Declares a colour input. As in PineScript, the default keeps an alpha of 2 decimals: an input default
|
|
464
508
|
* `color.new(c, 90)` has the alpha byte 26 (25 in the script). A value given by the host is not changed.
|
|
@@ -666,6 +710,7 @@ function plotImpl(series: Series, title?: string, options: ScriptPlotOptions = {
|
|
|
666
710
|
histbase: options.histbase,
|
|
667
711
|
forceOverlay: options.force_overlay,
|
|
668
712
|
});
|
|
713
|
+
c.outputs.push({ kind: 'plot', id, title: title ?? id });
|
|
669
714
|
const values = series.toArray();
|
|
670
715
|
const b = bars();
|
|
671
716
|
const data: TimeValue[] = [];
|
|
@@ -875,6 +920,18 @@ function markerPosition(location: MarkerLocation, shape: ShapeStyle | undefined)
|
|
|
875
920
|
/** Default colour of plotshape / plotchar markers. */
|
|
876
921
|
const MARKER_COLOR = '#2962FF';
|
|
877
922
|
|
|
923
|
+
/** The value of an output's series on each bar where it is not na (a condition: 1 or 0), at the bar it was computed
|
|
924
|
+
* on: what PineScript gives for the output in an alert message. */
|
|
925
|
+
function outputSeries(values: ArrayLike<unknown>, b: readonly Bar[]): TimeValue[] {
|
|
926
|
+
const series: TimeValue[] = [];
|
|
927
|
+
for (let i = 0; i < b.length; i++) {
|
|
928
|
+
const v = values[i];
|
|
929
|
+
if (typeof v === 'number' && Number.isFinite(v)) series.push({ time: b[i]!.time, value: v });
|
|
930
|
+
else if (typeof v === 'boolean') series.push({ time: b[i]!.time, value: v ? 1 : 0 });
|
|
931
|
+
}
|
|
932
|
+
return series;
|
|
933
|
+
}
|
|
934
|
+
|
|
878
935
|
/** Shared emitter for plotshape()/plotchar(). Emits one marker per bar where
|
|
879
936
|
* the condition is truthy (not na, not 0). A plotchar marker has the shape 'circle' and its character in `char`. */
|
|
880
937
|
function emitMarkers(
|
|
@@ -902,6 +959,7 @@ function emitMarkers(
|
|
|
902
959
|
offset: options.offset,
|
|
903
960
|
forceOverlay: options.force_overlay,
|
|
904
961
|
});
|
|
962
|
+
c.outputs.push({ kind, id, title });
|
|
905
963
|
const shapeStyle = kind === 'shape' ? (style as ShapeStyle) : undefined;
|
|
906
964
|
const template: Omit<MarkerData, 'time'> = {
|
|
907
965
|
position: markerPosition(location, shapeStyle),
|
|
@@ -918,6 +976,7 @@ function emitMarkers(
|
|
|
918
976
|
const values = condition.toArray();
|
|
919
977
|
const b = bars();
|
|
920
978
|
const off = options.offset ?? 0;
|
|
979
|
+
c.outputValues[id] = outputSeries(values, b);
|
|
921
980
|
for (let i = 0; i < b.length; i++) {
|
|
922
981
|
const v = values[i];
|
|
923
982
|
if (v === undefined || Number.isNaN(v) || v === 0) continue;
|
|
@@ -977,9 +1036,11 @@ export function plotarrow(series: Series, title?: string, options: PlotArrowOpti
|
|
|
977
1036
|
display: options.display,
|
|
978
1037
|
forceOverlay: options.force_overlay,
|
|
979
1038
|
});
|
|
1039
|
+
c.outputs.push({ kind: 'arrow', id, title });
|
|
980
1040
|
const values = series.toArray();
|
|
981
1041
|
const b = bars();
|
|
982
1042
|
const off = options.offset ?? 0;
|
|
1043
|
+
c.outputValues[id] = outputSeries(values, b);
|
|
983
1044
|
for (let i = 0; i < b.length; i++) {
|
|
984
1045
|
const v = values[i];
|
|
985
1046
|
if (v === undefined || Number.isNaN(v) || v === 0) continue;
|
|
@@ -1111,6 +1172,7 @@ export function plotcandle(
|
|
|
1111
1172
|
display: options.display,
|
|
1112
1173
|
forceOverlay: options.force_overlay,
|
|
1113
1174
|
});
|
|
1175
|
+
c.outputs.push({ kind: 'candle', id, title });
|
|
1114
1176
|
const b = bars();
|
|
1115
1177
|
c.plotCandles[id] = ohlcRows(open, high, low, close).map(({ i, ...ohlc }) => {
|
|
1116
1178
|
const candle: PlotCandleData = { time: b[i]!.time, ...ohlc };
|
|
@@ -1147,6 +1209,7 @@ export function plotbar(
|
|
|
1147
1209
|
display: options.display,
|
|
1148
1210
|
forceOverlay: options.force_overlay,
|
|
1149
1211
|
});
|
|
1212
|
+
c.outputs.push({ kind: 'bar', id, title });
|
|
1150
1213
|
const b = bars();
|
|
1151
1214
|
c.plotBars[id] = ohlcRows(open, high, low, close).map(({ i, ...ohlc }) => {
|
|
1152
1215
|
const bar: PlotBarData = { time: b[i]!.time, ...ohlc };
|
|
@@ -1573,6 +1636,8 @@ export interface ChartContext {
|
|
|
1573
1636
|
basecurrency?: string;
|
|
1574
1637
|
/** Root of the symbol (PineScript `syminfo.root`): "BTC" for CME:BTC1!, "ES" for CME_MINI:ES1!, "AAPL" for NASDAQ:AAPL (#180) */
|
|
1575
1638
|
root?: string;
|
|
1639
|
+
/** Description of the symbol (PineScript `syminfo.description`): "Apple Inc." for NASDAQ:AAPL, "Bitcoin / U.S. dollar" for BITSTAMP:BTCUSD (#184) */
|
|
1640
|
+
description?: string;
|
|
1576
1641
|
/** Chart foreground colour (PineScript `chart.fg_color`), e.g. "#DBDBDB" on a dark chart */
|
|
1577
1642
|
foregroundColor?: string;
|
|
1578
1643
|
/** Chart background colour (PineScript `chart.bg_color`), e.g. "#0F0F0F" on a dark chart */
|
|
@@ -1617,6 +1682,7 @@ export type SymbolInfo = Pick<
|
|
|
1617
1682
|
| 'currency'
|
|
1618
1683
|
| 'basecurrency'
|
|
1619
1684
|
| 'root'
|
|
1685
|
+
| 'description'
|
|
1620
1686
|
>;
|
|
1621
1687
|
|
|
1622
1688
|
/** A request of `request.security` for another symbol whose bars the host has not given. */
|
|
@@ -1723,7 +1789,10 @@ function symbolProperty(key: 'mintick' | 'pointvalue' | 'mincontract'): number {
|
|
|
1723
1789
|
}
|
|
1724
1790
|
|
|
1725
1791
|
/** A text value of the chart or the symbol that the host passes in the chart context. */
|
|
1726
|
-
function chartText(
|
|
1792
|
+
function chartText(
|
|
1793
|
+
key: 'symbolType' | 'currency' | 'basecurrency' | 'root' | 'description' | 'foregroundColor' | 'backgroundColor',
|
|
1794
|
+
name: string
|
|
1795
|
+
): string {
|
|
1727
1796
|
collector();
|
|
1728
1797
|
const value = chartCtx[key];
|
|
1729
1798
|
if (value === undefined) {
|
|
@@ -1744,7 +1813,7 @@ function symbolScale(): [number, number] {
|
|
|
1744
1813
|
/**
|
|
1745
1814
|
* PineScript `syminfo.timezone`, `syminfo.tickerid`, `syminfo.session` (session type), `syminfo.mintick`,
|
|
1746
1815
|
* `syminfo.minmove`, `syminfo.pricescale`, `syminfo.pointvalue`, `syminfo.mincontract`, `syminfo.type`,
|
|
1747
|
-
* `syminfo.currency`, `syminfo.basecurrency` and `syminfo.
|
|
1816
|
+
* `syminfo.currency`, `syminfo.basecurrency`, `syminfo.root` and `syminfo.description`, from the chart context.
|
|
1748
1817
|
*/
|
|
1749
1818
|
export const syminfo = {
|
|
1750
1819
|
get mintick(): number {
|
|
@@ -1788,6 +1857,9 @@ export const syminfo = {
|
|
|
1788
1857
|
get root(): string {
|
|
1789
1858
|
return chartText('root', 'syminfo.root');
|
|
1790
1859
|
},
|
|
1860
|
+
get description(): string {
|
|
1861
|
+
return chartText('description', 'syminfo.description');
|
|
1862
|
+
},
|
|
1791
1863
|
};
|
|
1792
1864
|
|
|
1793
1865
|
/** A calendar function: `(time, timezone?)` on a UNIX time or on a Series of times. */
|
|
@@ -2202,6 +2274,7 @@ function runExternal<T extends SecurityValue>(
|
|
|
2202
2274
|
currency: info.currency,
|
|
2203
2275
|
basecurrency: info.basecurrency,
|
|
2204
2276
|
root: info.root,
|
|
2277
|
+
description: info.description,
|
|
2205
2278
|
};
|
|
2206
2279
|
try {
|
|
2207
2280
|
result = expression();
|
|
@@ -2392,6 +2465,39 @@ export function alertcondition(condition: Series, title: string, message?: strin
|
|
|
2392
2465
|
c.alerts.push({ id, title, message, triggered: !isNA(last) && last !== 0, times });
|
|
2393
2466
|
}
|
|
2394
2467
|
|
|
2468
|
+
const ALERT_FREQUENCIES: readonly AlertFrequency[] = ['all', 'once_per_bar', 'once_per_bar_close'];
|
|
2469
|
+
|
|
2470
|
+
/**
|
|
2471
|
+
* PineScript `alert(message, freq)`, with the `alert.freq_*` constants: the calls are collected per bar with their
|
|
2472
|
+
* message and frequency (`result.alertCalls`) for the host's alert engine, which fires the ones made on the realtime
|
|
2473
|
+
* bar. Called inside eachBar() / strategy.eachBar() it is a call on the current bar; at the top level of the script
|
|
2474
|
+
* (which PineScript runs on every bar) it is a call on every bar, `message` then being a text or one text per bar
|
|
2475
|
+
* (a bar whose text is na makes no call). Default frequency: `alert.freq_once_per_bar`.
|
|
2476
|
+
*/
|
|
2477
|
+
function alertImpl(message: string | ReadonlyArray<string | undefined>, freq: AlertFrequency = 'once_per_bar'): void {
|
|
2478
|
+
const c = collector();
|
|
2479
|
+
if (!ALERT_FREQUENCIES.includes(freq)) {
|
|
2480
|
+
throw new Error(`alert(): freq must be alert.freq_all, alert.freq_once_per_bar or alert.freq_once_per_bar_close, not ${String(freq)}.`);
|
|
2481
|
+
}
|
|
2482
|
+
c.hasAlertFunction = true;
|
|
2483
|
+
const b = ctxBars.bars;
|
|
2484
|
+
const textAt = (i: number): string | undefined => (typeof message === 'string' ? message : message[i]);
|
|
2485
|
+
const call = (i: number): void => {
|
|
2486
|
+
const text = textAt(i);
|
|
2487
|
+
if (text === undefined || text === null) return;
|
|
2488
|
+
c.alertCalls.push({ time: b[i]!.time as number, message: String(text), freq });
|
|
2489
|
+
};
|
|
2490
|
+
if (currentBar >= 0) call(currentBar);
|
|
2491
|
+
else for (let i = 0; i < b.length; i++) call(i);
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2494
|
+
/** PineScript `alert()` with the `alert.freq_*` constants: `alert('Crossed', alert.freq_once_per_bar_close)`. */
|
|
2495
|
+
export const alert = Object.assign(alertImpl, {
|
|
2496
|
+
freq_all: 'all',
|
|
2497
|
+
freq_once_per_bar: 'once_per_bar',
|
|
2498
|
+
freq_once_per_bar_close: 'once_per_bar_close',
|
|
2499
|
+
} as const);
|
|
2500
|
+
|
|
2395
2501
|
// ── Convenience re-exports ───────────────────────────────────────────────────
|
|
2396
2502
|
|
|
2397
2503
|
export { Series, BarData, isNA as na, nz };
|
package/src/security/other.ts
CHANGED
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
* holidays, closed hours), gaps off repeats the last value
|
|
19
19
|
* - gaps on: a value only on the chart bar where the shown bar changes (and on the first chart bar), na on the others
|
|
20
20
|
* - the last bar while it is open (`lastBarConfirmed` false) with gaps off: the realtime update shows the bar given by
|
|
21
|
-
* lookahead on (the open bar of a higher timeframe), with lookahead off as well
|
|
21
|
+
* lookahead on (the open bar of a higher timeframe), with lookahead off as well; a lower timeframe keeps the rules
|
|
22
|
+
* above (the last lower bar so far with lookahead off, the first one of the chart bar with lookahead on)
|
|
22
23
|
*
|
|
23
24
|
* Close times, trading days and time zones come from the exchange calendars of the chart and of the other symbol
|
|
24
25
|
* (time zone and session, read by the session functions). Without them:
|
|
@@ -212,7 +213,9 @@ export function securityOther(
|
|
|
212
213
|
|
|
213
214
|
// by trading day when both timeframes are D / W / M; by open time with an intraday side (#181)
|
|
214
215
|
const daily = timeframe.info(chartTf).isdwm && timeframe.info(otherTf).isdwm;
|
|
215
|
-
|
|
216
|
+
// a lower timeframe keeps its rule on the open last bar: the last lower bar so far, not the first one (#184)
|
|
217
|
+
const realtime =
|
|
218
|
+
chart.lastBarConfirmed === false && !options.gaps && timeframe.in_seconds(otherTf) >= timeframe.in_seconds(chartTf);
|
|
216
219
|
let on: number[] = [];
|
|
217
220
|
if (options.lookahead || realtime) {
|
|
218
221
|
if (daily) {
|
package/src/ta/index.ts
CHANGED
|
@@ -1088,6 +1088,7 @@ export function falling(source: Source, length: simple_int): series_bool {
|
|
|
1088
1088
|
* - Equivalent to: `100 * (source - source[length]) / source[length]`
|
|
1089
1089
|
* - Returns percentage change, e.g., 5.0 means 5% increase
|
|
1090
1090
|
* - `na` values in the source series are included in calculations and will produce an `na` result
|
|
1091
|
+
* - A zero `source[length]` gives +/-Infinity (NaN when `source` is 0 too), as in PineScript
|
|
1091
1092
|
* - Useful for momentum analysis and trend strength measurement
|
|
1092
1093
|
*
|
|
1093
1094
|
* @example
|
|
@@ -1106,9 +1107,10 @@ export function roc(source: Source, length: simple_int): series_float {
|
|
|
1106
1107
|
result.push(NaN);
|
|
1107
1108
|
} else {
|
|
1108
1109
|
const oldValue = source[i - length]!;
|
|
1109
|
-
if (
|
|
1110
|
+
if (isNaN(oldValue) || isNaN(source[i]!)) {
|
|
1110
1111
|
result.push(NaN);
|
|
1111
1112
|
} else {
|
|
1113
|
+
// a zero base divides by zero as in PineScript: +/-Infinity, NaN for 0 / 0 (#184)
|
|
1112
1114
|
const changeValue = source[i]! - oldValue;
|
|
1113
1115
|
result.push((100 * changeValue) / oldValue);
|
|
1114
1116
|
}
|