@alphacharts/script 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +161 -2
- package/dist/builtins-BXxWK58s.js +812 -0
- package/dist/builtins-BXxWK58s.js.map +1 -0
- package/dist/editor.js +211 -0
- package/dist/editor.js.map +1 -0
- package/dist/index.js +342 -0
- package/dist/index.js.map +1 -0
- package/dist/sandbox-p2HPP8yl.js +2416 -0
- package/dist/sandbox-p2HPP8yl.js.map +1 -0
- package/dist/sandbox-worker.js +8 -0
- package/dist/sandbox-worker.js.map +1 -0
- package/dist/types/ast.d.ts +156 -0
- package/dist/types/builtins.d.ts +67 -0
- package/dist/types/check.d.ts +78 -0
- package/dist/types/codegen.d.ts +14 -0
- package/dist/types/compile.d.ts +52 -0
- package/dist/types/diag.d.ts +45 -0
- package/dist/types/editor/index.d.ts +23 -0
- package/dist/types/feeds.d.ts +33 -0
- package/dist/types/index.d.ts +17 -0
- package/dist/types/lexer.d.ts +14 -0
- package/dist/types/limits.d.ts +25 -0
- package/dist/types/parser.d.ts +3 -0
- package/dist/types/run.d.ts +69 -0
- package/dist/types/runner.d.ts +54 -0
- package/dist/types/sandbox-worker.d.ts +1 -0
- package/dist/types/sandbox.d.ts +78 -0
- package/dist/types/ui-adapter.d.ts +21 -0
- package/package.json +75 -3
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import type { Span } from "./diag.js";
|
|
2
|
+
export type Base = "int" | "float" | "bool" | "string" | "color" | "na" | "plot" | "void" | "tuple";
|
|
3
|
+
/** const: a literal; input: known when the study is built; series: varies per bar. */
|
|
4
|
+
export type Qual = "const" | "input" | "series";
|
|
5
|
+
export interface Ty {
|
|
6
|
+
b: Base;
|
|
7
|
+
q: Qual;
|
|
8
|
+
elems?: Ty[];
|
|
9
|
+
}
|
|
10
|
+
export interface Sym {
|
|
11
|
+
name: string;
|
|
12
|
+
kind: "builtin" | "input" | "simple" | "pure" | "state" | "local" | "loop" | "plot";
|
|
13
|
+
ty: Ty;
|
|
14
|
+
/** Builtin source name, input key, or slot / plot index. */
|
|
15
|
+
key?: string;
|
|
16
|
+
slot?: number;
|
|
17
|
+
/** A top-level variable kept in the exec program (var, or assigned with :=). */
|
|
18
|
+
isVar?: boolean;
|
|
19
|
+
decl?: Span;
|
|
20
|
+
/** A pure variable's domain (see `Base_.dom`). */
|
|
21
|
+
dom?: string;
|
|
22
|
+
}
|
|
23
|
+
interface Base_ extends Span {
|
|
24
|
+
/** Type, set by the checker. */
|
|
25
|
+
ty?: Ty;
|
|
26
|
+
/** Depends on a variable that changes while a bar is evaluated (state, locals, loop counters). */
|
|
27
|
+
st?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Whose bars the value lives on, set by the checker: "~" a constant (no bars of its own), "@" the chart's bars (the
|
|
30
|
+
* default), or the key of the outside series whose own bars it is computed on. See check.ts, `combineDom`.
|
|
31
|
+
*/
|
|
32
|
+
dom?: string;
|
|
33
|
+
}
|
|
34
|
+
/** `float` is how the literal was written: with a dot or an exponent (0.0, 1., 1e3) it is a float whatever its value. */
|
|
35
|
+
export interface NumLit extends Base_ {
|
|
36
|
+
k: "num";
|
|
37
|
+
value: number;
|
|
38
|
+
float: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface StrLit extends Base_ {
|
|
41
|
+
k: "str";
|
|
42
|
+
value: string;
|
|
43
|
+
}
|
|
44
|
+
export interface BoolLit extends Base_ {
|
|
45
|
+
k: "bool";
|
|
46
|
+
value: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface ColorLit extends Base_ {
|
|
49
|
+
k: "color";
|
|
50
|
+
value: string;
|
|
51
|
+
}
|
|
52
|
+
export interface Ident extends Base_ {
|
|
53
|
+
k: "id";
|
|
54
|
+
name: string;
|
|
55
|
+
sym?: Sym;
|
|
56
|
+
}
|
|
57
|
+
export interface Unary extends Base_ {
|
|
58
|
+
k: "un";
|
|
59
|
+
op: "-" | "+" | "not";
|
|
60
|
+
x: Expr;
|
|
61
|
+
}
|
|
62
|
+
export interface Binary extends Base_ {
|
|
63
|
+
k: "bin";
|
|
64
|
+
op: string;
|
|
65
|
+
a: Expr;
|
|
66
|
+
b: Expr;
|
|
67
|
+
}
|
|
68
|
+
export interface Ternary extends Base_ {
|
|
69
|
+
k: "tern";
|
|
70
|
+
c: Expr;
|
|
71
|
+
a: Expr;
|
|
72
|
+
b: Expr;
|
|
73
|
+
}
|
|
74
|
+
export interface Arg {
|
|
75
|
+
name: string | null;
|
|
76
|
+
nameSpan?: Span;
|
|
77
|
+
value: Expr;
|
|
78
|
+
}
|
|
79
|
+
export interface Call extends Base_ {
|
|
80
|
+
k: "call";
|
|
81
|
+
callee: Expr; /** For outside(): the key of the series it reads, and whether it has a timeframe of its own (then what is computed on it runs on its own bars). */
|
|
82
|
+
feed?: string;
|
|
83
|
+
own?: boolean;
|
|
84
|
+
args: Arg[]; /** Resolved signature name, e.g. "ta.sma". */
|
|
85
|
+
fn?: string; /** Arguments in parameter order (null = omitted). */
|
|
86
|
+
bound?: (Expr | null)[];
|
|
87
|
+
}
|
|
88
|
+
export interface Member extends Base_ {
|
|
89
|
+
k: "mem";
|
|
90
|
+
obj: Expr;
|
|
91
|
+
name: string;
|
|
92
|
+
nameSpan: Span; /** A namespace constant's value (math.pi, color.red, plot.style_line). */
|
|
93
|
+
cv?: number | string;
|
|
94
|
+
}
|
|
95
|
+
export interface Index extends Base_ {
|
|
96
|
+
k: "idx";
|
|
97
|
+
x: Expr;
|
|
98
|
+
i: Expr;
|
|
99
|
+
}
|
|
100
|
+
export interface ArrayLit extends Base_ {
|
|
101
|
+
k: "arr";
|
|
102
|
+
items: Expr[];
|
|
103
|
+
}
|
|
104
|
+
export type Expr = NumLit | StrLit | BoolLit | ColorLit | Ident | Unary | Binary | Ternary | Call | Member | Index | ArrayLit;
|
|
105
|
+
export type TypeName = "int" | "float" | "bool" | "string" | "color";
|
|
106
|
+
export interface VarDecl extends Span {
|
|
107
|
+
k: "decl";
|
|
108
|
+
isVar: boolean;
|
|
109
|
+
type: TypeName | null;
|
|
110
|
+
name: string;
|
|
111
|
+
nameSpan: Span;
|
|
112
|
+
init: Expr;
|
|
113
|
+
sym?: Sym;
|
|
114
|
+
}
|
|
115
|
+
export interface TupleDecl extends Span {
|
|
116
|
+
k: "tuple";
|
|
117
|
+
names: {
|
|
118
|
+
name: string;
|
|
119
|
+
span: Span;
|
|
120
|
+
}[];
|
|
121
|
+
init: Expr;
|
|
122
|
+
syms?: Sym[];
|
|
123
|
+
}
|
|
124
|
+
export interface Assign extends Span {
|
|
125
|
+
k: "assign";
|
|
126
|
+
name: string;
|
|
127
|
+
nameSpan: Span;
|
|
128
|
+
op: ":=" | "+=" | "-=" | "*=" | "/=" | "%=";
|
|
129
|
+
value: Expr;
|
|
130
|
+
sym?: Sym;
|
|
131
|
+
}
|
|
132
|
+
export interface If extends Span {
|
|
133
|
+
k: "if";
|
|
134
|
+
cond: Expr;
|
|
135
|
+
then: Stmt[];
|
|
136
|
+
else: Stmt[] | null;
|
|
137
|
+
}
|
|
138
|
+
export interface For extends Span {
|
|
139
|
+
k: "for";
|
|
140
|
+
name: string;
|
|
141
|
+
nameSpan: Span;
|
|
142
|
+
lo: Expr;
|
|
143
|
+
hi: Expr;
|
|
144
|
+
by: Expr | null;
|
|
145
|
+
body: Stmt[];
|
|
146
|
+
sym?: Sym;
|
|
147
|
+
}
|
|
148
|
+
export interface ExprStmt extends Span {
|
|
149
|
+
k: "expr";
|
|
150
|
+
expr: Expr;
|
|
151
|
+
}
|
|
152
|
+
export type Stmt = VarDecl | TupleDecl | Assign | If | For | ExprStmt;
|
|
153
|
+
export interface Program {
|
|
154
|
+
body: Stmt[];
|
|
155
|
+
}
|
|
156
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { InputDef, StudyDef } from "@alphacharts/indicators";
|
|
2
|
+
import type { Ty } from "./ast.js";
|
|
3
|
+
export declare const FLOAT_S: Ty;
|
|
4
|
+
export declare const INT_S: Ty;
|
|
5
|
+
export declare const BOOL_S: Ty;
|
|
6
|
+
export declare const t: (b: Ty["b"], q?: Ty["q"]) => Ty;
|
|
7
|
+
export declare const tuple: (elems: Ty[]) => Ty;
|
|
8
|
+
/** The fields of an outside series a script can read. */
|
|
9
|
+
export declare const OUTSIDE_FIELDS: readonly ["open", "high", "low", "close", "volume"];
|
|
10
|
+
export declare const NAMESPACES: ReadonlySet<string>;
|
|
11
|
+
/** Series available everywhere. `needs` is what the study must be given. */
|
|
12
|
+
export declare const BUILTIN_SERIES: Readonly<Record<string, {
|
|
13
|
+
ty: Ty;
|
|
14
|
+
needs: "value" | "ohlc" | "ohlcv";
|
|
15
|
+
}>>;
|
|
16
|
+
export declare const COLORS: Readonly<Record<string, string>>;
|
|
17
|
+
/** Constants reachable as `namespace.name`. */
|
|
18
|
+
export declare const MEMBER_CONSTS: Readonly<Record<string, {
|
|
19
|
+
ty: Ty;
|
|
20
|
+
value: number | string;
|
|
21
|
+
}>>;
|
|
22
|
+
export declare const ENUMS: {
|
|
23
|
+
plotStyle: string[];
|
|
24
|
+
lineStyle: string[];
|
|
25
|
+
shape: string[];
|
|
26
|
+
location: string[];
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* series: a numeric (or bool) series, any qualifier. num/int/bool/string/color: simple values (const or input).
|
|
30
|
+
* `enum`: one of a set, written as the namespace constant. strlist: an array literal of string literals.
|
|
31
|
+
*/
|
|
32
|
+
export type PKind = "series" | "num" | "int" | "bool" | "string" | "color" | "enum" | "strlist" | "plot" | "any";
|
|
33
|
+
export interface Param {
|
|
34
|
+
name: string;
|
|
35
|
+
kind: PKind;
|
|
36
|
+
opt?: boolean;
|
|
37
|
+
/** For "enum". */
|
|
38
|
+
oneOf?: readonly string[];
|
|
39
|
+
/** For "int"/"num": bounds checked when the argument is a literal; checked again at build otherwise. */
|
|
40
|
+
min?: number;
|
|
41
|
+
max?: number;
|
|
42
|
+
/** For generic study inputs: the input this parameter feeds. */
|
|
43
|
+
input?: InputDef;
|
|
44
|
+
}
|
|
45
|
+
export interface Sig {
|
|
46
|
+
/** Fully qualified name: "ta.sma", "nz". */
|
|
47
|
+
name: string;
|
|
48
|
+
params: Param[];
|
|
49
|
+
ret: Ty;
|
|
50
|
+
/** What the study must be given for this call to work. */
|
|
51
|
+
needs?: "value" | "ohlc" | "ohlcv";
|
|
52
|
+
/** Kind of lowering. */
|
|
53
|
+
op: "scalar" | "kernel" | "study" | "special";
|
|
54
|
+
/** Scalar math: elementwise. */
|
|
55
|
+
fn?: (...a: number[]) => number;
|
|
56
|
+
/** Generic study: the definition and the order of its non-source inputs. */
|
|
57
|
+
study?: StudyDef;
|
|
58
|
+
}
|
|
59
|
+
export declare const SIGS: Map<string, Sig>;
|
|
60
|
+
export declare const TA_TR: Ty;
|
|
61
|
+
export declare const studyFnName: (id: string) => string;
|
|
62
|
+
/** Names the editor can offer: every callable, every constant, the series and the keywords. */
|
|
63
|
+
export declare function completionNames(): {
|
|
64
|
+
label: string;
|
|
65
|
+
kind: "function" | "constant" | "variable" | "keyword" | "namespace";
|
|
66
|
+
detail?: string;
|
|
67
|
+
}[];
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Arg, Expr, Program, Stmt, Sym } from "./ast.js";
|
|
2
|
+
import type { Reporter, Span } from "./diag.js";
|
|
3
|
+
import { type Dependency } from "./feeds.js";
|
|
4
|
+
export type ColorRef = {
|
|
5
|
+
value: string;
|
|
6
|
+
} | {
|
|
7
|
+
input: string;
|
|
8
|
+
};
|
|
9
|
+
export interface InputSpec {
|
|
10
|
+
key: string;
|
|
11
|
+
kind: "int" | "float" | "bool" | "string" | "source" | "color";
|
|
12
|
+
label: string;
|
|
13
|
+
default: number | boolean | string;
|
|
14
|
+
min?: number;
|
|
15
|
+
max?: number;
|
|
16
|
+
step?: number;
|
|
17
|
+
options?: string[];
|
|
18
|
+
span: Span;
|
|
19
|
+
}
|
|
20
|
+
export interface PlotSpec {
|
|
21
|
+
kind: "line" | "histogram" | "area" | "hline" | "fill" | "markers" | "barcolor" | "bgcolor";
|
|
22
|
+
key: string;
|
|
23
|
+
title: string;
|
|
24
|
+
color: ColorRef;
|
|
25
|
+
/** A line coloured per bar: `color` where `cond` is false or absent, this colour where it is true. */
|
|
26
|
+
colorWhen?: {
|
|
27
|
+
cond: Expr;
|
|
28
|
+
color: string;
|
|
29
|
+
};
|
|
30
|
+
colorDown?: string;
|
|
31
|
+
width?: number;
|
|
32
|
+
lineStyle?: string;
|
|
33
|
+
offset?: number;
|
|
34
|
+
/** A bar shift written as an expression known when the study is built (`-right`): an int input or a literal combination of them. Wins over `offset`. */
|
|
35
|
+
offsetExpr?: Expr;
|
|
36
|
+
/** Series plotted (line/histogram/area/markers), the price of an hline, or the condition of a barcolor / bgcolor. */
|
|
37
|
+
expr?: Expr;
|
|
38
|
+
/** fill: indexes into the plots. */
|
|
39
|
+
a?: number;
|
|
40
|
+
b?: number;
|
|
41
|
+
/** hline: a fill draws between it and another plot, so its level is also a column (constant on every bar). */
|
|
42
|
+
column?: boolean;
|
|
43
|
+
shape?: string;
|
|
44
|
+
position?: string;
|
|
45
|
+
/** plotshape: only the most recent `last` marked bars keep their mark. */
|
|
46
|
+
last?: number;
|
|
47
|
+
/** plotshape: only marks on the final `within` bars are kept. */
|
|
48
|
+
within?: number;
|
|
49
|
+
span: Span;
|
|
50
|
+
}
|
|
51
|
+
export interface Plan {
|
|
52
|
+
title: string;
|
|
53
|
+
overlay: boolean;
|
|
54
|
+
/** Which price axis the script's series use. */
|
|
55
|
+
scale: "left" | "right";
|
|
56
|
+
/** Every `outside(...)` call, once per distinct (symbol, field, timeframe), in order of first use. */
|
|
57
|
+
dependencies: Dependency[];
|
|
58
|
+
inputs: InputSpec[];
|
|
59
|
+
plots: PlotSpec[];
|
|
60
|
+
body: Stmt[];
|
|
61
|
+
needs: "value" | "ohlc" | "ohlcv";
|
|
62
|
+
/** Frame size of the per-bar program. */
|
|
63
|
+
slots: number;
|
|
64
|
+
/** Top-level variables kept in columns by the per-bar program, in declaration order. */
|
|
65
|
+
stateVars: Sym[];
|
|
66
|
+
}
|
|
67
|
+
/** Domains: a value lives on the chart's bars ("@"), on an outside series' own bars (its key), or on none (a constant, "~"). */
|
|
68
|
+
export declare const CHART_DOM = "@";
|
|
69
|
+
export declare const CONST_DOM = "~";
|
|
70
|
+
/**
|
|
71
|
+
* The domain of an operation on operands of these domains: constants take the other's; operands of one outside series
|
|
72
|
+
* stay on its bars (so a window of 14 is 14 of its bars); anything else is on the chart's bars, each outside operand
|
|
73
|
+
* meeting them through the join first.
|
|
74
|
+
*/
|
|
75
|
+
export declare function combineDom(...doms: string[]): string;
|
|
76
|
+
export declare function withTransparency(hex: string, transp: number): string;
|
|
77
|
+
export declare function check(prog: Program, rep: Reporter, limits?: Readonly<import("./limits.js").Limits>): Plan;
|
|
78
|
+
export type { Arg };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { StudyDef } from "@alphacharts/indicators";
|
|
2
|
+
import type { Plan } from "./check.js";
|
|
3
|
+
import { type Limits } from "./limits.js";
|
|
4
|
+
export interface ColorInput {
|
|
5
|
+
key: string;
|
|
6
|
+
label: string;
|
|
7
|
+
default: string;
|
|
8
|
+
plotKeys: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface Compiled {
|
|
11
|
+
def: StudyDef;
|
|
12
|
+
colorInputs: ColorInput[];
|
|
13
|
+
}
|
|
14
|
+
export declare function generate(plan: Plan, source: string, limits?: Limits): Compiled;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { StudyDef } from "@alphacharts/indicators";
|
|
2
|
+
import { type Diagnostic } from "./diag.js";
|
|
3
|
+
import { type InputSpec, type Plan, type PlotSpec } from "./check.js";
|
|
4
|
+
import type { Expr, Stmt } from "./ast.js";
|
|
5
|
+
import { type ColorInput } from "./codegen.js";
|
|
6
|
+
import type { Dependency } from "./feeds.js";
|
|
7
|
+
import { type Limits } from "./limits.js";
|
|
8
|
+
/** One output statement of the script. `expr` is the series plotted (plot, plotshape) or the price of an hline; fill has none. */
|
|
9
|
+
export interface PlotView {
|
|
10
|
+
kind: PlotSpec["kind"];
|
|
11
|
+
title: string;
|
|
12
|
+
expr: Expr | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* What the script means, read off the checked syntax tree (nothing is executed). Read-only: the tree is shared with the
|
|
16
|
+
* compiled study, do not change it. Names are resolved: an `id` node's `sym` is the declaration it refers to (same object for every use
|
|
17
|
+
* and every assignment of one variable), `ty` is every expression's type, `call.fn` the resolved function name ("ta.sma").
|
|
18
|
+
*/
|
|
19
|
+
export interface ScriptPlan {
|
|
20
|
+
overlay: boolean;
|
|
21
|
+
/** The price axis the script's series use. */
|
|
22
|
+
scale: "left" | "right";
|
|
23
|
+
/**
|
|
24
|
+
* The outside series the script reads, one entry per distinct `outside(symbol, field, timeframe)` call, found by
|
|
25
|
+
* reading the program (nothing is run). `symbol` / `timeframe` are null for "this chart's". The host loads them and
|
|
26
|
+
* gives them to the script (`feedsOf(plan.dependencies)` groups them by series).
|
|
27
|
+
*/
|
|
28
|
+
dependencies: readonly Dependency[];
|
|
29
|
+
/** The most the script reads: "value" (close/time only), "ohlc", or "ohlcv" when it reads volume (the `volume` series or a study that does). */
|
|
30
|
+
needs: Plan["needs"];
|
|
31
|
+
plots: readonly PlotView[];
|
|
32
|
+
/** Top-level statements, in order. */
|
|
33
|
+
body: readonly Stmt[];
|
|
34
|
+
}
|
|
35
|
+
export interface CompileOk {
|
|
36
|
+
ok: true;
|
|
37
|
+
study: StudyDef;
|
|
38
|
+
/** Inputs the study schema has no type for (input.color): applied as plot colours. */
|
|
39
|
+
colorInputs: ColorInput[];
|
|
40
|
+
inputs: InputSpec[];
|
|
41
|
+
title: string;
|
|
42
|
+
/** Warnings only. */
|
|
43
|
+
diagnostics: Diagnostic[];
|
|
44
|
+
source: string;
|
|
45
|
+
plan: ScriptPlan;
|
|
46
|
+
}
|
|
47
|
+
export interface CompileFailed {
|
|
48
|
+
ok: false;
|
|
49
|
+
diagnostics: Diagnostic[];
|
|
50
|
+
}
|
|
51
|
+
export type CompileResult = CompileOk | CompileFailed;
|
|
52
|
+
export declare function compile(source: string, limits?: Limits): CompileResult;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export interface Diagnostic {
|
|
2
|
+
severity: "error" | "warning";
|
|
3
|
+
message: string;
|
|
4
|
+
/** 1-based. */
|
|
5
|
+
line: number;
|
|
6
|
+
column: number;
|
|
7
|
+
endLine: number;
|
|
8
|
+
endColumn: number;
|
|
9
|
+
/** Character offsets into the source, `to` exclusive. */
|
|
10
|
+
from: number;
|
|
11
|
+
to: number;
|
|
12
|
+
}
|
|
13
|
+
export interface Span {
|
|
14
|
+
from: number;
|
|
15
|
+
to: number;
|
|
16
|
+
}
|
|
17
|
+
/** Converts offsets to line:column for one source text. */
|
|
18
|
+
export declare class LineMap {
|
|
19
|
+
readonly text: string;
|
|
20
|
+
private readonly starts;
|
|
21
|
+
constructor(text: string);
|
|
22
|
+
at(offset: number): {
|
|
23
|
+
line: number;
|
|
24
|
+
column: number;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** Collects diagnostics; stops accepting errors after `max` (the last one says so). */
|
|
28
|
+
export declare class Reporter {
|
|
29
|
+
private readonly max;
|
|
30
|
+
readonly list: Diagnostic[];
|
|
31
|
+
private readonly map;
|
|
32
|
+
private errors;
|
|
33
|
+
constructor(text: string, max?: number);
|
|
34
|
+
get errorCount(): number;
|
|
35
|
+
error(message: string, span: Span): void;
|
|
36
|
+
warn(message: string, span: Span): void;
|
|
37
|
+
private add;
|
|
38
|
+
}
|
|
39
|
+
/** Thrown for failures found while building or running a script, with the range of the offending code. */
|
|
40
|
+
export declare class ScriptError extends Error {
|
|
41
|
+
readonly span: Span | null;
|
|
42
|
+
readonly kind: "build" | "runtime" | "budget";
|
|
43
|
+
constructor(message: string, span?: Span | null, kind?: "build" | "runtime" | "budget");
|
|
44
|
+
}
|
|
45
|
+
export declare function formatDiagnostic(d: Diagnostic): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Completion } from "@codemirror/autocomplete";
|
|
2
|
+
import { StreamLanguage } from "@codemirror/language";
|
|
3
|
+
import type { Diagnostic } from "../diag.js";
|
|
4
|
+
export interface ScriptEditorAdapter {
|
|
5
|
+
mount(el: HTMLElement, opts: {
|
|
6
|
+
value: string;
|
|
7
|
+
onChange(v: string): void;
|
|
8
|
+
onRun(v: string): void;
|
|
9
|
+
diagnostics: Diagnostic[];
|
|
10
|
+
}): {
|
|
11
|
+
setDiagnostics(d: Diagnostic[]): void;
|
|
12
|
+
destroy(): void;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
interface LState {
|
|
16
|
+
}
|
|
17
|
+
export declare const scriptLanguage: StreamLanguage<LState>;
|
|
18
|
+
/** Names declared in the text (variables, inputs, loop counters): `name =`, `var name =`, `float name =`, `for i =`, `[a, b] =`. */
|
|
19
|
+
export declare function declaredNames(text: string): string[];
|
|
20
|
+
/** Completion options for the word before the cursor (exported for tests). */
|
|
21
|
+
export declare function completionsFor(text: string, word: string): Completion[];
|
|
22
|
+
export declare function createScriptEditorAdapter(): ScriptEditorAdapter;
|
|
23
|
+
export type { Diagnostic };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { FeedAlign, FeedField } from "@alphacharts/indicators";
|
|
2
|
+
export { describeJoin } from "@alphacharts/indicators";
|
|
3
|
+
export type { FeedField, JoinReason, JoinReport } from "@alphacharts/indicators";
|
|
4
|
+
/** One `outside(symbol, field, timeframe)` call: `symbol` / `timeframe` are null when the script left them out (this chart's). */
|
|
5
|
+
export interface Dependency {
|
|
6
|
+
symbol: string | null;
|
|
7
|
+
field: FeedField;
|
|
8
|
+
timeframe: string | null;
|
|
9
|
+
}
|
|
10
|
+
/** One outside series the host must load: a distinct (symbol, timeframe), carrying every field the script reads from it. */
|
|
11
|
+
export interface FeedRef {
|
|
12
|
+
/** Pass to `handle.setSeries` / `handle.pushSeries`. */
|
|
13
|
+
key: string;
|
|
14
|
+
symbol: string | null;
|
|
15
|
+
timeframe: string | null;
|
|
16
|
+
fields: FeedField[];
|
|
17
|
+
}
|
|
18
|
+
/** Length in ms of a timeframe like "5m", "1h", "1d", "1w", or null when it is not written that way. */
|
|
19
|
+
export declare function parseTimeframe(tf: string): number | null;
|
|
20
|
+
/** The key of an outside series: symbol and timeframe, either empty for "this chart's". Symbols are opaque, so the separator is an unprintable one. */
|
|
21
|
+
export declare function feedKey(symbol: string | null, timeframe: string | null): string;
|
|
22
|
+
/** The distinct outside series a script reads, in order of first use, each with its fields. */
|
|
23
|
+
export declare function feedsOf(deps: readonly Dependency[]): FeedRef[];
|
|
24
|
+
/**
|
|
25
|
+
* How an outside series on `timeframe` (null: the chart's own) joins a chart whose bars last `intervalMs`:
|
|
26
|
+
* the same length joins on exact time ("same"); a longer one joins on the bar that has finished ("closed", its
|
|
27
|
+
* length is the nominal bar length); a shorter one is refused, since it would have to be aggregated and a
|
|
28
|
+
* silent choice of how would be a number nobody asked for.
|
|
29
|
+
*/
|
|
30
|
+
export declare function alignFor(timeframe: string | null, intervalMs: number): {
|
|
31
|
+
align: FeedAlign;
|
|
32
|
+
spanMs: number;
|
|
33
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { compile } from "./compile.js";
|
|
2
|
+
export type { CompileResult, CompileOk, CompileFailed, ScriptPlan, PlotView } from "./compile.js";
|
|
3
|
+
export type { Expr, Stmt, Sym, Ty, Call, Ident, NumLit, VarDecl, TupleDecl, Assign, If, For, ExprStmt, Arg } from "./ast.js";
|
|
4
|
+
export type { Diagnostic } from "./diag.js";
|
|
5
|
+
export { formatDiagnostic, ScriptError } from "./diag.js";
|
|
6
|
+
export type { ColorInput } from "./codegen.js";
|
|
7
|
+
export type { InputSpec } from "./check.js";
|
|
8
|
+
export { alignFor, describeJoin, feedKey, feedsOf, parseTimeframe } from "./feeds.js";
|
|
9
|
+
export type { Dependency, FeedField, FeedRef, JoinReason, JoinReport } from "./feeds.js";
|
|
10
|
+
export { DEFAULT_LIMITS } from "./limits.js";
|
|
11
|
+
export type { Limits } from "./limits.js";
|
|
12
|
+
export { runScript, restoreScript, ScriptDiagnosticsError } from "./run.js";
|
|
13
|
+
export type { ScriptHandle, SavedScript, RunScriptOptions } from "./run.js";
|
|
14
|
+
export { ScriptRunner } from "./runner.js";
|
|
15
|
+
export { lockdown, serveScripts, BLOCKED_GLOBALS } from "./sandbox.js";
|
|
16
|
+
export { createScriptRunAdapter } from "./ui-adapter.js";
|
|
17
|
+
export type { ScriptRunAdapter } from "./ui-adapter.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Reporter } from "./diag.js";
|
|
2
|
+
export type TokKind = "num" | "str" | "color" | "ident" | "kw" | "op" | "newline" | "indent" | "dedent" | "eof";
|
|
3
|
+
export interface Token {
|
|
4
|
+
kind: TokKind;
|
|
5
|
+
/** Text for ident/kw/op; decoded value for str; digits for num; "#rrggbb[aa]" for color. */
|
|
6
|
+
text: string;
|
|
7
|
+
value?: number;
|
|
8
|
+
from: number;
|
|
9
|
+
to: number;
|
|
10
|
+
}
|
|
11
|
+
export declare const KEYWORDS: ReadonlySet<string>;
|
|
12
|
+
/** Words that belong to other languages (or to features this one leaves out): refused with a pointer. */
|
|
13
|
+
export declare const RESERVED: Readonly<Record<string, string>>;
|
|
14
|
+
export declare function lex(src: string, rep: Reporter): Token[];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface Limits {
|
|
2
|
+
/** Largest period / length a ta.* call or history offset may use. Matches the indicators' own maximum. */
|
|
3
|
+
maxPeriod: number;
|
|
4
|
+
/** Iterations of one `for` statement execution. */
|
|
5
|
+
maxLoopIterations: number;
|
|
6
|
+
/** Loop iterations in the evaluation of one bar (the count restarts every bar, so it does not depend on the history length). */
|
|
7
|
+
maxSteps: number;
|
|
8
|
+
/** Columns of the compiled graph (every named series, ta.* result and intermediate). */
|
|
9
|
+
maxColumns: number;
|
|
10
|
+
/** Bytes a script may hold: columns x bars x 8, counted three times (the worker keeps a copy, and a column grows by half when a bar is appended). */
|
|
11
|
+
maxBytes: number;
|
|
12
|
+
/** Bars a script runs over. */
|
|
13
|
+
maxBars: number;
|
|
14
|
+
/** Nodes of the syntax tree / source length: refuses pathological inputs before they are parsed. */
|
|
15
|
+
maxSourceChars: number;
|
|
16
|
+
/** Distinct outside series (symbol and timeframe pairs) a script may read. Each is held twice (worker and page), in six columns of its own length. */
|
|
17
|
+
maxFeeds: number;
|
|
18
|
+
/** Wall-clock budget of one batch in the worker before it is terminated, milliseconds. */
|
|
19
|
+
batchMs: number;
|
|
20
|
+
/** Wall-clock budget of one tick, milliseconds. */
|
|
21
|
+
tickMs: number;
|
|
22
|
+
}
|
|
23
|
+
export declare const DEFAULT_LIMITS: Readonly<Limits>;
|
|
24
|
+
/** Largest history offset `x[n]`. */
|
|
25
|
+
export declare const MAX_HISTORY = 1000000;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type Study } from "@alphacharts/indicators";
|
|
2
|
+
import type { Chart, Series, SeriesType } from "@alphacharts/core";
|
|
3
|
+
import { type CompileOk } from "./compile.js";
|
|
4
|
+
import { type FeedRef } from "./feeds.js";
|
|
5
|
+
import { type Diagnostic } from "./diag.js";
|
|
6
|
+
import { ScriptRunner } from "./runner.js";
|
|
7
|
+
import type { Limits } from "./limits.js";
|
|
8
|
+
import type { FeedBar, FeedBars, InputValue, WorkerLike } from "@alphacharts/indicators";
|
|
9
|
+
type SourceSeries = Series<"candles" | "bars" | "line" | "area" | "histogram">;
|
|
10
|
+
type VolumeSeries = Series<"histogram" | "line" | "area">;
|
|
11
|
+
export declare class ScriptDiagnosticsError extends Error {
|
|
12
|
+
readonly diagnostics: Diagnostic[];
|
|
13
|
+
constructor(diagnostics: Diagnostic[]);
|
|
14
|
+
}
|
|
15
|
+
export interface RunScriptOptions {
|
|
16
|
+
volume?: VolumeSeries;
|
|
17
|
+
/** Share one runner (one worker) between scripts. Default: a private one that `remove()` disposes. */
|
|
18
|
+
runner?: ScriptRunner;
|
|
19
|
+
/** Creates the worker, from the host's bundler (`new Worker(new URL("@alphacharts/script/worker", import.meta.url), { type: "module" })`). Required unless `runner` is given: the package never guesses where its worker lives. */
|
|
20
|
+
workerFactory?: () => WorkerLike;
|
|
21
|
+
limits?: Partial<Limits>;
|
|
22
|
+
/**
|
|
23
|
+
* Length of one bar of the source series, ms. Required when the script reads outside series (`compile().plan.dependencies`):
|
|
24
|
+
* it decides whether each joins on exact time (same length) or on the bar that has finished (longer).
|
|
25
|
+
*/
|
|
26
|
+
intervalMs?: number;
|
|
27
|
+
id?: string;
|
|
28
|
+
/** Called when the script fails at run time (budget, runtime error, worker failure). */
|
|
29
|
+
onError?: (d: Diagnostic) => void;
|
|
30
|
+
}
|
|
31
|
+
export interface ScriptHandle {
|
|
32
|
+
readonly study: Study;
|
|
33
|
+
readonly compiled: CompileOk;
|
|
34
|
+
/** The outside series the script reads (what to load and pass to `setSeries`), empty for a script that reads none. */
|
|
35
|
+
readonly feeds: readonly FeedRef[];
|
|
36
|
+
/**
|
|
37
|
+
* Give the script the bars of outside series `key` (one of `feeds[i].key`), in that series' own time (UTC ms, strictly
|
|
38
|
+
* increasing), replacing what it had, and compute again. The script keeps its own copy.
|
|
39
|
+
*/
|
|
40
|
+
setSeries(key: string, bars: FeedBars): void;
|
|
41
|
+
/**
|
|
42
|
+
* A live bar of outside series `key`: the same time as its last bar revises it, a later time appends. Only the chart's
|
|
43
|
+
* last bar is evaluated again, and only when it sees a different bar of that series; otherwise nothing is computed or
|
|
44
|
+
* redrawn. Does nothing until `setSeries` has given the series.
|
|
45
|
+
*/
|
|
46
|
+
pushSeries(key: string, bar: FeedBar): void;
|
|
47
|
+
/** Last run-time failure, if any. */
|
|
48
|
+
error: Diagnostic | null;
|
|
49
|
+
/**
|
|
50
|
+
* Change inputs: those in `partial` take their value, the others keep theirs, and the keys in `reset` go back to the
|
|
51
|
+
* script's defaults (colour inputs included). Outside series the script was given stay.
|
|
52
|
+
*/
|
|
53
|
+
setInputs(partial: Readonly<Record<string, InputValue>>, reset?: readonly string[]): void;
|
|
54
|
+
remove(): void;
|
|
55
|
+
ready(): Promise<void>;
|
|
56
|
+
toJSON(): SavedScript;
|
|
57
|
+
}
|
|
58
|
+
export interface SavedScript {
|
|
59
|
+
version: 1;
|
|
60
|
+
source: string;
|
|
61
|
+
inputs: Record<string, InputValue>;
|
|
62
|
+
series: string;
|
|
63
|
+
volume?: string;
|
|
64
|
+
visible: boolean;
|
|
65
|
+
}
|
|
66
|
+
export declare function runScript(chart: Chart, source: SourceSeries, text: string, inputs: Readonly<Record<string, InputValue>>, opts: RunScriptOptions): ScriptHandle;
|
|
67
|
+
/** Recreate a saved script (SavedScript from `toJSON`) on a chart that holds its series. */
|
|
68
|
+
export declare function restoreScript(chart: Chart, saved: SavedScript, opts: RunScriptOptions): ScriptHandle;
|
|
69
|
+
export type { SeriesType };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type BarInput, type FeedBar, type RunRequest, type RunResult, type StudyDef, type StudyRunner, type WorkerLike } from "@alphacharts/indicators";
|
|
2
|
+
import { ScriptError } from "./diag.js";
|
|
3
|
+
import { type Limits } from "./limits.js";
|
|
4
|
+
export interface ScriptInfo {
|
|
5
|
+
sid: number;
|
|
6
|
+
source: string;
|
|
7
|
+
}
|
|
8
|
+
export interface TickListener {
|
|
9
|
+
values(index: number, values: Float64Array): void;
|
|
10
|
+
error(e: ScriptError): void;
|
|
11
|
+
}
|
|
12
|
+
export declare class ScriptRunner implements StudyRunner {
|
|
13
|
+
private readonly factory;
|
|
14
|
+
private worker;
|
|
15
|
+
private nextId;
|
|
16
|
+
private nextSid;
|
|
17
|
+
private readonly infos;
|
|
18
|
+
private readonly pending;
|
|
19
|
+
private readonly listeners;
|
|
20
|
+
private tickTimers;
|
|
21
|
+
/** Instances whose computed state died with a terminated worker: their bars are not sent until a new batch result. */
|
|
22
|
+
private readonly dead;
|
|
23
|
+
private limits;
|
|
24
|
+
private disposed;
|
|
25
|
+
constructor(factory: () => WorkerLike, limits?: Partial<Limits>);
|
|
26
|
+
/** Change budgets for later requests. */
|
|
27
|
+
setLimits(l: Partial<Limits>): void;
|
|
28
|
+
/** Bind a (mirror) definition to a script instance. Returns the instance id. */
|
|
29
|
+
attach(def: StudyDef, source: string, listener: TickListener): number;
|
|
30
|
+
detach(sid: number): void;
|
|
31
|
+
canRun(def: StudyDef): boolean;
|
|
32
|
+
private ensure;
|
|
33
|
+
private post;
|
|
34
|
+
run(def: StudyDef, req: RunRequest): {
|
|
35
|
+
promise: Promise<RunResult>;
|
|
36
|
+
cancel: () => void;
|
|
37
|
+
};
|
|
38
|
+
/** Send one bar of a tick (append or revision) to the script instance. */
|
|
39
|
+
sendBar(sid: number, index: number, bar: BarInput): void;
|
|
40
|
+
/** Send one live bar of an outside series to the script instance; it answers with the chart's last bar's values, or `idle` when nothing it sees changed. */
|
|
41
|
+
feedBar(def: StudyDef, key: string, bar: FeedBar): void;
|
|
42
|
+
private arm;
|
|
43
|
+
private clearTick;
|
|
44
|
+
private settle;
|
|
45
|
+
private onMessage;
|
|
46
|
+
private timeout;
|
|
47
|
+
/**
|
|
48
|
+
* Kill the worker. Every instance lost its computed state with it: each one is told, and stops
|
|
49
|
+
* sending bars until it is run again (a new batch, e.g. after an input change).
|
|
50
|
+
*/
|
|
51
|
+
private terminateWorker;
|
|
52
|
+
private fail;
|
|
53
|
+
dispose(): void;
|
|
54
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|