oakscriptjs 0.9.6 → 0.10.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/README.md +1 -1
- package/dist/cjs/array/index.d.ts +9 -23
- package/dist/cjs/array/index.d.ts.map +1 -1
- package/dist/cjs/array/index.js +4 -0
- package/dist/cjs/array/index.js.map +2 -2
- package/dist/cjs/drawing/bar-time.d.ts +24 -0
- package/dist/cjs/drawing/bar-time.d.ts.map +1 -0
- package/dist/cjs/drawing/bar-time.js +47 -0
- package/dist/cjs/drawing/bar-time.js.map +7 -0
- package/dist/cjs/drawing/output.d.ts +32 -0
- package/dist/cjs/drawing/output.d.ts.map +1 -0
- package/dist/cjs/drawing/output.js +184 -0
- package/dist/cjs/drawing/output.js.map +7 -0
- package/dist/cjs/drawing/registry.d.ts +5 -4
- package/dist/cjs/drawing/registry.d.ts.map +1 -1
- package/dist/cjs/drawing/registry.js +11 -2
- package/dist/cjs/drawing/registry.js.map +2 -2
- package/dist/cjs/index.d.ts +7 -3
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +11 -2
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/polyline/index.d.ts +3 -5
- package/dist/cjs/polyline/index.d.ts.map +1 -1
- package/dist/cjs/polyline/index.js +0 -5
- 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 +51 -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 +104 -8
- package/dist/cjs/script/index.d.ts.map +1 -1
- package/dist/cjs/script/index.js +163 -28
- package/dist/cjs/script/index.js.map +3 -3
- package/dist/cjs/str/index.d.ts +9 -3
- package/dist/cjs/str/index.d.ts.map +1 -1
- package/dist/cjs/str/index.js +11 -6
- package/dist/cjs/str/index.js.map +2 -2
- package/dist/cjs/str/numberformat.d.ts +6 -0
- package/dist/cjs/str/numberformat.d.ts.map +1 -1
- package/dist/cjs/str/numberformat.js +9 -1
- package/dist/cjs/str/numberformat.js.map +2 -2
- package/dist/cjs/table/index.d.ts +87 -0
- package/dist/cjs/table/index.d.ts.map +1 -0
- package/dist/cjs/table/index.js +150 -0
- package/dist/cjs/table/index.js.map +7 -0
- package/dist/cjs/text/index.d.ts +17 -2
- package/dist/cjs/text/index.d.ts.map +1 -1
- package/dist/cjs/text/index.js +15 -1
- package/dist/cjs/text/index.js.map +2 -2
- package/dist/cjs/types/index.d.ts +30 -1
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/index.js +12 -0
- package/dist/cjs/types/index.js.map +2 -2
- package/dist/cjs/types/metadata.d.ts +258 -26
- 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 +9 -23
- package/dist/esm/array/index.d.ts.map +1 -1
- package/dist/esm/array/index.js +10 -22
- package/dist/esm/array/index.js.map +1 -1
- package/dist/esm/drawing/bar-time.d.ts +24 -0
- package/dist/esm/drawing/bar-time.d.ts.map +1 -0
- package/dist/esm/drawing/bar-time.js +44 -0
- package/dist/esm/drawing/bar-time.js.map +1 -0
- package/dist/esm/drawing/output.d.ts +32 -0
- package/dist/esm/drawing/output.d.ts.map +1 -0
- package/dist/esm/drawing/output.js +190 -0
- package/dist/esm/drawing/output.js.map +1 -0
- package/dist/esm/drawing/registry.d.ts +5 -4
- package/dist/esm/drawing/registry.d.ts.map +1 -1
- package/dist/esm/drawing/registry.js +12 -2
- package/dist/esm/drawing/registry.js.map +1 -1
- package/dist/esm/index.d.ts +7 -3
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +8 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/polyline/index.d.ts +3 -5
- package/dist/esm/polyline/index.d.ts.map +1 -1
- package/dist/esm/polyline/index.js +3 -9
- 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 +51 -2
- package/dist/esm/runtime/types.d.ts.map +1 -1
- package/dist/esm/script/index.d.ts +104 -8
- package/dist/esm/script/index.d.ts.map +1 -1
- package/dist/esm/script/index.js +194 -24
- package/dist/esm/script/index.js.map +1 -1
- package/dist/esm/str/index.d.ts +9 -3
- package/dist/esm/str/index.d.ts.map +1 -1
- package/dist/esm/str/index.js +25 -10
- package/dist/esm/str/index.js.map +1 -1
- package/dist/esm/str/numberformat.d.ts +6 -0
- package/dist/esm/str/numberformat.d.ts.map +1 -1
- package/dist/esm/str/numberformat.js +12 -0
- package/dist/esm/str/numberformat.js.map +1 -1
- package/dist/esm/table/index.d.ts +87 -0
- package/dist/esm/table/index.d.ts.map +1 -0
- package/dist/esm/table/index.js +169 -0
- package/dist/esm/table/index.js.map +1 -0
- package/dist/esm/text/index.d.ts +17 -2
- package/dist/esm/text/index.d.ts.map +1 -1
- package/dist/esm/text/index.js +17 -2
- package/dist/esm/text/index.js.map +1 -1
- package/dist/esm/types/index.d.ts +30 -1
- package/dist/esm/types/index.d.ts.map +1 -1
- package/dist/esm/types/index.js +14 -0
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm/types/metadata.d.ts +258 -26
- package/dist/esm/types/metadata.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/array/index.ts +12 -23
- package/src/drawing/bar-time.ts +42 -0
- package/src/drawing/output.ts +214 -0
- package/src/drawing/registry.ts +16 -6
- package/src/index.ts +11 -3
- package/src/polyline/index.ts +3 -12
- package/src/runtime/index.ts +3 -0
- package/src/runtime/input-active.ts +50 -0
- package/src/runtime/types.ts +48 -2
- package/src/script/index.ts +301 -30
- package/src/str/index.ts +23 -10
- package/src/str/numberformat.ts +13 -0
- package/src/table/index.ts +221 -0
- package/src/text/index.ts +18 -2
- package/src/types/index.ts +32 -1
- package/src/types/metadata.ts +325 -26
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renderable form of the live drawing objects (labels, lines, boxes, linefills, polylines, tables): the
|
|
3
|
+
* `IndicatorResult` fields `labels`, `lines`, `boxes`, `linefills`, `polylines` and `tables`.
|
|
4
|
+
*
|
|
5
|
+
* Conversion rules:
|
|
6
|
+
* - x coordinates become bar times: a `bar_index` x is the time of that bar, or of a future bar after the last bar
|
|
7
|
+
* (see {@link barTime}); a `bar_time` x (UNIX ms, as PineScript) is converted to the unit of the bar times
|
|
8
|
+
* - an object with an `na` coordinate (or a bar index before the first bar) is not drawn, as in PineScript
|
|
9
|
+
* - a property the script did not set is omitted (the renderer uses the PineScript default); a colour set to `na`
|
|
10
|
+
* is 'transparent'
|
|
11
|
+
* - `force_overlay` is kept only when true
|
|
12
|
+
*
|
|
13
|
+
* @module drawing/output
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { all } from './registry.js';
|
|
17
|
+
import { barInterval, barTime } from './bar-time.js';
|
|
18
|
+
import type { Box, ChartPoint, Label, Line, Polyline, Table, color } from '../types/index.js';
|
|
19
|
+
import type {
|
|
20
|
+
BoxData,
|
|
21
|
+
LabelData,
|
|
22
|
+
LineDrawingData,
|
|
23
|
+
LinefillData,
|
|
24
|
+
PolylineData,
|
|
25
|
+
TableCellData,
|
|
26
|
+
TableData,
|
|
27
|
+
} from '../types/metadata.js';
|
|
28
|
+
|
|
29
|
+
/** Drawing fields of an IndicatorResult; a kind without live objects is undefined. */
|
|
30
|
+
export interface DrawingOutputs {
|
|
31
|
+
labels?: LabelData[];
|
|
32
|
+
lines?: LineDrawingData[];
|
|
33
|
+
boxes?: BoxData[];
|
|
34
|
+
linefills?: LinefillData[];
|
|
35
|
+
polylines?: PolylineData[];
|
|
36
|
+
tables?: TableData[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** A colour of the result: 'transparent' for na (null), '#rrggbb' for a numeric colour. */
|
|
40
|
+
function colorOut(c: color | null | undefined): string | undefined {
|
|
41
|
+
if (c === undefined) return undefined;
|
|
42
|
+
if (c === null || (typeof c === 'number' && Number.isNaN(c))) return 'transparent';
|
|
43
|
+
return typeof c === 'number' ? `#${(c & 0xffffff).toString(16).padStart(6, '0')}` : c;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The object without its undefined fields (so that the result has only the properties that were set). */
|
|
47
|
+
function compact<T extends object>(obj: T): T {
|
|
48
|
+
for (const k of Object.keys(obj) as Array<keyof T>) if (obj[k] === undefined) delete obj[k];
|
|
49
|
+
return obj;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const overlay = (flag: boolean | undefined): true | undefined => (flag ? true : undefined);
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Converts the live drawing objects of the registry. `bars` are the chart bars (their `time` in `timeUnit`, 's' by
|
|
56
|
+
* default as lightweight-charts); they give the time of a bar index.
|
|
57
|
+
*/
|
|
58
|
+
export function drawingOutputs(bars: ReadonlyArray<{ time: number }>, timeUnit: 's' | 'ms' = 's'): DrawingOutputs {
|
|
59
|
+
const interval = barInterval(bars);
|
|
60
|
+
const msUnit = timeUnit === 'ms' ? 1 : 1000;
|
|
61
|
+
const xTime = (x: number, xloc: 'bar_index' | 'bar_time'): number =>
|
|
62
|
+
xloc === 'bar_time' ? x / msUnit : barTime(bars, x, interval);
|
|
63
|
+
const ok = (...values: number[]): boolean => values.every(Number.isFinite);
|
|
64
|
+
|
|
65
|
+
const lineData = (l: Line): LineDrawingData | undefined => {
|
|
66
|
+
const time1 = xTime(l.x1, l.xloc);
|
|
67
|
+
const time2 = xTime(l.x2, l.xloc);
|
|
68
|
+
if (!ok(time1, time2, l.y1, l.y2)) return undefined;
|
|
69
|
+
return compact({
|
|
70
|
+
time1,
|
|
71
|
+
price1: l.y1,
|
|
72
|
+
time2,
|
|
73
|
+
price2: l.y2,
|
|
74
|
+
color: colorOut(l.color),
|
|
75
|
+
width: l.width,
|
|
76
|
+
style: l.style,
|
|
77
|
+
extend: l.extend,
|
|
78
|
+
forceOverlay: overlay(l.force_overlay),
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const labelData = (l: Label): LabelData | undefined => {
|
|
83
|
+
const time = xTime(l.x, l.xloc);
|
|
84
|
+
// abovebar / belowbar labels are placed at the bar, not at y
|
|
85
|
+
if (!ok(time) || (l.yloc === 'price' && !ok(l.y))) return undefined;
|
|
86
|
+
return compact({
|
|
87
|
+
time,
|
|
88
|
+
price: l.y,
|
|
89
|
+
text: l.text ?? '',
|
|
90
|
+
color: colorOut(l.color),
|
|
91
|
+
textColor: colorOut(l.textcolor),
|
|
92
|
+
style: l.style,
|
|
93
|
+
size: l.size as LabelData['size'],
|
|
94
|
+
yloc: l.yloc,
|
|
95
|
+
textAlign: l.textalign,
|
|
96
|
+
tooltip: l.tooltip,
|
|
97
|
+
fontFamily: l.text_font_family,
|
|
98
|
+
textFormatting: l.text_formatting,
|
|
99
|
+
forceOverlay: overlay(l.force_overlay),
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const boxData = (b: Box): BoxData | undefined => {
|
|
104
|
+
const time1 = xTime(b.left, b.xloc);
|
|
105
|
+
const time2 = xTime(b.right, b.xloc);
|
|
106
|
+
if (!ok(time1, time2, b.top, b.bottom)) return undefined;
|
|
107
|
+
return compact({
|
|
108
|
+
time1,
|
|
109
|
+
price1: b.top,
|
|
110
|
+
time2,
|
|
111
|
+
price2: b.bottom,
|
|
112
|
+
bgColor: colorOut(b.bgcolor),
|
|
113
|
+
borderColor: colorOut(b.border_color),
|
|
114
|
+
borderWidth: b.border_width,
|
|
115
|
+
borderStyle: b.border_style,
|
|
116
|
+
text: b.text,
|
|
117
|
+
textColor: colorOut(b.text_color),
|
|
118
|
+
textSize: b.text_size as BoxData['textSize'],
|
|
119
|
+
textHAlign: b.text_halign,
|
|
120
|
+
textVAlign: b.text_valign,
|
|
121
|
+
textWrap: b.text_wrap,
|
|
122
|
+
fontFamily: b.text_font_family,
|
|
123
|
+
textFormatting: b.text_formatting,
|
|
124
|
+
extend: b.extend,
|
|
125
|
+
forceOverlay: overlay(b.force_overlay),
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const polylineData = (p: Polyline): PolylineData | undefined => {
|
|
130
|
+
const points: PolylineData['points'] = [];
|
|
131
|
+
for (const point of p.points as ChartPoint[]) {
|
|
132
|
+
const x = p.xloc === 'bar_time' ? point.time : point.index;
|
|
133
|
+
const time = x === null ? NaN : xTime(x, p.xloc);
|
|
134
|
+
if (ok(time, point.price)) points.push({ time, price: point.price });
|
|
135
|
+
}
|
|
136
|
+
if (points.length === 0) return undefined;
|
|
137
|
+
return compact({
|
|
138
|
+
points,
|
|
139
|
+
curved: p.curved,
|
|
140
|
+
closed: p.closed,
|
|
141
|
+
lineColor: colorOut(p.line_color),
|
|
142
|
+
fillColor: p.fill_color === null ? undefined : colorOut(p.fill_color),
|
|
143
|
+
lineStyle: p.line_style,
|
|
144
|
+
lineWidth: p.line_width,
|
|
145
|
+
forceOverlay: overlay(p.force_overlay),
|
|
146
|
+
});
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const tableData = (t: Table): TableData => {
|
|
150
|
+
const cells: TableCellData[] = [];
|
|
151
|
+
for (const [key, c] of t.cells ?? []) {
|
|
152
|
+
const [column, row] = key.split(',').map(Number) as [number, number];
|
|
153
|
+
cells.push(
|
|
154
|
+
compact({
|
|
155
|
+
row,
|
|
156
|
+
column,
|
|
157
|
+
text: c.text ?? '',
|
|
158
|
+
bgColor: colorOut(c.bgcolor),
|
|
159
|
+
textColor: colorOut(c.text_color),
|
|
160
|
+
textSize: c.text_size as TableCellData['textSize'],
|
|
161
|
+
width: c.width,
|
|
162
|
+
height: c.height,
|
|
163
|
+
textHAlign: c.text_halign,
|
|
164
|
+
textVAlign: c.text_valign,
|
|
165
|
+
tooltip: c.tooltip,
|
|
166
|
+
fontFamily: c.text_font_family,
|
|
167
|
+
textFormatting: c.text_formatting,
|
|
168
|
+
})
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
cells.sort((a, b) => a.row - b.row || a.column - b.column);
|
|
172
|
+
const merges = (t.merges ?? []).map((m) => ({
|
|
173
|
+
startColumn: m.start_column,
|
|
174
|
+
startRow: m.start_row,
|
|
175
|
+
endColumn: m.end_column,
|
|
176
|
+
endRow: m.end_row,
|
|
177
|
+
}));
|
|
178
|
+
return compact({
|
|
179
|
+
position: t.position,
|
|
180
|
+
columns: t.columns,
|
|
181
|
+
rows: t.rows,
|
|
182
|
+
cells,
|
|
183
|
+
merges: merges.length ? merges : undefined,
|
|
184
|
+
bgColor: colorOut(t.bgcolor),
|
|
185
|
+
frameColor: colorOut(t.frame_color),
|
|
186
|
+
frameWidth: t.frame_width,
|
|
187
|
+
borderColor: colorOut(t.border_color),
|
|
188
|
+
borderWidth: t.border_width,
|
|
189
|
+
forceOverlay: overlay(t.force_overlay),
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const convert = <T, R>(items: T[], fn: (item: T) => R | undefined): R[] | undefined => {
|
|
194
|
+
const out: R[] = [];
|
|
195
|
+
for (const item of items) {
|
|
196
|
+
const r = fn(item);
|
|
197
|
+
if (r !== undefined) out.push(r);
|
|
198
|
+
}
|
|
199
|
+
return out.length ? out : undefined;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
labels: convert(all('label'), labelData),
|
|
204
|
+
lines: convert(all('line'), lineData),
|
|
205
|
+
boxes: convert(all('box'), boxData),
|
|
206
|
+
linefills: convert(all('linefill'), (f): LinefillData | undefined => {
|
|
207
|
+
const line1 = lineData(f.line1);
|
|
208
|
+
const line2 = lineData(f.line2);
|
|
209
|
+
return line1 && line2 ? compact({ line1, line2, color: colorOut(f.color) }) : undefined;
|
|
210
|
+
}),
|
|
211
|
+
polylines: convert(all('polyline'), polylineData),
|
|
212
|
+
tables: convert(all('table'), tableData),
|
|
213
|
+
};
|
|
214
|
+
}
|
package/src/drawing/registry.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Registry of the live drawing objects (lines, labels, boxes, polylines, linefills), as PineScript
|
|
2
|
+
* Registry of the live drawing objects (lines, labels, boxes, polylines, linefills, tables), as PineScript
|
|
3
3
|
* keeps them. PineScript rules:
|
|
4
4
|
*
|
|
5
5
|
* - `line.all`, `label.all`, ... list the live objects in creation order (a copy of the list)
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
* @module drawing/registry
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import type { Box, Label, Line, Linefill, Polyline } from '../types/index.js';
|
|
18
|
+
import type { Box, Label, Line, Linefill, Polyline, Table } from '../types/index.js';
|
|
19
19
|
|
|
20
|
-
export type DrawingKind = 'line' | 'label' | 'box' | 'polyline' | 'linefill';
|
|
20
|
+
export type DrawingKind = 'line' | 'label' | 'box' | 'polyline' | 'linefill' | 'table';
|
|
21
21
|
|
|
22
22
|
interface DrawingTypes {
|
|
23
23
|
line: Line;
|
|
@@ -25,6 +25,7 @@ interface DrawingTypes {
|
|
|
25
25
|
box: Box;
|
|
26
26
|
polyline: Polyline;
|
|
27
27
|
linefill: Linefill;
|
|
28
|
+
table: Table;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
/** Default `max_lines_count`, `max_labels_count`, `max_boxes_count`, `max_polylines_count`. */
|
|
@@ -32,9 +33,16 @@ export const DEFAULT_MAX_COUNT = 50;
|
|
|
32
33
|
/** Objects above the maximum that PineScript keeps before it deletes the oldest ones. */
|
|
33
34
|
const SLACK = 5;
|
|
34
35
|
|
|
35
|
-
export type DrawingLimits = Partial<Record<Exclude<DrawingKind, 'linefill'>, number>>;
|
|
36
|
+
export type DrawingLimits = Partial<Record<Exclude<DrawingKind, 'linefill' | 'table'>, number>>;
|
|
36
37
|
|
|
37
|
-
const live: { [K in DrawingKind]: Array<DrawingTypes[K]> } = {
|
|
38
|
+
const live: { [K in DrawingKind]: Array<DrawingTypes[K]> } = {
|
|
39
|
+
line: [],
|
|
40
|
+
label: [],
|
|
41
|
+
box: [],
|
|
42
|
+
polyline: [],
|
|
43
|
+
linefill: [],
|
|
44
|
+
table: [],
|
|
45
|
+
};
|
|
38
46
|
let limits: Required<DrawingLimits> = {
|
|
39
47
|
line: DEFAULT_MAX_COUNT,
|
|
40
48
|
label: DEFAULT_MAX_COUNT,
|
|
@@ -50,6 +58,7 @@ const COORDINATES: { [K in DrawingKind]: Array<keyof DrawingTypes[K]> } = {
|
|
|
50
58
|
box: ['left', 'top', 'right', 'bottom'],
|
|
51
59
|
polyline: [],
|
|
52
60
|
linefill: [],
|
|
61
|
+
table: [],
|
|
53
62
|
};
|
|
54
63
|
|
|
55
64
|
function markDeleted<K extends DrawingKind>(kind: K, obj: DrawingTypes[K], explicit: boolean): void {
|
|
@@ -64,7 +73,8 @@ function markDeleted<K extends DrawingKind>(kind: K, obj: DrawingTypes[K], expli
|
|
|
64
73
|
export function register<K extends DrawingKind>(kind: K, obj: DrawingTypes[K]): DrawingTypes[K] {
|
|
65
74
|
const list = live[kind];
|
|
66
75
|
list.push(obj);
|
|
67
|
-
|
|
76
|
+
if (kind === 'table') return obj; // tables have no maximum count
|
|
77
|
+
const max = limits[kind === 'linefill' ? 'line' : (kind as keyof DrawingLimits)];
|
|
68
78
|
if (list.length > max + SLACK) {
|
|
69
79
|
for (const old of list.splice(0, list.length - max)) markDeleted(kind, old, false);
|
|
70
80
|
}
|
package/src/index.ts
CHANGED
|
@@ -32,11 +32,16 @@ import * as label from './label/index.js';
|
|
|
32
32
|
import * as linefill from './linefill/index.js';
|
|
33
33
|
import * as chartPoint from './chartpoint/index.js';
|
|
34
34
|
import * as polyline from './polyline/index.js';
|
|
35
|
+
import * as table from './table/index.js';
|
|
35
36
|
import * as text from './text/index.js';
|
|
36
37
|
import * as compare from './compare/index.js';
|
|
37
38
|
import * as callsite from './callsite/index.js';
|
|
38
39
|
|
|
39
|
-
export { taCore, math, array, map, str, color, time, timeframe, matrix, line, box, label, linefill, chartPoint, polyline, text, compare, callsite };
|
|
40
|
+
export { taCore, math, array, map, str, color, time, timeframe, matrix, line, box, label, linefill, chartPoint, polyline, table, text, compare, callsite };
|
|
41
|
+
|
|
42
|
+
// Renderable drawings (IndicatorResult labels, lines, boxes, linefills, polylines, tables) and future bar times
|
|
43
|
+
export { drawingOutputs, type DrawingOutputs } from './drawing/output.js';
|
|
44
|
+
export { barInterval, barTime } from './drawing/bar-time.js';
|
|
40
45
|
|
|
41
46
|
// Export Series class (self-contained, no context)
|
|
42
47
|
export { Series, BarData } from './runtime/series.js';
|
|
@@ -134,6 +139,7 @@ export {
|
|
|
134
139
|
input_session,
|
|
135
140
|
input_time,
|
|
136
141
|
} from './runtime/inputs.js';
|
|
142
|
+
export { isInputActive } from './runtime/input-active.js';
|
|
137
143
|
|
|
138
144
|
export type {
|
|
139
145
|
OakScriptContext,
|
|
@@ -142,12 +148,14 @@ export type {
|
|
|
142
148
|
SeriesHandle,
|
|
143
149
|
SeriesOptions,
|
|
144
150
|
InputConfig,
|
|
151
|
+
InputCondition,
|
|
145
152
|
InputOptions,
|
|
146
153
|
OhlcvData,
|
|
147
154
|
PlotConfig,
|
|
148
155
|
HLineConfig,
|
|
149
156
|
FillConfig,
|
|
150
157
|
ArrowConfig,
|
|
158
|
+
CandleConfig,
|
|
151
159
|
} from './runtime/types.js';
|
|
152
160
|
|
|
153
161
|
// Strategy types and constants (the script API forwards strategy.* calls to a host engine)
|
|
@@ -164,7 +172,7 @@ export type { LightweightSeriesDefinitions } from './runtime/adapters/Lightweigh
|
|
|
164
172
|
export { SimpleInputAdapter } from './runtime/adapters/SimpleInputAdapter.js';
|
|
165
173
|
|
|
166
174
|
// Version
|
|
167
|
-
export const VERSION = '0.
|
|
175
|
+
export const VERSION = '0.10.1';
|
|
168
176
|
|
|
169
177
|
/**
|
|
170
178
|
* Library information
|
|
@@ -182,7 +190,7 @@ export const info = {
|
|
|
182
190
|
},
|
|
183
191
|
namespaces: {
|
|
184
192
|
core: ['ta', 'math', 'array', 'map', 'str', 'color', 'time', 'timeframe', 'matrix'],
|
|
185
|
-
drawing: ['line', 'box', 'label', 'linefill', 'chartPoint', 'polyline', 'text'],
|
|
193
|
+
drawing: ['line', 'box', 'label', 'linefill', 'chartPoint', 'polyline', 'table', 'text'],
|
|
186
194
|
runtime: ['setContext', 'plot', 'hline', 'input_*'],
|
|
187
195
|
indicator: ['indicator', 'input', 'plotHelper', 'createPlot']
|
|
188
196
|
}
|
package/src/polyline/index.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* @remarks
|
|
6
6
|
* Polylines allow connecting multiple points with line segments, enabling complex chart drawings
|
|
7
|
-
* like trend channels, patterns, and custom shapes.
|
|
8
|
-
* polylines
|
|
7
|
+
* like trend channels, patterns, and custom shapes. The `curved` flag goes to the renderer
|
|
8
|
+
* (`result.polylines` of the script API), which draws the curve.
|
|
9
9
|
*
|
|
10
10
|
* @version 6
|
|
11
11
|
*/
|
|
@@ -30,7 +30,7 @@ function generateId(): string {
|
|
|
30
30
|
* Creates a new polyline connecting all points.
|
|
31
31
|
*
|
|
32
32
|
* @param points - Array of chart.point objects to connect
|
|
33
|
-
* @param curved - If true, use curved line segments (default: false
|
|
33
|
+
* @param curved - If true, use curved line segments (default: false)
|
|
34
34
|
* @param closed - If true, connect first point to last point (default: false)
|
|
35
35
|
* @param xloc - X-coordinate mode: 'bar_index' or 'bar_time' (default: 'bar_index')
|
|
36
36
|
* @param line_color - Color of line segments (default: '#2196F3' - blue)
|
|
@@ -41,8 +41,6 @@ function generateId(): string {
|
|
|
41
41
|
* @returns New Polyline object
|
|
42
42
|
*
|
|
43
43
|
* @remarks
|
|
44
|
-
* - The curved parameter is accepted but currently logs a warning as curved lines
|
|
45
|
-
* are not yet supported. Straight-line connections are used instead.
|
|
46
44
|
* - For meaningful polylines, provide at least 2 points.
|
|
47
45
|
* - Closed polylines can be filled with a color by setting fill_color.
|
|
48
46
|
*
|
|
@@ -82,13 +80,6 @@ export function new_polyline(
|
|
|
82
80
|
line_width: number = 1,
|
|
83
81
|
force_overlay: boolean = false
|
|
84
82
|
): Polyline {
|
|
85
|
-
// Warn about curved polylines not being supported yet
|
|
86
|
-
if (curved) {
|
|
87
|
-
console.warn(
|
|
88
|
-
'polyline.new(): curved polylines are not yet supported. Using straight-line connections.'
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
83
|
// Validate line_width is positive
|
|
93
84
|
if (line_width < 1) {
|
|
94
85
|
console.warn('polyline.new(): line_width must be at least 1. Using 1.');
|
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
|
/**
|
|
@@ -138,6 +161,29 @@ export interface ArrowConfig {
|
|
|
138
161
|
forceOverlay?: boolean;
|
|
139
162
|
}
|
|
140
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Configuration of a PineScript `plotcandle()` (kind 'candle') or `plotbar()` (kind 'bar') declaration. The candles
|
|
166
|
+
* are in `result.plotCandles[id]`, the bars in `result.plotBars[id]`.
|
|
167
|
+
*/
|
|
168
|
+
export interface CandleConfig {
|
|
169
|
+
/** Unique identifier (key of the data in the result) */
|
|
170
|
+
id: string;
|
|
171
|
+
/** 'candle' for plotcandle, 'bar' for plotbar */
|
|
172
|
+
kind: 'candle' | 'bar';
|
|
173
|
+
/** Display title */
|
|
174
|
+
title?: string;
|
|
175
|
+
/** Static body colour (plotcandle) or bar colour (plotbar) */
|
|
176
|
+
color?: string;
|
|
177
|
+
/** Static wick colour (plotcandle only) */
|
|
178
|
+
wickColor?: string;
|
|
179
|
+
/** Static border colour (plotcandle only) */
|
|
180
|
+
borderColor?: string;
|
|
181
|
+
/** Display mode */
|
|
182
|
+
display?: 'all' | 'none' | 'data_window' | 'status_line' | 'pane';
|
|
183
|
+
/** Drawn on the main chart pane even when the script is not an overlay (PineScript `force_overlay`); default false */
|
|
184
|
+
forceOverlay?: boolean;
|
|
185
|
+
}
|
|
186
|
+
|
|
141
187
|
/**
|
|
142
188
|
* Configuration for horizontal line outputs in generated indicators
|
|
143
189
|
* Matches PineScript hline() function parameters
|