@coderyo/pine-lite 1.0.0-rc.3 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-JLVAE3JC.js +228 -0
- package/dist/chunk-JLVAE3JC.js.map +1 -0
- package/dist/index.d.ts +93 -8
- package/dist/index.js +760 -8
- package/dist/index.js.map +1 -1
- package/dist/pine.worker.d.ts +16 -0
- package/dist/pine.worker.js +21 -0
- package/dist/pine.worker.js.map +1 -0
- package/dist/vm-DSG6hmZe.d.ts +64 -0
- package/package.json +8 -1
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// src/vm.ts
|
|
2
|
+
import { ema, rsi, sma } from "@coderyo/indicators";
|
|
3
|
+
var MAX_STEPS_PER_BAR = 1e5;
|
|
4
|
+
function barsForSeries(bars, series) {
|
|
5
|
+
switch (series) {
|
|
6
|
+
case "hl2":
|
|
7
|
+
return bars.map((b) => ({ ...b, c: (b.h + b.l) / 2 }));
|
|
8
|
+
case "hlc3":
|
|
9
|
+
return bars.map((b) => ({ ...b, c: (b.h + b.l + b.c) / 3 }));
|
|
10
|
+
case "open":
|
|
11
|
+
return bars.map((b) => ({ ...b, c: b.o }));
|
|
12
|
+
case "high":
|
|
13
|
+
return bars.map((b) => ({ ...b, c: b.h }));
|
|
14
|
+
case "low":
|
|
15
|
+
return bars.map((b) => ({ ...b, c: b.l }));
|
|
16
|
+
case "volume":
|
|
17
|
+
return bars.map((b) => ({ ...b, c: b.v ?? 0 }));
|
|
18
|
+
case "close":
|
|
19
|
+
default:
|
|
20
|
+
return bars;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function seriesAt(bars, series, index) {
|
|
24
|
+
const b = bars[index];
|
|
25
|
+
switch (series) {
|
|
26
|
+
case "open":
|
|
27
|
+
return b.o;
|
|
28
|
+
case "high":
|
|
29
|
+
return b.h;
|
|
30
|
+
case "low":
|
|
31
|
+
return b.l;
|
|
32
|
+
case "volume":
|
|
33
|
+
return b.v ?? 0;
|
|
34
|
+
case "hl2":
|
|
35
|
+
return (b.h + b.l) / 2;
|
|
36
|
+
case "hlc3":
|
|
37
|
+
return (b.h + b.l + b.c) / 3;
|
|
38
|
+
case "close":
|
|
39
|
+
default:
|
|
40
|
+
return b.c;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function highestAt(bars, series, index, period) {
|
|
44
|
+
const p = Math.max(1, Math.floor(period));
|
|
45
|
+
if (index < p - 1) return null;
|
|
46
|
+
let max = -Infinity;
|
|
47
|
+
for (let i = index - p + 1; i <= index; i++) {
|
|
48
|
+
const v = seriesAt(bars, series, i);
|
|
49
|
+
if (v > max) max = v;
|
|
50
|
+
}
|
|
51
|
+
return Number.isFinite(max) ? max : null;
|
|
52
|
+
}
|
|
53
|
+
function lowestAt(bars, series, index, period) {
|
|
54
|
+
const p = Math.max(1, Math.floor(period));
|
|
55
|
+
if (index < p - 1) return null;
|
|
56
|
+
let min = Infinity;
|
|
57
|
+
for (let i = index - p + 1; i <= index; i++) {
|
|
58
|
+
const v = seriesAt(bars, series, i);
|
|
59
|
+
if (v < min) min = v;
|
|
60
|
+
}
|
|
61
|
+
return Number.isFinite(min) ? min : null;
|
|
62
|
+
}
|
|
63
|
+
function crossAt(bars, seriesA, seriesB, index, mode) {
|
|
64
|
+
if (index < 1) return 0;
|
|
65
|
+
const a0 = seriesAt(bars, seriesA, index);
|
|
66
|
+
const b0 = seriesAt(bars, seriesB, index);
|
|
67
|
+
const a1 = seriesAt(bars, seriesA, index - 1);
|
|
68
|
+
const b1 = seriesAt(bars, seriesB, index - 1);
|
|
69
|
+
if (mode === "over") return a1 <= b1 && a0 > b0 ? 1 : 0;
|
|
70
|
+
return a1 >= b1 && a0 < b0 ? 1 : 0;
|
|
71
|
+
}
|
|
72
|
+
function indicatorAt(fn, bars, series, index, period, series2) {
|
|
73
|
+
if (fn === "crossover" || fn === "crossunder") {
|
|
74
|
+
if (!series2) return 0;
|
|
75
|
+
return crossAt(bars, series, series2, index, fn === "crossover" ? "over" : "under");
|
|
76
|
+
}
|
|
77
|
+
if (fn === "highest") return highestAt(bars, series, index, period);
|
|
78
|
+
if (fn === "lowest") return lowestAt(bars, series, index, period);
|
|
79
|
+
const src = barsForSeries(bars, series);
|
|
80
|
+
const p = Math.max(1, Math.floor(period));
|
|
81
|
+
const slice = src.slice(0, index + 1);
|
|
82
|
+
if (fn === "sma") return sma(slice, p)[index] ?? null;
|
|
83
|
+
if (fn === "ema") return ema(slice, p)[index] ?? null;
|
|
84
|
+
return rsi(slice, p)[index] ?? null;
|
|
85
|
+
}
|
|
86
|
+
function truthy(v) {
|
|
87
|
+
return Number.isFinite(v) && v !== 0;
|
|
88
|
+
}
|
|
89
|
+
function execOp(op, stack, bars, barIndex, vars, plotBuffers) {
|
|
90
|
+
const pop = () => stack.pop() ?? NaN;
|
|
91
|
+
switch (op.op) {
|
|
92
|
+
case "push":
|
|
93
|
+
stack.push(op.value);
|
|
94
|
+
break;
|
|
95
|
+
case "load_series":
|
|
96
|
+
stack.push(seriesAt(bars, op.name, barIndex));
|
|
97
|
+
break;
|
|
98
|
+
case "load_var": {
|
|
99
|
+
const s = vars.get(op.name);
|
|
100
|
+
stack.push(s?.[barIndex] ?? NaN);
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
case "store_var": {
|
|
104
|
+
const v = pop();
|
|
105
|
+
const s = vars.get(op.name);
|
|
106
|
+
if (s) s[barIndex] = Number.isFinite(v) ? v : null;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case "call_ind": {
|
|
110
|
+
if (op.fn === "crossover" || op.fn === "crossunder") {
|
|
111
|
+
const v2 = indicatorAt(op.fn, bars, op.series, barIndex, 0, op.series2);
|
|
112
|
+
stack.push(v2 ?? 0);
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
const period = pop();
|
|
116
|
+
const v = indicatorAt(op.fn, bars, op.series, barIndex, period, op.series2);
|
|
117
|
+
stack.push(v ?? NaN);
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
case "add":
|
|
121
|
+
stack.push(pop() + pop());
|
|
122
|
+
break;
|
|
123
|
+
case "sub":
|
|
124
|
+
stack.push(pop() - pop());
|
|
125
|
+
break;
|
|
126
|
+
case "mul":
|
|
127
|
+
stack.push(pop() * pop());
|
|
128
|
+
break;
|
|
129
|
+
case "div": {
|
|
130
|
+
const b = pop();
|
|
131
|
+
const a = pop();
|
|
132
|
+
stack.push(b === 0 ? NaN : a / b);
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case "neg":
|
|
136
|
+
stack.push(-pop());
|
|
137
|
+
break;
|
|
138
|
+
case "not":
|
|
139
|
+
stack.push(truthy(pop()) ? 0 : 1);
|
|
140
|
+
break;
|
|
141
|
+
case "cmp": {
|
|
142
|
+
const b = pop();
|
|
143
|
+
const a = pop();
|
|
144
|
+
let r = false;
|
|
145
|
+
switch (op.mode) {
|
|
146
|
+
case "eq":
|
|
147
|
+
r = a === b;
|
|
148
|
+
break;
|
|
149
|
+
case "ne":
|
|
150
|
+
r = a !== b;
|
|
151
|
+
break;
|
|
152
|
+
case "lt":
|
|
153
|
+
r = a < b;
|
|
154
|
+
break;
|
|
155
|
+
case "gt":
|
|
156
|
+
r = a > b;
|
|
157
|
+
break;
|
|
158
|
+
case "le":
|
|
159
|
+
r = a <= b;
|
|
160
|
+
break;
|
|
161
|
+
case "ge":
|
|
162
|
+
r = a >= b;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
stack.push(r ? 1 : 0);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case "and": {
|
|
169
|
+
const b = pop();
|
|
170
|
+
const a = pop();
|
|
171
|
+
stack.push(truthy(a) && truthy(b) ? 1 : 0);
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
case "or": {
|
|
175
|
+
const b = pop();
|
|
176
|
+
const a = pop();
|
|
177
|
+
stack.push(truthy(a) || truthy(b) ? 1 : 0);
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
case "pop":
|
|
181
|
+
pop();
|
|
182
|
+
break;
|
|
183
|
+
case "plot": {
|
|
184
|
+
const v = pop();
|
|
185
|
+
const buf = plotBuffers.get(op.title);
|
|
186
|
+
if (buf) buf[barIndex] = Number.isFinite(v) ? v : null;
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
case "jump":
|
|
190
|
+
return op.target;
|
|
191
|
+
case "jump_if_false":
|
|
192
|
+
return truthy(pop()) ? -1 : op.target;
|
|
193
|
+
default:
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
return -1;
|
|
197
|
+
}
|
|
198
|
+
function runPineIr(ir, bars) {
|
|
199
|
+
const n = bars.length;
|
|
200
|
+
const vars = /* @__PURE__ */ new Map();
|
|
201
|
+
for (const name of ir.vars) vars.set(name, Array.from({ length: n }, () => null));
|
|
202
|
+
const plotBuffers = /* @__PURE__ */ new Map();
|
|
203
|
+
for (const title of ir.plots) {
|
|
204
|
+
plotBuffers.set(title, Array.from({ length: n }, () => null));
|
|
205
|
+
}
|
|
206
|
+
for (let i = 0; i < n; i++) {
|
|
207
|
+
const stack = [];
|
|
208
|
+
let pc = 0;
|
|
209
|
+
let steps = 0;
|
|
210
|
+
while (pc < ir.ops.length && steps < MAX_STEPS_PER_BAR) {
|
|
211
|
+
steps++;
|
|
212
|
+
const jmp = execOp(ir.ops[pc], stack, bars, i, vars, plotBuffers);
|
|
213
|
+
if (jmp >= 0) pc = jmp;
|
|
214
|
+
else pc++;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
plots: ir.plots.map((title) => ({
|
|
219
|
+
title,
|
|
220
|
+
values: plotBuffers.get(title) ?? []
|
|
221
|
+
}))
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export {
|
|
226
|
+
runPineIr
|
|
227
|
+
};
|
|
228
|
+
//# sourceMappingURL=chunk-JLVAE3JC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vm.ts"],"sourcesContent":["import type { Bar } from '@coderyo/data';\nimport { ema, rsi, sma } from '@coderyo/indicators';\nimport type { IrOp, PineIrProgram } from './ir.js';\n\nexport interface PinePlotSeries {\n title: string;\n values: (number | null)[];\n}\n\nexport interface PineRunResult {\n plots: PinePlotSeries[];\n}\n\nconst MAX_STEPS_PER_BAR = 100_000;\n\nfunction barsForSeries(bars: Bar[], series: string): Bar[] {\n switch (series) {\n case 'hl2':\n return bars.map((b) => ({ ...b, c: (b.h + b.l) / 2 }));\n case 'hlc3':\n return bars.map((b) => ({ ...b, c: (b.h + b.l + b.c) / 3 }));\n case 'open':\n return bars.map((b) => ({ ...b, c: b.o }));\n case 'high':\n return bars.map((b) => ({ ...b, c: b.h }));\n case 'low':\n return bars.map((b) => ({ ...b, c: b.l }));\n case 'volume':\n return bars.map((b) => ({ ...b, c: b.v ?? 0 }));\n case 'close':\n default:\n return bars;\n }\n}\n\nfunction seriesAt(bars: Bar[], series: string, index: number): number {\n const b = bars[index]!;\n switch (series) {\n case 'open':\n return b.o;\n case 'high':\n return b.h;\n case 'low':\n return b.l;\n case 'volume':\n return b.v ?? 0;\n case 'hl2':\n return (b.h + b.l) / 2;\n case 'hlc3':\n return (b.h + b.l + b.c) / 3;\n case 'close':\n default:\n return b.c;\n }\n}\n\nfunction highestAt(bars: Bar[], series: string, index: number, period: number): number | null {\n const p = Math.max(1, Math.floor(period));\n if (index < p - 1) return null;\n let max = -Infinity;\n for (let i = index - p + 1; i <= index; i++) {\n const v = seriesAt(bars, series, i);\n if (v > max) max = v;\n }\n return Number.isFinite(max) ? max : null;\n}\n\nfunction lowestAt(bars: Bar[], series: string, index: number, period: number): number | null {\n const p = Math.max(1, Math.floor(period));\n if (index < p - 1) return null;\n let min = Infinity;\n for (let i = index - p + 1; i <= index; i++) {\n const v = seriesAt(bars, series, i);\n if (v < min) min = v;\n }\n return Number.isFinite(min) ? min : null;\n}\n\nfunction crossAt(\n bars: Bar[],\n seriesA: string,\n seriesB: string,\n index: number,\n mode: 'over' | 'under',\n): number {\n if (index < 1) return 0;\n const a0 = seriesAt(bars, seriesA, index);\n const b0 = seriesAt(bars, seriesB, index);\n const a1 = seriesAt(bars, seriesA, index - 1);\n const b1 = seriesAt(bars, seriesB, index - 1);\n if (mode === 'over') return a1 <= b1 && a0 > b0 ? 1 : 0;\n return a1 >= b1 && a0 < b0 ? 1 : 0;\n}\n\nfunction indicatorAt(\n fn: 'sma' | 'ema' | 'rsi' | 'highest' | 'lowest' | 'crossover' | 'crossunder',\n bars: Bar[],\n series: string,\n index: number,\n period: number,\n series2?: string,\n): number | null {\n if (fn === 'crossover' || fn === 'crossunder') {\n if (!series2) return 0;\n return crossAt(bars, series, series2, index, fn === 'crossover' ? 'over' : 'under');\n }\n if (fn === 'highest') return highestAt(bars, series, index, period);\n if (fn === 'lowest') return lowestAt(bars, series, index, period);\n const src = barsForSeries(bars, series);\n const p = Math.max(1, Math.floor(period));\n const slice = src.slice(0, index + 1);\n if (fn === 'sma') return sma(slice, p)[index] ?? null;\n if (fn === 'ema') return ema(slice, p)[index] ?? null;\n return rsi(slice, p)[index] ?? null;\n}\n\nfunction truthy(v: number): boolean {\n return Number.isFinite(v) && v !== 0;\n}\n\nfunction execOp(\n op: IrOp,\n stack: number[],\n bars: Bar[],\n barIndex: number,\n vars: Map<string, (number | null)[]>,\n plotBuffers: Map<string, (number | null)[]>,\n): number {\n const pop = () => stack.pop() ?? NaN;\n switch (op.op) {\n case 'push':\n stack.push(op.value);\n break;\n case 'load_series':\n stack.push(seriesAt(bars, op.name, barIndex));\n break;\n case 'load_var': {\n const s = vars.get(op.name);\n stack.push(s?.[barIndex] ?? NaN);\n break;\n }\n case 'store_var': {\n const v = pop();\n const s = vars.get(op.name);\n if (s) s[barIndex] = Number.isFinite(v) ? v : null;\n break;\n }\n case 'call_ind': {\n if (op.fn === 'crossover' || op.fn === 'crossunder') {\n const v = indicatorAt(op.fn, bars, op.series, barIndex, 0, op.series2);\n stack.push(v ?? 0);\n break;\n }\n const period = pop();\n const v = indicatorAt(op.fn, bars, op.series, barIndex, period, op.series2);\n stack.push(v ?? NaN);\n break;\n }\n case 'add':\n stack.push(pop() + pop());\n break;\n case 'sub':\n stack.push(pop() - pop());\n break;\n case 'mul':\n stack.push(pop() * pop());\n break;\n case 'div': {\n const b = pop();\n const a = pop();\n stack.push(b === 0 ? NaN : a / b);\n break;\n }\n case 'neg':\n stack.push(-pop());\n break;\n case 'not':\n stack.push(truthy(pop()) ? 0 : 1);\n break;\n case 'cmp': {\n const b = pop();\n const a = pop();\n let r = false;\n switch (op.mode) {\n case 'eq':\n r = a === b;\n break;\n case 'ne':\n r = a !== b;\n break;\n case 'lt':\n r = a < b;\n break;\n case 'gt':\n r = a > b;\n break;\n case 'le':\n r = a <= b;\n break;\n case 'ge':\n r = a >= b;\n break;\n }\n stack.push(r ? 1 : 0);\n break;\n }\n case 'and': {\n const b = pop();\n const a = pop();\n stack.push(truthy(a) && truthy(b) ? 1 : 0);\n break;\n }\n case 'or': {\n const b = pop();\n const a = pop();\n stack.push(truthy(a) || truthy(b) ? 1 : 0);\n break;\n }\n case 'pop':\n pop();\n break;\n case 'plot': {\n const v = pop();\n const buf = plotBuffers.get(op.title);\n if (buf) buf[barIndex] = Number.isFinite(v) ? v : null;\n break;\n }\n case 'jump':\n return op.target;\n case 'jump_if_false':\n return truthy(pop()) ? -1 : op.target;\n default:\n break;\n }\n return -1;\n}\n\nexport function runPineIr(ir: PineIrProgram, bars: Bar[]): PineRunResult {\n const n = bars.length;\n const vars = new Map<string, (number | null)[]>();\n for (const name of ir.vars) vars.set(name, Array.from({ length: n }, () => null));\n\n const plotBuffers = new Map<string, (number | null)[]>();\n for (const title of ir.plots) {\n plotBuffers.set(title, Array.from({ length: n }, () => null));\n }\n\n for (let i = 0; i < n; i++) {\n const stack: number[] = [];\n let pc = 0;\n let steps = 0;\n while (pc < ir.ops.length && steps < MAX_STEPS_PER_BAR) {\n steps++;\n const jmp = execOp(ir.ops[pc]!, stack, bars, i, vars, plotBuffers);\n if (jmp >= 0) pc = jmp;\n else pc++;\n }\n }\n\n return {\n plots: ir.plots.map((title) => ({\n title,\n values: plotBuffers.get(title) ?? [],\n })),\n };\n}"],"mappings":"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","names":["v"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,100 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import * as _coderyo_data from '@coderyo/data';
|
|
2
|
+
import { Bar } from '@coderyo/data';
|
|
3
|
+
import { P as PineIrProgram, a as PineRunResult } from './vm-DSG6hmZe.js';
|
|
4
|
+
export { b as PinePlotSeries } from './vm-DSG6hmZe.js';
|
|
5
|
+
|
|
6
|
+
interface PineDiagnostic {
|
|
7
|
+
line: number;
|
|
8
|
+
col: number;
|
|
9
|
+
message: string;
|
|
10
|
+
severity: 'error' | 'warning';
|
|
11
|
+
endCol?: number;
|
|
12
|
+
}
|
|
13
|
+
declare function offsetToLineCol(source: string, offset: number): {
|
|
14
|
+
line: number;
|
|
15
|
+
col: number;
|
|
16
|
+
};
|
|
17
|
+
declare function diagnosticFromMessage(source: string, message: string): PineDiagnostic;
|
|
18
|
+
declare function diagnosticsFromMessages(source: string, messages: string[]): PineDiagnostic[];
|
|
19
|
+
|
|
20
|
+
type PineExpr = {
|
|
21
|
+
kind: 'number';
|
|
22
|
+
value: number;
|
|
23
|
+
} | {
|
|
24
|
+
kind: 'bool';
|
|
25
|
+
value: boolean;
|
|
26
|
+
} | {
|
|
27
|
+
kind: 'ident';
|
|
28
|
+
name: string;
|
|
29
|
+
} | {
|
|
30
|
+
kind: 'unary';
|
|
31
|
+
op: '-' | 'not';
|
|
32
|
+
arg: PineExpr;
|
|
33
|
+
} | {
|
|
34
|
+
kind: 'binary';
|
|
35
|
+
op: '+' | '-' | '*' | '/' | '==' | '!=' | '<' | '>' | '<=' | '>=' | 'and' | 'or';
|
|
36
|
+
left: PineExpr;
|
|
37
|
+
right: PineExpr;
|
|
38
|
+
} | {
|
|
39
|
+
kind: 'call';
|
|
40
|
+
name: string;
|
|
41
|
+
args: PineExpr[];
|
|
42
|
+
};
|
|
43
|
+
type PineStmt = {
|
|
44
|
+
kind: 'var';
|
|
45
|
+
name: string;
|
|
46
|
+
init: PineExpr;
|
|
47
|
+
} | {
|
|
48
|
+
kind: 'assign';
|
|
49
|
+
name: string;
|
|
50
|
+
value: PineExpr;
|
|
51
|
+
} | {
|
|
52
|
+
kind: 'plot';
|
|
53
|
+
expr: PineExpr;
|
|
54
|
+
title?: string;
|
|
55
|
+
} | {
|
|
56
|
+
kind: 'expr';
|
|
57
|
+
expr: PineExpr;
|
|
58
|
+
} | {
|
|
59
|
+
kind: 'if';
|
|
60
|
+
cond: PineExpr;
|
|
61
|
+
then: PineStmt[];
|
|
62
|
+
else?: PineStmt[];
|
|
63
|
+
} | {
|
|
64
|
+
kind: 'while';
|
|
65
|
+
cond: PineExpr;
|
|
66
|
+
body: PineStmt[];
|
|
67
|
+
} | {
|
|
68
|
+
kind: 'for';
|
|
69
|
+
name: string;
|
|
70
|
+
from: PineExpr;
|
|
71
|
+
to: PineExpr;
|
|
72
|
+
body: PineStmt[];
|
|
73
|
+
} | {
|
|
74
|
+
kind: 'block';
|
|
75
|
+
body: PineStmt[];
|
|
76
|
+
};
|
|
77
|
+
interface PineProgram {
|
|
78
|
+
kind: 'program';
|
|
79
|
+
body: PineStmt[];
|
|
3
80
|
}
|
|
4
|
-
/** Minimal stack VM stub (PR-18b) — no user scripts executed by default. */
|
|
5
|
-
declare function runPineVm(ir: NonNullable<PineCompileResult['ir']>, length: number): PineVmResult;
|
|
6
81
|
|
|
7
|
-
|
|
82
|
+
interface RunPineLiteAsyncOptions {
|
|
83
|
+
useWorker?: boolean;
|
|
84
|
+
}
|
|
85
|
+
declare function runPineLiteAsync(ir: PineIrProgram, bars: Bar[], opts?: RunPineLiteAsyncOptions): Promise<PineRunResult>;
|
|
86
|
+
declare function terminatePineWorker(): void;
|
|
87
|
+
|
|
8
88
|
interface PineCompileResult {
|
|
9
89
|
ok: boolean;
|
|
10
90
|
errors: string[];
|
|
11
|
-
|
|
91
|
+
diagnostics: PineDiagnostic[];
|
|
92
|
+
ir?: PineIrProgram;
|
|
12
93
|
}
|
|
13
|
-
declare function compilePineLite(
|
|
94
|
+
declare function compilePineLite(source: string): PineCompileResult;
|
|
95
|
+
declare function runPineLite(ir: PineIrProgram, bars: _coderyo_data.Bar[]): PineRunResult;
|
|
96
|
+
|
|
97
|
+
declare const PINE_SAMPLE_SCRIPT = "// Pine-lite \u2014 if / while / for\u3001\u6BD4\u8F03\u3001and/or/not\nvar len = 20\nif (close > 0) {\n plot(sma(close, len))\n} else {\n plot(open)\n}\nfor i = 1 to 2 {\n plot(rsi(close, 14))\n}\n";
|
|
98
|
+
declare const PINE_EDITOR_DEFAULT = "// Pine-lite \u2014 if / while / for\u3001\u6BD4\u8F03\u3001and/or/not\nvar len = 20\nif (close > 0) {\n plot(sma(close, len))\n} else {\n plot(open)\n}\nfor i = 1 to 2 {\n plot(rsi(close, 14))\n}\n";
|
|
14
99
|
|
|
15
|
-
export { type PineCompileResult, type
|
|
100
|
+
export { PINE_EDITOR_DEFAULT, PINE_SAMPLE_SCRIPT, type PineCompileResult, type PineDiagnostic, PineIrProgram, type PineProgram, PineRunResult, type RunPineLiteAsyncOptions, compilePineLite, diagnosticFromMessage, diagnosticsFromMessages, offsetToLineCol, runPineLite, runPineLiteAsync, terminatePineWorker };
|