@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/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
- try {
51060
- for (const stmt of body) {
51061
- const decl = captureDecl(stmt);
51062
- if (decl) {
51063
- if (script_name == null)
51064
- script_name = decl.name;
51065
- if (decl.kind === "strategy") {
51066
- script_type = "strategy";
51067
- applyStrategyDecl(stmt, env);
51068
- } else if (decl.kind === "library") {
51069
- script_type = "library";
51070
- applyDrawingDecl(stmt, env);
51071
- } else {
51072
- applyDrawingDecl(stmt, env);
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
- continue;
51396
+ execStmt(stmt, env);
51075
51397
  }
51076
- execStmt(stmt, env);
51077
- }
51078
- if (i === 0 && script_type === "library" && script_name) {
51079
- finalizeLibrary(env, script_name);
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
- } catch (err) {
51082
- if (err === LOOP_BREAK || err === LOOP_CONTINUE)
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.onceFired.add(onceNode);
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 last ? 0 : 1;
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(_env) {
53086
- return true;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hoox-sh/pynets",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "author": "jango_blockchained",
package/src/cli/rich.ts CHANGED
@@ -12,7 +12,7 @@ const MUTED = [203, 204, 189] as const;
12
12
  const FAIL = [231, 0, 11] as const;
13
13
  const WARN = [235, 169, 65] as const;
14
14
 
15
- export const VERSION = "0.8.0";
15
+ export const VERSION = "0.10.0";
16
16
 
17
17
  type Rgb = readonly [number, number, number];
18
18
 
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,