@hoox-sh/pynets 0.8.0 → 0.10.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/CHANGELOG.md +32 -0
- package/README.md +17 -1
- package/dist/browser.js +63 -63
- package/dist/index.js +408 -39
- package/package.json +1 -1
- package/src/cli/rich.ts +1 -1
- package/src/index.ts +1 -1
- package/src/runtime/array.ts +19 -0
- package/src/runtime/clone.ts +26 -0
- package/src/runtime/compile/collections.ts +13 -0
- package/src/runtime/compile/emit.ts +19 -1
- package/src/runtime/compile/emit_call.ts +15 -0
- package/src/runtime/compile/types.ts +2 -0
- package/src/runtime/interpret.ts +293 -36
- package/src/runtime/map.ts +25 -0
- package/src/runtime/matrix.ts +25 -0
- package/src/runtime/series.ts +6 -0
- package/src/runtime/strategy.ts +32 -0
- package/src/runtime/ta.ts +28 -0
- package/src/runtime/udt.ts +22 -0
package/dist/index.js
CHANGED
|
@@ -33581,6 +33581,31 @@ function tokenize(source) {
|
|
|
33581
33581
|
}
|
|
33582
33582
|
return tokens;
|
|
33583
33583
|
}
|
|
33584
|
+
// src/runtime/clone.ts
|
|
33585
|
+
function cloneValue(v) {
|
|
33586
|
+
if (v == null)
|
|
33587
|
+
return v;
|
|
33588
|
+
if (typeof v !== "object")
|
|
33589
|
+
return v;
|
|
33590
|
+
if (Array.isArray(v))
|
|
33591
|
+
return v.map(cloneValue);
|
|
33592
|
+
if (v instanceof Map) {
|
|
33593
|
+
const out = new Map;
|
|
33594
|
+
for (const [k, x] of v)
|
|
33595
|
+
out.set(k, cloneValue(x));
|
|
33596
|
+
return out;
|
|
33597
|
+
}
|
|
33598
|
+
if (v instanceof Set)
|
|
33599
|
+
return new Set(v);
|
|
33600
|
+
const clone = v.clone;
|
|
33601
|
+
if (typeof clone === "function")
|
|
33602
|
+
return clone.call(v);
|
|
33603
|
+
const out = {};
|
|
33604
|
+
for (const [k, x] of Object.entries(v))
|
|
33605
|
+
out[k] = cloneValue(x);
|
|
33606
|
+
return out;
|
|
33607
|
+
}
|
|
33608
|
+
|
|
33584
33609
|
// src/runtime/udt.ts
|
|
33585
33610
|
class UdtType {
|
|
33586
33611
|
name;
|
|
@@ -33637,6 +33662,22 @@ class UdtInstance {
|
|
|
33637
33662
|
getMethod(name) {
|
|
33638
33663
|
return this.type.getMethod(name);
|
|
33639
33664
|
}
|
|
33665
|
+
clone() {
|
|
33666
|
+
const out = new UdtInstance(this.type);
|
|
33667
|
+
out.restoreContents(this.snapshotContents());
|
|
33668
|
+
return out;
|
|
33669
|
+
}
|
|
33670
|
+
snapshotContents() {
|
|
33671
|
+
const out = [];
|
|
33672
|
+
for (const [k, v] of this.values)
|
|
33673
|
+
out.push([k, cloneValue(v)]);
|
|
33674
|
+
return out;
|
|
33675
|
+
}
|
|
33676
|
+
restoreContents(snap) {
|
|
33677
|
+
this.values.clear();
|
|
33678
|
+
for (const [k, v] of snap)
|
|
33679
|
+
this.values.set(k, cloneValue(v));
|
|
33680
|
+
}
|
|
33640
33681
|
}
|
|
33641
33682
|
|
|
33642
33683
|
class EnumMember {
|
|
@@ -33910,6 +33951,19 @@ class PineArray {
|
|
|
33910
33951
|
out.push(v);
|
|
33911
33952
|
return out;
|
|
33912
33953
|
}
|
|
33954
|
+
clone() {
|
|
33955
|
+
const out = new PineArray;
|
|
33956
|
+
out.restoreContents(this.snapshotContents());
|
|
33957
|
+
return out;
|
|
33958
|
+
}
|
|
33959
|
+
snapshotContents() {
|
|
33960
|
+
return this.cells.map(cloneValue);
|
|
33961
|
+
}
|
|
33962
|
+
restoreContents(snap) {
|
|
33963
|
+
this.cells.length = 0;
|
|
33964
|
+
for (const c of snap)
|
|
33965
|
+
this.cells.push(cloneValue(c));
|
|
33966
|
+
}
|
|
33913
33967
|
reverse() {
|
|
33914
33968
|
this.cells.reverse();
|
|
33915
33969
|
}
|
|
@@ -36928,6 +36982,12 @@ class PineSeries {
|
|
|
36928
36982
|
else
|
|
36929
36983
|
this.data[this.data.length - 1] = value;
|
|
36930
36984
|
}
|
|
36985
|
+
truncate(len) {
|
|
36986
|
+
if (len < 0)
|
|
36987
|
+
return;
|
|
36988
|
+
if (this.data.length > len)
|
|
36989
|
+
this.data.length = len;
|
|
36990
|
+
}
|
|
36931
36991
|
get current() {
|
|
36932
36992
|
return this.data.length === 0 ? NA : this.data[this.data.length - 1];
|
|
36933
36993
|
}
|
|
@@ -37555,6 +37615,30 @@ class StrategyBook {
|
|
|
37555
37615
|
if (settings)
|
|
37556
37616
|
this.applyDeclSettings(settings);
|
|
37557
37617
|
}
|
|
37618
|
+
snapshot() {
|
|
37619
|
+
const out = {};
|
|
37620
|
+
for (const [key, value] of Object.entries(this)) {
|
|
37621
|
+
if (typeof value === "function")
|
|
37622
|
+
continue;
|
|
37623
|
+
out[key] = cloneValue(value);
|
|
37624
|
+
}
|
|
37625
|
+
return out;
|
|
37626
|
+
}
|
|
37627
|
+
restore(snap) {
|
|
37628
|
+
const self = this;
|
|
37629
|
+
for (const [key, value] of Object.entries(snap)) {
|
|
37630
|
+
const live = self[key];
|
|
37631
|
+
if (Array.isArray(live)) {
|
|
37632
|
+
live.length = 0;
|
|
37633
|
+
for (const item of value)
|
|
37634
|
+
live.push(cloneValue(item));
|
|
37635
|
+
} else if (live !== null && typeof live === "object" && value !== null && typeof value === "object") {
|
|
37636
|
+
Object.assign(live, value);
|
|
37637
|
+
} else {
|
|
37638
|
+
self[key] = cloneValue(value);
|
|
37639
|
+
}
|
|
37640
|
+
}
|
|
37641
|
+
}
|
|
37558
37642
|
capitalHeld() {
|
|
37559
37643
|
let notional = 0;
|
|
37560
37644
|
for (const t of this.openTrades) {
|
|
@@ -38847,6 +38931,25 @@ class PineMap {
|
|
|
38847
38931
|
out.put(decodeKey(k), this.data.get(k));
|
|
38848
38932
|
return out;
|
|
38849
38933
|
}
|
|
38934
|
+
clone() {
|
|
38935
|
+
const out = new PineMap;
|
|
38936
|
+
out.restoreContents(this.snapshotContents());
|
|
38937
|
+
return out;
|
|
38938
|
+
}
|
|
38939
|
+
snapshotContents() {
|
|
38940
|
+
const data = [];
|
|
38941
|
+
for (const [k, v] of this.data)
|
|
38942
|
+
data.push([k, cloneValue(v)]);
|
|
38943
|
+
return { data, order: [...this.order] };
|
|
38944
|
+
}
|
|
38945
|
+
restoreContents(snap) {
|
|
38946
|
+
this.data.clear();
|
|
38947
|
+
this.order.length = 0;
|
|
38948
|
+
for (const [k, v] of snap.data)
|
|
38949
|
+
this.data.set(k, cloneValue(v));
|
|
38950
|
+
for (const k of snap.order)
|
|
38951
|
+
this.order.push(k);
|
|
38952
|
+
}
|
|
38850
38953
|
putAll(other) {
|
|
38851
38954
|
if (!(other instanceof PineMap))
|
|
38852
38955
|
return;
|
|
@@ -39436,6 +39539,25 @@ class PineMatrix {
|
|
|
39436
39539
|
row[j] = value;
|
|
39437
39540
|
}
|
|
39438
39541
|
}
|
|
39542
|
+
clone() {
|
|
39543
|
+
const out = new PineMatrix(this.nRows, this.nCols);
|
|
39544
|
+
out.restoreContents(this.snapshotContents());
|
|
39545
|
+
return out;
|
|
39546
|
+
}
|
|
39547
|
+
snapshotContents() {
|
|
39548
|
+
return {
|
|
39549
|
+
cells: this.cells.map((row) => row.map(cloneValue)),
|
|
39550
|
+
nRows: this.nRows,
|
|
39551
|
+
nCols: this.nCols
|
|
39552
|
+
};
|
|
39553
|
+
}
|
|
39554
|
+
restoreContents(snap) {
|
|
39555
|
+
this.cells.length = 0;
|
|
39556
|
+
for (const row of snap.cells)
|
|
39557
|
+
this.cells.push(row.map(cloneValue));
|
|
39558
|
+
this.nRows = snap.nRows;
|
|
39559
|
+
this.nCols = snap.nCols;
|
|
39560
|
+
}
|
|
39439
39561
|
transpose() {
|
|
39440
39562
|
const t = new PineMatrix(this.nCols, this.nRows);
|
|
39441
39563
|
for (let i = 0;i < this.nRows; i++) {
|
|
@@ -40538,6 +40660,29 @@ class TaEngine {
|
|
|
40538
40660
|
historySites = new Map;
|
|
40539
40661
|
momentumFilterSites = new Map;
|
|
40540
40662
|
volatilityRegimeSites = new Map;
|
|
40663
|
+
snapshot() {
|
|
40664
|
+
const out = [];
|
|
40665
|
+
for (const [key, value] of Object.entries(this)) {
|
|
40666
|
+
if (!(value instanceof Map))
|
|
40667
|
+
continue;
|
|
40668
|
+
const copy = new Map;
|
|
40669
|
+
for (const [site, state] of value)
|
|
40670
|
+
copy.set(site, cloneValue(state));
|
|
40671
|
+
out.push([key, copy]);
|
|
40672
|
+
}
|
|
40673
|
+
return out;
|
|
40674
|
+
}
|
|
40675
|
+
restore(snap) {
|
|
40676
|
+
const self = this;
|
|
40677
|
+
for (const [key, copy] of snap) {
|
|
40678
|
+
const live = self[key];
|
|
40679
|
+
if (!(live instanceof Map))
|
|
40680
|
+
continue;
|
|
40681
|
+
live.clear();
|
|
40682
|
+
for (const [site, state] of copy)
|
|
40683
|
+
live.set(site, cloneValue(state));
|
|
40684
|
+
}
|
|
40685
|
+
}
|
|
40541
40686
|
sma(site, source, period) {
|
|
40542
40687
|
const n = pinePeriod(period);
|
|
40543
40688
|
if (n === null)
|
|
@@ -45293,6 +45438,15 @@ function unwrapSpecialize(node) {
|
|
|
45293
45438
|
return n.value;
|
|
45294
45439
|
return node;
|
|
45295
45440
|
}
|
|
45441
|
+
function isArrayReturningCall(func) {
|
|
45442
|
+
const { name } = resolveCallee(func);
|
|
45443
|
+
if (name === "ta_gamma_levels" || name === "gamma_levels")
|
|
45444
|
+
return true;
|
|
45445
|
+
if (name === "array_from" || name === "array_copy" || name === "array_concat" || name === "array_slice") {
|
|
45446
|
+
return true;
|
|
45447
|
+
}
|
|
45448
|
+
return name.startsWith("array_new");
|
|
45449
|
+
}
|
|
45296
45450
|
function collectArgs(node, visit) {
|
|
45297
45451
|
const pos = [];
|
|
45298
45452
|
const kw = {};
|
|
@@ -47341,6 +47495,7 @@ var RESERVED2 = new Set([
|
|
|
47341
47495
|
function newEmitCtx() {
|
|
47342
47496
|
return {
|
|
47343
47497
|
arrays: new Set,
|
|
47498
|
+
arrayNames: new Set,
|
|
47344
47499
|
plots: [],
|
|
47345
47500
|
varNames: new Set,
|
|
47346
47501
|
functions: [],
|
|
@@ -48155,6 +48310,9 @@ function emitAttribute(state, node) {
|
|
|
48155
48310
|
function emitSubscript(state, node) {
|
|
48156
48311
|
const slice = node.slice != null ? emitExpr2(state, node.slice) : "0";
|
|
48157
48312
|
const arr = histArray(state, node.value);
|
|
48313
|
+
if (node.value.kind === "Name" && state.ctx.arrayNames.has(node.value.id)) {
|
|
48314
|
+
return `__h.array.sub(${arr}[__bar_idx], ${slice})`;
|
|
48315
|
+
}
|
|
48158
48316
|
return `__h.hist(${arr}, __bar_idx, ${slice})`;
|
|
48159
48317
|
}
|
|
48160
48318
|
function histArray(state, value) {
|
|
@@ -48253,11 +48411,22 @@ function emitImport2(state, node) {
|
|
|
48253
48411
|
function emitAssign2(state, node) {
|
|
48254
48412
|
const rhs = node.value != null ? emitExpr2(state, node.value) : "null";
|
|
48255
48413
|
const isVar = isVarMode2(node.mode);
|
|
48414
|
+
trackArrayName(state, node.target, node.value);
|
|
48256
48415
|
return emitStore(state, node.target, rhs, isVar);
|
|
48257
48416
|
}
|
|
48258
48417
|
function emitReAssign2(state, node) {
|
|
48418
|
+
trackArrayName(state, node.target, node.value);
|
|
48259
48419
|
return emitStore(state, node.target, emitExpr2(state, node.value), false);
|
|
48260
48420
|
}
|
|
48421
|
+
function trackArrayName(state, target, value) {
|
|
48422
|
+
if (target.kind !== "Name")
|
|
48423
|
+
return;
|
|
48424
|
+
if (value != null && value.kind === "Call" && isArrayReturningCall(value.func)) {
|
|
48425
|
+
state.ctx.arrayNames.add(target.id);
|
|
48426
|
+
} else {
|
|
48427
|
+
state.ctx.arrayNames.delete(target.id);
|
|
48428
|
+
}
|
|
48429
|
+
}
|
|
48261
48430
|
function emitAugAssign2(state, node) {
|
|
48262
48431
|
if (node.target.kind === "Attribute") {
|
|
48263
48432
|
return emitStore(state, node.target, emitExpr2(state, node.value), false);
|
|
@@ -48903,6 +49072,15 @@ var compileArray = {
|
|
|
48903
49072
|
get(id, index) {
|
|
48904
49073
|
return asArray(id)?.get(n2(index, 0)) ?? null;
|
|
48905
49074
|
},
|
|
49075
|
+
sub(id, offset) {
|
|
49076
|
+
const a = asArray(id);
|
|
49077
|
+
const off = cell(offset);
|
|
49078
|
+
if (a == null || off == null || off < 0)
|
|
49079
|
+
return null;
|
|
49080
|
+
const size = a.size();
|
|
49081
|
+
const i = size - 1 - Math.trunc(off);
|
|
49082
|
+
return i < 0 || i >= size ? null : a.get(i);
|
|
49083
|
+
},
|
|
48906
49084
|
set(id, index, value) {
|
|
48907
49085
|
asArray(id)?.set(n2(index, 0), store(value));
|
|
48908
49086
|
return id ?? null;
|
|
@@ -50903,13 +51081,21 @@ class Runtime {
|
|
|
50903
51081
|
const extraOpts = extra && !isPlainInputs(extra) ? extra : undefined;
|
|
50904
51082
|
const mode = extraOpts?.mode ?? this.mode;
|
|
50905
51083
|
const inputs = mergeInputs(this.inputs, extra);
|
|
51084
|
+
const rt = resolveRealtimeWindow(ohlcv.length, {
|
|
51085
|
+
realtimeLastBar: extraOpts?.realtimeLastBar,
|
|
51086
|
+
realtimeTicks: extraOpts?.realtimeTicks,
|
|
51087
|
+
realtimeBars: extraOpts?.realtimeBars,
|
|
51088
|
+
realtimeFromBar: extraOpts?.realtimeFromBar
|
|
51089
|
+
});
|
|
50906
51090
|
const host = {
|
|
50907
51091
|
symbol: this.symbol,
|
|
50908
51092
|
inputs,
|
|
50909
51093
|
broker: extraOpts?.broker ?? this.broker,
|
|
50910
51094
|
timeframe: extraOpts?.timeframe ?? this.timeframe,
|
|
50911
51095
|
libraries: extraOpts?.libraries != null ? resolveLibraries(extraOpts.libraries) : this.libraries,
|
|
50912
|
-
timeout_seconds: extraOpts?.timeout_seconds ?? this.timeout_seconds
|
|
51096
|
+
timeout_seconds: extraOpts?.timeout_seconds ?? this.timeout_seconds,
|
|
51097
|
+
realtime_first: rt.first,
|
|
51098
|
+
realtime_ticks: rt.ticks
|
|
50913
51099
|
};
|
|
50914
51100
|
if (mode === "compile") {
|
|
50915
51101
|
return runCompiled(source, ohlcv, host);
|
|
@@ -50972,7 +51158,7 @@ class RuntimeStream {
|
|
|
50972
51158
|
return;
|
|
50973
51159
|
this.bars.push(bar);
|
|
50974
51160
|
try {
|
|
50975
|
-
const out = this.runtime.run(this.source, this.bars);
|
|
51161
|
+
const out = this.runtime.run(this.source, this.bars, { realtimeLastBar: true });
|
|
50976
51162
|
for (const h of this.barHandlers)
|
|
50977
51163
|
h(out);
|
|
50978
51164
|
return out;
|
|
@@ -50983,9 +51169,29 @@ class RuntimeStream {
|
|
|
50983
51169
|
return;
|
|
50984
51170
|
}
|
|
50985
51171
|
}
|
|
51172
|
+
get barCount() {
|
|
51173
|
+
return this.bars.length;
|
|
51174
|
+
}
|
|
51175
|
+
updateLastBar(bar) {
|
|
51176
|
+
if (this.closed)
|
|
51177
|
+
throw new Error("stream is closed");
|
|
51178
|
+
if (this.bars.length === 0)
|
|
51179
|
+
throw new Error("updateLastBar requires at least one bar");
|
|
51180
|
+
this.bars[this.bars.length - 1] = bar;
|
|
51181
|
+
const out = this.runtime.run(this.source, this.bars, { realtimeLastBar: true });
|
|
51182
|
+
for (const h of this.barHandlers)
|
|
51183
|
+
h(out);
|
|
51184
|
+
return out;
|
|
51185
|
+
}
|
|
51186
|
+
appendBars(bars) {
|
|
51187
|
+
let out;
|
|
51188
|
+
for (const bar of bars)
|
|
51189
|
+
out = this.push(bar);
|
|
51190
|
+
return out;
|
|
51191
|
+
}
|
|
50986
51192
|
close() {
|
|
50987
51193
|
this.closed = true;
|
|
50988
|
-
const out = this.runtime.run(this.source, this.bars);
|
|
51194
|
+
const out = this.runtime.run(this.source, this.bars, { realtimeLastBar: false });
|
|
50989
51195
|
for (const h of this.endHandlers)
|
|
50990
51196
|
h(out);
|
|
50991
51197
|
return out;
|
|
@@ -50997,6 +51203,106 @@ function interpret(source, ohlcv) {
|
|
|
50997
51203
|
throw new Error(out.error);
|
|
50998
51204
|
return { plots: out.plots };
|
|
50999
51205
|
}
|
|
51206
|
+
function isSnapshotContainer(v) {
|
|
51207
|
+
return v !== null && typeof v === "object" && typeof v.snapshotContents === "function";
|
|
51208
|
+
}
|
|
51209
|
+
function isRestoreContainer(v) {
|
|
51210
|
+
return v !== null && typeof v === "object" && typeof v.restoreContents === "function";
|
|
51211
|
+
}
|
|
51212
|
+
function snapshotTickState(env) {
|
|
51213
|
+
const containers = [];
|
|
51214
|
+
for (const [id, v] of Object.entries(env.ctx)) {
|
|
51215
|
+
if (isSnapshotContainer(v)) {
|
|
51216
|
+
containers.push([id, v.snapshotContents()]);
|
|
51217
|
+
}
|
|
51218
|
+
}
|
|
51219
|
+
const plotsLens = new Map;
|
|
51220
|
+
for (const [key, arr] of Object.entries(env.plots))
|
|
51221
|
+
plotsLens.set(key, arr.length);
|
|
51222
|
+
const udfSites = [];
|
|
51223
|
+
for (const [key, f] of env.udfSites) {
|
|
51224
|
+
const seriesLens = new Map;
|
|
51225
|
+
for (const [name, s] of f.series)
|
|
51226
|
+
seriesLens.set(name, s.length);
|
|
51227
|
+
udfSites.push([key, { ...f.ctx }, new Set(f.varInited), seriesLens]);
|
|
51228
|
+
}
|
|
51229
|
+
return {
|
|
51230
|
+
ctx: { ...env.ctx },
|
|
51231
|
+
containers,
|
|
51232
|
+
varInited: new Set(env.varInited),
|
|
51233
|
+
plotsLens,
|
|
51234
|
+
plotMetaLen: env.plot_meta.length,
|
|
51235
|
+
ta: env.ta.snapshot(),
|
|
51236
|
+
book: env.book.snapshot(),
|
|
51237
|
+
udfSites
|
|
51238
|
+
};
|
|
51239
|
+
}
|
|
51240
|
+
function restoreTickState(env, snap) {
|
|
51241
|
+
const varips = env.varipNames;
|
|
51242
|
+
for (const key of Object.keys(env.ctx)) {
|
|
51243
|
+
if (!(key in snap.ctx) && !varips.has(key))
|
|
51244
|
+
delete env.ctx[key];
|
|
51245
|
+
}
|
|
51246
|
+
for (const [key, value] of Object.entries(snap.ctx)) {
|
|
51247
|
+
if (varips.has(key))
|
|
51248
|
+
continue;
|
|
51249
|
+
env.ctx[key] = value;
|
|
51250
|
+
}
|
|
51251
|
+
for (const [id, contents] of snap.containers) {
|
|
51252
|
+
if (varips.has(id))
|
|
51253
|
+
continue;
|
|
51254
|
+
const cur = env.ctx[id];
|
|
51255
|
+
if (isRestoreContainer(cur)) {
|
|
51256
|
+
cur.restoreContents(contents);
|
|
51257
|
+
}
|
|
51258
|
+
}
|
|
51259
|
+
const restoredInited = new Set(snap.varInited);
|
|
51260
|
+
for (const id of varips) {
|
|
51261
|
+
if (env.varInited.has(id))
|
|
51262
|
+
restoredInited.add(id);
|
|
51263
|
+
}
|
|
51264
|
+
env.varInited = restoredInited;
|
|
51265
|
+
for (const key of Object.keys(env.plots)) {
|
|
51266
|
+
const len = snap.plotsLens.get(key);
|
|
51267
|
+
if (len === undefined)
|
|
51268
|
+
delete env.plots[key];
|
|
51269
|
+
else if (env.plots[key].length > len)
|
|
51270
|
+
env.plots[key].length = len;
|
|
51271
|
+
}
|
|
51272
|
+
env.plot_meta.length = snap.plotMetaLen;
|
|
51273
|
+
env.ta.restore(snap.ta);
|
|
51274
|
+
env.book.restore(snap.book);
|
|
51275
|
+
const siteKeys = new Set(snap.udfSites.map(([key]) => key));
|
|
51276
|
+
for (const key of [...env.udfSites.keys()]) {
|
|
51277
|
+
if (!siteKeys.has(key))
|
|
51278
|
+
env.udfSites.delete(key);
|
|
51279
|
+
}
|
|
51280
|
+
for (const [key, ctx, varInited, seriesLens] of snap.udfSites) {
|
|
51281
|
+
const f = env.udfSites.get(key);
|
|
51282
|
+
if (f == null)
|
|
51283
|
+
continue;
|
|
51284
|
+
for (const k of Object.keys(f.ctx)) {
|
|
51285
|
+
if (!(k in ctx) && !varips.has(k))
|
|
51286
|
+
delete f.ctx[k];
|
|
51287
|
+
}
|
|
51288
|
+
for (const [k, v] of Object.entries(ctx)) {
|
|
51289
|
+
if (varips.has(k))
|
|
51290
|
+
continue;
|
|
51291
|
+
f.ctx[k] = v;
|
|
51292
|
+
}
|
|
51293
|
+
for (const [name, len] of seriesLens) {
|
|
51294
|
+
const s = f.series.get(name);
|
|
51295
|
+
if (s != null && s.length > len)
|
|
51296
|
+
s.truncate(len);
|
|
51297
|
+
}
|
|
51298
|
+
const restored = new Set(varInited);
|
|
51299
|
+
for (const id of varips) {
|
|
51300
|
+
if (f.varInited.has(id))
|
|
51301
|
+
restored.add(id);
|
|
51302
|
+
}
|
|
51303
|
+
f.varInited = restored;
|
|
51304
|
+
}
|
|
51305
|
+
}
|
|
51000
51306
|
function interpretTree(tree, ohlcv, host) {
|
|
51001
51307
|
const scriptNode = tree.kind === "Script" ? tree : null;
|
|
51002
51308
|
const body = scriptNode?.body ?? [];
|
|
@@ -51032,7 +51338,13 @@ function interpretTree(tree, ohlcv, host) {
|
|
|
51032
51338
|
pendingExports: new Map,
|
|
51033
51339
|
onceFired: new WeakSet,
|
|
51034
51340
|
maxBarsBackDecls: [],
|
|
51035
|
-
alertFireBars: new Map
|
|
51341
|
+
alertFireBars: new Map,
|
|
51342
|
+
realtimeFirst: host?.realtime_first ?? null,
|
|
51343
|
+
realtimeTicks: Math.max(1, host?.realtime_ticks ?? 1),
|
|
51344
|
+
barRealtime: false,
|
|
51345
|
+
tickIndex: 0,
|
|
51346
|
+
tickCount: 1,
|
|
51347
|
+
varipNames: new Set
|
|
51036
51348
|
};
|
|
51037
51349
|
const n = ohlcv.length;
|
|
51038
51350
|
let runError;
|
|
@@ -51040,8 +51352,9 @@ function interpretTree(tree, ohlcv, host) {
|
|
|
51040
51352
|
let barsDone = n;
|
|
51041
51353
|
const timeoutSec = host?.timeout_seconds;
|
|
51042
51354
|
const deadline = timeoutSec != null && Number.isFinite(timeoutSec) ? performance.now() + timeoutSec * 1000 : null;
|
|
51355
|
+
let aborted = false;
|
|
51043
51356
|
try {
|
|
51044
|
-
for (let i = 0;i < n; i++) {
|
|
51357
|
+
for (let i = 0;i < n && !aborted; i++) {
|
|
51045
51358
|
if (deadline != null && (i & 31) === 0 && performance.now() > deadline) {
|
|
51046
51359
|
timedOut = true;
|
|
51047
51360
|
barsDone = i;
|
|
@@ -51056,33 +51369,44 @@ function interpretTree(tree, ohlcv, host) {
|
|
|
51056
51369
|
time: num2(env.ctx.time) ?? undefined
|
|
51057
51370
|
});
|
|
51058
51371
|
env.book.markOpenTrades(num2(env.ctx.high) ?? num2(env.ctx.close) ?? 0, num2(env.ctx.low) ?? num2(env.ctx.close) ?? 0, num2(env.ctx.close) ?? 0);
|
|
51059
|
-
|
|
51060
|
-
|
|
51061
|
-
|
|
51062
|
-
|
|
51063
|
-
|
|
51064
|
-
|
|
51065
|
-
|
|
51066
|
-
|
|
51067
|
-
|
|
51068
|
-
|
|
51069
|
-
|
|
51070
|
-
|
|
51071
|
-
|
|
51072
|
-
|
|
51372
|
+
const barRt = env.realtimeFirst != null && i >= env.realtimeFirst;
|
|
51373
|
+
const ticks = barRt ? env.realtimeTicks : 1;
|
|
51374
|
+
env.barRealtime = barRt;
|
|
51375
|
+
env.tickCount = ticks;
|
|
51376
|
+
for (let tick = 0;tick < ticks; tick++) {
|
|
51377
|
+
env.tickIndex = tick;
|
|
51378
|
+
const snap = barRt && tick < ticks - 1 ? snapshotTickState(env) : null;
|
|
51379
|
+
try {
|
|
51380
|
+
for (const stmt of body) {
|
|
51381
|
+
const decl = captureDecl(stmt);
|
|
51382
|
+
if (decl) {
|
|
51383
|
+
if (script_name == null)
|
|
51384
|
+
script_name = decl.name;
|
|
51385
|
+
if (decl.kind === "strategy") {
|
|
51386
|
+
script_type = "strategy";
|
|
51387
|
+
applyStrategyDecl(stmt, env);
|
|
51388
|
+
} else if (decl.kind === "library") {
|
|
51389
|
+
script_type = "library";
|
|
51390
|
+
applyDrawingDecl(stmt, env);
|
|
51391
|
+
} else {
|
|
51392
|
+
applyDrawingDecl(stmt, env);
|
|
51393
|
+
}
|
|
51394
|
+
continue;
|
|
51073
51395
|
}
|
|
51074
|
-
|
|
51396
|
+
execStmt(stmt, env);
|
|
51075
51397
|
}
|
|
51076
|
-
|
|
51077
|
-
|
|
51078
|
-
|
|
51079
|
-
|
|
51398
|
+
if (i === 0 && script_type === "library" && script_name) {
|
|
51399
|
+
finalizeLibrary(env, script_name);
|
|
51400
|
+
}
|
|
51401
|
+
} catch (err) {
|
|
51402
|
+
if (err === LOOP_BREAK || err === LOOP_CONTINUE)
|
|
51403
|
+
break;
|
|
51404
|
+
runError = { error: formatRunError(err), error_kind: "runtime" };
|
|
51405
|
+
aborted = true;
|
|
51406
|
+
break;
|
|
51080
51407
|
}
|
|
51081
|
-
|
|
51082
|
-
|
|
51083
|
-
continue;
|
|
51084
|
-
runError = { error: formatRunError(err), error_kind: "runtime" };
|
|
51085
|
-
break;
|
|
51408
|
+
if (snap)
|
|
51409
|
+
restoreTickState(env, snap);
|
|
51086
51410
|
}
|
|
51087
51411
|
}
|
|
51088
51412
|
} catch (err) {
|
|
@@ -51349,7 +51673,7 @@ function uniquifyPlotKey(env, node, title) {
|
|
|
51349
51673
|
return key;
|
|
51350
51674
|
}
|
|
51351
51675
|
function isVarMode3(stmt) {
|
|
51352
|
-
return stmt.mode?.kind === "Var";
|
|
51676
|
+
return stmt.mode?.kind === "Var" || stmt.mode?.kind === "VarIp";
|
|
51353
51677
|
}
|
|
51354
51678
|
function isTuple(v) {
|
|
51355
51679
|
return typeof v === "object" && v !== null && v.__tuple === true;
|
|
@@ -51464,6 +51788,15 @@ function evalAssign(stmt, env) {
|
|
|
51464
51788
|
if (stmt.target.kind !== "Name")
|
|
51465
51789
|
return NA;
|
|
51466
51790
|
const id = stmt.target.id;
|
|
51791
|
+
const isVarip = stmt.mode?.kind === "VarIp";
|
|
51792
|
+
if (isVarip)
|
|
51793
|
+
env.varipNames.add(id);
|
|
51794
|
+
if (isVarip && env.barRealtime) {
|
|
51795
|
+
const value = evalExpr(stmt.value, env);
|
|
51796
|
+
bindName(env, id, value);
|
|
51797
|
+
inited.add(id);
|
|
51798
|
+
return value;
|
|
51799
|
+
}
|
|
51467
51800
|
if (isVarMode3(stmt) && (inited.has(id) || env.barIndex !== 0 && ctxGet(env, id) !== undefined)) {
|
|
51468
51801
|
inited.add(id);
|
|
51469
51802
|
const cur = ctxGet(env, id);
|
|
@@ -51732,6 +52065,12 @@ function evalExpr(node, env) {
|
|
|
51732
52065
|
const s = seriesGet(env, node.value.id);
|
|
51733
52066
|
if (s)
|
|
51734
52067
|
return s.get(offset);
|
|
52068
|
+
const v = ctxGet(env, node.value.id);
|
|
52069
|
+
if (v instanceof PineArray) {
|
|
52070
|
+
const size = v.size();
|
|
52071
|
+
const i = size - 1 - offset;
|
|
52072
|
+
return i < 0 || i >= size ? NA : v.get(i);
|
|
52073
|
+
}
|
|
51735
52074
|
}
|
|
51736
52075
|
return NA;
|
|
51737
52076
|
}
|
|
@@ -51781,7 +52120,8 @@ function evalExpr(node, env) {
|
|
|
51781
52120
|
return NA;
|
|
51782
52121
|
for (const s of onceNode.body)
|
|
51783
52122
|
execStmt(s, env);
|
|
51784
|
-
env
|
|
52123
|
+
if (barIsConfirmed(env))
|
|
52124
|
+
env.onceFired.add(onceNode);
|
|
51785
52125
|
return NA;
|
|
51786
52126
|
}
|
|
51787
52127
|
case "BoolOp":
|
|
@@ -52128,20 +52468,21 @@ function evalAttribute(node, env) {
|
|
|
52128
52468
|
}
|
|
52129
52469
|
if (node.value.id === "barstate") {
|
|
52130
52470
|
const last = env.barIndex === env.barCount - 1;
|
|
52471
|
+
const rt = env.barRealtime;
|
|
52131
52472
|
if (node.attr === "isfirst")
|
|
52132
52473
|
return env.barIndex === 0 ? 1 : 0;
|
|
52133
52474
|
if (node.attr === "islast")
|
|
52134
52475
|
return last ? 1 : 0;
|
|
52135
52476
|
if (node.attr === "ishistory")
|
|
52136
|
-
return
|
|
52477
|
+
return rt ? 0 : 1;
|
|
52137
52478
|
if (node.attr === "isconfirmed")
|
|
52138
|
-
return 1;
|
|
52479
|
+
return barIsConfirmed(env) ? 1 : 0;
|
|
52139
52480
|
if (node.attr === "isnew")
|
|
52140
|
-
return 1;
|
|
52481
|
+
return rt && env.tickIndex > 0 ? 0 : 1;
|
|
52141
52482
|
if (node.attr === "isrealtime")
|
|
52142
|
-
return 0;
|
|
52483
|
+
return rt ? 1 : 0;
|
|
52143
52484
|
if (node.attr === "islastconfirmedhistory")
|
|
52144
|
-
return last ? 1 : 0;
|
|
52485
|
+
return rt ? 0 : last ? 1 : 0;
|
|
52145
52486
|
}
|
|
52146
52487
|
if (node.value.id === "session") {
|
|
52147
52488
|
if (node.attr === "regular")
|
|
@@ -52909,8 +53250,35 @@ function formatRunError(err) {
|
|
|
52909
53250
|
}
|
|
52910
53251
|
return "runtime error";
|
|
52911
53252
|
}
|
|
53253
|
+
function resolveRealtimeWindow(nBars, opts) {
|
|
53254
|
+
const intOr = (v, fallback) => {
|
|
53255
|
+
if (v == null || !Number.isFinite(v))
|
|
53256
|
+
return fallback;
|
|
53257
|
+
return Math.trunc(v);
|
|
53258
|
+
};
|
|
53259
|
+
let ticks = intOr(opts.realtimeTicks, 1);
|
|
53260
|
+
if (ticks < 1)
|
|
53261
|
+
ticks = 1;
|
|
53262
|
+
let rtBars = intOr(opts.realtimeBars, 0);
|
|
53263
|
+
if (rtBars < 0)
|
|
53264
|
+
rtBars = 0;
|
|
53265
|
+
if (opts.realtimeFromBar != null) {
|
|
53266
|
+
let first = intOr(opts.realtimeFromBar, 0);
|
|
53267
|
+
if (first < 0)
|
|
53268
|
+
first = 0;
|
|
53269
|
+
if (first >= nBars)
|
|
53270
|
+
return { first: null, ticks };
|
|
53271
|
+
return { first, ticks };
|
|
53272
|
+
}
|
|
53273
|
+
if (rtBars > 0)
|
|
53274
|
+
return { first: nBars > rtBars ? nBars - rtBars : 0, ticks };
|
|
53275
|
+
if (opts.realtimeLastBar || ticks > 1) {
|
|
53276
|
+
return { first: nBars > 0 ? nBars - 1 : null, ticks };
|
|
53277
|
+
}
|
|
53278
|
+
return { first: null, ticks };
|
|
53279
|
+
}
|
|
52912
53280
|
function isPlainInputs(extra) {
|
|
52913
|
-
return !("inputs" in extra) && !("broker" in extra) && !("timeframe" in extra) && !("libraries" in extra) && !("mode" in extra) && !("timeout_seconds" in extra);
|
|
53281
|
+
return !("inputs" in extra) && !("broker" in extra) && !("timeframe" in extra) && !("libraries" in extra) && !("mode" in extra) && !("timeout_seconds" in extra) && !("realtimeLastBar" in extra) && !("realtimeTicks" in extra) && !("realtimeBars" in extra) && !("realtimeFromBar" in extra);
|
|
52914
53282
|
}
|
|
52915
53283
|
function resolveLibraries(libs) {
|
|
52916
53284
|
if (libs instanceof LibraryRegistry)
|
|
@@ -53082,8 +53450,8 @@ function normalizeAlertFreq(freq) {
|
|
|
53082
53450
|
const s = String(freq).trim().toLowerCase().replace(/ /g, "_");
|
|
53083
53451
|
return ALERT_FREQ_ALIASES[s] ?? (s ? s : FREQ_ONCE_PER_BAR);
|
|
53084
53452
|
}
|
|
53085
|
-
function barIsConfirmed(
|
|
53086
|
-
return
|
|
53453
|
+
function barIsConfirmed(env) {
|
|
53454
|
+
return !env.barRealtime || env.tickIndex === env.tickCount - 1;
|
|
53087
53455
|
}
|
|
53088
53456
|
function shouldFireAlert(env, source, title, message, freq) {
|
|
53089
53457
|
const freqN = normalizeAlertFreq(freq);
|
|
@@ -56792,6 +57160,7 @@ export {
|
|
|
56792
57160
|
mapJsonBars,
|
|
56793
57161
|
parse,
|
|
56794
57162
|
parseTimestampString,
|
|
57163
|
+
resolveRealtimeWindow,
|
|
56795
57164
|
runScript,
|
|
56796
57165
|
runtimeError,
|
|
56797
57166
|
tickerHeikinashi,
|
package/package.json
CHANGED
package/src/cli/rich.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
export { dump, parse, tokenize, unparse, PinescriptSyntaxError } from "./ast/helper.ts";
|
|
10
10
|
export type { ParseMode } from "./ast/helper.ts";
|
|
11
11
|
export type { AST, Script, Expression } from "./ast/nodes.ts";
|
|
12
|
-
export { Runtime, RuntimeStream, interpret, interpretTree } from "./runtime/interpret.ts";
|
|
12
|
+
export { Runtime, RuntimeStream, interpret, interpretTree, resolveRealtimeWindow } from "./runtime/interpret.ts";
|
|
13
13
|
export type {
|
|
14
14
|
DrawingEvent,
|
|
15
15
|
InputOverrides,
|