oakscriptjs 0.10.0 → 0.11.0
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/box/index.d.ts.map +1 -1
- package/dist/cjs/box/index.js +7 -1
- package/dist/cjs/box/index.js.map +2 -2
- package/dist/cjs/callsite/index.d.ts +73 -32
- package/dist/cjs/callsite/index.d.ts.map +1 -1
- package/dist/cjs/callsite/index.js +69 -65
- package/dist/cjs/callsite/index.js.map +2 -2
- package/dist/cjs/drawing/registry.d.ts +75 -0
- package/dist/cjs/drawing/registry.d.ts.map +1 -1
- package/dist/cjs/drawing/registry.js +139 -6
- package/dist/cjs/drawing/registry.js.map +2 -2
- package/dist/cjs/index.d.ts +8 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +30 -1
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/label/index.d.ts.map +1 -1
- package/dist/cjs/label/index.js +3 -0
- package/dist/cjs/label/index.js.map +2 -2
- package/dist/cjs/line/index.d.ts.map +1 -1
- package/dist/cjs/line/index.js +7 -1
- package/dist/cjs/line/index.js.map +2 -2
- package/dist/cjs/math/index.d.ts.map +1 -1
- package/dist/cjs/math/index.js +2 -0
- package/dist/cjs/math/index.js.map +2 -2
- package/dist/cjs/polyline/index.d.ts.map +1 -1
- package/dist/cjs/polyline/index.js +3 -0
- package/dist/cjs/polyline/index.js.map +2 -2
- package/dist/cjs/runtime/index.d.ts +2 -1
- package/dist/cjs/runtime/index.d.ts.map +1 -1
- package/dist/cjs/runtime/index.js +2 -0
- package/dist/cjs/runtime/index.js.map +2 -2
- package/dist/cjs/runtime/input-active.d.ts +27 -0
- package/dist/cjs/runtime/input-active.d.ts.map +1 -0
- package/dist/cjs/runtime/input-active.js +44 -0
- package/dist/cjs/runtime/input-active.js.map +7 -0
- package/dist/cjs/runtime/types.d.ts +29 -2
- 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 +53 -17
- package/dist/cjs/script/index.d.ts.map +1 -1
- package/dist/cjs/script/index.js +70 -11
- package/dist/cjs/script/index.js.map +3 -3
- package/dist/cjs/session/bars.d.ts +15 -1
- package/dist/cjs/session/bars.d.ts.map +1 -1
- package/dist/cjs/session/bars.js +41 -6
- package/dist/cjs/session/bars.js.map +3 -3
- package/dist/cjs/session/calendar.d.ts +9 -1
- package/dist/cjs/session/calendar.d.ts.map +1 -1
- package/dist/cjs/session/calendar.js +28 -2
- package/dist/cjs/session/calendar.js.map +2 -2
- package/dist/cjs/session/context.d.ts +75 -0
- package/dist/cjs/session/context.d.ts.map +1 -0
- package/dist/cjs/session/context.js +113 -0
- package/dist/cjs/session/context.js.map +7 -0
- package/dist/cjs/str/index.d.ts +12 -4
- package/dist/cjs/str/index.d.ts.map +1 -1
- package/dist/cjs/str/index.js +13 -7
- package/dist/cjs/str/index.js.map +2 -2
- package/dist/cjs/str/numberformat.d.ts +10 -2
- package/dist/cjs/str/numberformat.d.ts.map +1 -1
- package/dist/cjs/str/numberformat.js +10 -2
- package/dist/cjs/str/numberformat.js.map +2 -2
- package/dist/cjs/ta/index.d.ts +33 -17
- package/dist/cjs/ta/index.d.ts.map +1 -1
- package/dist/cjs/ta/index.js +70 -29
- package/dist/cjs/ta/index.js.map +2 -2
- package/dist/cjs/ta/limits.d.ts +24 -0
- package/dist/cjs/ta/limits.d.ts.map +1 -0
- package/dist/cjs/ta/limits.js +50 -0
- package/dist/cjs/ta/limits.js.map +7 -0
- package/dist/cjs/ta/running-sum.d.ts +0 -16
- package/dist/cjs/ta/running-sum.d.ts.map +1 -1
- package/dist/cjs/ta/running-sum.js +2 -0
- package/dist/cjs/ta/running-sum.js.map +2 -2
- package/dist/cjs/ta-series.d.ts +7 -7
- package/dist/cjs/ta-series.d.ts.map +1 -1
- package/dist/cjs/ta-series.js +9 -7
- package/dist/cjs/ta-series.js.map +2 -2
- package/dist/cjs/time/index.d.ts +5 -2
- package/dist/cjs/time/index.d.ts.map +1 -1
- package/dist/cjs/time/index.js +2 -2
- package/dist/cjs/time/index.js.map +2 -2
- package/dist/cjs/time/session.d.ts +17 -1
- package/dist/cjs/time/session.d.ts.map +1 -1
- package/dist/cjs/time/session.js +61 -7
- package/dist/cjs/time/session.js.map +2 -2
- package/dist/cjs/types/metadata.d.ts +27 -3
- package/dist/cjs/types/metadata.d.ts.map +1 -1
- package/dist/cjs/types/metadata.js.map +1 -1
- package/dist/esm/box/index.d.ts.map +1 -1
- package/dist/esm/box/index.js +8 -2
- package/dist/esm/box/index.js.map +1 -1
- package/dist/esm/callsite/index.d.ts +73 -32
- package/dist/esm/callsite/index.d.ts.map +1 -1
- package/dist/esm/callsite/index.js +143 -106
- package/dist/esm/callsite/index.js.map +1 -1
- package/dist/esm/drawing/registry.d.ts +75 -0
- package/dist/esm/drawing/registry.d.ts.map +1 -1
- package/dist/esm/drawing/registry.js +237 -6
- package/dist/esm/drawing/registry.js.map +1 -1
- package/dist/esm/index.d.ts +8 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +11 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/label/index.d.ts.map +1 -1
- package/dist/esm/label/index.js +4 -1
- package/dist/esm/label/index.js.map +1 -1
- package/dist/esm/line/index.d.ts.map +1 -1
- package/dist/esm/line/index.js +8 -2
- package/dist/esm/line/index.js.map +1 -1
- package/dist/esm/math/index.d.ts.map +1 -1
- package/dist/esm/math/index.js +3 -0
- package/dist/esm/math/index.js.map +1 -1
- package/dist/esm/polyline/index.d.ts.map +1 -1
- package/dist/esm/polyline/index.js +5 -1
- package/dist/esm/polyline/index.js.map +1 -1
- package/dist/esm/runtime/index.d.ts +2 -1
- package/dist/esm/runtime/index.d.ts.map +1 -1
- package/dist/esm/runtime/index.js +1 -0
- package/dist/esm/runtime/index.js.map +1 -1
- package/dist/esm/runtime/input-active.d.ts +27 -0
- package/dist/esm/runtime/input-active.d.ts.map +1 -0
- package/dist/esm/runtime/input-active.js +54 -0
- package/dist/esm/runtime/input-active.js.map +1 -0
- package/dist/esm/runtime/types.d.ts +29 -2
- package/dist/esm/runtime/types.d.ts.map +1 -1
- package/dist/esm/script/index.d.ts +53 -17
- package/dist/esm/script/index.d.ts.map +1 -1
- package/dist/esm/script/index.js +80 -13
- package/dist/esm/script/index.js.map +1 -1
- package/dist/esm/session/bars.d.ts +15 -1
- package/dist/esm/session/bars.d.ts.map +1 -1
- package/dist/esm/session/bars.js +50 -6
- package/dist/esm/session/bars.js.map +1 -1
- package/dist/esm/session/calendar.d.ts +9 -1
- package/dist/esm/session/calendar.d.ts.map +1 -1
- package/dist/esm/session/calendar.js +35 -3
- package/dist/esm/session/calendar.js.map +1 -1
- package/dist/esm/session/context.d.ts +75 -0
- package/dist/esm/session/context.d.ts.map +1 -0
- package/dist/esm/session/context.js +122 -0
- package/dist/esm/session/context.js.map +1 -0
- package/dist/esm/str/index.d.ts +12 -4
- package/dist/esm/str/index.d.ts.map +1 -1
- package/dist/esm/str/index.js +33 -12
- package/dist/esm/str/index.js.map +1 -1
- package/dist/esm/str/numberformat.d.ts +10 -2
- package/dist/esm/str/numberformat.d.ts.map +1 -1
- package/dist/esm/str/numberformat.js +16 -2
- package/dist/esm/str/numberformat.js.map +1 -1
- package/dist/esm/ta/index.d.ts +33 -17
- package/dist/esm/ta/index.d.ts.map +1 -1
- package/dist/esm/ta/index.js +130 -56
- package/dist/esm/ta/index.js.map +1 -1
- package/dist/esm/ta/limits.d.ts +24 -0
- package/dist/esm/ta/limits.d.ts.map +1 -0
- package/dist/esm/ta/limits.js +42 -0
- package/dist/esm/ta/limits.js.map +1 -0
- package/dist/esm/ta/running-sum.d.ts +0 -16
- package/dist/esm/ta/running-sum.d.ts.map +1 -1
- package/dist/esm/ta/running-sum.js +2 -0
- package/dist/esm/ta/running-sum.js.map +1 -1
- package/dist/esm/ta-series.d.ts +7 -7
- package/dist/esm/ta-series.d.ts.map +1 -1
- package/dist/esm/ta-series.js +9 -7
- package/dist/esm/ta-series.js.map +1 -1
- package/dist/esm/time/index.d.ts +5 -2
- package/dist/esm/time/index.d.ts.map +1 -1
- package/dist/esm/time/index.js +6 -3
- package/dist/esm/time/index.js.map +1 -1
- package/dist/esm/time/session.d.ts +17 -1
- package/dist/esm/time/session.d.ts.map +1 -1
- package/dist/esm/time/session.js +97 -10
- package/dist/esm/time/session.js.map +1 -1
- package/dist/esm/types/metadata.d.ts +27 -3
- package/dist/esm/types/metadata.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/box/index.ts +8 -2
- package/src/callsite/index.ts +150 -100
- package/src/drawing/registry.ts +255 -5
- package/src/index.ts +36 -1
- package/src/label/index.ts +4 -1
- package/src/line/index.ts +8 -2
- package/src/math/index.ts +2 -0
- package/src/polyline/index.ts +3 -1
- package/src/runtime/index.ts +3 -0
- package/src/runtime/input-active.ts +50 -0
- package/src/runtime/types.ts +25 -2
- package/src/script/index.ts +123 -23
- package/src/session/bars.ts +47 -6
- package/src/session/calendar.ts +37 -3
- package/src/session/context.ts +160 -0
- package/src/str/index.ts +30 -12
- package/src/str/numberformat.ts +18 -3
- package/src/ta/index.ts +148 -66
- package/src/ta/limits.ts +47 -0
- package/src/ta/running-sum.ts +2 -0
- package/src/ta-series.ts +16 -14
- package/src/time/index.ts +6 -3
- package/src/time/session.ts +89 -9
- package/src/types/metadata.ts +27 -3
package/src/drawing/registry.ts
CHANGED
|
@@ -8,6 +8,41 @@
|
|
|
8
8
|
* - when a creation brings the count above `max_*_count + 5`, the oldest objects are deleted until
|
|
9
9
|
* `max_*_count` remain (default 50). Copies count as creations. Linefills follow the same rule with
|
|
10
10
|
* `max_lines_count`; lines deleted by this rule do not delete their linefills
|
|
11
|
+
* - the object that was just created is never deleted by this rule
|
|
12
|
+
* - an object that a `var` variable of the drawing type refers to is never deleted by this rule, and it still counts
|
|
13
|
+
* (measured for lines, labels and boxes: with 9 held boxes and a maximum of 50, 9 held + 46 others stay; with 8
|
|
14
|
+
* held lines and a maximum of 5, the 8 and the newest line stay). The protection starts on the bar after the
|
|
15
|
+
* assignment: 12 `var` lines created on the first bar with a maximum of 5 lose the first 6. Only
|
|
16
|
+
* the variable itself protects: an object in a `var` array, in a field of a user type or in a variable that got
|
|
17
|
+
* another object or `na` later is deleted like any other. JavaScript has no `var` declaration to observe, so the
|
|
18
|
+
* script says it: {@link varDrawing} (a variable), or {@link holdDrawing} / {@link releaseDrawing}
|
|
19
|
+
* - linefills have the limit of `max_lines_count` with another rule for the held ones (measured on one script, two
|
|
20
|
+
* long runs): a fill is skipped when a `var` variable holds it or released it less than 5,000 bars ago (the bar
|
|
21
|
+
* of {@link setDrawingBar}); when the count is still above the maximum + 5 after that, the oldest fills are
|
|
22
|
+
* deleted until the maximum remain, the held ones too
|
|
23
|
+
* - the script deletes count (`line.delete`, `label.delete`, ...): each kind has a number `P` of deleted objects. A
|
|
24
|
+
* delete adds 1; a creation first sets `P` to 0 when it is 5 or more (3 or more for polylines)
|
|
25
|
+
* - polylines use `P` on every bar: a creation cuts when the count is above `max_polylines_count + 5 + P`, down to
|
|
26
|
+
* the maximum + `P`, and the polylines of the cut are added to `P`. A script that deletes and creates one polyline
|
|
27
|
+
* per bar therefore sees the cut 0, 1 or 2 bars late
|
|
28
|
+
* - lines, labels and boxes use `P` on the last bar only, with its value at the start of that bar: there the cut is
|
|
29
|
+
* above the maximum + 5 + `P`, down to the maximum + `P` (up to 4 more objects)
|
|
30
|
+
* - the last bar has rules of its own (measured from the count after each creation, on a closed and on an open last
|
|
31
|
+
* bar): a cut deletes the objects of the bars before first, at most those (a line takes its linefills with it);
|
|
32
|
+
* once none is left, a cut deletes objects of the last bar as on any bar. With 10 lines and a maximum of 10, 13
|
|
33
|
+
* lines on the last bar leave these 13: the cut at the 16th line deletes the 10 old ones only. Lines, labels and
|
|
34
|
+
* boxes: equal to PineScript, count after every operation and objects alive at the end, on 72 of 72 runs checked
|
|
35
|
+
* after the rule was written (and 218 of 218 end states before)
|
|
36
|
+
* - polylines on the last bar: the `P` carried from the bar before is counted twice (the first creation adds it once
|
|
37
|
+
* more, unless it sets `P` to 0), later creations do not set `P` to 0, and the polylines of the bars before that a
|
|
38
|
+
* cut deletes are added to `P`. Once none is
|
|
39
|
+
* left, a cut deletes polylines of the last bar and `P` becomes the number of polylines of the bars before deleted
|
|
40
|
+
* on the last bar (by the count or by the script). Equal to PineScript for the polylines alive at the end on 271 of
|
|
41
|
+
* 281 probe runs; the count inside the bar can differ when the script deletes polylines of the last bar
|
|
42
|
+
*
|
|
43
|
+
* - a bar index (`xloc.bar_index`) more than 10,000 bars before the current bar stops the script (runtime error
|
|
44
|
+
* RE10026) in `line.new`, `box.new`, `label.new`, `polyline.new` and the setters of x. The current bar is the one
|
|
45
|
+
* of `eachBar` in a script run; a port with its own bar loop gives it with {@link setDrawingBar}
|
|
11
46
|
*
|
|
12
47
|
* The script API (`executeScript`) resets the registry at the start of every run and applies the
|
|
13
48
|
* `max_*_count` values of `indicator()`. Outside a script run the registry is global to the module.
|
|
@@ -50,6 +85,150 @@ let limits: Required<DrawingLimits> = {
|
|
|
50
85
|
polyline: DEFAULT_MAX_COUNT,
|
|
51
86
|
};
|
|
52
87
|
const deleted = new WeakSet<object>();
|
|
88
|
+
/** Objects held by a `var` variable, with the number of variables that hold them. */
|
|
89
|
+
let held = new WeakMap<object, number>();
|
|
90
|
+
/** Bar on which the last `var` variable released an object (linefill rule). */
|
|
91
|
+
let releasedAt = new WeakMap<object, number>();
|
|
92
|
+
/** Bars during which a released linefill is still skipped by the maximum count. */
|
|
93
|
+
const LINEFILL_RELEASE_BARS = 5000;
|
|
94
|
+
/** Bar on which a `var` variable got an object: the maximum count skips it from the next bar on. */
|
|
95
|
+
let heldAt = new WeakMap<object, number>();
|
|
96
|
+
/** Kinds with a maximum count of their own. */
|
|
97
|
+
type CountedKind = 'line' | 'label' | 'box' | 'polyline';
|
|
98
|
+
const COUNTED_KINDS: readonly CountedKind[] = ['line', 'label', 'box', 'polyline'];
|
|
99
|
+
const isCounted = (kind: DrawingKind): kind is CountedKind => (COUNTED_KINDS as readonly DrawingKind[]).includes(kind);
|
|
100
|
+
/** `P` of the module notes: objects deleted by the script (for polylines also by the maximum count). */
|
|
101
|
+
let pending: Record<CountedKind, number> = { line: 0, label: 0, box: 0, polyline: 0 };
|
|
102
|
+
/** A creation sets `P` to 0 from this value on. */
|
|
103
|
+
const PENDING_RESET: Record<CountedKind, number> = { line: 5, label: 5, box: 5, polyline: 3 };
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Marks an object as held by a `var` variable (PineScript `var line l = ...` or `l := line.new(...)` on a `var`
|
|
107
|
+
* variable): the maximum count never deletes it, and it still counts. Returns the object.
|
|
108
|
+
*/
|
|
109
|
+
export function holdDrawing<T extends object>(obj: T): T {
|
|
110
|
+
if (!held.has(obj)) {
|
|
111
|
+
if (currentBar === null) heldAt.delete(obj);
|
|
112
|
+
else heldAt.set(obj, currentBar);
|
|
113
|
+
}
|
|
114
|
+
held.set(obj, (held.get(obj) ?? 0) + 1);
|
|
115
|
+
return obj;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** The `var` variable no longer refers to the object (it got another object or `na`). */
|
|
119
|
+
export function releaseDrawing(obj: object | null | undefined): void {
|
|
120
|
+
if (!obj) return;
|
|
121
|
+
const count = held.get(obj) ?? 0;
|
|
122
|
+
if (count > 1) held.set(obj, count - 1);
|
|
123
|
+
else if (held.delete(obj) && currentBar !== null) releasedAt.set(obj, currentBar);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Held by a `var` variable since a bar before the current one (or outside a bar loop). */
|
|
127
|
+
function heldBefore(obj: object): boolean {
|
|
128
|
+
if (!held.has(obj)) return false;
|
|
129
|
+
const bar = heldAt.get(obj);
|
|
130
|
+
return bar === undefined || currentBar === null || bar < currentBar;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Linefill rule: held, or released less than 5,000 bars ago. */
|
|
134
|
+
function fillProtected(obj: object): boolean {
|
|
135
|
+
if (held.has(obj)) return true;
|
|
136
|
+
const bar = releasedAt.get(obj);
|
|
137
|
+
return bar !== undefined && currentBar !== null && currentBar - bar < LINEFILL_RELEASE_BARS;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** A `var` variable of a drawing type: see {@link varDrawing}. */
|
|
141
|
+
export interface DrawingVariable<T extends object> {
|
|
142
|
+
/** The object of the variable; setting it holds the new object and releases the one before */
|
|
143
|
+
value: T | undefined;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* A PineScript `var` variable of a drawing type (`var line l = na`). The object it refers to is not deleted by the
|
|
148
|
+
* maximum count; assigning another object (or `undefined` for `na`) releases the one before.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```typescript
|
|
152
|
+
* // Pine: var line level = na
|
|
153
|
+
* // level := line.new(bar_index, close, bar_index + 1, close)
|
|
154
|
+
* const level = varDrawing<Line>();
|
|
155
|
+
* level.value = line.new(i, close, i + 1, close);
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
export function varDrawing<T extends object>(initial?: T): DrawingVariable<T> {
|
|
159
|
+
let current: T | undefined = initial ? holdDrawing(initial) : undefined;
|
|
160
|
+
return {
|
|
161
|
+
get value() {
|
|
162
|
+
return current;
|
|
163
|
+
},
|
|
164
|
+
set value(next: T | undefined) {
|
|
165
|
+
if (next === current) return;
|
|
166
|
+
releaseDrawing(current);
|
|
167
|
+
current = next ? holdDrawing(next) : undefined;
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** Largest distance, in bars, of a bar index before the current bar (PineScript runtime error RE10026 above it). */
|
|
173
|
+
export const MAX_DRAWING_BARS_BACK = 10000;
|
|
174
|
+
let currentBar: number | null = null;
|
|
175
|
+
|
|
176
|
+
/** Kinds whose allowance on the last bar is the `P` they had when the bar started. */
|
|
177
|
+
type AllowanceKind = 'line' | 'label' | 'box';
|
|
178
|
+
const isAllowanceKind = (kind: DrawingKind): kind is AllowanceKind => kind === 'line' || kind === 'label' || kind === 'box';
|
|
179
|
+
|
|
180
|
+
/** State of the last bar (see the module notes). */
|
|
181
|
+
interface LastBar {
|
|
182
|
+
bar: number;
|
|
183
|
+
/** The objects alive when the bar started (the objects of the bars before) */
|
|
184
|
+
old: Set<object>;
|
|
185
|
+
/** `P` of lines, labels and boxes when the bar started: their allowance for the whole bar */
|
|
186
|
+
allowance: Record<AllowanceKind, number>;
|
|
187
|
+
/** `P` of polylines when the bar started */
|
|
188
|
+
carried: number;
|
|
189
|
+
/** A polyline was created on this bar */
|
|
190
|
+
polyline: boolean;
|
|
191
|
+
/** Polylines of the bars before deleted on this bar (by the count or by the script) */
|
|
192
|
+
oldPolylinesGone: number;
|
|
193
|
+
}
|
|
194
|
+
let lastBar: LastBar | null = null;
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Tells the drawing functions which bar is being calculated (`bar_index`), so that a bar index more than 10,000
|
|
198
|
+
* bars back throws as in PineScript; `null` turns the check off. `eachBar` of the script API calls it.
|
|
199
|
+
*
|
|
200
|
+
* The bar also dates the objects held by a `var` variable (protected from the next bar on). `last` says that it is
|
|
201
|
+
* the last bar of the data, which has rules of its own for the maximum count.
|
|
202
|
+
*/
|
|
203
|
+
export function setDrawingBar(barIndex: number | null, last: boolean = false): void {
|
|
204
|
+
if (lastBar && !(last && barIndex === lastBar.bar)) lastBar = null;
|
|
205
|
+
currentBar = barIndex;
|
|
206
|
+
if (barIndex !== null && last && !lastBar) {
|
|
207
|
+
const start = (kind: AllowanceKind): number => (pending[kind] >= PENDING_RESET[kind] ? 0 : pending[kind]);
|
|
208
|
+
lastBar = {
|
|
209
|
+
bar: barIndex,
|
|
210
|
+
old: new Set<object>([...live.line, ...live.label, ...live.box, ...live.polyline]),
|
|
211
|
+
allowance: { line: start('line'), label: start('label'), box: start('box') },
|
|
212
|
+
carried: pending.polyline,
|
|
213
|
+
polyline: false,
|
|
214
|
+
oldPolylinesGone: 0,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Throws the PineScript runtime error RE10026 when `x` is a bar index more than 10,000 bars before the current bar.
|
|
221
|
+
* `method` and `variable` are the names of the PineScript message ("line.new", "x1").
|
|
222
|
+
*/
|
|
223
|
+
export function checkBarIndex(method: string, variable: string, x: number, xloc: string | undefined): void {
|
|
224
|
+
if (currentBar === null || (xloc ?? 'bar_index') !== 'bar_index') return;
|
|
225
|
+
if (currentBar - x > MAX_DRAWING_BARS_BACK) {
|
|
226
|
+
throw new Error(
|
|
227
|
+
`Error on bar ${currentBar}: Bar index value of the \`${variable}\` argument (${x}) in \`${method}()\` is too far ` +
|
|
228
|
+
'from the current bar index. Try using `time` instead.'
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
53
232
|
|
|
54
233
|
/** Numeric fields that become NaN when an object is deleted, so that its getters return `na`. */
|
|
55
234
|
const COORDINATES: { [K in DrawingKind]: Array<keyof DrawingTypes[K]> } = {
|
|
@@ -69,14 +248,75 @@ function markDeleted<K extends DrawingKind>(kind: K, obj: DrawingTypes[K], expli
|
|
|
69
248
|
}
|
|
70
249
|
}
|
|
71
250
|
|
|
251
|
+
/** Objects above the maximum that the rule allows for, besides the 5: `P` of the module notes. */
|
|
252
|
+
function allowance(kind: DrawingKind): number {
|
|
253
|
+
if (kind === 'polyline') return pending.polyline;
|
|
254
|
+
return lastBar && isAllowanceKind(kind) ? lastBar.allowance[kind] : 0;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* The maximum count after the creation of `obj`: removes the objects to delete from `list` (the oldest first; the new
|
|
259
|
+
* object and an object held by a `var` variable are skipped and still count) and returns them.
|
|
260
|
+
*/
|
|
261
|
+
function cutOldest<K extends DrawingKind>(
|
|
262
|
+
kind: K,
|
|
263
|
+
list: Array<DrawingTypes[K]>,
|
|
264
|
+
obj: DrawingTypes[K],
|
|
265
|
+
only?: (old: object) => boolean
|
|
266
|
+
): Array<DrawingTypes[K]> {
|
|
267
|
+
if (kind === 'table') return []; // tables have no maximum count
|
|
268
|
+
const max = limits[kind === 'linefill' ? 'line' : (kind as keyof DrawingLimits)] + allowance(kind);
|
|
269
|
+
if (list.length <= max + SLACK) return [];
|
|
270
|
+
const kept: Array<DrawingTypes[K]> = [];
|
|
271
|
+
const cut: Array<DrawingTypes[K]> = [];
|
|
272
|
+
let excess = list.length - max;
|
|
273
|
+
for (const old of list) {
|
|
274
|
+
if (excess > 0 && old !== obj && (!only || only(old)) && !(kind === 'linefill' ? fillProtected(old) : heldBefore(old))) {
|
|
275
|
+
excess--;
|
|
276
|
+
cut.push(old);
|
|
277
|
+
} else kept.push(old);
|
|
278
|
+
}
|
|
279
|
+
// linefills: still above the maximum + 5, the oldest go, the held ones too
|
|
280
|
+
if (kind === 'linefill' && kept.length > max + SLACK) cut.push(...kept.splice(0, kept.length - max));
|
|
281
|
+
list.length = 0;
|
|
282
|
+
list.push(...kept);
|
|
283
|
+
return cut;
|
|
284
|
+
}
|
|
285
|
+
|
|
72
286
|
/** Records a new object and deletes the oldest objects of its kind when the count is too high. */
|
|
73
287
|
export function register<K extends DrawingKind>(kind: K, obj: DrawingTypes[K]): DrawingTypes[K] {
|
|
288
|
+
const list = live[kind];
|
|
289
|
+
if (lastBar && isCounted(kind)) return registerLast(lastBar, kind, obj);
|
|
290
|
+
if (isCounted(kind) && pending[kind] >= PENDING_RESET[kind]) pending[kind] = 0;
|
|
291
|
+
list.push(obj);
|
|
292
|
+
const cut = cutOldest(kind, list, obj);
|
|
293
|
+
if (kind === 'polyline') pending.polyline += cut.length;
|
|
294
|
+
for (const old of cut) markDeleted(kind, old, false);
|
|
295
|
+
return obj;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** An object created on the last bar (see the module notes). */
|
|
299
|
+
function registerLast<K extends DrawingKind>(bar: LastBar, kind: K, obj: DrawingTypes[K]): DrawingTypes[K] {
|
|
300
|
+
if (kind === 'polyline' && !bar.polyline) {
|
|
301
|
+
bar.polyline = true;
|
|
302
|
+
if (pending.polyline >= PENDING_RESET.polyline) pending.polyline = 0;
|
|
303
|
+
else pending.polyline += bar.carried; // counted twice
|
|
304
|
+
}
|
|
74
305
|
const list = live[kind];
|
|
75
306
|
list.push(obj);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
307
|
+
const isOld = (old: object): boolean => bar.old.has(old);
|
|
308
|
+
if (list.some((old) => old !== obj && isOld(old) && !heldBefore(old))) {
|
|
309
|
+
// the objects of the bars before only; a line takes its linefills with it
|
|
310
|
+
const cut = cutOldest(kind, list, obj, isOld);
|
|
311
|
+
if (kind === 'polyline') {
|
|
312
|
+
pending.polyline += cut.length;
|
|
313
|
+
bar.oldPolylinesGone += cut.length;
|
|
314
|
+
}
|
|
315
|
+
for (const old of cut) markDeleted(kind, old, true);
|
|
316
|
+
} else {
|
|
317
|
+
const cut = cutOldest(kind, list, obj);
|
|
318
|
+
if (kind === 'polyline' && cut.length > 0) pending.polyline = bar.oldPolylinesGone;
|
|
319
|
+
for (const old of cut) markDeleted(kind, old, false);
|
|
80
320
|
}
|
|
81
321
|
return obj;
|
|
82
322
|
}
|
|
@@ -85,7 +325,11 @@ export function register<K extends DrawingKind>(kind: K, obj: DrawingTypes[K]):
|
|
|
85
325
|
export function remove<K extends DrawingKind>(kind: K, obj: DrawingTypes[K]): void {
|
|
86
326
|
const list = live[kind];
|
|
87
327
|
const index = list.indexOf(obj);
|
|
88
|
-
if (index !== -1)
|
|
328
|
+
if (index !== -1) {
|
|
329
|
+
list.splice(index, 1);
|
|
330
|
+
if (isCounted(kind)) pending[kind]++;
|
|
331
|
+
if (kind === 'polyline' && lastBar?.old.has(obj)) lastBar.oldPolylinesGone++;
|
|
332
|
+
}
|
|
89
333
|
if (!deleted.has(obj)) markDeleted(kind, obj, true);
|
|
90
334
|
}
|
|
91
335
|
|
|
@@ -102,6 +346,12 @@ export function all<K extends DrawingKind>(kind: K): Array<DrawingTypes[K]> {
|
|
|
102
346
|
/** Forgets all objects (without deleting them) and sets the maximum counts (default 50). */
|
|
103
347
|
export function resetDrawings(newLimits: DrawingLimits = {}): void {
|
|
104
348
|
for (const kind of Object.keys(live) as DrawingKind[]) live[kind].length = 0;
|
|
349
|
+
held = new WeakMap();
|
|
350
|
+
releasedAt = new WeakMap();
|
|
351
|
+
heldAt = new WeakMap();
|
|
352
|
+
pending = { line: 0, label: 0, box: 0, polyline: 0 };
|
|
353
|
+
currentBar = null;
|
|
354
|
+
lastBar = null;
|
|
105
355
|
limits = {
|
|
106
356
|
line: newLimits.line ?? DEFAULT_MAX_COUNT,
|
|
107
357
|
label: newLimits.label ?? DEFAULT_MAX_COUNT,
|
package/src/index.ts
CHANGED
|
@@ -43,6 +43,39 @@ export { taCore, math, array, map, str, color, time, timeframe, matrix, line, bo
|
|
|
43
43
|
export { drawingOutputs, type DrawingOutputs } from './drawing/output.js';
|
|
44
44
|
export { barInterval, barTime } from './drawing/bar-time.js';
|
|
45
45
|
|
|
46
|
+
// Drawing registry limits (PineScript indicator(max_lines_count / max_labels_count / max_boxes_count / max_polylines_count))
|
|
47
|
+
export {
|
|
48
|
+
resetDrawings,
|
|
49
|
+
setDrawingLimits,
|
|
50
|
+
setDrawingBar,
|
|
51
|
+
holdDrawing,
|
|
52
|
+
releaseDrawing,
|
|
53
|
+
varDrawing,
|
|
54
|
+
type DrawingLimits,
|
|
55
|
+
type DrawingVariable,
|
|
56
|
+
} from './drawing/registry.js';
|
|
57
|
+
|
|
58
|
+
// The session of a chart context without a script run: time(tf), time_close(tf), time_tradingday, session.* flags,
|
|
59
|
+
// request.security periods with the session and holidays, and bars after the last bar on the trading calendar
|
|
60
|
+
export {
|
|
61
|
+
chartSessions,
|
|
62
|
+
periodTime,
|
|
63
|
+
periodClose,
|
|
64
|
+
tradingDayTime,
|
|
65
|
+
chartSessionFlags,
|
|
66
|
+
resampleSession,
|
|
67
|
+
barTimeAfter,
|
|
68
|
+
barsUntil,
|
|
69
|
+
type SessionContext,
|
|
70
|
+
type ChartSessions,
|
|
71
|
+
type SessionResample,
|
|
72
|
+
} from './session/context.js';
|
|
73
|
+
export { TradingCalendar, type SessionSpec } from './session/calendar.js';
|
|
74
|
+
export { SessionBars, sessionFlags, type SessionFlags } from './session/bars.js';
|
|
75
|
+
|
|
76
|
+
// Same-symbol request.security on a higher timeframe (completion and lookahead rules) and ticker.heikinashi
|
|
77
|
+
export { resample, periodsOf, afterCompletion, mapToChart, heikinAshi, type Resampled } from './security/resample.js';
|
|
78
|
+
|
|
46
79
|
// Export Series class (self-contained, no context)
|
|
47
80
|
export { Series, BarData } from './runtime/series.js';
|
|
48
81
|
export type { SeriesExtractor } from './runtime/series.js';
|
|
@@ -139,6 +172,7 @@ export {
|
|
|
139
172
|
input_session,
|
|
140
173
|
input_time,
|
|
141
174
|
} from './runtime/inputs.js';
|
|
175
|
+
export { isInputActive } from './runtime/input-active.js';
|
|
142
176
|
|
|
143
177
|
export type {
|
|
144
178
|
OakScriptContext,
|
|
@@ -147,6 +181,7 @@ export type {
|
|
|
147
181
|
SeriesHandle,
|
|
148
182
|
SeriesOptions,
|
|
149
183
|
InputConfig,
|
|
184
|
+
InputCondition,
|
|
150
185
|
InputOptions,
|
|
151
186
|
OhlcvData,
|
|
152
187
|
PlotConfig,
|
|
@@ -170,7 +205,7 @@ export type { LightweightSeriesDefinitions } from './runtime/adapters/Lightweigh
|
|
|
170
205
|
export { SimpleInputAdapter } from './runtime/adapters/SimpleInputAdapter.js';
|
|
171
206
|
|
|
172
207
|
// Version
|
|
173
|
-
export const VERSION = '0.
|
|
208
|
+
export const VERSION = '0.11.0';
|
|
174
209
|
|
|
175
210
|
/**
|
|
176
211
|
* Library information
|
package/src/label/index.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* @version 6
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { all as allDrawings, isDeleted, register, remove } from '../drawing/registry.js';
|
|
13
|
+
import { all as allDrawings, checkBarIndex, isDeleted, register, remove } from '../drawing/registry.js';
|
|
14
14
|
import type { ChartPoint, Label, color } from '../types/index.js';
|
|
15
15
|
|
|
16
16
|
type LabelXloc = 'bar_index' | 'bar_time';
|
|
@@ -80,6 +80,7 @@ export function new_label(...args: unknown[]): Label {
|
|
|
80
80
|
string?, LabelXloc?, LabelYloc?, color?, LabelStyle?, color?, (string | number)?,
|
|
81
81
|
('left' | 'center' | 'right')?, string?, ('default' | 'monospace')?, boolean?, number?,
|
|
82
82
|
];
|
|
83
|
+
checkBarIndex('label.new', 'x', x, xloc);
|
|
83
84
|
return register('label', {
|
|
84
85
|
x,
|
|
85
86
|
y,
|
|
@@ -188,6 +189,7 @@ export function copy(id: Label): Label {
|
|
|
188
189
|
*/
|
|
189
190
|
export function set_x(id: Label, x: number): Label {
|
|
190
191
|
if (isDeleted(id)) return id;
|
|
192
|
+
checkBarIndex('label.set_x', 'x', x, id.xloc);
|
|
191
193
|
id.x = x;
|
|
192
194
|
return id;
|
|
193
195
|
}
|
|
@@ -227,6 +229,7 @@ export function set_y(id: Label, y: number): Label {
|
|
|
227
229
|
*/
|
|
228
230
|
export function set_xy(id: Label, x: number, y: number): Label {
|
|
229
231
|
if (isDeleted(id)) return id;
|
|
232
|
+
checkBarIndex('label.set_x', 'x', x, id.xloc);
|
|
230
233
|
id.x = x;
|
|
231
234
|
id.y = y;
|
|
232
235
|
return id;
|
package/src/line/index.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* @version 6
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { all as allDrawings, isDeleted, register, remove } from '../drawing/registry.js';
|
|
13
|
+
import { all as allDrawings, checkBarIndex, isDeleted, register, remove } from '../drawing/registry.js';
|
|
14
14
|
import type { ChartPoint, Line, color } from '../types/index.js';
|
|
15
15
|
|
|
16
16
|
type LineXloc = 'bar_index' | 'bar_time';
|
|
@@ -70,6 +70,8 @@ export function new_line(...args: unknown[]): Line {
|
|
|
70
70
|
const [xloc, extend, lineColor, style, width, force_overlay] = rest as [
|
|
71
71
|
LineXloc?, LineExtend?, color?, LineStyle?, number?, boolean?,
|
|
72
72
|
];
|
|
73
|
+
checkBarIndex('line.new', 'x1', x1, xloc);
|
|
74
|
+
checkBarIndex('line.new', 'x2', x2, xloc);
|
|
73
75
|
return register('line', {
|
|
74
76
|
x1,
|
|
75
77
|
y1,
|
|
@@ -79,7 +81,7 @@ export function new_line(...args: unknown[]): Line {
|
|
|
79
81
|
extend: extend ?? 'none',
|
|
80
82
|
color: lineColor,
|
|
81
83
|
style: style || 'solid',
|
|
82
|
-
width: width
|
|
84
|
+
width: width ?? 1,
|
|
83
85
|
force_overlay: force_overlay ?? false,
|
|
84
86
|
});
|
|
85
87
|
}
|
|
@@ -265,6 +267,7 @@ export function copy(id: Line): Line {
|
|
|
265
267
|
*/
|
|
266
268
|
export function set_x1(id: Line, x: number): Line {
|
|
267
269
|
if (isDeleted(id)) return id;
|
|
270
|
+
checkBarIndex('line.set_x***', 'x1', x, id.xloc);
|
|
268
271
|
id.x1 = x;
|
|
269
272
|
return id;
|
|
270
273
|
}
|
|
@@ -284,6 +287,7 @@ export function set_x1(id: Line, x: number): Line {
|
|
|
284
287
|
*/
|
|
285
288
|
export function set_x2(id: Line, x: number): Line {
|
|
286
289
|
if (isDeleted(id)) return id;
|
|
290
|
+
checkBarIndex('line.set_x***', 'x2', x, id.xloc);
|
|
287
291
|
id.x2 = x;
|
|
288
292
|
return id;
|
|
289
293
|
}
|
|
@@ -342,6 +346,7 @@ export function set_y2(id: Line, y: number): Line {
|
|
|
342
346
|
*/
|
|
343
347
|
export function set_xy1(id: Line, x: number, y: number): Line {
|
|
344
348
|
if (isDeleted(id)) return id;
|
|
349
|
+
checkBarIndex('line.set_x***', 'x1', x, id.xloc);
|
|
345
350
|
id.x1 = x;
|
|
346
351
|
id.y1 = y;
|
|
347
352
|
return id;
|
|
@@ -363,6 +368,7 @@ export function set_xy1(id: Line, x: number, y: number): Line {
|
|
|
363
368
|
*/
|
|
364
369
|
export function set_xy2(id: Line, x: number, y: number): Line {
|
|
365
370
|
if (isDeleted(id)) return id;
|
|
371
|
+
checkBarIndex('line.set_x***', 'x2', x, id.xloc);
|
|
366
372
|
id.x2 = x;
|
|
367
373
|
id.y2 = y;
|
|
368
374
|
return id;
|
package/src/math/index.ts
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
import type { float, int, simple_int, series_float } from '../types/index.js';
|
|
20
20
|
import { Series } from '../runtime/series.js';
|
|
21
21
|
import { runningSum, runningSumSeries } from '../ta/running-sum.js';
|
|
22
|
+
import { checkSumLength } from '../ta/limits.js';
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Returns the absolute value of a number.
|
|
@@ -489,6 +490,7 @@ export function sum(
|
|
|
489
490
|
): series_float | Series {
|
|
490
491
|
// Handle Series objects - extract to array first
|
|
491
492
|
const sourceArray = source instanceof Series ? source.toArray() : source;
|
|
493
|
+
if (typeof length === 'number') checkSumLength('math.sum', length, 0);
|
|
492
494
|
// PineScript: the sum of the last `length` non-na values (also +/-Infinity skipped); an na bar keeps the previous
|
|
493
495
|
// result. A compensated running sum, bit for bit as PineScript.
|
|
494
496
|
const result: series_float =
|
package/src/polyline/index.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import type { ChartPoint, Polyline, color } from '../types/index.js';
|
|
14
|
-
import { all as allDrawings, register, remove } from '../drawing/registry.js';
|
|
14
|
+
import { all as allDrawings, checkBarIndex, register, remove } from '../drawing/registry.js';
|
|
15
15
|
|
|
16
16
|
// Re-export the Polyline type for convenience
|
|
17
17
|
export type { Polyline };
|
|
@@ -86,6 +86,8 @@ export function new_polyline(
|
|
|
86
86
|
line_width = 1;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
if (xloc === 'bar_index') for (const point of points) if (point.index !== null) checkBarIndex('polyline.new', 'points', point.index, xloc);
|
|
90
|
+
|
|
89
91
|
const polyline: Polyline = {
|
|
90
92
|
id: generateId(),
|
|
91
93
|
points: [...points], // Create a copy of the points array
|
package/src/runtime/index.ts
CHANGED
|
@@ -41,11 +41,14 @@ export type {
|
|
|
41
41
|
SeriesHandle,
|
|
42
42
|
SeriesOptions,
|
|
43
43
|
InputConfig,
|
|
44
|
+
InputCondition,
|
|
44
45
|
InputOptions,
|
|
45
46
|
OhlcvData,
|
|
46
47
|
PlotConfig,
|
|
47
48
|
} from './types.js';
|
|
48
49
|
|
|
50
|
+
export { isInputActive } from './input-active.js';
|
|
51
|
+
|
|
49
52
|
// Adapter exports
|
|
50
53
|
export { LightweightChartsAdapter } from './adapters/LightweightChartsAdapter.js';
|
|
51
54
|
export type { LightweightSeriesDefinitions } from './adapters/LightweightChartsAdapter.js';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview PineScript `active` of an input: whether the settings dialog lets the user edit it
|
|
3
|
+
* @module runtime/input-active
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { InputConfig, InputCondition } from './types.js';
|
|
7
|
+
|
|
8
|
+
/** Current value of an input: the host value, else the default of its config. */
|
|
9
|
+
function inputValue(id: string, inputs: Record<string, unknown>, configs?: readonly InputConfig[]): unknown {
|
|
10
|
+
const value = inputs[id];
|
|
11
|
+
if (value !== undefined) return value;
|
|
12
|
+
return configs?.find((c) => c.id === id)?.defval;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function holds(condition: InputCondition, inputs: Record<string, unknown>, configs?: readonly InputConfig[]): boolean {
|
|
16
|
+
if (typeof condition === 'string') return inputValue(condition, inputs, configs) === true;
|
|
17
|
+
if ('not' in condition) return !holds(condition.not, inputs, configs);
|
|
18
|
+
if ('any' in condition) return condition.any.some((c) => holds(c, inputs, configs));
|
|
19
|
+
if ('all' in condition) return condition.all.every((c) => holds(c, inputs, configs));
|
|
20
|
+
const value = inputValue(condition.input, inputs, configs);
|
|
21
|
+
if (!('eq' in condition) && !('ne' in condition)) return value === true;
|
|
22
|
+
return (!('eq' in condition) || value === condition.eq) && (!('ne' in condition) || value !== condition.ne);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Whether an input is active (PineScript `active`): an inactive input is shown greyed out in the settings and
|
|
27
|
+
* cannot be edited. It still gives its value to the script.
|
|
28
|
+
*
|
|
29
|
+
* @param config - The input
|
|
30
|
+
* @param inputs - Current input values by id
|
|
31
|
+
* @param configs - All the inputs of the indicator: gives the default of an input that has no value in `inputs`
|
|
32
|
+
* @returns true when `config.active` is not set, is true, or is a condition that holds
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const configs: InputConfig[] = [
|
|
37
|
+
* { id: 'showMa1', type: 'bool', defval: true, title: 'MA #1' },
|
|
38
|
+
* { id: 'ma1Length', type: 'int', defval: 20, active: 'showMa1' },
|
|
39
|
+
* { id: 'bbMult', type: 'float', defval: 2, active: { input: 'maType', eq: 'SMA + Bollinger Bands' } },
|
|
40
|
+
* ];
|
|
41
|
+
* isInputActive(configs[1], { showMa1: false }) // false
|
|
42
|
+
* isInputActive(configs[1], {}, configs) // true: the default of showMa1
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function isInputActive(config: InputConfig, inputs: Record<string, unknown> = {}, configs?: readonly InputConfig[]): boolean {
|
|
46
|
+
const { active } = config;
|
|
47
|
+
if (active === undefined) return true;
|
|
48
|
+
if (typeof active === 'boolean') return active;
|
|
49
|
+
return holds(active, inputs, configs);
|
|
50
|
+
}
|
package/src/runtime/types.ts
CHANGED
|
@@ -46,6 +46,22 @@ export interface ChartAdapter {
|
|
|
46
46
|
createPane?(): number;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Condition on other inputs, as plain data (PineScript `active = <expression>`):
|
|
51
|
+
* - `'showMa'`: the bool input `showMa` is true
|
|
52
|
+
* - `{ input: 'maType', eq: 'SMA' }` / `{ input: 'maType', ne: 'None' }`: the value of an input is / is not a value
|
|
53
|
+
* (strict equality; without `eq` and `ne`: the input is true)
|
|
54
|
+
* - `{ not: c }`, `{ any: [c1, c2] }` (or), `{ all: [c1, c2] }` (and)
|
|
55
|
+
*
|
|
56
|
+
* Evaluated by `isInputActive()`.
|
|
57
|
+
*/
|
|
58
|
+
export type InputCondition =
|
|
59
|
+
| string
|
|
60
|
+
| { input: string; eq?: unknown; ne?: unknown }
|
|
61
|
+
| { not: InputCondition }
|
|
62
|
+
| { any: InputCondition[] }
|
|
63
|
+
| { all: InputCondition[] };
|
|
64
|
+
|
|
49
65
|
/**
|
|
50
66
|
* Configuration for registering an input
|
|
51
67
|
*/
|
|
@@ -78,10 +94,17 @@ export interface InputConfig {
|
|
|
78
94
|
/** Ask for the value when the script is added to a chart (PineScript `confirm`) */
|
|
79
95
|
confirm?: boolean;
|
|
80
96
|
/**
|
|
81
|
-
* Where the input value is shown (PineScript `display`); not set means the PineScript default: '
|
|
82
|
-
* color inputs
|
|
97
|
+
* Where the input value is shown (PineScript `display`); not set means the PineScript default: 'none' for
|
|
98
|
+
* bool, color and time inputs, 'all' for the others
|
|
83
99
|
*/
|
|
84
100
|
display?: 'all' | 'none' | 'data_window' | 'status_line';
|
|
101
|
+
/**
|
|
102
|
+
* Whether the input can be edited (PineScript `active`): an inactive input is shown greyed out in the settings.
|
|
103
|
+
* UI only: an inactive input still gives its value to the script. Not set means always active. A boolean is the
|
|
104
|
+
* value for the current inputs; an `InputCondition` names the inputs it depends on, so a host can apply it
|
|
105
|
+
* without running the script (see `isInputActive()`)
|
|
106
|
+
*/
|
|
107
|
+
active?: boolean | InputCondition;
|
|
85
108
|
}
|
|
86
109
|
|
|
87
110
|
/**
|