oakscriptjs 0.13.2 → 0.14.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/AGENTS.md +6 -1
- package/README.md +1 -1
- package/bin/oakscript.mjs +5 -0
- package/dist/cjs/check/checks.d.ts +78 -0
- package/dist/cjs/check/checks.d.ts.map +1 -0
- package/dist/cjs/check/checks.js +109 -0
- package/dist/cjs/check/checks.js.map +7 -0
- package/dist/cjs/check/format.d.ts +26 -0
- package/dist/cjs/check/format.d.ts.map +1 -0
- package/dist/cjs/check/format.js +106 -0
- package/dist/cjs/check/format.js.map +7 -0
- package/dist/cjs/check/harness.d.ts +94 -0
- package/dist/cjs/check/harness.d.ts.map +1 -0
- package/dist/cjs/check/harness.js +302 -0
- package/dist/cjs/check/harness.js.map +7 -0
- package/dist/cjs/check/index.d.ts +253 -0
- package/dist/cjs/check/index.d.ts.map +1 -0
- package/dist/cjs/check/index.js +466 -0
- package/dist/cjs/check/index.js.map +7 -0
- package/dist/cjs/check/node.d.ts +53 -0
- package/dist/cjs/check/node.d.ts.map +1 -0
- package/dist/cjs/check/node.js +318 -0
- package/dist/cjs/check/node.js.map +7 -0
- package/dist/cjs/check/spec.d.ts +44 -0
- package/dist/cjs/check/spec.d.ts.map +1 -0
- package/dist/cjs/check/spec.js +199 -0
- package/dist/cjs/check/spec.js.map +7 -0
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/runtime/series.d.ts +6 -0
- package/dist/cjs/runtime/series.d.ts.map +1 -1
- package/dist/cjs/runtime/series.js +15 -0
- package/dist/cjs/runtime/series.js.map +2 -2
- package/dist/cjs/script/constants.d.ts +200 -0
- package/dist/cjs/script/constants.d.ts.map +1 -0
- package/dist/cjs/script/constants.js +217 -0
- package/dist/cjs/script/constants.js.map +7 -0
- package/dist/cjs/script/drawing-args.d.ts +25 -0
- package/dist/cjs/script/drawing-args.d.ts.map +1 -0
- package/dist/cjs/script/drawing-args.js +203 -0
- package/dist/cjs/script/drawing-args.js.map +7 -0
- package/dist/cjs/script/globals.d.ts +127 -0
- package/dist/cjs/script/globals.d.ts.map +1 -0
- package/dist/cjs/script/globals.js +17 -0
- package/dist/cjs/script/globals.js.map +7 -0
- package/dist/cjs/script/index.d.ts +499 -166
- package/dist/cjs/script/index.d.ts.map +1 -1
- package/dist/cjs/script/index.js +236 -96
- package/dist/cjs/script/index.js.map +3 -3
- package/dist/esm/check/checks.d.ts +78 -0
- package/dist/esm/check/checks.d.ts.map +1 -0
- package/dist/esm/check/checks.js +95 -0
- package/dist/esm/check/checks.js.map +1 -0
- package/dist/esm/check/format.d.ts +26 -0
- package/dist/esm/check/format.d.ts.map +1 -0
- package/dist/esm/check/format.js +105 -0
- package/dist/esm/check/format.js.map +1 -0
- package/dist/esm/check/harness.d.ts +94 -0
- package/dist/esm/check/harness.d.ts.map +1 -0
- package/dist/esm/check/harness.js +317 -0
- package/dist/esm/check/harness.js.map +1 -0
- package/dist/esm/check/index.d.ts +253 -0
- package/dist/esm/check/index.d.ts.map +1 -0
- package/dist/esm/check/index.js +470 -0
- package/dist/esm/check/index.js.map +1 -0
- package/dist/esm/check/node.d.ts +53 -0
- package/dist/esm/check/node.d.ts.map +1 -0
- package/dist/esm/check/node.js +347 -0
- package/dist/esm/check/node.js.map +1 -0
- package/dist/esm/check/spec.d.ts +44 -0
- package/dist/esm/check/spec.d.ts.map +1 -0
- package/dist/esm/check/spec.js +198 -0
- package/dist/esm/check/spec.js.map +1 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/runtime/series.d.ts +6 -0
- package/dist/esm/runtime/series.d.ts.map +1 -1
- package/dist/esm/runtime/series.js +14 -0
- package/dist/esm/runtime/series.js.map +1 -1
- package/dist/esm/script/constants.d.ts +200 -0
- package/dist/esm/script/constants.d.ts.map +1 -0
- package/dist/esm/script/constants.js +151 -0
- package/dist/esm/script/constants.js.map +1 -0
- package/dist/esm/script/drawing-args.d.ts +25 -0
- package/dist/esm/script/drawing-args.d.ts.map +1 -0
- package/dist/esm/script/drawing-args.js +171 -0
- package/dist/esm/script/drawing-args.js.map +1 -0
- package/dist/esm/script/globals.d.ts +127 -0
- package/dist/esm/script/globals.d.ts.map +1 -0
- package/dist/esm/script/globals.js +28 -0
- package/dist/esm/script/globals.js.map +1 -0
- package/dist/esm/script/index.d.ts +499 -166
- package/dist/esm/script/index.d.ts.map +1 -1
- package/dist/esm/script/index.js +256 -83
- package/dist/esm/script/index.js.map +1 -1
- package/package.json +31 -1
- package/skills/oakscript/SKILL.md +62 -26
- package/skills/oakscript/examples/ma-cross.js +2 -2
- package/skills/oakscript/examples/mtf-trend-filter.js +3 -3
- package/skills/oakscript/reference/check.md +150 -0
- package/skills/oakscript/reference/errors.md +31 -7
- package/skills/oakscript/reference/pine-differences.md +17 -16
- package/skills/oakscript/reference/plotting.md +25 -19
- package/skills/oakscript/reference/script-structure.md +8 -5
- package/skills/oakscript/reference/timeframes-symbols.md +5 -1
- package/skills/oakscript/spec.schema.json +199 -0
- package/src/check/checks.ts +175 -0
- package/src/check/format.ts +117 -0
- package/src/check/harness.ts +372 -0
- package/src/check/index.ts +708 -0
- package/src/check/node.ts +368 -0
- package/src/check/spec.ts +200 -0
- package/src/index.ts +1 -1
- package/src/runtime/series.ts +19 -0
- package/src/script/constants.ts +169 -0
- package/src/script/drawing-args.ts +179 -0
- package/src/script/globals.ts +129 -0
- package/src/script/index.ts +457 -81
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var harness_exports = {};
|
|
30
|
+
__export(harness_exports, {
|
|
31
|
+
LIBRARY_PARAMETER: () => LIBRARY_PARAMETER,
|
|
32
|
+
SCRIPT_GLOBALS: () => SCRIPT_GLOBALS,
|
|
33
|
+
SCRIPT_PREFIX: () => SCRIPT_PREFIX,
|
|
34
|
+
SCRIPT_SUFFIX: () => SCRIPT_SUFFIX,
|
|
35
|
+
TestEngine: () => TestEngine,
|
|
36
|
+
compileScript: () => compileScript,
|
|
37
|
+
inferTimeframe: () => inferTimeframe,
|
|
38
|
+
rewriteImports: () => rewriteImports,
|
|
39
|
+
runScript: () => runScript,
|
|
40
|
+
scriptArguments: () => scriptArguments,
|
|
41
|
+
syntheticBars: () => syntheticBars,
|
|
42
|
+
testChart: () => testChart,
|
|
43
|
+
timeframeSeconds: () => timeframeSeconds,
|
|
44
|
+
wrapSource: () => wrapSource
|
|
45
|
+
});
|
|
46
|
+
module.exports = __toCommonJS(harness_exports);
|
|
47
|
+
var lib = __toESM(require("../index.js"), 1);
|
|
48
|
+
var api = __toESM(require("../script/index.js"), 1);
|
|
49
|
+
var import_script = require("../script/index.js");
|
|
50
|
+
const SCRIPT_GLOBALS = Object.keys(api).filter(
|
|
51
|
+
(k) => k !== "default" && k !== "executeScript" && /^[A-Za-z_$][\w$]*$/.test(k)
|
|
52
|
+
);
|
|
53
|
+
const LIBRARY_PARAMETER = "__oakscriptjs";
|
|
54
|
+
function scriptArguments() {
|
|
55
|
+
return [...SCRIPT_GLOBALS.map((k) => api[k]), lib];
|
|
56
|
+
}
|
|
57
|
+
function rewriteImports(source) {
|
|
58
|
+
return source.replace(/^([ \t]*)import\s*(\{[^}]*\}|\*\s+as\s+[A-Za-z_$][\w$]*)\s*from\s*(['"])([^'"]+)\3\s*;?/gm, (all, indent, what, _q, from) => {
|
|
59
|
+
if (from !== "oakscriptjs" && from !== "oakscriptjs/script") {
|
|
60
|
+
throw new SyntaxError(`A script can only import from "oakscriptjs" (found "${from}").`);
|
|
61
|
+
}
|
|
62
|
+
const lines = all.split("\n").length - 1;
|
|
63
|
+
const binding = what.startsWith("*") ? what.replace(/^\*\s+as\s+/, "") : what.replace(/\s+as\s+/g, ": ").replace(/\s+/g, " ");
|
|
64
|
+
return `${indent}const ${binding} = ${LIBRARY_PARAMETER};${"\n".repeat(lines)}`;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const SCRIPT_PREFIX = '"use strict"; return (function () { ';
|
|
68
|
+
const SCRIPT_SUFFIX = "\n})();";
|
|
69
|
+
function wrapSource(source) {
|
|
70
|
+
return SCRIPT_PREFIX + rewriteImports(source) + SCRIPT_SUFFIX;
|
|
71
|
+
}
|
|
72
|
+
function compileScript(source) {
|
|
73
|
+
const fn = new Function(...SCRIPT_GLOBALS, LIBRARY_PARAMETER, wrapSource(source));
|
|
74
|
+
const values = scriptArguments();
|
|
75
|
+
return () => fn(...values);
|
|
76
|
+
}
|
|
77
|
+
const HOUR = 3600;
|
|
78
|
+
const START = 1704067200;
|
|
79
|
+
function syntheticBars(count, step = HOUR, seed = 1) {
|
|
80
|
+
let s = seed >>> 0 || 1;
|
|
81
|
+
const rand = () => {
|
|
82
|
+
s = Math.imul(s, 1664525) + 1013904223 >>> 0;
|
|
83
|
+
return s / 2 ** 32;
|
|
84
|
+
};
|
|
85
|
+
const scale = Math.sqrt(step / HOUR);
|
|
86
|
+
const bars = [];
|
|
87
|
+
let prev = 100;
|
|
88
|
+
for (let i = 0; i < count; i++) {
|
|
89
|
+
const t = i * step / HOUR;
|
|
90
|
+
const close = 100 + 12 * Math.sin(t / 60) + 4 * Math.sin(t / 11) + t * 4e-3 + (rand() - 0.5) * 1.5 * scale;
|
|
91
|
+
const open = prev;
|
|
92
|
+
const high = Math.max(open, close) + rand() * 0.8 * scale;
|
|
93
|
+
const low = Math.min(open, close) - rand() * 0.8 * scale;
|
|
94
|
+
bars.push({ time: START + i * step, open, high, low, close, volume: Math.round(1e3 + rand() * 4e3) });
|
|
95
|
+
prev = close;
|
|
96
|
+
}
|
|
97
|
+
return bars;
|
|
98
|
+
}
|
|
99
|
+
function timeframeSeconds(timeframe) {
|
|
100
|
+
const m = /^(\d*)([SDWM]?)$/.exec(timeframe.trim().toUpperCase());
|
|
101
|
+
if (!m) return NaN;
|
|
102
|
+
const n = m[1] ? Number(m[1]) : 1;
|
|
103
|
+
const unit = { "": 60, S: 1, D: 86400, W: 7 * 86400, M: 30 * 86400 }[m[2]];
|
|
104
|
+
return n * unit;
|
|
105
|
+
}
|
|
106
|
+
function inferTimeframe(bars) {
|
|
107
|
+
const counts = /* @__PURE__ */ new Map();
|
|
108
|
+
for (let i = 1; i < bars.length; i++) {
|
|
109
|
+
const d = bars[i].time - bars[i - 1].time;
|
|
110
|
+
if (d > 0) counts.set(d, (counts.get(d) ?? 0) + 1);
|
|
111
|
+
}
|
|
112
|
+
let step = 0;
|
|
113
|
+
let best = 0;
|
|
114
|
+
for (const [d, c] of counts) if (c > best) [step, best] = [d, c];
|
|
115
|
+
if (!step) return "60";
|
|
116
|
+
if (step >= 28 * 86400) return "M";
|
|
117
|
+
if (step >= 7 * 86400) return "W";
|
|
118
|
+
if (step >= 86400) return "D";
|
|
119
|
+
if (step < 60) return `${step}S`;
|
|
120
|
+
return String(Math.round(step / 60));
|
|
121
|
+
}
|
|
122
|
+
function testChart(bars, options = {}) {
|
|
123
|
+
const timezone = options.timezone ?? "Etc/UTC";
|
|
124
|
+
const session = options.session ?? "24x7";
|
|
125
|
+
const chartStep = timeframeSeconds(options.timeframe ?? "60") || HOUR;
|
|
126
|
+
const span = bars.length ? bars[bars.length - 1].time - bars[0].time + chartStep : 0;
|
|
127
|
+
return {
|
|
128
|
+
tickerid: options.tickerid ?? "TEST:SYN",
|
|
129
|
+
timeframe: options.timeframe ?? "60",
|
|
130
|
+
timezone,
|
|
131
|
+
session,
|
|
132
|
+
mintick: 0.01,
|
|
133
|
+
pointvalue: 1,
|
|
134
|
+
mincontract: 1,
|
|
135
|
+
currency: "USD",
|
|
136
|
+
bars: (symbol, timeframe) => {
|
|
137
|
+
const step = timeframeSeconds(timeframe);
|
|
138
|
+
if (!step) return [];
|
|
139
|
+
if (!bars.length) return [{ time: 0, open: 0, high: 0, low: 0, close: 0, volume: 0 }];
|
|
140
|
+
const first = bars[0].time;
|
|
141
|
+
return syntheticBars(Math.ceil(span / step), step, symbol.length + 7).map((b) => ({
|
|
142
|
+
...b,
|
|
143
|
+
time: first + (b.time - START)
|
|
144
|
+
}));
|
|
145
|
+
},
|
|
146
|
+
symbolInfo: () => ({ timezone, session, mintick: 0.01, currency: "USD" })
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
class TestEngine {
|
|
150
|
+
constructor(setup) {
|
|
151
|
+
this.setup = setup;
|
|
152
|
+
}
|
|
153
|
+
setup;
|
|
154
|
+
closed = [];
|
|
155
|
+
open = null;
|
|
156
|
+
pendingEntry = null;
|
|
157
|
+
pendingClose = false;
|
|
158
|
+
exits = /* @__PURE__ */ new Map();
|
|
159
|
+
net = 0;
|
|
160
|
+
bar = 0;
|
|
161
|
+
get bars() {
|
|
162
|
+
return this.setup.bars;
|
|
163
|
+
}
|
|
164
|
+
equity(price) {
|
|
165
|
+
return this.setup.properties.initial_capital + this.net + this.openProfit(price);
|
|
166
|
+
}
|
|
167
|
+
openProfit(price) {
|
|
168
|
+
return this.open ? (price - this.open.entry_price) * this.open.size : 0;
|
|
169
|
+
}
|
|
170
|
+
commission(value) {
|
|
171
|
+
const p = this.setup.properties;
|
|
172
|
+
return p.commission_type === "percent" ? Math.abs(value) * p.commission_value / 100 : 0;
|
|
173
|
+
}
|
|
174
|
+
closeAt(price, exitId) {
|
|
175
|
+
const t = this.open;
|
|
176
|
+
if (!t) return;
|
|
177
|
+
const commission = t.commission + this.commission(price * t.size);
|
|
178
|
+
const profit = (price - t.entry_price) * t.size - commission;
|
|
179
|
+
this.net += profit;
|
|
180
|
+
this.closed.push({
|
|
181
|
+
...t,
|
|
182
|
+
commission,
|
|
183
|
+
profit,
|
|
184
|
+
profit_percent: profit / Math.abs(t.entry_price * t.size) * 100,
|
|
185
|
+
exit_id: exitId,
|
|
186
|
+
exit_price: price,
|
|
187
|
+
exit_bar_index: this.bar,
|
|
188
|
+
exit_time: this.bars[this.bar].time * 1e3
|
|
189
|
+
});
|
|
190
|
+
this.open = null;
|
|
191
|
+
this.exits.clear();
|
|
192
|
+
}
|
|
193
|
+
/** The open trade, if any. */
|
|
194
|
+
get openTradeNow() {
|
|
195
|
+
return this.open;
|
|
196
|
+
}
|
|
197
|
+
processBar(bar) {
|
|
198
|
+
this.bar = bar;
|
|
199
|
+
const b = this.bars[bar];
|
|
200
|
+
if (this.pendingClose) this.closeAt(b.open, "Close");
|
|
201
|
+
this.pendingClose = false;
|
|
202
|
+
const e = this.pendingEntry;
|
|
203
|
+
this.pendingEntry = null;
|
|
204
|
+
if (e && !(this.open && Math.sign(this.open.size) === (e.direction === "long" ? 1 : -1))) {
|
|
205
|
+
if (this.open) this.closeAt(b.open, e.id);
|
|
206
|
+
const p = this.setup.properties;
|
|
207
|
+
const equity = this.equity(b.open);
|
|
208
|
+
const qty = e.qty ?? (p.default_qty_type === "fixed" ? p.default_qty_value : p.default_qty_type === "cash" ? p.default_qty_value / b.open : equity * p.default_qty_value / 100 / b.open);
|
|
209
|
+
const size = e.direction === "long" ? qty : -qty;
|
|
210
|
+
this.open = {
|
|
211
|
+
entry_id: e.id,
|
|
212
|
+
entry_price: b.open,
|
|
213
|
+
entry_bar_index: bar,
|
|
214
|
+
entry_time: b.time * 1e3,
|
|
215
|
+
size,
|
|
216
|
+
profit: 0,
|
|
217
|
+
profit_percent: 0,
|
|
218
|
+
commission: this.commission(b.open * size),
|
|
219
|
+
max_runup: 0,
|
|
220
|
+
max_runup_percent: 0,
|
|
221
|
+
max_drawdown: 0,
|
|
222
|
+
max_drawdown_percent: 0
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
const t = this.open;
|
|
226
|
+
if (!t) return;
|
|
227
|
+
for (const [id, x] of this.exits) {
|
|
228
|
+
if (x.from_entry !== void 0 && x.from_entry !== t.entry_id) continue;
|
|
229
|
+
const long = t.size > 0;
|
|
230
|
+
if (x.stop !== void 0 && (long ? b.low <= x.stop : b.high >= x.stop)) {
|
|
231
|
+
this.closeAt(long ? Math.min(b.open, x.stop) : Math.max(b.open, x.stop), id);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (x.limit !== void 0 && (long ? b.high >= x.limit : b.low <= x.limit)) {
|
|
235
|
+
this.closeAt(long ? Math.max(b.open, x.limit) : Math.min(b.open, x.limit), id);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
processClose() {
|
|
241
|
+
}
|
|
242
|
+
entry(id, direction, options) {
|
|
243
|
+
this.pendingEntry = { id, direction, qty: options.qty };
|
|
244
|
+
}
|
|
245
|
+
order(id, direction, options) {
|
|
246
|
+
this.entry(id, direction, options);
|
|
247
|
+
}
|
|
248
|
+
exit(id, options) {
|
|
249
|
+
this.exits.set(id, options);
|
|
250
|
+
}
|
|
251
|
+
close(id, _options) {
|
|
252
|
+
if (this.open?.entry_id === id) this.pendingClose = true;
|
|
253
|
+
}
|
|
254
|
+
close_all() {
|
|
255
|
+
if (this.open) this.pendingClose = true;
|
|
256
|
+
}
|
|
257
|
+
cancel(id) {
|
|
258
|
+
this.exits.delete(id);
|
|
259
|
+
if (this.pendingEntry?.id === id) this.pendingEntry = null;
|
|
260
|
+
}
|
|
261
|
+
cancel_all() {
|
|
262
|
+
this.exits.clear();
|
|
263
|
+
this.pendingEntry = null;
|
|
264
|
+
}
|
|
265
|
+
rules = [];
|
|
266
|
+
risk(rule) {
|
|
267
|
+
this.rules.push(rule);
|
|
268
|
+
}
|
|
269
|
+
get(variable) {
|
|
270
|
+
const price = this.bars[this.bar]?.close ?? NaN;
|
|
271
|
+
const wins = this.closed.filter((t) => t.profit > 0).length;
|
|
272
|
+
const values = {
|
|
273
|
+
position_size: this.open?.size ?? 0,
|
|
274
|
+
position_avg_price: this.open?.entry_price ?? NaN,
|
|
275
|
+
initial_capital: this.setup.properties.initial_capital,
|
|
276
|
+
equity: this.equity(price),
|
|
277
|
+
netprofit: this.net,
|
|
278
|
+
openprofit: this.openProfit(price),
|
|
279
|
+
opentrades: this.open ? 1 : 0,
|
|
280
|
+
closedtrades: this.closed.length,
|
|
281
|
+
wintrades: wins,
|
|
282
|
+
losstrades: this.closed.length - wins,
|
|
283
|
+
account_currency: "USD"
|
|
284
|
+
};
|
|
285
|
+
return values[variable];
|
|
286
|
+
}
|
|
287
|
+
openTrade(index) {
|
|
288
|
+
return index === 0 && this.open ? this.open : void 0;
|
|
289
|
+
}
|
|
290
|
+
closedTrade(index) {
|
|
291
|
+
return this.closed[index];
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function runScript(source, bars, inputs = {}, options = {}) {
|
|
295
|
+
let engine;
|
|
296
|
+
const body = (options.compile ?? compileScript)(source);
|
|
297
|
+
const run = (0, import_script.executeScript)(body, bars, inputs, testChart(bars, options), {
|
|
298
|
+
strategyEngine: (setup) => engine = new TestEngine(setup)
|
|
299
|
+
});
|
|
300
|
+
return { run, engine };
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=harness.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/check/harness.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * @fileoverview Runs a script source the way a host app runs a script written in its editor: the source is the body\n * of the script, with every value export of `oakscriptjs/script` but `executeScript` as an implicit global, on\n * deterministic synthetic bars (or given bars), with a chart context and, for a strategy, a small order engine.\n * Used by {@link checkScript}, the `oakscript check` command and the tests of the agent guide.\n *\n * @module check/harness\n */\nimport * as lib from '../index.js';\nimport * as api from '../script/index.js';\nimport {\n executeScript,\n type ChartContext,\n type ScriptRunResult,\n type StrategyCloseOptions,\n type StrategyDirection,\n type StrategyEngine,\n type StrategyEntryOptions,\n type StrategyExitOptions,\n type StrategyRiskRule,\n type StrategySetup,\n type StrategyTrade,\n type StrategyVariable,\n} from '../script/index.js';\nimport type { Bar } from '../types/index.js';\n\n/** The implicit globals of a script: every value export of the script API but the host entry. */\nexport const SCRIPT_GLOBALS: readonly string[] = Object.keys(api).filter(\n (k) => k !== 'default' && k !== 'executeScript' && /^[A-Za-z_$][\\w$]*$/.test(k)\n);\n\n/** Name of the parameter that receives the `oakscriptjs` module in a compiled script (its `import` statements). */\nexport const LIBRARY_PARAMETER = '__oakscriptjs';\n\n/** The values of {@link SCRIPT_GLOBALS}, then the `oakscriptjs` module, in the order of the compiled parameters. */\nexport function scriptArguments(): unknown[] {\n return [...SCRIPT_GLOBALS.map((k) => (api as Record<string, unknown>)[k]), lib];\n}\n\n/**\n * Rewrites the `import { a, b as c } from \"oakscriptjs\"` statements of a script into `const { a, b: c } = ...` on the\n * same lines (the line numbers of the source do not change). Throws on an import of another module: a script runs\n * self-contained.\n */\nexport function rewriteImports(source: string): string {\n return source.replace(/^([ \\t]*)import\\s*(\\{[^}]*\\}|\\*\\s+as\\s+[A-Za-z_$][\\w$]*)\\s*from\\s*(['\"])([^'\"]+)\\3\\s*;?/gm, (all, indent, what, _q, from) => {\n if (from !== 'oakscriptjs' && from !== 'oakscriptjs/script') {\n throw new SyntaxError(`A script can only import from \"oakscriptjs\" (found \"${from}\").`);\n }\n const lines = all.split('\\n').length - 1;\n const binding = what.startsWith('*')\n ? what.replace(/^\\*\\s+as\\s+/, '')\n : what.replace(/\\s+as\\s+/g, ': ').replace(/\\s+/g, ' ');\n return `${indent}const ${binding} = ${LIBRARY_PARAMETER};${'\\n'.repeat(lines)}`;\n });\n}\n\n/**\n * Start and end of the function the script source is wrapped in. The globals are the parameters of an outer function\n * and the source is the body of an inner one, so a script can declare a name of a global (`const size = 2`), as in an\n * app that imports the globals at the top of a module. The start goes on the first line of the source.\n */\nexport const SCRIPT_PREFIX = '\"use strict\"; return (function () { ';\nexport const SCRIPT_SUFFIX = '\\n})();';\n\n/** The source of the function body of a compiled script (imports rewritten, lines kept). */\nexport function wrapSource(source: string): string {\n return SCRIPT_PREFIX + rewriteImports(source) + SCRIPT_SUFFIX;\n}\n\n/** Compiles a script source into a body for executeScript(); throws a SyntaxError on invalid code. */\nexport function compileScript(source: string): () => void {\n const fn = new Function(...SCRIPT_GLOBALS, LIBRARY_PARAMETER, wrapSource(source)) as (...args: unknown[]) => void;\n const values = scriptArguments();\n return () => fn(...values);\n}\n\nconst HOUR = 3600;\n/** 2024-01-01 00:00 UTC, in seconds. */\nconst START = 1704067200;\n\n/** Deterministic synthetic bars: two waves, a slow trend and seeded noise. `step`: seconds between bars. */\nexport function syntheticBars(count: number, step = HOUR, seed = 1): Bar[] {\n let s = seed >>> 0 || 1;\n const rand = (): number => {\n s = (Math.imul(s, 1664525) + 1013904223) >>> 0;\n return s / 2 ** 32;\n };\n const scale = Math.sqrt(step / HOUR);\n const bars: Bar[] = [];\n let prev = 100;\n for (let i = 0; i < count; i++) {\n const t = (i * step) / HOUR;\n const close = 100 + 12 * Math.sin(t / 60) + 4 * Math.sin(t / 11) + t * 0.004 + (rand() - 0.5) * 1.5 * scale;\n const open = prev;\n const high = Math.max(open, close) + rand() * 0.8 * scale;\n const low = Math.min(open, close) - rand() * 0.8 * scale;\n bars.push({ time: START + i * step, open, high, low, close, volume: Math.round(1000 + rand() * 4000) });\n prev = close;\n }\n return bars;\n}\n\n/** Seconds of a timeframe string (\"1\", \"60\", \"240\", \"D\", \"1D\", \"W\", \"M\"); NaN when it is not one. */\nexport function timeframeSeconds(timeframe: string): number {\n const m = /^(\\d*)([SDWM]?)$/.exec(timeframe.trim().toUpperCase());\n if (!m) return NaN;\n const n = m[1] ? Number(m[1]) : 1;\n const unit = { '': 60, S: 1, D: 86400, W: 7 * 86400, M: 30 * 86400 }[m[2] as '' | 'S' | 'D' | 'W' | 'M'];\n return n * unit;\n}\n\n/** The timeframe of bars from the most common spacing of their times (\"60\", \"D\", \"W\"...); \"60\" for fewer than 2 bars. */\nexport function inferTimeframe(bars: readonly Bar[]): string {\n const counts = new Map<number, number>();\n for (let i = 1; i < bars.length; i++) {\n const d = bars[i]!.time - bars[i - 1]!.time;\n if (d > 0) counts.set(d, (counts.get(d) ?? 0) + 1);\n }\n let step = 0;\n let best = 0;\n for (const [d, c] of counts) if (c > best) [step, best] = [d, c];\n if (!step) return '60';\n if (step >= 28 * 86400) return 'M';\n if (step >= 7 * 86400) return 'W';\n if (step >= 86400) return 'D';\n if (step < 60) return `${step}S`;\n return String(Math.round(step / 60));\n}\n\nexport interface TestChartOptions {\n /** Chart timeframe (default \"60\"). */\n timeframe?: string;\n /** Chart ticker id (default \"TEST:SYN\"). */\n tickerid?: string;\n /** Time zone of the chart and of the other symbols (default \"Etc/UTC\"). */\n timezone?: string;\n /** Session of the chart and of the other symbols (default \"24x7\"). */\n session?: string;\n}\n\n/**\n * Chart context of the test runs: a 24x7 symbol in UTC. Higher timeframes of the chart symbol are resampled from the\n * chart bars by the library; other symbols get synthetic bars of their own (seeded by the symbol name).\n */\nexport function testChart(bars: Bar[], options: TestChartOptions = {}): ChartContext {\n const timezone = options.timezone ?? 'Etc/UTC';\n const session = options.session ?? '24x7';\n const chartStep = timeframeSeconds(options.timeframe ?? '60') || HOUR;\n const span = bars.length ? bars[bars.length - 1]!.time - bars[0]!.time + chartStep : 0;\n return {\n tickerid: options.tickerid ?? 'TEST:SYN',\n timeframe: options.timeframe ?? '60',\n timezone,\n session,\n mintick: 0.01,\n pointvalue: 1,\n mincontract: 1,\n currency: 'USD',\n bars: (symbol, timeframe) => {\n const step = timeframeSeconds(timeframe);\n if (!step) return [];\n // a run on zero bars (the declaration run of a host) gets one empty bar: no bars at all is an invalid symbol\n if (!bars.length) return [{ time: 0, open: 0, high: 0, low: 0, close: 0, volume: 0 }];\n const first = bars[0]!.time;\n return syntheticBars(Math.ceil(span / step), step, symbol.length + 7).map((b) => ({\n ...b,\n time: first + (b.time - START),\n }));\n },\n symbolInfo: () => ({ timezone, session, mintick: 0.01, currency: 'USD' }),\n };\n}\n\n/**\n * A small order engine for checks and tests (the library does not fill orders). Market entries and closes fill at the\n * next bar open; `strategy.exit` stop / limit levels are checked inside each bar (stop first when both are hit).\n * Entry limit / stop prices, pyramiding and process_orders_on_close are not simulated.\n */\nexport class TestEngine implements StrategyEngine {\n readonly closed: StrategyTrade[] = [];\n private open: StrategyTrade | null = null;\n private pendingEntry: { id: string; direction: StrategyDirection; qty?: number } | null = null;\n private pendingClose = false;\n private exits = new Map<string, StrategyExitOptions>();\n private net = 0;\n private bar = 0;\n\n constructor(readonly setup: StrategySetup) {}\n\n private get bars(): readonly Bar[] {\n return this.setup.bars;\n }\n\n private equity(price: number): number {\n return this.setup.properties.initial_capital + this.net + this.openProfit(price);\n }\n\n private openProfit(price: number): number {\n return this.open ? (price - this.open.entry_price) * this.open.size : 0;\n }\n\n private commission(value: number): number {\n const p = this.setup.properties;\n return p.commission_type === 'percent' ? (Math.abs(value) * p.commission_value) / 100 : 0;\n }\n\n private closeAt(price: number, exitId: string): void {\n const t = this.open;\n if (!t) return;\n const commission = t.commission + this.commission(price * t.size);\n const profit = (price - t.entry_price) * t.size - commission;\n this.net += profit;\n this.closed.push({\n ...t,\n commission,\n profit,\n profit_percent: (profit / Math.abs(t.entry_price * t.size)) * 100,\n exit_id: exitId,\n exit_price: price,\n exit_bar_index: this.bar,\n exit_time: this.bars[this.bar]!.time * 1000,\n });\n this.open = null;\n this.exits.clear();\n }\n\n /** The open trade, if any. */\n get openTradeNow(): StrategyTrade | null {\n return this.open;\n }\n\n processBar(bar: number): void {\n this.bar = bar;\n const b = this.bars[bar]!;\n if (this.pendingClose) this.closeAt(b.open, 'Close');\n this.pendingClose = false;\n const e = this.pendingEntry;\n this.pendingEntry = null;\n if (e && !(this.open && Math.sign(this.open.size) === (e.direction === 'long' ? 1 : -1))) {\n if (this.open) this.closeAt(b.open, e.id);\n const p = this.setup.properties;\n const equity = this.equity(b.open);\n const qty =\n e.qty ??\n (p.default_qty_type === 'fixed'\n ? p.default_qty_value\n : p.default_qty_type === 'cash'\n ? p.default_qty_value / b.open\n : (equity * p.default_qty_value) / 100 / b.open);\n const size = e.direction === 'long' ? qty : -qty;\n this.open = {\n entry_id: e.id,\n entry_price: b.open,\n entry_bar_index: bar,\n entry_time: b.time * 1000,\n size,\n profit: 0,\n profit_percent: 0,\n commission: this.commission(b.open * size),\n max_runup: 0,\n max_runup_percent: 0,\n max_drawdown: 0,\n max_drawdown_percent: 0,\n };\n }\n const t = this.open;\n if (!t) return;\n for (const [id, x] of this.exits) {\n if (x.from_entry !== undefined && x.from_entry !== t.entry_id) continue;\n const long = t.size > 0;\n if (x.stop !== undefined && (long ? b.low <= x.stop : b.high >= x.stop)) {\n this.closeAt(long ? Math.min(b.open, x.stop) : Math.max(b.open, x.stop), id);\n return;\n }\n if (x.limit !== undefined && (long ? b.high >= x.limit : b.low <= x.limit)) {\n this.closeAt(long ? Math.max(b.open, x.limit) : Math.min(b.open, x.limit), id);\n return;\n }\n }\n }\n\n processClose(): void {}\n\n entry(id: string, direction: StrategyDirection, options: StrategyEntryOptions): void {\n this.pendingEntry = { id, direction, qty: options.qty };\n }\n\n order(id: string, direction: StrategyDirection, options: StrategyEntryOptions): void {\n this.entry(id, direction, options);\n }\n\n exit(id: string, options: StrategyExitOptions): void {\n this.exits.set(id, options);\n }\n\n close(id: string, _options: StrategyCloseOptions): void {\n if (this.open?.entry_id === id) this.pendingClose = true;\n }\n\n close_all(): void {\n if (this.open) this.pendingClose = true;\n }\n\n cancel(id: string): void {\n this.exits.delete(id);\n if (this.pendingEntry?.id === id) this.pendingEntry = null;\n }\n\n cancel_all(): void {\n this.exits.clear();\n this.pendingEntry = null;\n }\n\n readonly rules: StrategyRiskRule[] = [];\n\n risk(rule: StrategyRiskRule): void {\n this.rules.push(rule);\n }\n\n get(variable: StrategyVariable): number | string | undefined {\n const price = this.bars[this.bar]?.close ?? NaN;\n const wins = this.closed.filter((t) => t.profit > 0).length;\n const values: Partial<Record<StrategyVariable, number | string>> = {\n position_size: this.open?.size ?? 0,\n position_avg_price: this.open?.entry_price ?? NaN,\n initial_capital: this.setup.properties.initial_capital,\n equity: this.equity(price),\n netprofit: this.net,\n openprofit: this.openProfit(price),\n opentrades: this.open ? 1 : 0,\n closedtrades: this.closed.length,\n wintrades: wins,\n losstrades: this.closed.length - wins,\n account_currency: 'USD',\n };\n return values[variable];\n }\n\n openTrade(index: number): StrategyTrade | undefined {\n return index === 0 && this.open ? this.open : undefined;\n }\n\n closedTrade(index: number): StrategyTrade | undefined {\n return this.closed[index];\n }\n}\n\nexport interface ScriptRun {\n run: ScriptRunResult;\n engine?: TestEngine;\n}\n\nexport interface RunScriptOptions extends TestChartOptions {\n /** Compiles the source (default {@link compileScript}); the CLI compiles with file lines. */\n compile?: (source: string) => () => void;\n}\n\n/** Runs a script source on `bars` with the test chart context and, for a strategy, the test engine. */\nexport function runScript(\n source: string,\n bars: Bar[],\n inputs: Record<string, unknown> = {},\n options: RunScriptOptions = {}\n): ScriptRun {\n let engine: TestEngine | undefined;\n const body = (options.compile ?? compileScript)(source);\n const run = executeScript(body, bars, inputs, testChart(bars, options), {\n strategyEngine: (setup) => (engine = new TestEngine(setup)),\n });\n return { run, engine };\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,UAAqB;AACrB,UAAqB;AACrB,oBAaO;AAIA,MAAM,iBAAoC,OAAO,KAAK,GAAG,EAAE;AAAA,EAChE,CAAC,MAAM,MAAM,aAAa,MAAM,mBAAmB,qBAAqB,KAAK,CAAC;AAChF;AAGO,MAAM,oBAAoB;AAG1B,SAAS,kBAA6B;AAC3C,SAAO,CAAC,GAAG,eAAe,IAAI,CAAC,MAAO,IAAgC,CAAC,CAAC,GAAG,GAAG;AAChF;AAOO,SAAS,eAAe,QAAwB;AACrD,SAAO,OAAO,QAAQ,6FAA6F,CAAC,KAAK,QAAQ,MAAM,IAAI,SAAS;AAClJ,QAAI,SAAS,iBAAiB,SAAS,sBAAsB;AAC3D,YAAM,IAAI,YAAY,uDAAuD,IAAI,KAAK;AAAA,IACxF;AACA,UAAM,QAAQ,IAAI,MAAM,IAAI,EAAE,SAAS;AACvC,UAAM,UAAU,KAAK,WAAW,GAAG,IAC/B,KAAK,QAAQ,eAAe,EAAE,IAC9B,KAAK,QAAQ,aAAa,IAAI,EAAE,QAAQ,QAAQ,GAAG;AACvD,WAAO,GAAG,MAAM,SAAS,OAAO,MAAM,iBAAiB,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,EAC/E,CAAC;AACH;AAOO,MAAM,gBAAgB;AACtB,MAAM,gBAAgB;AAGtB,SAAS,WAAW,QAAwB;AACjD,SAAO,gBAAgB,eAAe,MAAM,IAAI;AAClD;AAGO,SAAS,cAAc,QAA4B;AACxD,QAAM,KAAK,IAAI,SAAS,GAAG,gBAAgB,mBAAmB,WAAW,MAAM,CAAC;AAChF,QAAM,SAAS,gBAAgB;AAC/B,SAAO,MAAM,GAAG,GAAG,MAAM;AAC3B;AAEA,MAAM,OAAO;AAEb,MAAM,QAAQ;AAGP,SAAS,cAAc,OAAe,OAAO,MAAM,OAAO,GAAU;AACzE,MAAI,IAAI,SAAS,KAAK;AACtB,QAAM,OAAO,MAAc;AACzB,QAAK,KAAK,KAAK,GAAG,OAAO,IAAI,eAAgB;AAC7C,WAAO,IAAI,KAAK;AAAA,EAClB;AACA,QAAM,QAAQ,KAAK,KAAK,OAAO,IAAI;AACnC,QAAM,OAAc,CAAC;AACrB,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,UAAM,IAAK,IAAI,OAAQ;AACvB,UAAM,QAAQ,MAAM,KAAK,KAAK,IAAI,IAAI,EAAE,IAAI,IAAI,KAAK,IAAI,IAAI,EAAE,IAAI,IAAI,QAAS,KAAK,IAAI,OAAO,MAAM;AACtG,UAAM,OAAO;AACb,UAAM,OAAO,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,IAAI,MAAM;AACpD,UAAM,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,IAAI,MAAM;AACnD,SAAK,KAAK,EAAE,MAAM,QAAQ,IAAI,MAAM,MAAM,MAAM,KAAK,OAAO,QAAQ,KAAK,MAAM,MAAO,KAAK,IAAI,GAAI,EAAE,CAAC;AACtG,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGO,SAAS,iBAAiB,WAA2B;AAC1D,QAAM,IAAI,mBAAmB,KAAK,UAAU,KAAK,EAAE,YAAY,CAAC;AAChE,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,IAAI,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC,IAAI;AAChC,QAAM,OAAO,EAAE,IAAI,IAAI,GAAG,GAAG,GAAG,OAAO,GAAG,IAAI,OAAO,GAAG,KAAK,MAAM,EAAE,EAAE,CAAC,CAA+B;AACvG,SAAO,IAAI;AACb;AAGO,SAAS,eAAe,MAA8B;AAC3D,QAAM,SAAS,oBAAI,IAAoB;AACvC,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,IAAI,KAAK,CAAC,EAAG,OAAO,KAAK,IAAI,CAAC,EAAG;AACvC,QAAI,IAAI,EAAG,QAAO,IAAI,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,CAAC;AAAA,EACnD;AACA,MAAI,OAAO;AACX,MAAI,OAAO;AACX,aAAW,CAAC,GAAG,CAAC,KAAK,OAAQ,KAAI,IAAI,KAAM,EAAC,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC;AAC/D,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,QAAQ,KAAK,MAAO,QAAO;AAC/B,MAAI,QAAQ,IAAI,MAAO,QAAO;AAC9B,MAAI,QAAQ,MAAO,QAAO;AAC1B,MAAI,OAAO,GAAI,QAAO,GAAG,IAAI;AAC7B,SAAO,OAAO,KAAK,MAAM,OAAO,EAAE,CAAC;AACrC;AAiBO,SAAS,UAAU,MAAa,UAA4B,CAAC,GAAiB;AACnF,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,YAAY,iBAAiB,QAAQ,aAAa,IAAI,KAAK;AACjE,QAAM,OAAO,KAAK,SAAS,KAAK,KAAK,SAAS,CAAC,EAAG,OAAO,KAAK,CAAC,EAAG,OAAO,YAAY;AACrF,SAAO;AAAA,IACL,UAAU,QAAQ,YAAY;AAAA,IAC9B,WAAW,QAAQ,aAAa;AAAA,IAChC;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,QAAQ,cAAc;AAC3B,YAAM,OAAO,iBAAiB,SAAS;AACvC,UAAI,CAAC,KAAM,QAAO,CAAC;AAEnB,UAAI,CAAC,KAAK,OAAQ,QAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,EAAE,CAAC;AACpF,YAAM,QAAQ,KAAK,CAAC,EAAG;AACvB,aAAO,cAAc,KAAK,KAAK,OAAO,IAAI,GAAG,MAAM,OAAO,SAAS,CAAC,EAAE,IAAI,CAAC,OAAO;AAAA,QAChF,GAAG;AAAA,QACH,MAAM,SAAS,EAAE,OAAO;AAAA,MAC1B,EAAE;AAAA,IACJ;AAAA,IACA,YAAY,OAAO,EAAE,UAAU,SAAS,SAAS,MAAM,UAAU,MAAM;AAAA,EACzE;AACF;AAOO,MAAM,WAAqC;AAAA,EAShD,YAAqB,OAAsB;AAAtB;AAAA,EAAuB;AAAA,EAAvB;AAAA,EARZ,SAA0B,CAAC;AAAA,EAC5B,OAA6B;AAAA,EAC7B,eAAkF;AAAA,EAClF,eAAe;AAAA,EACf,QAAQ,oBAAI,IAAiC;AAAA,EAC7C,MAAM;AAAA,EACN,MAAM;AAAA,EAId,IAAY,OAAuB;AACjC,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEQ,OAAO,OAAuB;AACpC,WAAO,KAAK,MAAM,WAAW,kBAAkB,KAAK,MAAM,KAAK,WAAW,KAAK;AAAA,EACjF;AAAA,EAEQ,WAAW,OAAuB;AACxC,WAAO,KAAK,QAAQ,QAAQ,KAAK,KAAK,eAAe,KAAK,KAAK,OAAO;AAAA,EACxE;AAAA,EAEQ,WAAW,OAAuB;AACxC,UAAM,IAAI,KAAK,MAAM;AACrB,WAAO,EAAE,oBAAoB,YAAa,KAAK,IAAI,KAAK,IAAI,EAAE,mBAAoB,MAAM;AAAA,EAC1F;AAAA,EAEQ,QAAQ,OAAe,QAAsB;AACnD,UAAM,IAAI,KAAK;AACf,QAAI,CAAC,EAAG;AACR,UAAM,aAAa,EAAE,aAAa,KAAK,WAAW,QAAQ,EAAE,IAAI;AAChE,UAAM,UAAU,QAAQ,EAAE,eAAe,EAAE,OAAO;AAClD,SAAK,OAAO;AACZ,SAAK,OAAO,KAAK;AAAA,MACf,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA,gBAAiB,SAAS,KAAK,IAAI,EAAE,cAAc,EAAE,IAAI,IAAK;AAAA,MAC9D,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,gBAAgB,KAAK;AAAA,MACrB,WAAW,KAAK,KAAK,KAAK,GAAG,EAAG,OAAO;AAAA,IACzC,CAAC;AACD,SAAK,OAAO;AACZ,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA;AAAA,EAGA,IAAI,eAAqC;AACvC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,WAAW,KAAmB;AAC5B,SAAK,MAAM;AACX,UAAM,IAAI,KAAK,KAAK,GAAG;AACvB,QAAI,KAAK,aAAc,MAAK,QAAQ,EAAE,MAAM,OAAO;AACnD,SAAK,eAAe;AACpB,UAAM,IAAI,KAAK;AACf,SAAK,eAAe;AACpB,QAAI,KAAK,EAAE,KAAK,QAAQ,KAAK,KAAK,KAAK,KAAK,IAAI,OAAO,EAAE,cAAc,SAAS,IAAI,MAAM;AACxF,UAAI,KAAK,KAAM,MAAK,QAAQ,EAAE,MAAM,EAAE,EAAE;AACxC,YAAM,IAAI,KAAK,MAAM;AACrB,YAAM,SAAS,KAAK,OAAO,EAAE,IAAI;AACjC,YAAM,MACJ,EAAE,QACD,EAAE,qBAAqB,UACpB,EAAE,oBACF,EAAE,qBAAqB,SACrB,EAAE,oBAAoB,EAAE,OACvB,SAAS,EAAE,oBAAqB,MAAM,EAAE;AACjD,YAAM,OAAO,EAAE,cAAc,SAAS,MAAM,CAAC;AAC7C,WAAK,OAAO;AAAA,QACV,UAAU,EAAE;AAAA,QACZ,aAAa,EAAE;AAAA,QACf,iBAAiB;AAAA,QACjB,YAAY,EAAE,OAAO;AAAA,QACrB;AAAA,QACA,QAAQ;AAAA,QACR,gBAAgB;AAAA,QAChB,YAAY,KAAK,WAAW,EAAE,OAAO,IAAI;AAAA,QACzC,WAAW;AAAA,QACX,mBAAmB;AAAA,QACnB,cAAc;AAAA,QACd,sBAAsB;AAAA,MACxB;AAAA,IACF;AACA,UAAM,IAAI,KAAK;AACf,QAAI,CAAC,EAAG;AACR,eAAW,CAAC,IAAI,CAAC,KAAK,KAAK,OAAO;AAChC,UAAI,EAAE,eAAe,UAAa,EAAE,eAAe,EAAE,SAAU;AAC/D,YAAM,OAAO,EAAE,OAAO;AACtB,UAAI,EAAE,SAAS,WAAc,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO;AACvE,aAAK,QAAQ,OAAO,KAAK,IAAI,EAAE,MAAM,EAAE,IAAI,IAAI,KAAK,IAAI,EAAE,MAAM,EAAE,IAAI,GAAG,EAAE;AAC3E;AAAA,MACF;AACA,UAAI,EAAE,UAAU,WAAc,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ;AAC1E,aAAK,QAAQ,OAAO,KAAK,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,KAAK,IAAI,EAAE,MAAM,EAAE,KAAK,GAAG,EAAE;AAC7E;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,eAAqB;AAAA,EAAC;AAAA,EAEtB,MAAM,IAAY,WAA8B,SAAqC;AACnF,SAAK,eAAe,EAAE,IAAI,WAAW,KAAK,QAAQ,IAAI;AAAA,EACxD;AAAA,EAEA,MAAM,IAAY,WAA8B,SAAqC;AACnF,SAAK,MAAM,IAAI,WAAW,OAAO;AAAA,EACnC;AAAA,EAEA,KAAK,IAAY,SAAoC;AACnD,SAAK,MAAM,IAAI,IAAI,OAAO;AAAA,EAC5B;AAAA,EAEA,MAAM,IAAY,UAAsC;AACtD,QAAI,KAAK,MAAM,aAAa,GAAI,MAAK,eAAe;AAAA,EACtD;AAAA,EAEA,YAAkB;AAChB,QAAI,KAAK,KAAM,MAAK,eAAe;AAAA,EACrC;AAAA,EAEA,OAAO,IAAkB;AACvB,SAAK,MAAM,OAAO,EAAE;AACpB,QAAI,KAAK,cAAc,OAAO,GAAI,MAAK,eAAe;AAAA,EACxD;AAAA,EAEA,aAAmB;AACjB,SAAK,MAAM,MAAM;AACjB,SAAK,eAAe;AAAA,EACtB;AAAA,EAES,QAA4B,CAAC;AAAA,EAEtC,KAAK,MAA8B;AACjC,SAAK,MAAM,KAAK,IAAI;AAAA,EACtB;AAAA,EAEA,IAAI,UAAyD;AAC3D,UAAM,QAAQ,KAAK,KAAK,KAAK,GAAG,GAAG,SAAS;AAC5C,UAAM,OAAO,KAAK,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE;AACrD,UAAM,SAA6D;AAAA,MACjE,eAAe,KAAK,MAAM,QAAQ;AAAA,MAClC,oBAAoB,KAAK,MAAM,eAAe;AAAA,MAC9C,iBAAiB,KAAK,MAAM,WAAW;AAAA,MACvC,QAAQ,KAAK,OAAO,KAAK;AAAA,MACzB,WAAW,KAAK;AAAA,MAChB,YAAY,KAAK,WAAW,KAAK;AAAA,MACjC,YAAY,KAAK,OAAO,IAAI;AAAA,MAC5B,cAAc,KAAK,OAAO;AAAA,MAC1B,WAAW;AAAA,MACX,YAAY,KAAK,OAAO,SAAS;AAAA,MACjC,kBAAkB;AAAA,IACpB;AACA,WAAO,OAAO,QAAQ;AAAA,EACxB;AAAA,EAEA,UAAU,OAA0C;AAClD,WAAO,UAAU,KAAK,KAAK,OAAO,KAAK,OAAO;AAAA,EAChD;AAAA,EAEA,YAAY,OAA0C;AACpD,WAAO,KAAK,OAAO,KAAK;AAAA,EAC1B;AACF;AAaO,SAAS,UACd,QACA,MACA,SAAkC,CAAC,GACnC,UAA4B,CAAC,GAClB;AACX,MAAI;AACJ,QAAM,QAAQ,QAAQ,WAAW,eAAe,MAAM;AACtD,QAAM,UAAM,6BAAc,MAAM,MAAM,QAAQ,UAAU,MAAM,OAAO,GAAG;AAAA,IACtE,gBAAgB,CAAC,UAAW,SAAS,IAAI,WAAW,KAAK;AAAA,EAC3D,CAAC;AACD,SAAO,EAAE,KAAK,OAAO;AACvB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Checks a script source: runs it like a host (a declaration run on zero bars, then a run on bars) and
|
|
3
|
+
* returns a report an agent or a host can act on: what the script declares (inputs, outputs, strategy), what its outputs
|
|
4
|
+
* contain (values, warm-up, ranges, signal counts, trades), warnings for the mistakes that give no error (an empty plot,
|
|
5
|
+
* a signal on every bar or never, an input that changes nothing...), and the result of a spec (the expected inputs,
|
|
6
|
+
* outputs and signals) and of a reference (expected values per bar). The `oakscript check` command prints it.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { checkScript } from 'oakscriptjs/check';
|
|
10
|
+
* const report = checkScript(source, { spec: { overlay: true, outputs: ['Fast', 'Slow'] } });
|
|
11
|
+
* report.ok; report.errors; report.warnings; report.spec?.items;
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* @module check
|
|
15
|
+
*/
|
|
16
|
+
import type { Bar } from '../types/index.js';
|
|
17
|
+
import type { InputConfig } from '../runtime/types.js';
|
|
18
|
+
import { type TestChartOptions } from './harness.js';
|
|
19
|
+
import { type CheckContext, type CheckItem } from './checks.js';
|
|
20
|
+
export { validateSpec, specJsonSchema, SPEC_FIELDS, SPEC_FILE_FIELDS } from './spec.js';
|
|
21
|
+
export { runChecks, signalBars, type CheckContext, type CheckItem, type CheckPlot, type CheckSignal, type SignalBars } from './checks.js';
|
|
22
|
+
export { formatReport, assertCheck } from './format.js';
|
|
23
|
+
export { compileScript, inferTimeframe, rewriteImports, runScript, scriptArguments, syntheticBars, testChart, timeframeSeconds, LIBRARY_PARAMETER, SCRIPT_GLOBALS, SCRIPT_PREFIX, SCRIPT_SUFFIX, TestEngine, wrapSource, type RunScriptOptions, type ScriptRun, type TestChartOptions, } from './harness.js';
|
|
24
|
+
/** Expected count of a signal (a shape, character, arrow, alert condition, background or bar colour) over the bars. */
|
|
25
|
+
export interface SignalSpec {
|
|
26
|
+
/** At least this many bars with the signal. */
|
|
27
|
+
min?: number;
|
|
28
|
+
/** At most this many bars with the signal. */
|
|
29
|
+
max?: number;
|
|
30
|
+
/** At least this share of the bars (0 to 1). */
|
|
31
|
+
minShare?: number;
|
|
32
|
+
/** At most this share of the bars (0 to 1). */
|
|
33
|
+
maxShare?: number;
|
|
34
|
+
}
|
|
35
|
+
/** Expected values of a plot. */
|
|
36
|
+
export interface PlotSpec {
|
|
37
|
+
/** Every value is at least this. */
|
|
38
|
+
min?: number;
|
|
39
|
+
/** Every value is at most this. */
|
|
40
|
+
max?: number;
|
|
41
|
+
/** The first value comes at this bar index or before (the warm-up). */
|
|
42
|
+
warmup?: number;
|
|
43
|
+
}
|
|
44
|
+
/** Expected input: the keys are compared when given. */
|
|
45
|
+
export interface InputSpec {
|
|
46
|
+
type?: InputConfig['type'];
|
|
47
|
+
defval?: unknown;
|
|
48
|
+
title?: string;
|
|
49
|
+
min?: number;
|
|
50
|
+
max?: number;
|
|
51
|
+
options?: string[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* What the user asked for, written before the script: each given entry is checked. Inputs, plots and signals are
|
|
55
|
+
* found by id or title (case insensitive).
|
|
56
|
+
*/
|
|
57
|
+
export interface CheckSpec {
|
|
58
|
+
kind?: 'indicator' | 'strategy';
|
|
59
|
+
title?: string;
|
|
60
|
+
overlay?: boolean;
|
|
61
|
+
/** Inputs that must exist, with the expected type, default... */
|
|
62
|
+
inputs?: Record<string, InputSpec>;
|
|
63
|
+
/** Outputs that must exist (a title, or a title and a kind: plot, shape, char, arrow, candle, bar, hline, bgcolor, barcolor, alertcondition). */
|
|
64
|
+
outputs?: Array<string | {
|
|
65
|
+
title: string;
|
|
66
|
+
kind?: string;
|
|
67
|
+
}>;
|
|
68
|
+
/** Value checks per plot. */
|
|
69
|
+
plots?: Record<string, PlotSpec>;
|
|
70
|
+
/** Count checks per signal. */
|
|
71
|
+
signals?: Record<string, SignalSpec>;
|
|
72
|
+
/** Number of closed trades of a strategy. */
|
|
73
|
+
trades?: {
|
|
74
|
+
min?: number;
|
|
75
|
+
max?: number;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** Expected values per bar, e.g. the outputs of the Pine script a port follows, on the same bars. */
|
|
79
|
+
export interface CheckReference {
|
|
80
|
+
/** Bar times (UNIX seconds). */
|
|
81
|
+
times: number[];
|
|
82
|
+
/** Expected values per plot id or title, aligned with `times` (NaN or null: na). */
|
|
83
|
+
columns: Record<string, Array<number | null>>;
|
|
84
|
+
/** Equal when |a - b| <= tolerance * max(1, |a|, |b|) (default 1e-10), or both na. */
|
|
85
|
+
tolerance?: number;
|
|
86
|
+
/** A column without a plot of that id or title is listed as ignored instead of failing (a chart export holds other columns). */
|
|
87
|
+
ignoreUnknown?: boolean;
|
|
88
|
+
}
|
|
89
|
+
/** A run on edge-case bars (`scenarios: true`): a short history, daily bars, flat prices, no volume, a gap. */
|
|
90
|
+
export interface CheckScenario {
|
|
91
|
+
name: string;
|
|
92
|
+
description: string;
|
|
93
|
+
timeframe: string;
|
|
94
|
+
bars: () => Bar[];
|
|
95
|
+
}
|
|
96
|
+
export interface CheckOptions extends TestChartOptions {
|
|
97
|
+
/** Bars of the run (default: 1,500 deterministic synthetic bars of the timeframe). */
|
|
98
|
+
bars?: Bar[];
|
|
99
|
+
/** Input values by id (default: the defaults). */
|
|
100
|
+
inputs?: Record<string, unknown>;
|
|
101
|
+
spec?: CheckSpec;
|
|
102
|
+
reference?: CheckReference;
|
|
103
|
+
/** Compiles the source (default: `new Function`; the CLI compiles with the file name for error lines). */
|
|
104
|
+
compile?: (source: string) => () => void;
|
|
105
|
+
/** Wraps each run (the CLI stops a run that takes too long). */
|
|
106
|
+
run?: <T>(fn: () => T) => T;
|
|
107
|
+
/** File name of the source, to read the error lines from the stack (`<file>:line:column`). */
|
|
108
|
+
filename?: string;
|
|
109
|
+
/** Re-run with each input changed to find inputs that change no output (default true). */
|
|
110
|
+
inputSweep?: boolean;
|
|
111
|
+
/** Behaviour checks: called with the outputs of the run per bar (see {@link CheckContext}); their results join the spec items. */
|
|
112
|
+
checks?: (t: CheckContext) => void;
|
|
113
|
+
/** Also run on the edge-case bars of {@link SCENARIOS} (or the given ones): their errors fail the check. */
|
|
114
|
+
scenarios?: boolean | CheckScenario[];
|
|
115
|
+
}
|
|
116
|
+
export type CheckStage = 'syntax' | 'types' | 'declaration' | 'run' | 'timeout' | 'spec' | 'reference' | 'scenario';
|
|
117
|
+
export interface CheckError {
|
|
118
|
+
stage: CheckStage;
|
|
119
|
+
message: string;
|
|
120
|
+
line?: number;
|
|
121
|
+
column?: number;
|
|
122
|
+
/** TypeScript error code (stage "types"). */
|
|
123
|
+
code?: string;
|
|
124
|
+
}
|
|
125
|
+
export interface CheckWarning {
|
|
126
|
+
code: 'empty-plot' | 'constant-plot' | 'late-start' | 'signal-never' | 'signal-everywhere' | 'one-colour' | 'unused-input' | 'input-error' | 'no-trades' | 'no-output';
|
|
127
|
+
message: string;
|
|
128
|
+
/** Output or input title (or id). */
|
|
129
|
+
target?: string;
|
|
130
|
+
}
|
|
131
|
+
export interface PlotSummary {
|
|
132
|
+
id: string;
|
|
133
|
+
title: string;
|
|
134
|
+
/** Bars with a value (not na). */
|
|
135
|
+
values: number;
|
|
136
|
+
/** Bar index of the first value (-1: none). */
|
|
137
|
+
firstBar: number;
|
|
138
|
+
min: number | null;
|
|
139
|
+
max: number | null;
|
|
140
|
+
/** Values of the last 5 bars (null: na). */
|
|
141
|
+
last: Array<number | null>;
|
|
142
|
+
/** Distinct per-bar colours (0: the plot colour is the same on every bar). */
|
|
143
|
+
colours: number;
|
|
144
|
+
}
|
|
145
|
+
export interface SignalSummary {
|
|
146
|
+
kind: 'shape' | 'char' | 'arrow' | 'alertcondition' | 'bgcolor' | 'barcolor';
|
|
147
|
+
id: string;
|
|
148
|
+
title: string;
|
|
149
|
+
/** Bars with the signal. */
|
|
150
|
+
count: number;
|
|
151
|
+
/** count / number of bars. */
|
|
152
|
+
share: number;
|
|
153
|
+
firstBar: number;
|
|
154
|
+
lastBar: number;
|
|
155
|
+
}
|
|
156
|
+
export interface TradeSummary {
|
|
157
|
+
entry: string;
|
|
158
|
+
direction: 'long' | 'short';
|
|
159
|
+
entryBar: number;
|
|
160
|
+
entryPrice: number;
|
|
161
|
+
exitBar: number | null;
|
|
162
|
+
exitPrice: number | null;
|
|
163
|
+
profit: number;
|
|
164
|
+
}
|
|
165
|
+
export interface CheckReport {
|
|
166
|
+
/** No error, no failed spec or reference check. Warnings do not change it. */
|
|
167
|
+
ok: boolean;
|
|
168
|
+
bars: {
|
|
169
|
+
count: number;
|
|
170
|
+
first: number | null;
|
|
171
|
+
last: number | null;
|
|
172
|
+
timeframe: string;
|
|
173
|
+
synthetic: boolean;
|
|
174
|
+
};
|
|
175
|
+
errors: CheckError[];
|
|
176
|
+
warnings: CheckWarning[];
|
|
177
|
+
declaration?: {
|
|
178
|
+
kind: 'indicator' | 'strategy';
|
|
179
|
+
title: string;
|
|
180
|
+
shortTitle?: string;
|
|
181
|
+
overlay: boolean;
|
|
182
|
+
inputs: Array<Pick<InputConfig, 'id' | 'type' | 'defval' | 'title' | 'min' | 'max' | 'options'>>;
|
|
183
|
+
outputs: Array<{
|
|
184
|
+
kind: string;
|
|
185
|
+
id: string;
|
|
186
|
+
title: string;
|
|
187
|
+
}>;
|
|
188
|
+
strategy?: Record<string, unknown>;
|
|
189
|
+
};
|
|
190
|
+
plots: PlotSummary[];
|
|
191
|
+
signals: SignalSummary[];
|
|
192
|
+
drawings: {
|
|
193
|
+
labels: number;
|
|
194
|
+
lines: number;
|
|
195
|
+
boxes: number;
|
|
196
|
+
tables: number;
|
|
197
|
+
polylines: number;
|
|
198
|
+
linefills: number;
|
|
199
|
+
};
|
|
200
|
+
/** alert() calls of the script (all bars). */
|
|
201
|
+
alertCalls: number;
|
|
202
|
+
strategy?: {
|
|
203
|
+
closedTrades: number;
|
|
204
|
+
openTrade: boolean;
|
|
205
|
+
netProfit: number;
|
|
206
|
+
wins: number;
|
|
207
|
+
first: TradeSummary[];
|
|
208
|
+
};
|
|
209
|
+
/** Spec items and behaviour checks. */
|
|
210
|
+
spec?: {
|
|
211
|
+
passed: number;
|
|
212
|
+
failed: number;
|
|
213
|
+
items: CheckItem[];
|
|
214
|
+
};
|
|
215
|
+
reference?: Array<{
|
|
216
|
+
column: string;
|
|
217
|
+
output?: string;
|
|
218
|
+
/** No plot of this id or title, and `ignoreUnknown` is set. */
|
|
219
|
+
ignored?: boolean;
|
|
220
|
+
equal: number;
|
|
221
|
+
total: number;
|
|
222
|
+
firstMismatch?: {
|
|
223
|
+
bar: number;
|
|
224
|
+
time: number;
|
|
225
|
+
expected: number | null;
|
|
226
|
+
actual: number | null;
|
|
227
|
+
};
|
|
228
|
+
}>;
|
|
229
|
+
/** Runs on edge-case bars: their errors (also in `errors`, stage "scenario") and the plots with no value the main run does not have. */
|
|
230
|
+
scenarios?: Array<{
|
|
231
|
+
name: string;
|
|
232
|
+
description: string;
|
|
233
|
+
bars: number;
|
|
234
|
+
errors: CheckError[];
|
|
235
|
+
warnings: CheckWarning[];
|
|
236
|
+
}>;
|
|
237
|
+
}
|
|
238
|
+
/** Line and column of a script error, from `error.scriptLine` or the `<filename>:line:column` frames of its stack. */
|
|
239
|
+
export declare function errorLocation(error: unknown, filename?: string): {
|
|
240
|
+
line?: number;
|
|
241
|
+
column?: number;
|
|
242
|
+
};
|
|
243
|
+
/** Default number of synthetic bars of a check. */
|
|
244
|
+
export declare const CHECK_BARS = 1500;
|
|
245
|
+
/** The edge-case bars of `scenarios: true`. */
|
|
246
|
+
export declare const SCENARIOS: readonly CheckScenario[];
|
|
247
|
+
/**
|
|
248
|
+
* Checks a script source (the body of a script, as a host runs it): compiles it, runs it on zero bars (the
|
|
249
|
+
* declarations) and on the bars, and reports its declarations, outputs, warnings and the spec / reference results.
|
|
250
|
+
* Never throws for a script error: the errors are in the report.
|
|
251
|
+
*/
|
|
252
|
+
export declare function checkScript(source: string, options?: CheckOptions): CheckReport;
|
|
253
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/check/index.ts"],"names":[],"mappings":"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"}
|