@hoox-sh/pynets 0.4.0 → 0.6.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
@@ -6287,6 +6287,7 @@ class PinescriptLexerBase extends cn {
6287
6287
  _lastPendingTokenType = 0;
6288
6288
  _lastPendingTokenTypeFromDefaultChannel = 0;
6289
6289
  _numOpens = 0;
6290
+ _numSqBrackets = 0;
6290
6291
  _indentLengthStack = [];
6291
6292
  _inputStarted = false;
6292
6293
  constructor(input) {
@@ -6340,6 +6341,7 @@ class PinescriptLexerBase extends cn {
6340
6341
  this._lastPendingTokenType = 0;
6341
6342
  this._lastPendingTokenTypeFromDefaultChannel = 0;
6342
6343
  this._numOpens = 0;
6344
+ this._numSqBrackets = 0;
6343
6345
  this._indentLengthStack = [];
6344
6346
  this._inputStarted = false;
6345
6347
  }
@@ -6356,11 +6358,17 @@ class PinescriptLexerBase extends cn {
6356
6358
  const tok = this._currentToken;
6357
6359
  const tokType = tok.type;
6358
6360
  const C = this.C;
6359
- if (tokType === C.LPAR || tokType === C.LSQB) {
6361
+ if (tokType === C.LPAR) {
6360
6362
  this._numOpens += 1;
6361
6363
  this._addPendingToken(tok);
6362
- } else if (tokType === C.RPAR || tokType === C.RSQB) {
6363
- this._numOpens -= 1;
6364
+ } else if (tokType === C.LSQB) {
6365
+ this._numSqBrackets += 1;
6366
+ this._addPendingToken(tok);
6367
+ } else if (tokType === C.RPAR) {
6368
+ this._numOpens = Math.max(0, this._numOpens - 1);
6369
+ this._addPendingToken(tok);
6370
+ } else if (tokType === C.RSQB) {
6371
+ this._numSqBrackets = Math.max(0, this._numSqBrackets - 1);
6364
6372
  this._addPendingToken(tok);
6365
6373
  } else if (tokType === C.NEWLINE) {
6366
6374
  this._handleNEWLINEToken();
@@ -6452,7 +6460,7 @@ class PinescriptLexerBase extends cn {
6452
6460
  return tok;
6453
6461
  }
6454
6462
  _handleNEWLINEToken() {
6455
- if (this._numOpens > 0 || this._operators.has(this._lastPendingTokenTypeFromDefaultChannel)) {
6463
+ if (this._numOpens > 0 || this._numSqBrackets > 0 || this._operators.has(this._lastPendingTokenTypeFromDefaultChannel)) {
6456
6464
  this._hideAndAddPendingToken(this._currentToken);
6457
6465
  return;
6458
6466
  }
@@ -34428,6 +34436,235 @@ function colorT(c) {
34428
34436
  return col ? alphaToTransp(col.a) : null;
34429
34437
  }
34430
34438
 
34439
+ // src/runtime/footprint.ts
34440
+ class VolumeRow {
34441
+ up_price;
34442
+ down_price;
34443
+ buy_volume;
34444
+ sell_volume;
34445
+ delta;
34446
+ is_imbalance;
34447
+ is_poc;
34448
+ is_vah;
34449
+ is_val;
34450
+ constructor(up_price = 0, down_price = 0, buy_volume = 0, sell_volume = 0, delta = 0, is_imbalance = false, is_poc = false, is_vah = false, is_val = false) {
34451
+ this.up_price = up_price;
34452
+ this.down_price = down_price;
34453
+ this.buy_volume = buy_volume;
34454
+ this.sell_volume = sell_volume;
34455
+ this.delta = delta;
34456
+ this.is_imbalance = is_imbalance;
34457
+ this.is_poc = is_poc;
34458
+ this.is_vah = is_vah;
34459
+ this.is_val = is_val;
34460
+ }
34461
+ }
34462
+
34463
+ class Footprint {
34464
+ num_ticks;
34465
+ va_percentage;
34466
+ buy_volume;
34467
+ sell_volume;
34468
+ delta;
34469
+ total_volume;
34470
+ vah_row;
34471
+ val_row;
34472
+ poc_row;
34473
+ rows;
34474
+ constructor(num_ticks = 100, va_percentage = 70, buy_volume = 0, sell_volume = 0, delta = 0, total_volume = 0, vah_row = null, val_row = null, poc_row = null, rows = []) {
34475
+ this.num_ticks = num_ticks;
34476
+ this.va_percentage = va_percentage;
34477
+ this.buy_volume = buy_volume;
34478
+ this.sell_volume = sell_volume;
34479
+ this.delta = delta;
34480
+ this.total_volume = total_volume;
34481
+ this.vah_row = vah_row;
34482
+ this.val_row = val_row;
34483
+ this.poc_row = poc_row;
34484
+ this.rows = rows;
34485
+ }
34486
+ }
34487
+ var N2 = 624;
34488
+ var M2 = 397;
34489
+ var MATRIX_A = 2567483615;
34490
+ var UPPER_MASK = 2147483648;
34491
+ var LOWER_MASK = 2147483647;
34492
+
34493
+ class PyRandom {
34494
+ mt = new Uint32Array(N2);
34495
+ index = N2 + 1;
34496
+ seed(a) {
34497
+ const n = Math.trunc(a);
34498
+ const abs = n < 0 ? -n : n;
34499
+ const key = [];
34500
+ if (abs === 0)
34501
+ key.push(0);
34502
+ else {
34503
+ let x = abs;
34504
+ while (x > 0) {
34505
+ key.push(x >>> 0);
34506
+ x = Math.floor(x / 4294967296);
34507
+ }
34508
+ }
34509
+ this.initByArray(key);
34510
+ }
34511
+ random() {
34512
+ const a = this.genrand() >>> 5;
34513
+ const b = this.genrand() >>> 6;
34514
+ return (a * 67108864 + b) * (1 / 9007199254740992);
34515
+ }
34516
+ initGenrand(s) {
34517
+ const mt = this.mt;
34518
+ mt[0] = s >>> 0;
34519
+ for (let mti = 1;mti < N2; mti++) {
34520
+ mt[mti] = Math.imul(1812433253, mt[mti - 1] ^ mt[mti - 1] >>> 30) + mti >>> 0;
34521
+ }
34522
+ this.index = N2;
34523
+ }
34524
+ initByArray(initKey) {
34525
+ const mt = this.mt;
34526
+ this.initGenrand(19650218);
34527
+ let i = 1;
34528
+ let j = 0;
34529
+ const keyLength = initKey.length;
34530
+ let k = N2 > keyLength ? N2 : keyLength;
34531
+ for (;k > 0; k--) {
34532
+ mt[i] = (mt[i] ^ Math.imul(mt[i - 1] ^ mt[i - 1] >>> 30, 1664525)) + initKey[j] + j >>> 0;
34533
+ i++;
34534
+ j++;
34535
+ if (i >= N2) {
34536
+ mt[0] = mt[N2 - 1];
34537
+ i = 1;
34538
+ }
34539
+ if (j >= keyLength)
34540
+ j = 0;
34541
+ }
34542
+ for (k = N2 - 1;k > 0; k--) {
34543
+ mt[i] = (mt[i] ^ Math.imul(mt[i - 1] ^ mt[i - 1] >>> 30, 1566083941)) - i >>> 0;
34544
+ i++;
34545
+ if (i >= N2) {
34546
+ mt[0] = mt[N2 - 1];
34547
+ i = 1;
34548
+ }
34549
+ }
34550
+ mt[0] = 2147483648;
34551
+ this.index = N2;
34552
+ }
34553
+ genrand() {
34554
+ const mt = this.mt;
34555
+ if (this.index >= N2) {
34556
+ for (let kk = 0;kk < N2 - M2; kk++) {
34557
+ const y = mt[kk] & UPPER_MASK | mt[kk + 1] & LOWER_MASK;
34558
+ mt[kk] = (mt[kk + M2] ^ y >>> 1 ^ (y & 1 ? MATRIX_A : 0)) >>> 0;
34559
+ }
34560
+ for (let kk = N2 - M2;kk < N2 - 1; kk++) {
34561
+ const y = mt[kk] & UPPER_MASK | mt[kk + 1] & LOWER_MASK;
34562
+ mt[kk] = (mt[kk + (M2 - N2)] ^ y >>> 1 ^ (y & 1 ? MATRIX_A : 0)) >>> 0;
34563
+ }
34564
+ const y = mt[N2 - 1] & UPPER_MASK | mt[0] & LOWER_MASK;
34565
+ mt[N2 - 1] = (mt[M2 - 1] ^ y >>> 1 ^ (y & 1 ? MATRIX_A : 0)) >>> 0;
34566
+ this.index = 0;
34567
+ }
34568
+ let y = mt[this.index++];
34569
+ y ^= y >>> 11;
34570
+ y ^= y << 7 & 2636928640;
34571
+ y ^= y << 15 & 4022730752;
34572
+ y ^= y >>> 18;
34573
+ return y >>> 0;
34574
+ }
34575
+ }
34576
+ var pyRng = null;
34577
+ function seedFootprintRng(seed) {
34578
+ pyRng = new PyRandom;
34579
+ pyRng.seed(seed);
34580
+ }
34581
+ function nextRandom() {
34582
+ return pyRng != null ? pyRng.random() : Math.random();
34583
+ }
34584
+ function asCount(value, fallback) {
34585
+ if (typeof value === "number" && Number.isFinite(value))
34586
+ return Math.trunc(value);
34587
+ return fallback;
34588
+ }
34589
+ function rowAt(rows, idx) {
34590
+ return idx >= 0 && idx < rows.length ? rows[idx] : null;
34591
+ }
34592
+ function createFootprint(numTicks = 100, vaPercentage = 70) {
34593
+ const n = asCount(numTicks, 100);
34594
+ const va = asCount(vaPercentage, 70);
34595
+ const rows = [];
34596
+ const basePrice = 100;
34597
+ const tickSize = 0.01;
34598
+ for (let i = 0;i < n; i++) {
34599
+ const priceLevel = basePrice + i * tickSize;
34600
+ rows.push(new VolumeRow(priceLevel + tickSize, priceLevel, 1000 + nextRandom() * 500, 900 + nextRandom() * 500, 100 + (nextRandom() * 200 - 100), nextRandom() < 0.1, i === Math.floor(n / 2), i === Math.trunc(n * 0.7), i === Math.trunc(n * 0.3)));
34601
+ }
34602
+ const totalBuy = rows.reduce((s, r) => s + r.buy_volume, 0);
34603
+ const totalSell = rows.reduce((s, r) => s + r.sell_volume, 0);
34604
+ return new Footprint(n, va, totalBuy, totalSell, totalBuy - totalSell, totalBuy + totalSell, rowAt(rows, Math.trunc(n * 0.7)), rowAt(rows, Math.trunc(n * 0.3)), rowAt(rows, Math.floor(n / 2)), rows);
34605
+ }
34606
+ function footprintBuyVolume(fp) {
34607
+ return fp instanceof Footprint ? fp.buy_volume : 0;
34608
+ }
34609
+ function footprintSellVolume(fp) {
34610
+ return fp instanceof Footprint ? fp.sell_volume : 0;
34611
+ }
34612
+ function footprintDelta(fp) {
34613
+ return fp instanceof Footprint ? fp.delta : 0;
34614
+ }
34615
+ function footprintTotalVolume(fp) {
34616
+ return fp instanceof Footprint ? fp.total_volume : 0;
34617
+ }
34618
+ function footprintVah(fp) {
34619
+ return fp instanceof Footprint ? fp.vah_row : null;
34620
+ }
34621
+ function footprintVal(fp) {
34622
+ return fp instanceof Footprint ? fp.val_row : null;
34623
+ }
34624
+ function footprintPoc(fp) {
34625
+ return fp instanceof Footprint ? fp.poc_row : null;
34626
+ }
34627
+ function footprintRows(fp) {
34628
+ return fp instanceof Footprint ? fp.rows.slice() : [];
34629
+ }
34630
+ function footprintGetRowByPrice(fp, price) {
34631
+ if (!(fp instanceof Footprint) || price == null)
34632
+ return null;
34633
+ if (typeof price !== "number" || !Number.isFinite(price))
34634
+ return null;
34635
+ for (const row of fp.rows) {
34636
+ const lo = Math.min(row.down_price, row.up_price);
34637
+ const hi = Math.max(row.down_price, row.up_price);
34638
+ if (lo <= price && price <= hi)
34639
+ return row;
34640
+ }
34641
+ return null;
34642
+ }
34643
+ function volumeRowUpPrice(vr) {
34644
+ return vr instanceof VolumeRow ? vr.up_price : 0;
34645
+ }
34646
+ function volumeRowDownPrice(vr) {
34647
+ return vr instanceof VolumeRow ? vr.down_price : 0;
34648
+ }
34649
+ function volumeRowBuyVolume(vr) {
34650
+ return vr instanceof VolumeRow ? vr.buy_volume : 0;
34651
+ }
34652
+ function volumeRowSellVolume(vr) {
34653
+ return vr instanceof VolumeRow ? vr.sell_volume : 0;
34654
+ }
34655
+ function volumeRowDelta(vr) {
34656
+ return vr instanceof VolumeRow ? vr.delta : 0;
34657
+ }
34658
+ function volumeRowTotalVolume(vr) {
34659
+ return vr instanceof VolumeRow ? vr.buy_volume + vr.sell_volume : 0;
34660
+ }
34661
+ function volumeRowHasBuyImbalance(vr) {
34662
+ return vr instanceof VolumeRow ? Boolean(vr.is_imbalance && vr.buy_volume > vr.sell_volume) : false;
34663
+ }
34664
+ function volumeRowHasSellImbalance(vr) {
34665
+ return vr instanceof VolumeRow ? Boolean(vr.is_imbalance && vr.sell_volume > vr.buy_volume) : false;
34666
+ }
34667
+
34431
34668
  // src/runtime/request.ts
34432
34669
  var REQUEST_FNS = new Set([
34433
34670
  "request.security",
@@ -34547,6 +34784,7 @@ function resolveCurrencyRate(from, to) {
34547
34784
  }
34548
34785
  function resolveSeed(seed) {
34549
34786
  lastSeed = coerceSeed(seed ?? 0);
34787
+ seedFootprintRng(lastSeed);
34550
34788
  return null;
34551
34789
  }
34552
34790
  function resolveRequest(fname, host, args = {}) {
@@ -34565,6 +34803,10 @@ function resolveRequest(fname, host, args = {}) {
34565
34803
  if (fname === "request.seed") {
34566
34804
  return resolveSeed(seedFromArgs(args));
34567
34805
  }
34806
+ if (fname === "request.footprint") {
34807
+ const [numTicks, va] = footprintFromArgs(args);
34808
+ return createFootprint(numTicks, va);
34809
+ }
34568
34810
  return resolveForeignNa();
34569
34811
  }
34570
34812
  function isNamedArgs(args) {
@@ -34603,6 +34845,11 @@ function seedFromArgs(args) {
34603
34845
  return args[0] ?? 0;
34604
34846
  return args.seed ?? 0;
34605
34847
  }
34848
+ function footprintFromArgs(args) {
34849
+ if (!isNamedArgs(args))
34850
+ return [args[0] ?? 100, args[1] ?? 70];
34851
+ return [args.num_ticks ?? 100, args.va_percentage ?? 70];
34852
+ }
34606
34853
  function currencyPair(from, to) {
34607
34854
  const a = (from ?? "").trim().toUpperCase();
34608
34855
  const b = (to ?? "").trim().toUpperCase();
@@ -36081,6 +36328,13 @@ function mathRandom(a, b, rng = Math.random) {
36081
36328
  // src/runtime/time.ts
36082
36329
  var MIN_T = -62167219200;
36083
36330
  var MAX_T = 253402300799;
36331
+ function timestampToMs(ts) {
36332
+ if (ts == null || !Number.isFinite(ts))
36333
+ return null;
36334
+ if (Math.abs(ts) < 100000000000)
36335
+ return ts * 1000;
36336
+ return ts;
36337
+ }
36084
36338
  function utcPartsFromMs(ms) {
36085
36339
  let t = Number.isFinite(ms) ? Math.trunc(ms / 1000) : 0;
36086
36340
  if (t < MIN_T)
@@ -36937,8 +37191,7 @@ function coerceFormatTimeMs(time) {
36937
37191
  if (typeof raw !== "number" || !Number.isFinite(raw))
36938
37192
  return null;
36939
37193
  let ts = Math.trunc(raw);
36940
- if (ts > 0 && ts < 10000000000)
36941
- ts *= 1000;
37194
+ ts = timestampToMs(ts) ?? ts;
36942
37195
  return ts;
36943
37196
  }
36944
37197
  function formatOffsetHours(offsetHours) {
@@ -37691,6 +37944,48 @@ class StrategyBook {
37691
37944
  bar: isFiniteNumber2(bar) ? bar : 0
37692
37945
  });
37693
37946
  }
37947
+ placeClose(bar, id, price, opts) {
37948
+ const b = isFiniteNumber2(bar) ? bar : 0;
37949
+ const oid = String(id ?? "");
37950
+ this.ensureSanePosition();
37951
+ if (this.position.qty !== 0) {
37952
+ const absPos = Math.abs(this.position.qty);
37953
+ const rawQty = opts?.qty;
37954
+ const q = isFiniteNumber2(rawQty) && rawQty >= 0 ? Math.min(Math.abs(rawQty), absPos) : absPos;
37955
+ if (q > 0) {
37956
+ this.upsertPending({
37957
+ id: `${oid}:close`,
37958
+ direction: this.position.qty > 0 ? "short" : "long",
37959
+ qty: q,
37960
+ limit: null,
37961
+ stop: null,
37962
+ bar: b,
37963
+ kind: "close",
37964
+ deferred: true,
37965
+ comment: opts?.comment
37966
+ });
37967
+ }
37968
+ }
37969
+ this.close(b, oid);
37970
+ }
37971
+ placeCloseAll(bar, price, opts) {
37972
+ const b = isFiniteNumber2(bar) ? bar : 0;
37973
+ this.ensureSanePosition();
37974
+ if (this.position.qty !== 0) {
37975
+ this.upsertPending({
37976
+ id: "close_all",
37977
+ direction: this.position.qty > 0 ? "short" : "long",
37978
+ qty: Math.abs(this.position.qty),
37979
+ limit: null,
37980
+ stop: null,
37981
+ bar: b,
37982
+ kind: "close_all",
37983
+ deferred: true,
37984
+ comment: opts?.comment
37985
+ });
37986
+ }
37987
+ this.events.push({ type: "close_all", id: "", bar: b });
37988
+ }
37694
37989
  exit(bar, id, qty) {
37695
37990
  const event = {
37696
37991
  type: "exit",
@@ -37728,10 +38023,46 @@ class StrategyBook {
37728
38023
  placeEntry(bar, id, direction, qty, opts) {
37729
38024
  const limit = optLevel(opts?.limit);
37730
38025
  const stop = optLevel(opts?.stop);
38026
+ const b = isFiniteNumber2(bar) ? bar : 0;
38027
+ const oid = String(id ?? "");
37731
38028
  if (limit == null && stop == null) {
38029
+ if (opts?.deferMarket === true) {
38030
+ const dir = mapDirection(direction);
38031
+ const absQty = isFiniteNumber2(qty) ? Math.abs(qty) : Number.NaN;
38032
+ if (!isFiniteNumber2(absQty) || absQty <= 0)
38033
+ return;
38034
+ const t = isFiniteNumber2(opts?.time) ? opts.time : b;
38035
+ if (!this.riskAllowsEntry(dir, t))
38036
+ return;
38037
+ const mark = isFiniteNumber2(opts?.price) ? opts.price : 0;
38038
+ const capped = this.capQtyByMaxPosition(absQty, mark);
38039
+ if (!isFiniteNumber2(capped) || capped <= 0)
38040
+ return;
38041
+ const signed = dir === "long" ? capped : -capped;
38042
+ if (this.position.qty !== 0 && Math.sign(this.position.qty) === Math.sign(signed)) {
38043
+ const maxEntries = this.pyramiding !== undefined ? this.pyramiding + 1 : 1;
38044
+ const allowed = this.pyramiding !== undefined && this.pyramiding > 0 && this.opentrades < maxEntries;
38045
+ if (!allowed)
38046
+ return;
38047
+ }
38048
+ this.upsertPending({
38049
+ id: oid,
38050
+ direction: dir,
38051
+ qty: capped,
38052
+ limit: null,
38053
+ stop: null,
38054
+ bar: b,
38055
+ kind: "entry",
38056
+ is_entry: true,
38057
+ deferred: true,
38058
+ comment: opts?.comment
38059
+ });
38060
+ this.events.push({ type: "order", id: oid, direction: dir, qty: capped, bar: b });
38061
+ return;
38062
+ }
37732
38063
  if (isFiniteNumber2(opts?.price)) {
37733
38064
  const dir = mapDirection(direction);
37734
- const t = isFiniteNumber2(opts?.time) ? opts.time : bar;
38065
+ const t = isFiniteNumber2(opts?.time) ? opts.time : b;
37735
38066
  this.updateEquityExtremes(opts.price);
37736
38067
  if (!this.riskAllowsEntry(dir, t))
37737
38068
  return;
@@ -37742,8 +38073,6 @@ class StrategyBook {
37742
38073
  }
37743
38074
  const dir = mapDirection(direction);
37744
38075
  const absQty = isFiniteNumber2(qty) ? Math.abs(qty) : Number.NaN;
37745
- const b = isFiniteNumber2(bar) ? bar : 0;
37746
- const oid = String(id ?? "");
37747
38076
  this.entry(b, oid, dir, isFiniteNumber2(absQty) ? absQty : qty);
37748
38077
  if (!isFiniteNumber2(absQty) || absQty === 0)
37749
38078
  return;
@@ -37793,6 +38122,23 @@ class StrategyBook {
37793
38122
  return;
37794
38123
  const t = isFiniteNumber2(opts?.time) ? opts.time : b;
37795
38124
  if (limitP == null && stopP == null && !hasTrail) {
38125
+ if (opts?.deferMarket === true) {
38126
+ const closeDir = isLong ? "short" : "long";
38127
+ this.upsertPending({
38128
+ id: `${oid}:close`,
38129
+ direction: closeDir,
38130
+ qty,
38131
+ limit: null,
38132
+ stop: null,
38133
+ bar: b,
38134
+ kind: "exit",
38135
+ from_entry: fromEntry,
38136
+ deferred: true,
38137
+ comment: opts?.comment
38138
+ });
38139
+ this.events.push({ type: "order", id: oid, direction: closeDir, qty, bar: b });
38140
+ return;
38141
+ }
37796
38142
  if (!isFiniteNumber2(opts?.price))
37797
38143
  return;
37798
38144
  this.reducePosition(b, oid, opts.price, qty, fromEntry, t, opts?.comment);
@@ -37863,13 +38209,24 @@ class StrategyBook {
37863
38209
  for (const order of this.pending.slice()) {
37864
38210
  if (!this.pending.some((p) => p.id === order.id))
37865
38211
  continue;
38212
+ if (order.bar === b)
38213
+ continue;
37866
38214
  if (order.kind === "exit" && isTrailOrder(order))
37867
38215
  updateTrailStop(order, high, low);
37868
- const px = triggerPrice(order, open, high, low);
38216
+ let px;
38217
+ if (order.limit == null && order.stop == null)
38218
+ px = open;
38219
+ else
38220
+ px = triggerPrice(order, open, high, low);
37869
38221
  if (px == null)
37870
38222
  continue;
37871
38223
  this.dropPending(order.id);
37872
- const applied = order.kind === "exit" ? this.applyExitFill(b, order, px) : this.applyEntryFill(b, order.id, order.direction, order.qty, px, false);
38224
+ const emitEntry = order.kind === "entry" || order.deferred === true;
38225
+ const barTime = isFiniteNumber2(ohlc.time) ? ohlc.time : undefined;
38226
+ const applied = order.kind === "exit" ? this.applyExitFill(b, order, px, barTime) : order.kind === "close" || order.kind === "close_all" ? this.applyCloseFill(b, order, px, barTime) : this.applyEntryFill(b, order.id, order.direction, order.qty, px, emitEntry, {
38227
+ comment: order.comment,
38228
+ time: barTime
38229
+ });
37873
38230
  if (applied) {
37874
38231
  const q = Math.abs(this.fills.at(-1)?.qty ?? order.qty);
37875
38232
  this.ocaAfterFill(order, q, b);
@@ -37885,6 +38242,22 @@ class StrategyBook {
37885
38242
  }
37886
38243
  return filled;
37887
38244
  }
38245
+ applyCloseFill(bar, order, price, time) {
38246
+ this.ensureSanePosition();
38247
+ if (this.position.qty === 0 || !isFiniteNumber2(price))
38248
+ return false;
38249
+ const absPos = Math.abs(this.position.qty);
38250
+ const rawQty = order.qty;
38251
+ const q = isFiniteNumber2(rawQty) && rawQty > 0 ? Math.min(Math.abs(rawQty), absPos) : absPos;
38252
+ if (!(q > 0))
38253
+ return false;
38254
+ if (q < absPos - 0.000000000001) {
38255
+ this.reducePosition(bar, order.id, price, q, order.from_entry ?? null, time, order.comment);
38256
+ } else {
38257
+ this.flattenAt(bar, order.id, price, time, order.comment);
38258
+ }
38259
+ return true;
38260
+ }
37888
38261
  fillEntry(bar, id, direction, qty, price, opts) {
37889
38262
  this.applyEntryFill(bar, id, direction, qty, price, true, opts);
37890
38263
  }
@@ -38007,9 +38380,9 @@ class StrategyBook {
38007
38380
  return { status: "invalid", qty: 0 };
38008
38381
  return { status: "ok", qty: Math.min(rawQty, target) };
38009
38382
  }
38010
- applyExitFill(bar, order, price) {
38383
+ applyExitFill(bar, order, price, time) {
38011
38384
  const t = isFiniteNumber2(bar) ? bar : 0;
38012
- return this.reducePosition(t, order.id, price, order.qty, order.from_entry ?? null, t);
38385
+ return this.reducePosition(t, order.id, price, order.qty, order.from_entry ?? null, time);
38013
38386
  }
38014
38387
  closeLeg(ot, bar, exitPrice, qty, profit, commission, exitTime, exitComment) {
38015
38388
  const closed = {
@@ -40016,6 +40389,37 @@ function pushCap(window2, value, cap) {
40016
40389
  function finiteOut2(value) {
40017
40390
  return Number.isFinite(value) ? value : null;
40018
40391
  }
40392
+ function smaOf(series, period) {
40393
+ if (period <= 0 || series.length < period)
40394
+ return null;
40395
+ const window2 = series.slice(series.length - period);
40396
+ let sum = 0;
40397
+ for (const v of window2) {
40398
+ if (v === null)
40399
+ return null;
40400
+ sum += v;
40401
+ }
40402
+ return sum / period;
40403
+ }
40404
+ function stdevOf(series, period) {
40405
+ if (period <= 1 || series.length < period)
40406
+ return null;
40407
+ const window2 = series.slice(series.length - period);
40408
+ const vals = [];
40409
+ for (const v of window2) {
40410
+ if (v === null)
40411
+ return null;
40412
+ vals.push(v);
40413
+ }
40414
+ let mean = 0;
40415
+ for (const v of vals)
40416
+ mean += v;
40417
+ mean /= period;
40418
+ let sumSq = 0;
40419
+ for (const v of vals)
40420
+ sumSq += (v - mean) ** 2;
40421
+ return Math.sqrt(sumSq / period);
40422
+ }
40019
40423
  var PERIOD_INT_EPS = 0.000000001;
40020
40424
  function pinePeriod(period) {
40021
40425
  if (!Number.isFinite(period) || period <= 0)
@@ -40114,6 +40518,22 @@ class TaEngine {
40114
40518
  emvSites = new Map;
40115
40519
  fractalSites = new Map;
40116
40520
  zigzagSites = new Map;
40521
+ engulfingSites = new Map;
40522
+ insideBarSites = new Map;
40523
+ doubleTopBottomSites = new Map;
40524
+ rsiDivergenceSites = new Map;
40525
+ stochSmoothSites = new Map;
40526
+ smaWeightedSites = new Map;
40527
+ betaSites = new Map;
40528
+ rSquaredSites = new Map;
40529
+ comovementSites = new Map;
40530
+ skewnessSites = new Map;
40531
+ kurtosisSites = new Map;
40532
+ vwmSites = new Map;
40533
+ meanReversionSites = new Map;
40534
+ marketConditionSites = new Map;
40535
+ orderFlowSites = new Map;
40536
+ liquiditySites = new Map;
40117
40537
  sma(site, source, period) {
40118
40538
  const n = pinePeriod(period);
40119
40539
  if (n === null)
@@ -40188,18 +40608,24 @@ class TaEngine {
40188
40608
  st = {
40189
40609
  period: n,
40190
40610
  prevClose: null,
40611
+ started: false,
40191
40612
  rma: { period: n, rma: null, seeded: false, started: false, seedBuf: [] }
40192
40613
  };
40193
40614
  this.atrSites.set(site, st);
40194
40615
  }
40195
- const prev = st.prevClose;
40196
- st.prevClose = finiteCell2(close);
40197
- if (prev === null)
40198
- return null;
40199
40616
  const h = finiteCell2(high);
40200
40617
  const l = finiteCell2(low);
40201
40618
  const c = finiteCell2(close);
40202
- if (h === null || l === null || c === null)
40619
+ if (!st.started) {
40620
+ st.started = true;
40621
+ st.prevClose = c;
40622
+ if (h === null || l === null)
40623
+ return null;
40624
+ return rmaStep(st.rma, h - l, n);
40625
+ }
40626
+ const prev = st.prevClose;
40627
+ st.prevClose = c;
40628
+ if (prev === null || h === null || l === null || c === null)
40203
40629
  return null;
40204
40630
  const tr = Math.max(h - l, Math.abs(h - prev), Math.abs(l - prev));
40205
40631
  return rmaStep(st.rma, tr, n);
@@ -40365,7 +40791,7 @@ class TaEngine {
40365
40791
  }
40366
40792
  if (st.window.length < n || st.count !== n)
40367
40793
  return null;
40368
- let v = (st.sumsq - st.sum * st.sum / n) / (n - 1);
40794
+ let v = (st.sumsq - st.sum * st.sum / n) / n;
40369
40795
  if (v < 0)
40370
40796
  v = 0;
40371
40797
  return Math.sqrt(v);
@@ -41571,7 +41997,7 @@ class TaEngine {
41571
41997
  }
41572
41998
  if (st.window.length < n || st.count !== n)
41573
41999
  return null;
41574
- let v = (st.sumsq - st.sum * st.sum / n) / (n - 1);
42000
+ let v = (st.sumsq - st.sum * st.sum / n) / n;
41575
42001
  if (v < 0)
41576
42002
  v = 0;
41577
42003
  return v;
@@ -42175,20 +42601,17 @@ class TaEngine {
42175
42601
  st = { samples: [] };
42176
42602
  this.zigzagSites.set(site, st);
42177
42603
  }
42178
- pushCap(st.samples, finiteCell2(source), 1000);
42179
- const finite = [];
42180
- for (const v of st.samples) {
42181
- if (v !== null)
42182
- finite.push(v);
42183
- }
42184
- if (finite.length < 2)
42604
+ const x = finiteCell2(source);
42605
+ if (x !== null)
42606
+ pushCap(st.samples, x, 2);
42607
+ if (st.samples.length < 2)
42185
42608
  return { high: null, low: null, dir: 0 };
42186
- const oldest = finite[0];
42187
- const second = finite[1];
42188
- const recentHigh = Math.max(oldest, second);
42189
- const recentLow = Math.min(oldest, second);
42609
+ const oldest = st.samples[0];
42610
+ const newest = st.samples[1];
42611
+ const recentHigh = Math.max(oldest, newest);
42612
+ const recentLow = Math.min(oldest, newest);
42190
42613
  const pct = recentLow !== 0 ? (recentHigh - recentLow) / recentLow * 100 : 0;
42191
- const direction = recentHigh === oldest ? 1 : -1;
42614
+ const direction = recentHigh === newest ? 1 : -1;
42192
42615
  return { high: recentHigh, low: recentLow, dir: pct > th ? 1 : direction };
42193
42616
  }
42194
42617
  accelSites = new Map;
@@ -42255,30 +42678,31 @@ class TaEngine {
42255
42678
  }
42256
42679
  accelerationFactor(site, source, period) {
42257
42680
  const p = this.coerceTaInt(period, "ta.acceleration_factor() requires 2 arguments");
42258
- let samples = this.accelSites.get(site);
42681
+ if (p <= 0)
42682
+ return 0;
42683
+ const key = `${site}:${p}`;
42684
+ let samples = this.accelSites.get(key);
42259
42685
  if (samples === undefined) {
42260
42686
  samples = [];
42261
- this.accelSites.set(site, samples);
42687
+ this.accelSites.set(key, samples);
42262
42688
  }
42263
- pushCap(samples, finiteCell2(source), 1000);
42264
- if (samples.length < p + 1 || p <= 0)
42689
+ pushCap(samples, finiteCell2(source), p + 1);
42690
+ if (samples.length < p + 1)
42265
42691
  return 0;
42266
- const oldest = samples.slice(0, p + 1);
42267
- const newestFirst = [];
42268
- for (let i = oldest.length - 1;i >= 0; i--) {
42269
- const v = oldest[i];
42692
+ const clean = [];
42693
+ for (const v of samples) {
42270
42694
  if (v !== null)
42271
- newestFirst.push(v);
42695
+ clean.push(v);
42272
42696
  }
42273
- if (newestFirst.length < 2)
42697
+ if (clean.length < 2)
42274
42698
  return 0;
42275
42699
  let oldSum = 0;
42276
- for (let i = 0;i < newestFirst.length - 1; i++)
42277
- oldSum += newestFirst[i];
42278
- const oldMom = oldSum / (newestFirst.length - 1);
42700
+ for (let i = 0;i < clean.length - 1; i++)
42701
+ oldSum += clean[i];
42702
+ const oldMom = oldSum / (clean.length - 1);
42703
+ const newMom = clean[clean.length - 1];
42279
42704
  if (Math.abs(oldMom) < 0.0000000001)
42280
42705
  return 0;
42281
- const newMom = newestFirst[newestFirst.length - 1];
42282
42706
  let acc = (newMom - oldMom) / oldMom;
42283
42707
  if (acc < -2)
42284
42708
  acc = -2;
@@ -42286,32 +42710,141 @@ class TaEngine {
42286
42710
  acc = 2;
42287
42711
  return finiteOut2(acc);
42288
42712
  }
42289
- stochSmooth(high, low, close, period, smoothK, smoothD) {
42713
+ stochSmooth(site, high, low, close, period, smoothK, smoothD) {
42290
42714
  const p = this.coerceTaInt(period, "ta.stoch_smooth period must be integer");
42291
42715
  const k = this.coerceTaInt(smoothK, "ta.stoch_smooth smooth_k must be integer");
42292
42716
  const d = this.coerceTaInt(smoothD, "ta.stoch_smooth smooth_d must be integer");
42293
- if (p <= 0)
42294
- throw new Error("max() iterable argument is empty");
42295
- if (high === null || low === null || close === null) {
42296
- throw new Error("unsupported operand type(s) for /: 'float' and 'NoneType'");
42297
- }
42298
- if (k !== 1 || d !== 1)
42717
+ if (p < 1 || k < 1 || d < 1)
42299
42718
  return null;
42300
- const span = high - low;
42301
- const stoch = span !== 0 ? 100 * (close - low) / span : 50;
42302
- return finiteOut2(stoch);
42303
- }
42304
- engulfing() {
42305
- return taRec({ is_bullish: false, is_bearish: false, pattern_strength: 0 });
42306
- }
42307
- insideBarPattern() {
42308
- return false;
42719
+ const key = `${site}:${p}:${k}:${d}`;
42720
+ let st = this.stochSmoothSites.get(key);
42721
+ if (st === undefined) {
42722
+ st = { highs: [], lows: [] };
42723
+ this.stochSmoothSites.set(key, st);
42724
+ }
42725
+ pushCap(st.highs, finiteCell2(high), p);
42726
+ pushCap(st.lows, finiteCell2(low), p);
42727
+ const c = finiteCell2(close);
42728
+ let stoch = null;
42729
+ if (c !== null && !st.highs.includes(null) && !st.lows.includes(null)) {
42730
+ let hh = -Infinity;
42731
+ let ll = Infinity;
42732
+ for (const v of st.highs) {
42733
+ if (v > hh)
42734
+ hh = v;
42735
+ }
42736
+ for (const v of st.lows) {
42737
+ if (v < ll)
42738
+ ll = v;
42739
+ }
42740
+ stoch = hh === ll ? 50 : 100 * (c - ll) / (hh - ll);
42741
+ }
42742
+ const kVal = this.ema(`${site}:k`, stoch, k);
42743
+ return this.ema(`${site}:d`, kVal, d);
42744
+ }
42745
+ engulfing(site, open, close) {
42746
+ const off = taRec({ is_bullish: false, is_bearish: false, pattern_strength: 0 });
42747
+ let st = this.engulfingSites.get(site);
42748
+ if (st === undefined) {
42749
+ st = { prevOpen: null, prevClose: null, count: 0 };
42750
+ this.engulfingSites.set(site, st);
42751
+ }
42752
+ const o = finiteCell2(open);
42753
+ const c = finiteCell2(close);
42754
+ st.count += 1;
42755
+ const prevO = st.prevOpen;
42756
+ const prevC = st.prevClose;
42757
+ if (st.count < 2 || prevO === null || prevC === null || o === null || c === null) {
42758
+ st.prevOpen = o;
42759
+ st.prevClose = c;
42760
+ return off;
42761
+ }
42762
+ const isBullish = o < prevC && c > prevO && c > o;
42763
+ const isBearish = o > prevC && c < prevO && c < o;
42764
+ let engulf = 0;
42765
+ if (isBullish) {
42766
+ engulf = Math.max(0, Math.min(1, (c - prevO) / Math.abs(prevO - prevC + 0.0001)));
42767
+ } else if (isBearish) {
42768
+ engulf = Math.max(0, Math.min(1, (prevO - c) / Math.abs(prevC - prevO + 0.0001)));
42769
+ }
42770
+ st.prevOpen = o;
42771
+ st.prevClose = c;
42772
+ return taRec({
42773
+ is_bullish: isBullish,
42774
+ is_bearish: isBearish,
42775
+ pattern_strength: finiteOut2(engulf) ?? 0
42776
+ });
42309
42777
  }
42310
- doubleTopBottom(period) {
42311
- if (period === null || !Number.isFinite(period)) {
42312
- throw new Error("period must be integer. Got: na");
42778
+ insideBarPattern(site, high, low) {
42779
+ let st = this.insideBarSites.get(site);
42780
+ if (st === undefined) {
42781
+ st = { prevHigh: null, prevLow: null, count: 0 };
42782
+ this.insideBarSites.set(site, st);
42783
+ }
42784
+ const currH = high !== null && Number.isFinite(high) ? high : 0;
42785
+ const currL = low !== null && Number.isFinite(low) ? low : 0;
42786
+ st.count += 1;
42787
+ const prevH = st.prevHigh;
42788
+ const prevL = st.prevLow;
42789
+ if (st.count < 2 || prevH === null || prevL === null) {
42790
+ st.prevHigh = currH;
42791
+ st.prevLow = currL;
42792
+ return false;
42793
+ }
42794
+ const val = currH < prevH && currL > prevL;
42795
+ st.prevHigh = currH;
42796
+ st.prevLow = currL;
42797
+ return val;
42798
+ }
42799
+ doubleTopBottom(site, high, low, period) {
42800
+ const n = this.coerceTaInt(period, "period must be integer");
42801
+ const off = taRec({ pattern_type: "none", strength: 0, breakout_level: 0 });
42802
+ if (n < 1)
42803
+ return off;
42804
+ const key = `${site}:${n}`;
42805
+ let st = this.doubleTopBottomSites.get(key);
42806
+ if (st === undefined) {
42807
+ st = { highs: [], lows: [], count: 0 };
42808
+ this.doubleTopBottomSites.set(key, st);
42809
+ }
42810
+ pushCap(st.highs, finiteCell2(high), n);
42811
+ pushCap(st.lows, finiteCell2(low), n);
42812
+ st.count += 1;
42813
+ if (st.count < n)
42814
+ return off;
42815
+ const recentHigh = [];
42816
+ for (const v of st.highs) {
42817
+ if (v !== null)
42818
+ recentHigh.push(v);
42819
+ }
42820
+ const recentLow = [];
42821
+ for (const v of st.lows) {
42822
+ if (v !== null)
42823
+ recentLow.push(v);
42824
+ }
42825
+ if (recentHigh.length < 3 || recentLow.length === 0)
42826
+ return off;
42827
+ const peaks = [recentHigh[0]];
42828
+ for (let i = 1;i < recentHigh.length - 1; i++) {
42829
+ if (recentHigh[i] > recentHigh[i - 1] && recentHigh[i] > recentHigh[i + 1]) {
42830
+ peaks.push(recentHigh[i]);
42831
+ }
42832
+ }
42833
+ if (peaks.length < 2)
42834
+ return off;
42835
+ const peakDiff = Math.abs(peaks[peaks.length - 1] - peaks[peaks.length - 2]);
42836
+ const avgPeak = (peaks[peaks.length - 1] + peaks[peaks.length - 2]) / 2;
42837
+ const strength = avgPeak > 0 ? 1 - Math.min(1, peakDiff / avgPeak) : 0;
42838
+ let minLow = recentLow[0];
42839
+ for (const v of recentLow) {
42840
+ if (v < minLow)
42841
+ minLow = v;
42313
42842
  }
42314
- return taRec({ pattern_type: "none", strength: 0, breakout_level: 0 });
42843
+ return taRec({
42844
+ pattern_type: "double_top",
42845
+ strength: finiteOut2(strength) ?? 0,
42846
+ breakout_level: finiteOut2(minLow - avgPeak * 0.1) ?? 0
42847
+ });
42315
42848
  }
42316
42849
  cumDeltaSites = new Map;
42317
42850
  volMomSites = new Map;
@@ -42364,96 +42897,91 @@ class TaEngine {
42364
42897
  }
42365
42898
  return taRec({ is_oversold: rsi < os, is_overbought: rsi > ob, rsi });
42366
42899
  }
42367
- rsiDivergence(series, period) {
42900
+ rsiDivergence(site, value, period) {
42368
42901
  const p = this.asCount(period);
42369
- if (p === null || series.length === 0)
42370
- return null;
42371
- let last = 0;
42372
- for (let i = 0;i < series.length; i++) {
42373
- if (i < p) {
42374
- last = 0;
42375
- continue;
42376
- }
42377
- const start = Math.max(0, i - p);
42378
- const vals = [];
42379
- for (let j = start;j <= i; j++) {
42380
- const v = series[j];
42381
- if (v !== null && Number.isFinite(v))
42382
- vals.push(v);
42383
- }
42384
- if (vals.length < 2) {
42385
- last = 0;
42386
- continue;
42387
- }
42388
- let rsiMin = vals[0];
42389
- let rsiMax = vals[0];
42390
- for (const v of vals) {
42391
- if (v < rsiMin)
42392
- rsiMin = v;
42393
- if (v > rsiMax)
42394
- rsiMax = v;
42395
- }
42396
- const cur = series[i];
42397
- const range = rsiMax - rsiMin;
42398
- if (cur === null || !Number.isFinite(cur) || range <= 0) {
42399
- last = 0;
42400
- continue;
42401
- }
42402
- last = (cur - rsiMin) / range * 2 - 1;
42902
+ if (p === null || p < 1)
42903
+ return 0;
42904
+ let st = this.rsiDivergenceSites.get(`${site}:${p}`);
42905
+ if (st === undefined) {
42906
+ st = { window: [], count: 0 };
42907
+ this.rsiDivergenceSites.set(`${site}:${p}`, st);
42908
+ }
42909
+ const x = finiteCell2(value);
42910
+ pushCap(st.window, x, p + 1);
42911
+ st.count += 1;
42912
+ if (st.count <= p)
42913
+ return 0;
42914
+ const vals = [];
42915
+ for (const v of st.window) {
42916
+ if (v !== null)
42917
+ vals.push(v);
42918
+ }
42919
+ if (vals.length < 2 || x === null)
42920
+ return 0;
42921
+ let lo = vals[0];
42922
+ let hi = vals[0];
42923
+ for (const v of vals) {
42924
+ if (v < lo)
42925
+ lo = v;
42926
+ if (v > hi)
42927
+ hi = v;
42403
42928
  }
42404
- return finiteOut2(last);
42929
+ const range = hi - lo;
42930
+ return range > 0 ? finiteOut2((x - lo) / range * 2 - 1) : 0;
42405
42931
  }
42406
42932
  cumulativeDelta(site, close, volume, period) {
42407
42933
  const n = this.asCount(period);
42408
- let st = this.cumDeltaSites.get(site);
42934
+ if (n === null || n <= 0)
42935
+ return 0;
42936
+ let st = this.cumDeltaSites.get(`${site}:${n}`);
42409
42937
  if (st === undefined) {
42410
- st = { close: [], volume: [] };
42411
- this.cumDeltaSites.set(site, st);
42938
+ st = { closes: [], volumes: [], count: 0 };
42939
+ this.cumDeltaSites.set(`${site}:${n}`, st);
42412
42940
  }
42413
- this.pushChrono(st.close, close);
42414
- this.pushChrono(st.volume, volume);
42415
- if (n === null || n <= 0 || st.close.length < n || st.volume.length < n)
42941
+ const c = finiteCell2(close);
42942
+ const v = volume !== null && Number.isFinite(volume) ? volume : 0;
42943
+ pushCap(st.closes, c, n + 1);
42944
+ pushCap(st.volumes, v, n);
42945
+ st.count += 1;
42946
+ if (st.count < n)
42416
42947
  return 0;
42417
42948
  let delta = 0;
42418
- for (let i = -n;i < 0; i++) {
42419
- const cRaw = this.nf(st.close, i);
42420
- const vRaw = this.nf(st.volume, i);
42421
- const c = cRaw !== null && Number.isFinite(cRaw) ? cRaw : 0;
42422
- const v = vRaw !== null && Number.isFinite(vRaw) ? vRaw : 0;
42423
- if (i > -n) {
42424
- const prevRaw = this.nf(st.close, i - 1);
42425
- const prev = prevRaw !== null && Number.isFinite(prevRaw) ? prevRaw : c;
42426
- if (c > prev)
42427
- delta += v;
42428
- else if (c < prev)
42429
- delta -= v;
42430
- }
42949
+ const offset = st.closes.length - st.volumes.length;
42950
+ for (let j = 0;j < st.volumes.length; j++) {
42951
+ const idx = offset + j;
42952
+ const cRaw = st.closes[idx] ?? null;
42953
+ const cur = cRaw ?? 0;
42954
+ const prevRaw = idx === 0 ? null : st.closes[idx - 1] ?? null;
42955
+ const prev = prevRaw ?? cur;
42956
+ const vol = st.volumes[j];
42957
+ if (cur > prev)
42958
+ delta += vol;
42959
+ else if (cur < prev)
42960
+ delta -= vol;
42431
42961
  }
42432
42962
  return finiteOut2(delta);
42433
42963
  }
42434
42964
  volumeMomentum(site, volume, period) {
42435
42965
  const n = this.asCount(period);
42436
- let st = this.volMomSites.get(site);
42437
- if (st === undefined) {
42438
- st = { volume: [] };
42439
- this.volMomSites.set(site, st);
42440
- }
42441
- this.pushChrono(st.volume, volume);
42442
- if (n === null || n <= 0 || st.volume.length < n + 1)
42966
+ if (n === null || n <= 0)
42443
42967
  return 0;
42444
- const clean = [];
42445
- for (let i = 0;i < n + 1; i++) {
42446
- const v = st.volume[i];
42447
- if (v !== null && Number.isFinite(v))
42448
- clean.push(v);
42968
+ let st = this.volMomSites.get(`${site}:${n}`);
42969
+ if (st === undefined) {
42970
+ st = { window: [] };
42971
+ this.volMomSites.set(`${site}:${n}`, st);
42449
42972
  }
42450
- if (clean.length < 2)
42973
+ if (volume !== null && Number.isFinite(volume))
42974
+ pushCap(st.window, volume, n + 1);
42975
+ if (st.window.length < n + 1)
42451
42976
  return 0;
42452
- const newVol = clean[0];
42453
- let sum = 0;
42454
- for (let i = 1;i < clean.length; i++)
42455
- sum += clean[i];
42456
- const oldVol = sum / (clean.length - 1);
42977
+ let oldSum = 0;
42978
+ for (let i = 0;i < n; i++)
42979
+ oldSum += st.window[i];
42980
+ let newSum = 0;
42981
+ for (let i = 1;i <= n; i++)
42982
+ newSum += st.window[i];
42983
+ const oldVol = oldSum / n;
42984
+ const newVol = newSum / n;
42457
42985
  if (oldVol === 0)
42458
42986
  return 0;
42459
42987
  let momentum = (newVol - oldVol) / oldVol * 100;
@@ -42463,6 +42991,667 @@ class TaEngine {
42463
42991
  momentum = -100;
42464
42992
  return finiteOut2(momentum);
42465
42993
  }
42994
+ smaWeighted(site, source, period, weightType) {
42995
+ const n = this.coerceTaInt(period, "period must be integer");
42996
+ const kind = typeof weightType === "string" ? weightType : "linear";
42997
+ if (n < 1)
42998
+ return null;
42999
+ const key = `${site}:${n}:${kind}`;
43000
+ let st = this.smaWeightedSites.get(key);
43001
+ if (st === undefined) {
43002
+ const weights = [];
43003
+ for (let i = 0;i < n; i++) {
43004
+ if (kind === "quadratic")
43005
+ weights.push((i + 1) ** 2);
43006
+ else if (kind === "sqrt")
43007
+ weights.push((i + 1) ** 0.5);
43008
+ else
43009
+ weights.push(i + 1);
43010
+ }
43011
+ st = { window: [], weights, wsum: weights.reduce((a, b) => a + b, 0) };
43012
+ this.smaWeightedSites.set(key, st);
43013
+ }
43014
+ pushCap(st.window, finiteCell2(source), n);
43015
+ if (st.window.length < n || st.window.includes(null) || st.wsum <= 0)
43016
+ return null;
43017
+ let total = 0;
43018
+ for (let i = 0;i < n; i++)
43019
+ total += st.window[i] * st.weights[i];
43020
+ return finiteOut2(total / st.wsum);
43021
+ }
43022
+ apo(site, source, fast, slow) {
43023
+ const f = this.coerceTaInt(fast, "ta.apo fast_period must be integer");
43024
+ const s = this.coerceTaInt(slow, "ta.apo slow_period must be integer");
43025
+ const fastV = this.ema(`${site}:fast`, source, f);
43026
+ const slowV = this.ema(`${site}:slow`, source, s);
43027
+ if (fastV === null || slowV === null)
43028
+ return null;
43029
+ return finiteOut2(fastV - slowV);
43030
+ }
43031
+ atrNormalized(site, high, low, close, period) {
43032
+ const n = this.coerceTaInt(period, "period must be integer");
43033
+ const atr = this.atr(`${site}:atr`, high, low, close, n);
43034
+ const c = finiteCell2(close);
43035
+ if (c === null || c === 0 || atr === null)
43036
+ return null;
43037
+ return finiteOut2(atr / c * 100);
43038
+ }
43039
+ pairWindow(sites, site, a, b, length) {
43040
+ const n = this.coerceTaInt(length, "length must be integer");
43041
+ if (n < 1)
43042
+ return null;
43043
+ const key = `${site}:${n}`;
43044
+ let st = sites.get(key);
43045
+ if (st === undefined) {
43046
+ st = { a: [], b: [] };
43047
+ sites.set(key, st);
43048
+ }
43049
+ pushCap(st.a, finiteCell2(a), n);
43050
+ pushCap(st.b, finiteCell2(b), n);
43051
+ if (st.a.length < n || st.b.length < n)
43052
+ return null;
43053
+ const left = [];
43054
+ const right = [];
43055
+ for (let i = 0;i < n; i++) {
43056
+ const av = st.a[i];
43057
+ const bv = st.b[i];
43058
+ if (av === null || bv === null)
43059
+ return null;
43060
+ left.push(av);
43061
+ right.push(bv);
43062
+ }
43063
+ return { a: left, b: right };
43064
+ }
43065
+ beta(site, a, b, length) {
43066
+ const pair = this.pairWindow(this.betaSites, site, a, b, length);
43067
+ if (pair === null)
43068
+ return null;
43069
+ const n = pair.a.length;
43070
+ let meanA = 0;
43071
+ let meanB = 0;
43072
+ for (let i = 0;i < n; i++) {
43073
+ meanA += pair.a[i];
43074
+ meanB += pair.b[i];
43075
+ }
43076
+ meanA /= n;
43077
+ meanB /= n;
43078
+ let covariance = 0;
43079
+ let varianceB = 0;
43080
+ for (let i = 0;i < n; i++) {
43081
+ covariance += (pair.a[i] - meanA) * (pair.b[i] - meanB);
43082
+ varianceB += (pair.b[i] - meanB) ** 2;
43083
+ }
43084
+ covariance /= n;
43085
+ varianceB /= n;
43086
+ if (varianceB === 0)
43087
+ return 0;
43088
+ return finiteOut2(covariance / varianceB);
43089
+ }
43090
+ rSquared(site, a, b, length) {
43091
+ const pair = this.pairWindow(this.rSquaredSites, site, a, b, length);
43092
+ if (pair === null)
43093
+ return null;
43094
+ const n = pair.a.length;
43095
+ let meanA = 0;
43096
+ let meanB = 0;
43097
+ for (let i = 0;i < n; i++) {
43098
+ meanA += pair.a[i];
43099
+ meanB += pair.b[i];
43100
+ }
43101
+ meanA /= n;
43102
+ meanB /= n;
43103
+ let covariance = 0;
43104
+ let varA = 0;
43105
+ let varB = 0;
43106
+ for (let i = 0;i < n; i++) {
43107
+ covariance += (pair.a[i] - meanA) * (pair.b[i] - meanB);
43108
+ varA += (pair.a[i] - meanA) ** 2;
43109
+ varB += (pair.b[i] - meanB) ** 2;
43110
+ }
43111
+ covariance /= n;
43112
+ varA /= n;
43113
+ varB /= n;
43114
+ if (varA === 0 || varB === 0)
43115
+ return 0;
43116
+ const corr = covariance / Math.sqrt(varA * varB);
43117
+ return finiteOut2(Math.max(0, Math.min(1, corr ** 2)));
43118
+ }
43119
+ comovement(site, a, b, length) {
43120
+ const pair = this.pairWindow(this.comovementSites, site, a, b, length);
43121
+ if (pair === null)
43122
+ return null;
43123
+ const n = pair.a.length;
43124
+ if (n <= 1)
43125
+ return 0;
43126
+ let same = 0;
43127
+ for (let i = 1;i < n; i++) {
43128
+ if ((pair.a[i] - pair.a[i - 1]) * (pair.b[i] - pair.b[i - 1]) > 0)
43129
+ same += 1;
43130
+ }
43131
+ return finiteOut2(same / (n - 1) * 100);
43132
+ }
43133
+ skewness(site, source, period) {
43134
+ const n = this.coerceTaInt(period, "period must be integer");
43135
+ if (n < 1)
43136
+ return null;
43137
+ const key = `${site}:${n}`;
43138
+ let st = this.skewnessSites.get(key);
43139
+ if (st === undefined) {
43140
+ st = { window: [] };
43141
+ this.skewnessSites.set(key, st);
43142
+ }
43143
+ pushCap(st.window, finiteCell2(source), n);
43144
+ if (st.window.length < n || st.window.includes(null))
43145
+ return null;
43146
+ const vals = st.window;
43147
+ let mean = 0;
43148
+ for (const v of vals)
43149
+ mean += v;
43150
+ mean /= n;
43151
+ let variance = 0;
43152
+ for (const v of vals)
43153
+ variance += (v - mean) ** 2;
43154
+ variance /= n;
43155
+ const std = Math.sqrt(variance);
43156
+ if (std === 0)
43157
+ return 0;
43158
+ let third = 0;
43159
+ for (const v of vals)
43160
+ third += (v - mean) ** 3;
43161
+ return finiteOut2(third / (n * std ** 3));
43162
+ }
43163
+ kurtosis(site, source, period) {
43164
+ const n = this.coerceTaInt(period, "period must be integer");
43165
+ if (n < 1)
43166
+ return null;
43167
+ const key = `${site}:${n}`;
43168
+ let st = this.kurtosisSites.get(key);
43169
+ if (st === undefined) {
43170
+ st = { window: [] };
43171
+ this.kurtosisSites.set(key, st);
43172
+ }
43173
+ pushCap(st.window, finiteCell2(source), n);
43174
+ if (st.window.length < n || st.window.includes(null))
43175
+ return null;
43176
+ const vals = st.window;
43177
+ let mean = 0;
43178
+ for (const v of vals)
43179
+ mean += v;
43180
+ mean /= n;
43181
+ let variance = 0;
43182
+ for (const v of vals)
43183
+ variance += (v - mean) ** 2;
43184
+ variance /= n;
43185
+ const std = Math.sqrt(variance);
43186
+ if (std === 0)
43187
+ return 0;
43188
+ let fourth = 0;
43189
+ for (const v of vals)
43190
+ fourth += (v - mean) ** 4;
43191
+ fourth /= n;
43192
+ return finiteOut2(fourth / std ** 4 - 3);
43193
+ }
43194
+ volumeWeightedMomentum(site, source, volume, length) {
43195
+ const n = this.coerceTaInt(length, "length must be integer");
43196
+ if (n < 1)
43197
+ return null;
43198
+ const key = `${site}:${n}`;
43199
+ let st = this.vwmSites.get(key);
43200
+ if (st === undefined) {
43201
+ st = { prices: [], volumes: [] };
43202
+ this.vwmSites.set(key, st);
43203
+ }
43204
+ pushCap(st.prices, finiteCell2(source), n + 1);
43205
+ pushCap(st.volumes, finiteCell2(volume), n);
43206
+ if (st.volumes.length < n)
43207
+ return null;
43208
+ const ps = st.prices;
43209
+ const vs = st.volumes;
43210
+ let momentumSum = 0;
43211
+ let volumeSum = 0;
43212
+ for (let i = 0;i < n; i++) {
43213
+ const pEnd = ps.length - 1 - i;
43214
+ const pPrev = pEnd - 1;
43215
+ if (pPrev < 0)
43216
+ break;
43217
+ const pv = ps[pEnd] ?? null;
43218
+ const pp = ps[pPrev] ?? null;
43219
+ if (pv === null || pp === null)
43220
+ return null;
43221
+ const vol = vs[vs.length - 1 - i] ?? 0;
43222
+ momentumSum += (pv - pp) * vol;
43223
+ volumeSum += vol;
43224
+ }
43225
+ return finiteOut2(volumeSum > 0 ? momentumSum / volumeSum : 0);
43226
+ }
43227
+ parkinson(high, low) {
43228
+ const h = finiteCell2(high);
43229
+ const l = finiteCell2(low);
43230
+ if (h === null || l === null || h <= l)
43231
+ return null;
43232
+ const ratio = h / l;
43233
+ if (ratio <= 0)
43234
+ return null;
43235
+ return finiteOut2(Math.sqrt(Math.log(ratio) ** 2 / (4 * Math.log(2))));
43236
+ }
43237
+ garmanKlass(high, low, close, open) {
43238
+ const h = finiteCell2(high);
43239
+ const l = finiteCell2(low);
43240
+ const c = finiteCell2(close);
43241
+ const o = finiteCell2(open);
43242
+ if (h === null || l === null || c === null || o === null)
43243
+ return null;
43244
+ if (h <= l || h <= 0 || c <= 0)
43245
+ return null;
43246
+ const term1 = 0.5 * Math.log(h / l) ** 2;
43247
+ const term2 = (2 * Math.log(2) - 1) * Math.log(c / o) ** 2;
43248
+ return finiteOut2(Math.sqrt(term1 - term2));
43249
+ }
43250
+ meanReversionScore(site, close, sma, stdev, period) {
43251
+ const n = this.coerceTaInt(period, "ta.mean_reversion_score() requires 4 arguments");
43252
+ if (n <= 0)
43253
+ return 50;
43254
+ let st = this.meanReversionSites.get(`${site}:${n}`);
43255
+ if (st === undefined) {
43256
+ st = { countClose: 0, countSma: 0 };
43257
+ this.meanReversionSites.set(`${site}:${n}`, st);
43258
+ }
43259
+ st.countClose += 1;
43260
+ st.countSma += 1;
43261
+ if (st.countClose < n || st.countSma < n)
43262
+ return 50;
43263
+ const c = finiteCell2(close) ?? 100;
43264
+ const s = finiteCell2(sma) ?? 100;
43265
+ const sd = finiteCell2(stdev) ?? 1;
43266
+ if (sd === 0)
43267
+ return 50;
43268
+ return Math.max(0, Math.min(100, Math.min(100, Math.abs(c - s) / sd * 20)));
43269
+ }
43270
+ marketCondition(site, close, atr, smaPeriod, stdevPeriod) {
43271
+ const smaN = this.coerceTaInt(smaPeriod, "sma period must be integer");
43272
+ const stdevN = this.coerceTaInt(stdevPeriod, "stdev period must be integer");
43273
+ if (smaN <= 0 || stdevN <= 0)
43274
+ return "ranging";
43275
+ const win = Math.max(smaN, stdevN);
43276
+ const key = `${site}:${smaN}:${stdevN}`;
43277
+ let st = this.marketConditionSites.get(key);
43278
+ if (st === undefined) {
43279
+ st = { window: [], atr: null };
43280
+ this.marketConditionSites.set(key, st);
43281
+ }
43282
+ pushCap(st.window, finiteCell2(close), win);
43283
+ st.atr = finiteCell2(atr);
43284
+ if (st.window.length < win)
43285
+ return "ranging";
43286
+ const cLast = st.window[st.window.length - 1] ?? null;
43287
+ const currentClose = cLast ?? 0;
43288
+ const currentAtr = st.atr ?? 1;
43289
+ const currentSma = smaOf(st.window, smaN) ?? currentClose;
43290
+ const stdevVal = stdevOf(st.window, stdevN);
43291
+ if (stdevVal !== null && stdevVal > currentAtr * 1.5)
43292
+ return "volatile";
43293
+ if (currentClose > currentSma && currentAtr > 0.5)
43294
+ return "trending_up";
43295
+ if (currentClose < currentSma && currentAtr > 0.5)
43296
+ return "trending_down";
43297
+ return "ranging";
43298
+ }
43299
+ orderFlowImbalance(site, high, low, close, volume, period) {
43300
+ const n = this.coerceTaInt(period, "period must be integer");
43301
+ if (n <= 0)
43302
+ return 0;
43303
+ const key = `${site}:${n}`;
43304
+ let st = this.orderFlowSites.get(key);
43305
+ if (st === undefined) {
43306
+ st = { highs: [], lows: [], closes: [], volumes: [] };
43307
+ this.orderFlowSites.set(key, st);
43308
+ }
43309
+ pushCap(st.highs, finiteCell2(high), n);
43310
+ pushCap(st.lows, finiteCell2(low), n);
43311
+ pushCap(st.closes, finiteCell2(close), n);
43312
+ pushCap(st.volumes, finiteCell2(volume), n);
43313
+ if (st.highs.length < n || st.lows.length < n)
43314
+ return 0;
43315
+ let buy = 0;
43316
+ let sell = 0;
43317
+ for (let i = 0;i < n; i++) {
43318
+ const h = st.highs[i] ?? 0;
43319
+ const l = st.lows[i] ?? 0;
43320
+ const c = st.closes[i] ?? 0;
43321
+ const v = st.volumes[i] ?? 0;
43322
+ if (h > l) {
43323
+ const mid = (h + l) / 2;
43324
+ if (c > mid)
43325
+ buy += v;
43326
+ else
43327
+ sell += v;
43328
+ }
43329
+ }
43330
+ const total = buy + sell;
43331
+ if (total === 0)
43332
+ return 0;
43333
+ return finiteOut2((buy - sell) / total) ?? 0;
43334
+ }
43335
+ liquidityScore(site, volume, volatility, spread, period) {
43336
+ const n = this.coerceTaInt(period, "period must be integer");
43337
+ if (n <= 0)
43338
+ return 50;
43339
+ const key = `${site}:${n}`;
43340
+ let st = this.liquiditySites.get(key);
43341
+ if (st === undefined) {
43342
+ st = { volume: [], volatility: [], spread: [] };
43343
+ this.liquiditySites.set(key, st);
43344
+ }
43345
+ pushCap(st.volume, finiteCell2(volume), n);
43346
+ pushCap(st.volatility, finiteCell2(volatility), n);
43347
+ pushCap(st.spread, finiteCell2(spread), n);
43348
+ if (st.volume.length < n || st.volatility.length < n || st.spread.length < n)
43349
+ return 50;
43350
+ let volSum = 0;
43351
+ for (const v of st.volume)
43352
+ if (v !== null)
43353
+ volSum += v;
43354
+ let volaSum = 0;
43355
+ for (const v of st.volatility)
43356
+ if (v !== null)
43357
+ volaSum += v;
43358
+ let spreadSum = 0;
43359
+ for (const v of st.spread)
43360
+ if (v !== null)
43361
+ spreadSum += v;
43362
+ const volScore = Math.min(100, volSum / n / 100);
43363
+ const volatilityScore = Math.max(0, 100 - volaSum / n * 50);
43364
+ const spreadScore = Math.max(0, 100 - spreadSum / n * 100);
43365
+ const liquidity = volScore * 0.4 + volatilityScore * 0.3 + spreadScore * 0.3;
43366
+ return Math.max(0, Math.min(100, liquidity));
43367
+ }
43368
+ fearGreedIndex(rsi, vix, putCall, breadth) {
43369
+ const r = finiteCell2(rsi) ?? 50;
43370
+ const v = finiteCell2(vix) ?? 2;
43371
+ const pc = finiteCell2(putCall) ?? 1;
43372
+ const b = finiteCell2(breadth) ?? 0.5;
43373
+ const index = ((r - 50) * 1 + (v - 2) * 10 + (1 - pc) * 50 + (b - 0.5) * 100) / 4;
43374
+ return Math.max(-100, Math.min(100, index));
43375
+ }
43376
+ crowdSentiment(priceAgreement, volumeAgreement, timeAgreement) {
43377
+ const p = finiteCell2(priceAgreement) ?? 0.5;
43378
+ const v = finiteCell2(volumeAgreement) ?? 0.5;
43379
+ const t = finiteCell2(timeAgreement) ?? 0.5;
43380
+ return Math.max(0, Math.min(100, (p + v + t) / 3 * 100));
43381
+ }
43382
+ smartMoneyFlow(priceChange, volume, timeHigh, timeLow) {
43383
+ const p = finiteCell2(priceChange) ?? 0;
43384
+ const v = finiteCell2(volume) ?? 1000;
43385
+ const th = finiteCell2(timeHigh) ?? 10;
43386
+ const tl = finiteCell2(timeLow) ?? 10;
43387
+ const volFactor = Math.min(1, v / 5000);
43388
+ let flow = 0;
43389
+ if (p > 0 && th < tl)
43390
+ flow = volFactor * 0.8;
43391
+ else if (p < 0 && tl < th)
43392
+ flow = -volFactor * 0.8;
43393
+ return Math.max(-1, Math.min(1, flow));
43394
+ }
43395
+ trendConfirmationScore(momentum, trendAlignment, strength, rsi, rsiAlignment) {
43396
+ const m = finiteCell2(momentum) ?? 0;
43397
+ const t = finiteCell2(trendAlignment) ?? 0;
43398
+ const s = finiteCell2(strength) ?? 1;
43399
+ const r = finiteCell2(rsi) ?? 50;
43400
+ const a = finiteCell2(rsiAlignment) ?? 0;
43401
+ const momentumScore = Math.min(100, Math.abs(m) * 20);
43402
+ const trendScore = Math.max(0, (t + 1) / 2 * 100);
43403
+ const strengthScore = Math.min(100, s * 50);
43404
+ const rsiScore = Math.abs(r - 50) > 10 ? Math.min(100, Math.abs(r - 50) * 2) : 40;
43405
+ const alignmentBonus = Math.abs(a) > 0.5 ? 20 : 0;
43406
+ const total = momentumScore * 0.25 + trendScore * 0.3 + strengthScore * 0.25 + rsiScore * 0.15 + alignmentBonus;
43407
+ return Math.max(0, Math.min(100, total));
43408
+ }
43409
+ maxLossLevel(entry, account, maxLossPct) {
43410
+ const e = finiteCell2(entry) ?? 100;
43411
+ const a = finiteCell2(account) ?? 1e4;
43412
+ const p = finiteCell2(maxLossPct) ?? 1;
43413
+ const maxLossAmount = a * (p / 100);
43414
+ if (e <= 0)
43415
+ return 0;
43416
+ const shares = a / e;
43417
+ const stop = shares > 0 ? e - maxLossAmount / shares : 0;
43418
+ return Math.max(0, stop);
43419
+ }
43420
+ profitLockLevel(entry, current, trailPct, direction) {
43421
+ const e = finiteCell2(entry) ?? 100;
43422
+ const c = finiteCell2(current) ?? 100;
43423
+ const t = Math.max(0, Math.min(1, finiteCell2(trailPct) ?? 0.05));
43424
+ const d = finiteCell2(direction) ?? 1;
43425
+ return d > 0 ? Math.max(e * 0.9, c - c * t) : Math.min(e * 1.1, c + c * t);
43426
+ }
43427
+ positionSizing(account, riskPct, entry, stop) {
43428
+ const a = finiteCell2(account) ?? 1e4;
43429
+ const r = finiteCell2(riskPct) ?? 0.01;
43430
+ const e = finiteCell2(entry) ?? 100;
43431
+ const s = finiteCell2(stop) ?? 95;
43432
+ const riskAmount = a * (r / 100);
43433
+ const distance = e - s;
43434
+ if (Math.abs(distance) < 0.0000000001)
43435
+ return 0;
43436
+ return Math.max(0, riskAmount / Math.abs(distance));
43437
+ }
43438
+ kellyCriterion(winRate, avgWin, avgLoss) {
43439
+ const wr = Math.max(0, Math.min(1, finiteCell2(winRate) ?? 0.5));
43440
+ const win = finiteCell2(avgWin) ?? 1;
43441
+ const loss = finiteCell2(avgLoss) ?? 1;
43442
+ if (Math.abs(win) < 0.0000000001)
43443
+ return 0;
43444
+ const kelly = (wr * win - (1 - wr) * loss) / win;
43445
+ return Math.max(0, kelly);
43446
+ }
43447
+ riskRewardRatio(entry, stop, target) {
43448
+ const e = finiteCell2(entry) ?? 0;
43449
+ const s = finiteCell2(stop) ?? 0;
43450
+ const t = finiteCell2(target) ?? 0;
43451
+ const risk = e - s;
43452
+ if (Math.abs(risk) < 0.0000000001)
43453
+ return null;
43454
+ return finiteOut2((t - e) / risk);
43455
+ }
43456
+ riskRewardAsymmetry(entry, stop, target, winRate) {
43457
+ const e = finiteCell2(entry) ?? 0;
43458
+ const s = finiteCell2(stop) ?? 0;
43459
+ const t = finiteCell2(target) ?? 0;
43460
+ const wr = finiteCell2(winRate) ?? 0.5;
43461
+ const risk = Math.abs(e - s);
43462
+ const reward = Math.abs(t - e);
43463
+ const ratio = risk > 0 ? reward / risk : 0;
43464
+ const ev = wr * reward - (1 - wr) * risk;
43465
+ const kelly = ratio > 0 ? wr - (1 - wr) / ratio : 0;
43466
+ return taRec({
43467
+ ratio: finiteOut2(ratio) ?? 0,
43468
+ expected_value: finiteOut2(ev) ?? 0,
43469
+ kelly_percent: finiteOut2(kelly * 100) ?? 0,
43470
+ is_favorable: ev > 0,
43471
+ risk_reward_ratio: finiteOut2(ratio) ?? 0,
43472
+ kelly_percentage: finiteOut2(kelly * 100) ?? 0
43473
+ });
43474
+ }
43475
+ probabilityOfMovement(current, target, atr, period) {
43476
+ const c = finiteCell2(current) ?? 100;
43477
+ const t = finiteCell2(target) ?? 100;
43478
+ const a = finiteCell2(atr) ?? 1;
43479
+ const n = this.coerceTaInt(period, "period must be integer");
43480
+ if (Math.abs(c) < 0.0000000001 || Math.abs(a) < 0.0000000001)
43481
+ return 0.5;
43482
+ const distance = Math.abs(t - c);
43483
+ const expected = a * Math.sqrt(n);
43484
+ if (expected === 0)
43485
+ return 0.5;
43486
+ return Math.max(0, Math.min(1, Math.min(1, distance / expected) * 0.8 + 0.1));
43487
+ }
43488
+ trendStrength(price, adx, rsi) {
43489
+ const a = finiteCell2(adx) ?? 20;
43490
+ const r = finiteCell2(rsi) ?? 50;
43491
+ const adxNorm = Math.min(100, Math.max(0, a));
43492
+ const rsiExtremeness = Math.abs(r - 50) / 50;
43493
+ return Math.min(100, Math.max(0, adxNorm * 0.6 + rsiExtremeness * 40));
43494
+ }
43495
+ breakevenLevel(entry, qty, commission, slippage, direction) {
43496
+ const e = finiteCell2(entry) ?? 0;
43497
+ const q = finiteCell2(qty) ?? 0;
43498
+ const comm = finiteCell2(commission) ?? 0;
43499
+ const slip = finiteCell2(slippage) ?? 0;
43500
+ const d = finiteCell2(direction) ?? 1;
43501
+ const cost = comm + slip * q;
43502
+ const impact = q > 0 ? cost / q : 0;
43503
+ const breakeven = d >= 0 ? e + impact : e - impact;
43504
+ const move = e > 0 ? Math.abs(breakeven - e) / e * 100 : 0;
43505
+ return taRec({
43506
+ breakeven_price: finiteOut2(breakeven) ?? 0,
43507
+ total_cost: finiteOut2(cost) ?? 0,
43508
+ move_required_percent: finiteOut2(move) ?? 0
43509
+ });
43510
+ }
43511
+ marketStructurePivot(close) {
43512
+ const c = finiteCell2(close) ?? 0;
43513
+ return taRec({ pivot_price: c, structure: "fractal", type: "high" });
43514
+ }
43515
+ positionSizingScore(risk, volatility, conviction, correlation) {
43516
+ const r = finiteCell2(risk) ?? 0;
43517
+ const v = finiteCell2(volatility) ?? 0;
43518
+ const c = finiteCell2(conviction) ?? 0;
43519
+ const corr = finiteCell2(correlation) ?? 0;
43520
+ let score = r / (v + 0.1) * c * (1 - corr);
43521
+ score = Math.max(0, Math.min(1, score * 0.1));
43522
+ return taRec({
43523
+ score: finiteOut2(score * 100) ?? 0,
43524
+ position_size_ratio: finiteOut2(score) ?? 0,
43525
+ kelly_fraction: finiteOut2(score * 0.5) ?? 0,
43526
+ correlation_adjustment: finiteOut2(1 - corr) ?? 0
43527
+ });
43528
+ }
43529
+ trailingExitLevel(entry, current, atr, mult, step) {
43530
+ const e = finiteCell2(entry) ?? 0;
43531
+ const c = finiteCell2(current) ?? 0;
43532
+ const a = finiteCell2(atr) ?? 0;
43533
+ const m = finiteCell2(mult) ?? 0;
43534
+ finiteCell2(step);
43535
+ const trail = c > e ? Math.max(e * 1.001, c - a * m) : c + a * m;
43536
+ return taRec({
43537
+ trail_stop: finiteOut2(trail) ?? 0,
43538
+ protected_profit: c > e ? finiteOut2(Math.max(0, c - e)) ?? 0 : 0,
43539
+ risk_reward_current: a > 0 ? finiteOut2(Math.abs(c - e) / a) ?? 0 : 0
43540
+ });
43541
+ }
43542
+ optimalEntryZone(close) {
43543
+ const c = finiteCell2(close) ?? 0;
43544
+ return taRec({
43545
+ min: finiteOut2(c * 0.99) ?? 0,
43546
+ max: finiteOut2(c * 1.01) ?? 0,
43547
+ optimal: c,
43548
+ entry_zone_low: finiteOut2(c * 0.99) ?? 0,
43549
+ entry_zone_high: finiteOut2(c * 1.01) ?? 0,
43550
+ best_entry: c,
43551
+ zone_strength: 85
43552
+ });
43553
+ }
43554
+ meanReversionEntry(price, sma, stdev, threshold) {
43555
+ const p = finiteCell2(price) ?? 0;
43556
+ const s = finiteCell2(sma) ?? 0;
43557
+ const sd = finiteCell2(stdev) ?? 1;
43558
+ const th = finiteCell2(threshold) ?? 0;
43559
+ const z = sd !== 0 ? (p - s) / sd : 0;
43560
+ return taRec({
43561
+ entry_price: 100,
43562
+ stop_loss: 95,
43563
+ take_profit: 105,
43564
+ probability: 0.7,
43565
+ reversion_probability: 0.75,
43566
+ target_price: 105,
43567
+ z_score: finiteOut2(z) ?? 0,
43568
+ is_mean_reversion_setup: Math.abs(z) > th
43569
+ });
43570
+ }
43571
+ multiTimeframeSignal(s1, s2, s3, w1, w2, w3) {
43572
+ const score = (finiteCell2(s1) ?? 0) * (finiteCell2(w1) ?? 0) + (finiteCell2(s2) ?? 0) * (finiteCell2(w2) ?? 0) + (finiteCell2(s3) ?? 0) * (finiteCell2(w3) ?? 0);
43573
+ return taRec({ score: finiteOut2(score) ?? 0, signal: score > 0.5 ? "buy" : "sell", agreement: true });
43574
+ }
43575
+ marketTimingIndex(trend, momentum, volatility, sentiment) {
43576
+ const t = finiteCell2(trend) ?? 0;
43577
+ const m = finiteCell2(momentum) ?? 0;
43578
+ const v = finiteCell2(volatility) ?? 0;
43579
+ const s = finiteCell2(sentiment) ?? 0;
43580
+ const score = t * 0.3 + m * 0.3 + v * 0.2 + s * 0.2;
43581
+ let recommendation = "hold";
43582
+ if (score > 80)
43583
+ recommendation = "strong_buy";
43584
+ else if (score > 60)
43585
+ recommendation = "buy";
43586
+ else if (score < 20)
43587
+ recommendation = "strong_sell";
43588
+ else if (score < 40)
43589
+ recommendation = "sell";
43590
+ return taRec({
43591
+ score: finiteOut2(score) ?? 0,
43592
+ recommendation,
43593
+ regime: Math.abs(t) > 50 ? "trending" : "ranging",
43594
+ timing_index: finiteOut2(score) ?? 0,
43595
+ market_condition: score > 80 ? "optimal_long" : "neutral",
43596
+ confidence: 0.85
43597
+ });
43598
+ }
43599
+ regimeAdaptiveSignal(strength, volRegime, trendRegime) {
43600
+ const vol = typeof volRegime === "string" ? volRegime : "";
43601
+ const trend = typeof trendRegime === "string" ? trendRegime : "";
43602
+ let adapted = finiteCell2(strength) ?? 0;
43603
+ let fit = 1;
43604
+ if (vol === "high") {
43605
+ adapted *= 0.8;
43606
+ fit *= 0.8;
43607
+ }
43608
+ if (trend === "ranging") {
43609
+ adapted *= 0.5;
43610
+ fit *= 0.5;
43611
+ }
43612
+ return taRec({
43613
+ signal: adapted > 0.5 ? "buy" : "sell",
43614
+ strength: finiteOut2(adapted) ?? 0,
43615
+ confidence: finiteOut2(adapted * 100) ?? 0,
43616
+ adapted_signal: finiteOut2(adapted) ?? 0,
43617
+ regime_fit: finiteOut2(fit) ?? 0,
43618
+ strategy_recommendation: trend === "trending" ? "trend_following" : "mean_reversion",
43619
+ signal_confidence: finiteOut2(adapted) ?? 0
43620
+ });
43621
+ }
43622
+ strategyScore(rsi, macd, emaCross, trend) {
43623
+ const r = finiteCell2(rsi) ?? 50;
43624
+ const m = finiteCell2(macd) ?? 0;
43625
+ const cross = emaCross != null && emaCross !== 0;
43626
+ const t = finiteCell2(trend) ?? 50;
43627
+ const rsiNorm = (r - 50) / 50 * 25;
43628
+ const macdNorm = Math.max(-25, Math.min(25, m * 50));
43629
+ const emaBonus = cross ? 25 : -25;
43630
+ const trendNorm = (t - 50) / 50 * 25;
43631
+ return Math.max(-100, Math.min(100, rsiNorm + macdNorm + emaBonus + trendNorm));
43632
+ }
43633
+ breakoutDetection(close, resistance, support) {
43634
+ const c = finiteCell2(close) ?? 0;
43635
+ const r = finiteCell2(resistance) ?? 0;
43636
+ const s = finiteCell2(support) ?? 0;
43637
+ if (c > r) {
43638
+ const strength = r > 0 ? (c - r) / r * 100 : 0;
43639
+ return taRec({
43640
+ is_breakout: true,
43641
+ breakout_type: "resistance",
43642
+ breakout_strength: finiteOut2(strength) ?? 0
43643
+ });
43644
+ }
43645
+ if (c < s) {
43646
+ const strength = s > 0 ? (s - c) / s * 100 : 0;
43647
+ return taRec({
43648
+ is_breakout: true,
43649
+ breakout_type: "support",
43650
+ breakout_strength: finiteOut2(strength) ?? 0
43651
+ });
43652
+ }
43653
+ return taRec({ is_breakout: false, breakout_type: "none", breakout_strength: 0 });
43654
+ }
42466
43655
  volumeProfileHigh(prices, volumes) {
42467
43656
  if (prices.length === 0 || volumes.length === 0 || prices.length !== volumes.length)
42468
43657
  return 0;
@@ -42535,19 +43724,27 @@ class TaEngine {
42535
43724
  const sens = Number.isFinite(sensitivity) ? sensitivity : 0.3;
42536
43725
  let st = this.volThrustSites.get(site);
42537
43726
  if (st === undefined) {
42538
- st = { close: [], volume: [], sma: [] };
43727
+ st = { closes: [], volume: null, sma: null, nClose: 0, nVolume: 0, nSma: 0 };
42539
43728
  this.volThrustSites.set(site, st);
42540
43729
  }
42541
- this.pushChrono(st.close, close);
42542
- this.pushChrono(st.volume, volume);
42543
- this.pushChrono(st.sma, volSma);
42544
- if (st.close.length === 0 || st.volume.length === 0 || st.sma.length === 0)
43730
+ if (!(close === null && st.nClose === 0)) {
43731
+ pushCap(st.closes, finiteCell2(close), 2);
43732
+ st.nClose += 1;
43733
+ }
43734
+ if (!(volume === null && st.nVolume === 0)) {
43735
+ st.volume = finiteCell2(volume);
43736
+ st.nVolume += 1;
43737
+ }
43738
+ if (!(volSma === null && st.nSma === 0)) {
43739
+ st.sma = finiteCell2(volSma);
43740
+ st.nSma += 1;
43741
+ }
43742
+ if (st.nClose < 1 || st.nVolume < 1 || st.nSma < 1)
42545
43743
  return 0;
42546
- const numOr = (v, fallback) => v !== null && Number.isFinite(v) ? v : fallback;
42547
- const cVal = numOr(this.nf(st.close, -1), 100);
42548
- const cPrev = st.close.length > 1 ? numOr(this.nf(st.close, -2), 100) : 100;
42549
- const vVal = numOr(this.nf(st.volume, -1), 1000);
42550
- const vsVal = numOr(this.nf(st.sma, -1), 1000);
43744
+ const cVal = st.closes[st.closes.length - 1] ?? 100;
43745
+ const cPrev = st.closes.length > 1 ? st.closes[st.closes.length - 2] ?? 100 : 100;
43746
+ const vVal = st.volume ?? 1000;
43747
+ const vsVal = st.sma ?? 1000;
42551
43748
  const spike = vVal > vsVal * (1 + sens);
42552
43749
  const move = cPrev !== 0 ? Math.abs(cVal - cPrev) / cPrev > 0.01 : false;
42553
43750
  return spike && move ? 1 : 0;
@@ -42933,7 +44130,9 @@ var NS = new Set([
42933
44130
  "session",
42934
44131
  "syminfo",
42935
44132
  "timenow",
42936
- "chart"
44133
+ "chart",
44134
+ "footprint",
44135
+ "volume_row"
42937
44136
  ]);
42938
44137
  var TA_METHODS = new Set([
42939
44138
  "sma",
@@ -43038,7 +44237,45 @@ var TA_METHODS = new Set([
43038
44237
  "volume_momentum",
43039
44238
  "volume_profile_high",
43040
44239
  "volume_profile_low",
43041
- "volume_thrust"
44240
+ "volume_thrust",
44241
+ "sma_weighted",
44242
+ "apo",
44243
+ "atr_normalized",
44244
+ "beta",
44245
+ "r_squared",
44246
+ "comovement",
44247
+ "skewness",
44248
+ "kurtosis",
44249
+ "volume_weighted_momentum",
44250
+ "parkinson",
44251
+ "garman_klass",
44252
+ "mean_reversion_score",
44253
+ "market_condition",
44254
+ "order_flow_imbalance",
44255
+ "liquidity_score",
44256
+ "fear_greed_index",
44257
+ "crowd_sentiment",
44258
+ "smart_money_flow",
44259
+ "trend_confirmation_score",
44260
+ "max_loss_level",
44261
+ "profit_lock_level",
44262
+ "position_sizing",
44263
+ "kelly_criterion",
44264
+ "risk_reward_ratio",
44265
+ "risk_reward_asymmetry",
44266
+ "probability_of_movement",
44267
+ "trend_strength",
44268
+ "breakeven_level",
44269
+ "market_structure_pivot",
44270
+ "position_sizing_score",
44271
+ "trailing_exit_level",
44272
+ "optimal_entry_zone",
44273
+ "mean_reversion_entry",
44274
+ "multi_timeframe_signal",
44275
+ "market_timing_index",
44276
+ "regime_adaptive_signal",
44277
+ "strategy_score",
44278
+ "breakout_detection"
43042
44279
  ]);
43043
44280
  var TA_BARE_ATTRS = new Set([
43044
44281
  "accdist",
@@ -43311,6 +44548,9 @@ function emitCall2(ctx, node, visit) {
43311
44548
  const req = emitRequest(ctx, name, args);
43312
44549
  if (req != null)
43313
44550
  return req;
44551
+ const fp = emitFootprint(name, args);
44552
+ if (fp != null)
44553
+ return fp;
43314
44554
  return "null";
43315
44555
  }
43316
44556
  function resolveCallee(func) {
@@ -43380,6 +44620,23 @@ function hasArg(args, index, names) {
43380
44620
  }
43381
44621
  return index >= 0 && index < args.pos.length;
43382
44622
  }
44623
+ var BARE_SERIES_NAMES = new Set([
44624
+ "open",
44625
+ "high",
44626
+ "low",
44627
+ "close",
44628
+ "volume",
44629
+ "hl2",
44630
+ "hlc3",
44631
+ "ohlc4",
44632
+ "hlcc4",
44633
+ "time",
44634
+ "time_close"
44635
+ ]);
44636
+ function hasSeriesArg(args) {
44637
+ const isSeries = (n) => n.kind === "Name" && BARE_SERIES_NAMES.has(n.id);
44638
+ return args.posNodes.some(isSeries) || Object.values(args.kwNodes).some(isSeries);
44639
+ }
43383
44640
  function hasAnyKw(args, names) {
43384
44641
  return names.some((n) => Object.hasOwn(args.kw, n));
43385
44642
  }
@@ -43395,6 +44652,9 @@ function cellOf(expr) {
43395
44652
  function cellList(expr) {
43396
44653
  return `(() => { const __v = ${expr}; const __cell = (e) => (e == null ? null : typeof e === "boolean" ? (e ? 1 : 0) : (typeof e === "number" && Number.isFinite(e) ? e : null)); if (__v != null && typeof __v.size === "function" && typeof __v.get === "function") { const __n = __v.size(); const __o = []; for (let __i = 0; __i < __n; __i++) __o.push(__cell(__v.get(__i))); return __o; } return [__cell(__v)]; })()`;
43397
44654
  }
44655
+ function cellLast(expr) {
44656
+ return `(() => { const __v = ${expr}; const __cell = (e) => (e == null ? null : typeof e === "boolean" ? (e ? 1 : 0) : (typeof e === "number" && Number.isFinite(e) ? e : null)); if (__v != null && typeof __v.size === "function" && typeof __v.get === "function") { const __n = __v.size(); return __n === 0 ? null : __cell(__v.get(__n - 1)); } return __cell(__v); })()`;
44657
+ }
43398
44658
  var DRAW_KINDS = new Set(["label", "line", "box", "table", "polyline", "linefill"]);
43399
44659
  var ARRAY_SIGS = {
43400
44660
  new: [["size"], ["initial_value", "initial"]],
@@ -43774,6 +45034,8 @@ function emitDraw(ctx, name, methodSrc, args) {
43774
45034
  code = `__h.draw.box_new(__bar_idx, ${pick(args, 0, ["left"], "0")}, ${pick(args, 1, ["top"], "0")}, ${pick(args, 2, ["right"], "0")}, ${pick(args, 3, ["bottom"], "0")})`;
43775
45035
  } else if (kind === "polyline") {
43776
45036
  code = `__h.draw.polyline_new(__bar_idx, ${pick(args, 0, ["points"], "null")})`;
45037
+ } else if (kind === "table") {
45038
+ code = `__h.draw.table_new(__bar_idx, ${pick(args, 0, ["position"], "null")}, ${pick(args, 1, ["columns"], "null")}, ${pick(args, 2, ["rows"], "null")}, ${pick(args, 3, ["bgcolor"], "null")}, ${pick(args, 4, ["frame_color"], "null")}, ${pick(args, 5, ["frame_width"], "null")}, ${pick(args, 6, ["border_color"], "null")}, ${pick(args, 7, ["border_width"], "null")}, ${pick(args, 8, ["force_overlay"], "null")})`;
43777
45039
  } else if (kind === "linefill") {
43778
45040
  const color = hasArg(args, 2, ["color"]) ? pick(args, 2, ["color"], "null") : "null";
43779
45041
  code = `__h.draw.linefill_new(__bar_idx, ${pick(args, 0, ["id1", "line1"], "null")}, ${pick(args, 1, ["id2", "line2"], "null")}, ${color})`;
@@ -43840,8 +45102,7 @@ var SECURITY_FUNCS = new Set([
43840
45102
  "security",
43841
45103
  "security_lower_tf",
43842
45104
  "request_security",
43843
- "request_security_lower_tf",
43844
- "request_seed"
45105
+ "request_security_lower_tf"
43845
45106
  ]);
43846
45107
  var SIMPLE_CHART_EXPR = new Set([
43847
45108
  "close",
@@ -43879,10 +45140,58 @@ function emitRequest(ctx, name, args) {
43879
45140
  if (name === "request_currency_rate" || name === "currency_rate") {
43880
45141
  return `__h.currencyRate(${pick(args, 0, ["from", "from_currency"], "null")}, ${pick(args, 1, ["to", "to_currency"], "null")})`;
43881
45142
  }
45143
+ if (name === "request_seed") {
45144
+ return `__h.requestSeed(${pick(args, 0, ["seed"], "0")})`;
45145
+ }
45146
+ if (name === "request_footprint") {
45147
+ return `__h.requestFootprint(${pick(args, 0, ["num_ticks"], "100")}, ${pick(args, 1, ["va_percentage"], "70")})`;
45148
+ }
43882
45149
  if (name.startsWith("request_"))
43883
45150
  return "null";
43884
45151
  return null;
43885
45152
  }
45153
+ function emitFootprint(name, args) {
45154
+ const fp = pick(args, 0, ["id", "footprint"], "null");
45155
+ const vr = pick(args, 0, ["id", "volume_row"], "null");
45156
+ switch (name) {
45157
+ case "footprint_buy_volume":
45158
+ return `__h.footprint.buy_volume(${fp})`;
45159
+ case "footprint_sell_volume":
45160
+ return `__h.footprint.sell_volume(${fp})`;
45161
+ case "footprint_delta":
45162
+ return `__h.footprint.delta(${fp})`;
45163
+ case "footprint_total_volume":
45164
+ return `__h.footprint.total_volume(${fp})`;
45165
+ case "footprint_vah":
45166
+ return `__h.footprint.vah(${fp})`;
45167
+ case "footprint_val":
45168
+ return `__h.footprint.val(${fp})`;
45169
+ case "footprint_poc":
45170
+ return `__h.footprint.poc(${fp})`;
45171
+ case "footprint_rows":
45172
+ return `__h.footprint.rows(${fp})`;
45173
+ case "footprint_get_row_by_price":
45174
+ return `__h.footprint.get_row_by_price(${fp}, ${pick(args, 1, ["price"], "null")})`;
45175
+ case "volume_row_up_price":
45176
+ return `__h.footprint.volume_row.up_price(${vr})`;
45177
+ case "volume_row_down_price":
45178
+ return `__h.footprint.volume_row.down_price(${vr})`;
45179
+ case "volume_row_buy_volume":
45180
+ return `__h.footprint.volume_row.buy_volume(${vr})`;
45181
+ case "volume_row_sell_volume":
45182
+ return `__h.footprint.volume_row.sell_volume(${vr})`;
45183
+ case "volume_row_delta":
45184
+ return `__h.footprint.volume_row.delta(${vr})`;
45185
+ case "volume_row_total_volume":
45186
+ return `__h.footprint.volume_row.total_volume(${vr})`;
45187
+ case "volume_row_has_buy_imbalance":
45188
+ return `__h.footprint.volume_row.has_buy_imbalance(${vr})`;
45189
+ case "volume_row_has_sell_imbalance":
45190
+ return `__h.footprint.volume_row.has_sell_imbalance(${vr})`;
45191
+ default:
45192
+ return null;
45193
+ }
45194
+ }
43886
45195
  function isSimpleSecurityExpr(expr) {
43887
45196
  const e = expr.trim();
43888
45197
  if (!e)
@@ -44349,6 +45658,9 @@ function allocSite(ctx) {
44349
45658
  function taCall(method, site, parts) {
44350
45659
  return `__h.ta.${method}(${site}, ${parts.join(", ")})`;
44351
45660
  }
45661
+ function taPure(method, parts) {
45662
+ return `__h.ta.${method}(${parts.join(", ")})`;
45663
+ }
44352
45664
  function emitTa(ctx, method, args) {
44353
45665
  if (!TA_METHODS.has(method))
44354
45666
  return "null";
@@ -44772,16 +46084,30 @@ function emitTa(ctx, method, args) {
44772
46084
  ]);
44773
46085
  }
44774
46086
  if (method === "stoch_smooth") {
44775
- return `__h.ta.stochSmooth(${cellOf(pick(args, 0, ["high"], "null"))}, ${cellOf(pick(args, 1, ["low"], "null"))}, ${cellOf(pick(args, 2, ["close"], "null"))}, ${cellOf(pick(args, 3, ["period", "length"], "null"))}, ${cellOf(pick(args, 4, ["smooth_k", "k"], "null"))}, ${cellOf(pick(args, 5, ["smooth_d", "d"], "null"))})`;
46087
+ return taCall("stochSmooth", site, [
46088
+ cellOf(pick(args, 0, ["high"], "null")),
46089
+ cellOf(pick(args, 1, ["low"], "null")),
46090
+ cellOf(pick(args, 2, ["close"], "null")),
46091
+ cellOf(pick(args, 3, ["period", "length"], "null")),
46092
+ cellOf(pick(args, 4, ["smooth_k", "k"], "null")),
46093
+ cellOf(pick(args, 5, ["smooth_d", "d"], "null"))
46094
+ ]);
44776
46095
  }
44777
46096
  if (method === "engulfing") {
44778
- return `(() => { ${cellOf(pick(args, 0, ["open"], "null"))}; ${cellOf(pick(args, 1, ["high"], "null"))}; ${cellOf(pick(args, 2, ["low"], "null"))}; ${cellOf(pick(args, 3, ["close"], "null"))}; return __h.ta.engulfing(); })()`;
46097
+ return `(() => { const __o = ${cellOf(pick(args, 0, ["open"], "null"))}; ${cellOf(pick(args, 1, ["high"], "null"))}; ${cellOf(pick(args, 2, ["low"], "null"))}; const __c = ${cellOf(pick(args, 3, ["close"], "null"))}; return __h.ta.engulfing(${site}, __o, __c); })()`;
44779
46098
  }
44780
46099
  if (method === "inside_bar_pattern") {
44781
- return `(() => { ${cellOf(pick(args, 0, ["high"], "null"))}; ${cellOf(pick(args, 1, ["low"], "null"))}; return __h.ta.insideBarPattern(); })()`;
46100
+ return taCall("insideBarPattern", site, [
46101
+ cellOf(pick(args, 0, ["high"], "null")),
46102
+ cellOf(pick(args, 1, ["low"], "null"))
46103
+ ]);
44782
46104
  }
44783
46105
  if (method === "double_top_bottom") {
44784
- return `(() => { ${cellOf(pick(args, 0, ["high"], "null"))}; ${cellOf(pick(args, 1, ["low"], "null"))}; return __h.ta.doubleTopBottom(${cellOf(pick(args, 2, ["period", "length"], "null"))}); })()`;
46106
+ return taCall("doubleTopBottom", site, [
46107
+ cellOf(pick(args, 0, ["high"], "null")),
46108
+ cellOf(pick(args, 1, ["low"], "null")),
46109
+ cellOf(pick(args, 2, ["period", "length"], "null"))
46110
+ ]);
44785
46111
  }
44786
46112
  if (method === "voi") {
44787
46113
  return `__h.ta.voi(${cellOf(pick(args, 0, ["buy_volume", "buy"], "null"))}, ${cellOf(pick(args, 1, ["sell_volume", "sell"], "null"))})`;
@@ -44794,7 +46120,10 @@ function emitTa(ctx, method, args) {
44794
46120
  }
44795
46121
  if (method === "rsi_divergence") {
44796
46122
  const period = `((__n) => (__n == null ? 0 : __n))(${cellOf(pick(args, 1, ["period", "length"], "null"))})`;
44797
- return `__h.ta.rsiDivergence(${cellList(pick(args, 0, ["rsi_series", "series", "source"], "null"))}, ${period})`;
46123
+ return taCall("rsiDivergence", site, [
46124
+ cellLast(pick(args, 0, ["rsi_series", "series", "source"], "null")),
46125
+ period
46126
+ ]);
44798
46127
  }
44799
46128
  if (method === "cumulative_delta") {
44800
46129
  return taCall("cumulativeDelta", site, [
@@ -44829,6 +46158,237 @@ function emitTa(ctx, method, args) {
44829
46158
  `((__n) => (__n == null ? 0.3 : __n))(${sens})`
44830
46159
  ]);
44831
46160
  }
46161
+ if (method === "sma_weighted") {
46162
+ return taCall("smaWeighted", site, [
46163
+ cellOf(pick(args, 0, ["series", "source"], "null")),
46164
+ cellOf(pick(args, 1, ["period", "length"], "null")),
46165
+ pick(args, 2, ["weight_type", "weight"], '"linear"')
46166
+ ]);
46167
+ }
46168
+ if (method === "apo") {
46169
+ return taCall("apo", site, [
46170
+ cellOf(pick(args, 0, ["series", "source"], "null")),
46171
+ cellOf(pick(args, 1, ["fast_period", "fast"], "null")),
46172
+ cellOf(pick(args, 2, ["slow_period", "slow"], "null"))
46173
+ ]);
46174
+ }
46175
+ if (method === "atr_normalized") {
46176
+ return taCall("atrNormalized", site, [
46177
+ cellOf(pick(args, 0, ["high"], "null")),
46178
+ cellOf(pick(args, 1, ["low"], "null")),
46179
+ cellOf(pick(args, 2, ["close"], "null")),
46180
+ cellOf(pick(args, 3, ["period", "length"], "null"))
46181
+ ]);
46182
+ }
46183
+ if (method === "beta" || method === "r_squared" || method === "comovement") {
46184
+ const fn = method === "beta" ? "beta" : method === "r_squared" ? "rSquared" : "comovement";
46185
+ return taCall(fn, site, [
46186
+ cellOf(pick(args, 0, ["series1", "series", "source"], "null")),
46187
+ cellOf(pick(args, 1, ["series2", "series_b", "other"], "null")),
46188
+ cellOf(pick(args, 2, ["length", "period"], "null"))
46189
+ ]);
46190
+ }
46191
+ if (method === "skewness" || method === "kurtosis") {
46192
+ return taCall(method, site, [
46193
+ cellOf(pick(args, 0, ["series", "source"], "null")),
46194
+ cellOf(pick(args, 1, ["period", "length"], "null"))
46195
+ ]);
46196
+ }
46197
+ if (method === "volume_weighted_momentum") {
46198
+ return taCall("volumeWeightedMomentum", site, [
46199
+ cellOf(pick(args, 0, ["series", "source"], "null")),
46200
+ cellOf(pick(args, 1, ["volume"], "null")),
46201
+ cellOf(pick(args, 2, ["length", "period"], "null"))
46202
+ ]);
46203
+ }
46204
+ if (method === "parkinson") {
46205
+ if (hasSeriesArg(args))
46206
+ return "null";
46207
+ return `__h.ta.parkinson(${cellOf(pick(args, 0, ["high"], "null"))}, ${cellOf(pick(args, 1, ["low"], "null"))})`;
46208
+ }
46209
+ if (method === "garman_klass") {
46210
+ if (hasSeriesArg(args))
46211
+ return "null";
46212
+ return `__h.ta.garmanKlass(${cellOf(pick(args, 0, ["high"], "null"))}, ${cellOf(pick(args, 1, ["low"], "null"))}, ${cellOf(pick(args, 2, ["close"], "null"))}, ${cellOf(pick(args, 3, ["open"], "null"))})`;
46213
+ }
46214
+ if (method === "mean_reversion_score") {
46215
+ return taCall("meanReversionScore", site, [
46216
+ cellOf(pick(args, 0, ["close", "source"], "null")),
46217
+ cellOf(pick(args, 1, ["sma"], "null")),
46218
+ cellOf(pick(args, 2, ["stdev", "std_dev"], "null")),
46219
+ cellOf(pick(args, 3, ["period", "length"], "null"))
46220
+ ]);
46221
+ }
46222
+ if (method === "market_condition") {
46223
+ return taCall("marketCondition", site, [
46224
+ cellOf(pick(args, 0, ["close", "source"], "null")),
46225
+ cellOf(pick(args, 1, ["atr"], "null")),
46226
+ cellOf(pick(args, 2, ["sma_period", "sma_length"], "null")),
46227
+ cellOf(pick(args, 3, ["stdev_period", "stdev_length"], "null"))
46228
+ ]);
46229
+ }
46230
+ if (method === "order_flow_imbalance") {
46231
+ return taCall("orderFlowImbalance", site, [
46232
+ cellOf(pick(args, 0, ["high"], "null")),
46233
+ cellOf(pick(args, 1, ["low"], "null")),
46234
+ cellOf(pick(args, 2, ["close"], "null")),
46235
+ cellOf(pick(args, 3, ["volume"], "null")),
46236
+ cellOf(pick(args, 4, ["period", "length"], "null"))
46237
+ ]);
46238
+ }
46239
+ if (method === "liquidity_score") {
46240
+ return taCall("liquidityScore", site, [
46241
+ cellOf(pick(args, 0, ["volume"], "null")),
46242
+ cellOf(pick(args, 1, ["volatility"], "null")),
46243
+ cellOf(pick(args, 2, ["spread"], "null")),
46244
+ cellOf(pick(args, 3, ["period", "length"], "null"))
46245
+ ]);
46246
+ }
46247
+ if (method === "fear_greed_index") {
46248
+ return `__h.ta.fearGreedIndex(${cellOf(pick(args, 0, ["rsi"], "null"))}, ${cellOf(pick(args, 1, ["vix"], "null"))}, ${cellOf(pick(args, 2, ["put_call", "put_call_ratio"], "null"))}, ${cellOf(pick(args, 3, ["breadth"], "null"))})`;
46249
+ }
46250
+ if (method === "crowd_sentiment") {
46251
+ return `__h.ta.crowdSentiment(${cellOf(pick(args, 0, ["price_agreement", "price"], "null"))}, ${cellOf(pick(args, 1, ["volume_agreement", "volume"], "null"))}, ${cellOf(pick(args, 2, ["time_agreement", "time"], "null"))})`;
46252
+ }
46253
+ if (method === "smart_money_flow") {
46254
+ return `__h.ta.smartMoneyFlow(${cellOf(pick(args, 0, ["price_change"], "null"))}, ${cellOf(pick(args, 1, ["volume"], "null"))}, ${cellOf(pick(args, 2, ["time_since_high", "time_high"], "null"))}, ${cellOf(pick(args, 3, ["time_since_low", "time_low"], "null"))})`;
46255
+ }
46256
+ if (method === "trend_confirmation_score") {
46257
+ return `__h.ta.trendConfirmationScore(${cellOf(pick(args, 0, ["momentum"], "null"))}, ${cellOf(pick(args, 1, ["trend_alignment"], "null"))}, ${cellOf(pick(args, 2, ["strength"], "null"))}, ${cellOf(pick(args, 3, ["rsi"], "null"))}, ${cellOf(pick(args, 4, ["rsi_alignment"], "null"))})`;
46258
+ }
46259
+ if (method === "max_loss_level") {
46260
+ return `__h.ta.maxLossLevel(${cellOf(pick(args, 0, ["entry", "entry_price"], "null"))}, ${cellOf(pick(args, 1, ["account", "account_size"], "null"))}, ${cellOf(pick(args, 2, ["max_loss_pct", "max_loss_percent"], "null"))})`;
46261
+ }
46262
+ if (method === "profit_lock_level") {
46263
+ return `__h.ta.profitLockLevel(${cellOf(pick(args, 0, ["entry", "entry_price"], "null"))}, ${cellOf(pick(args, 1, ["current", "current_price"], "null"))}, ${cellOf(pick(args, 2, ["trail_pct", "trail_percent"], "null"))}, ${cellOf(pick(args, 3, ["direction"], "null"))})`;
46264
+ }
46265
+ if (method === "position_sizing") {
46266
+ return taPure("positionSizing", [
46267
+ cellOf(pick(args, 0, ["account", "account_size"], "null")),
46268
+ cellOf(pick(args, 1, ["risk_pct", "risk_percent"], "null")),
46269
+ cellOf(pick(args, 2, ["entry", "entry_price"], "null")),
46270
+ cellOf(pick(args, 3, ["stop", "stop_price"], "null"))
46271
+ ]);
46272
+ }
46273
+ if (method === "kelly_criterion") {
46274
+ return taPure("kellyCriterion", [
46275
+ cellOf(pick(args, 0, ["win_rate"], "null")),
46276
+ cellOf(pick(args, 1, ["avg_win"], "null")),
46277
+ cellOf(pick(args, 2, ["avg_loss"], "null"))
46278
+ ]);
46279
+ }
46280
+ if (method === "risk_reward_ratio") {
46281
+ return taPure("riskRewardRatio", [
46282
+ cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
46283
+ cellOf(pick(args, 1, ["stop", "stop_price"], "null")),
46284
+ cellOf(pick(args, 2, ["target", "target_price"], "null"))
46285
+ ]);
46286
+ }
46287
+ if (method === "risk_reward_asymmetry") {
46288
+ return taPure("riskRewardAsymmetry", [
46289
+ cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
46290
+ cellOf(pick(args, 1, ["stop", "stop_price"], "null")),
46291
+ cellOf(pick(args, 2, ["target", "target_price"], "null")),
46292
+ cellOf(pick(args, 3, ["win_rate"], "null"))
46293
+ ]);
46294
+ }
46295
+ if (method === "probability_of_movement") {
46296
+ return taPure("probabilityOfMovement", [
46297
+ cellOf(pick(args, 0, ["current", "current_price"], "null")),
46298
+ cellOf(pick(args, 1, ["target", "target_price"], "null")),
46299
+ cellOf(pick(args, 2, ["atr"], "null")),
46300
+ cellOf(pick(args, 3, ["period", "length"], "null"))
46301
+ ]);
46302
+ }
46303
+ if (method === "trend_strength") {
46304
+ return taPure("trendStrength", [
46305
+ cellOf(pick(args, 0, ["price", "source"], "null")),
46306
+ cellOf(pick(args, 1, ["adx"], "null")),
46307
+ cellOf(pick(args, 2, ["rsi"], "null"))
46308
+ ]);
46309
+ }
46310
+ if (method === "breakeven_level") {
46311
+ return taPure("breakevenLevel", [
46312
+ cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
46313
+ cellOf(pick(args, 1, ["quantity", "qty"], "null")),
46314
+ cellOf(pick(args, 2, ["commission"], "null")),
46315
+ cellOf(pick(args, 3, ["slippage"], "null")),
46316
+ cellOf(pick(args, 4, ["direction"], "null"))
46317
+ ]);
46318
+ }
46319
+ if (method === "market_structure_pivot") {
46320
+ return taPure("marketStructurePivot", [
46321
+ cellOf(pick(args, 2, ["close"], "null"))
46322
+ ]);
46323
+ }
46324
+ if (method === "position_sizing_score") {
46325
+ return taPure("positionSizingScore", [
46326
+ cellOf(pick(args, 0, ["account_risk", "risk"], "null")),
46327
+ cellOf(pick(args, 1, ["volatility"], "null")),
46328
+ cellOf(pick(args, 2, ["conviction"], "null")),
46329
+ cellOf(pick(args, 3, ["correlation"], "null"))
46330
+ ]);
46331
+ }
46332
+ if (method === "trailing_exit_level") {
46333
+ return taPure("trailingExitLevel", [
46334
+ cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
46335
+ cellOf(pick(args, 1, ["current", "current_price"], "null")),
46336
+ cellOf(pick(args, 2, ["atr"], "null")),
46337
+ cellOf(pick(args, 3, ["multiplier", "mult"], "null")),
46338
+ cellOf(pick(args, 4, ["step"], "null"))
46339
+ ]);
46340
+ }
46341
+ if (method === "optimal_entry_zone") {
46342
+ return taPure("optimalEntryZone", [cellOf(pick(args, 2, ["close"], "null"))]);
46343
+ }
46344
+ if (method === "mean_reversion_entry") {
46345
+ return taPure("meanReversionEntry", [
46346
+ cellOf(pick(args, 0, ["price", "source"], "null")),
46347
+ cellOf(pick(args, 1, ["sma"], "null")),
46348
+ cellOf(pick(args, 2, ["stdev", "std_dev"], "null")),
46349
+ cellOf(pick(args, 4, ["threshold"], "null"))
46350
+ ]);
46351
+ }
46352
+ if (method === "multi_timeframe_signal") {
46353
+ return taPure("multiTimeframeSignal", [
46354
+ cellOf(pick(args, 0, ["s1", "signal1"], "null")),
46355
+ cellOf(pick(args, 1, ["s2", "signal2"], "null")),
46356
+ cellOf(pick(args, 2, ["s3", "signal3"], "null")),
46357
+ cellOf(pick(args, 3, ["w1", "weight1"], "null")),
46358
+ cellOf(pick(args, 4, ["w2", "weight2"], "null")),
46359
+ cellOf(pick(args, 5, ["w3", "weight3"], "null"))
46360
+ ]);
46361
+ }
46362
+ if (method === "market_timing_index") {
46363
+ return taPure("marketTimingIndex", [
46364
+ cellOf(pick(args, 0, ["trend"], "null")),
46365
+ cellOf(pick(args, 1, ["momentum"], "null")),
46366
+ cellOf(pick(args, 2, ["volatility"], "null")),
46367
+ cellOf(pick(args, 3, ["sentiment"], "null"))
46368
+ ]);
46369
+ }
46370
+ if (method === "regime_adaptive_signal") {
46371
+ return taPure("regimeAdaptiveSignal", [
46372
+ cellOf(pick(args, 0, ["signal_strength", "strength"], "null")),
46373
+ pick(args, 1, ["volatility_regime", "vol_regime"], '""'),
46374
+ pick(args, 2, ["trend_regime"], '""')
46375
+ ]);
46376
+ }
46377
+ if (method === "strategy_score") {
46378
+ return taPure("strategyScore", [
46379
+ cellOf(pick(args, 0, ["rsi"], "null")),
46380
+ cellOf(pick(args, 1, ["macd"], "null")),
46381
+ cellOf(pick(args, 2, ["ema_cross"], "null")),
46382
+ cellOf(pick(args, 3, ["trend"], "null"))
46383
+ ]);
46384
+ }
46385
+ if (method === "breakout_detection") {
46386
+ return taPure("breakoutDetection", [
46387
+ cellOf(pick(args, 0, ["close", "source"], "null")),
46388
+ cellOf(pick(args, 1, ["resistance"], "null")),
46389
+ cellOf(pick(args, 2, ["support"], "null"))
46390
+ ]);
46391
+ }
44832
46392
  return "null";
44833
46393
  }
44834
46394
 
@@ -45477,6 +47037,20 @@ var ATTR_CONSTANTS = {
45477
47037
  "plot.linestyle_solid": "linestyle_solid",
45478
47038
  "plot.linestyle_dashed": "linestyle_dashed",
45479
47039
  "plot.linestyle_dotted": "linestyle_dotted",
47040
+ "plot.style_line": "style_line",
47041
+ "plot.style_linebr": "style_linebr",
47042
+ "plot.style_stepline": "style_stepline",
47043
+ "plot.style_steplinebr": "style_steplinebr",
47044
+ "plot.style_stepline_diamond": "style_stepline_diamond",
47045
+ "plot.style_histogram": "style_histogram",
47046
+ "plot.style_columns": "style_columns",
47047
+ "plot.style_cross": "style_cross",
47048
+ "plot.style_area": "style_area",
47049
+ "plot.style_areabr": "style_areabr",
47050
+ "plot.style_circles": "style_circles",
47051
+ "alert.freq_once_per_bar": "once_per_bar",
47052
+ "alert.freq_once_per_bar_close": "once_per_bar_close",
47053
+ "alert.freq_all": "all",
45480
47054
  "dayofweek.sunday": 1,
45481
47055
  "dayofweek.monday": 2,
45482
47056
  "dayofweek.tuesday": 3,
@@ -45513,6 +47087,7 @@ var ATTR_CONST_NS = new Set([
45513
47087
  "position",
45514
47088
  "hline",
45515
47089
  "plot",
47090
+ "alert",
45516
47091
  "dayofweek",
45517
47092
  "month"
45518
47093
  ]);
@@ -46282,6 +47857,8 @@ function naNum(v) {
46282
47857
  function hold(v) {
46283
47858
  if (v != null && typeof v === "object")
46284
47859
  return v;
47860
+ if (typeof v === "string")
47861
+ return v;
46285
47862
  return naNum(v);
46286
47863
  }
46287
47864
  function pineEq(a, b) {
@@ -46974,8 +48551,23 @@ class CompileDraw {
46974
48551
  putNum(extra, "bottom", bottom);
46975
48552
  return this.book.boxNew(n3(bar, 0), Object.keys(extra).length ? extra : undefined);
46976
48553
  }
46977
- table_new(bar) {
46978
- return this.book.tableNew(n3(bar, 0));
48554
+ table_new(bar, position, columns, rows, bgcolor, frameColor, frameWidth, borderColor, borderWidth, forceOverlay) {
48555
+ const extra = {};
48556
+ if (position != null)
48557
+ extra.position = position;
48558
+ putNum(extra, "columns", columns);
48559
+ putNum(extra, "rows", rows);
48560
+ if (bgcolor != null)
48561
+ extra.bgcolor = bgcolor;
48562
+ if (frameColor != null)
48563
+ extra.frame_color = frameColor;
48564
+ putNum(extra, "frame_width", frameWidth);
48565
+ if (borderColor != null)
48566
+ extra.border_color = borderColor;
48567
+ putNum(extra, "border_width", borderWidth);
48568
+ if (forceOverlay != null)
48569
+ extra.force_overlay = forceOverlay;
48570
+ return this.book.tableNew(n3(bar, 0), Object.keys(extra).length ? extra : undefined);
46979
48571
  }
46980
48572
  polyline_new(bar, points) {
46981
48573
  const pts = pointsOf(points);
@@ -47609,7 +49201,8 @@ class CompileStrategy {
47609
49201
  open: num(open, this.mark),
47610
49202
  high: num(high, this.mark),
47611
49203
  low: num(low, this.mark),
47612
- close: this.mark
49204
+ close: this.mark,
49205
+ time: this.time
47613
49206
  };
47614
49207
  this.ohlc = ohlc;
47615
49208
  this.book.processPending(this.bar, ohlc);
@@ -47625,17 +49218,18 @@ class CompileStrategy {
47625
49218
  stop: opts?.stop,
47626
49219
  comment: opts?.comment,
47627
49220
  oca_name: opts?.oca_name,
47628
- oca_type: opts?.oca_type
49221
+ oca_type: opts?.oca_type,
49222
+ deferMarket: true
47629
49223
  });
47630
49224
  }
47631
49225
  close(id, qty) {
47632
- this.book.fillClose(this.bar, str(id, ""), this.mark, {
49226
+ this.book.placeClose(this.bar, str(id, ""), this.mark, {
47633
49227
  time: this.time,
47634
49228
  qty: optNum(qty)
47635
49229
  });
47636
49230
  }
47637
49231
  close_all(_comment) {
47638
- this.book.closeAll(this.bar, this.mark);
49232
+ this.book.placeCloseAll(this.bar, this.mark);
47639
49233
  }
47640
49234
  order(id, direction, qty, opts) {
47641
49235
  this.entry(id, direction, qty, opts);
@@ -47652,7 +49246,8 @@ class CompileStrategy {
47652
49246
  ...parsed,
47653
49247
  price: this.mark,
47654
49248
  time: this.time,
47655
- ohlc: this.ohlc
49249
+ ohlc: this.ohlc,
49250
+ deferMarket: true
47656
49251
  });
47657
49252
  }
47658
49253
  position_size() {
@@ -48020,8 +49615,8 @@ function createCompileHelpers(opts) {
48020
49615
  second: calendarSecond,
48021
49616
  dayofweek: calendarDayofweek,
48022
49617
  timestamp,
48023
- weekOfYear,
48024
- timeTradingDay,
49618
+ weekOfYear: calendarWeekOfYear,
49619
+ timeTradingDay: calendarTimeTradingDay,
48025
49620
  timeframeInSeconds: timeframeInSecondsOrDaily,
48026
49621
  timeframeChange,
48027
49622
  timeClose,
@@ -48065,11 +49660,40 @@ function createCompileHelpers(opts) {
48065
49660
  udtSet,
48066
49661
  udtRegister,
48067
49662
  currencyRate: resolveCurrencyRate,
49663
+ requestSeed: resolveSeed,
49664
+ requestFootprint: createFootprint,
49665
+ footprint: {
49666
+ buy_volume: footprintBuyVolume,
49667
+ sell_volume: footprintSellVolume,
49668
+ delta: footprintDelta,
49669
+ total_volume: footprintTotalVolume,
49670
+ vah: footprintVah,
49671
+ val: footprintVal,
49672
+ poc: footprintPoc,
49673
+ rows: compileFootprintRows,
49674
+ get_row_by_price: footprintGetRowByPrice,
49675
+ volume_row: {
49676
+ up_price: volumeRowUpPrice,
49677
+ down_price: volumeRowDownPrice,
49678
+ buy_volume: volumeRowBuyVolume,
49679
+ sell_volume: volumeRowSellVolume,
49680
+ delta: volumeRowDelta,
49681
+ total_volume: volumeRowTotalVolume,
49682
+ has_buy_imbalance: volumeRowHasBuyImbalance,
49683
+ has_sell_imbalance: volumeRowHasSellImbalance
49684
+ }
49685
+ },
48068
49686
  runtimeError(msg) {
48069
49687
  throw new Error(String(msg));
48070
49688
  }
48071
49689
  };
48072
49690
  }
49691
+ function compileFootprintRows(fp) {
49692
+ const arr = new PineArray;
49693
+ for (const row of footprintRows(fp))
49694
+ arr.push(row);
49695
+ return arr;
49696
+ }
48073
49697
  function compileColorNew(color, transp) {
48074
49698
  const parsed = asColor(color);
48075
49699
  if (!parsed)
@@ -48116,7 +49740,20 @@ function NA_FN(v) {
48116
49740
  function utcPart(t, key) {
48117
49741
  if (typeof t !== "number" || !Number.isFinite(t))
48118
49742
  return null;
48119
- return utcPartsFromMs(t)[key];
49743
+ const ms = timestampToMs(t);
49744
+ return ms == null ? null : utcPartsFromMs(ms)[key];
49745
+ }
49746
+ function calendarWeekOfYear(t) {
49747
+ if (typeof t !== "number" || !Number.isFinite(t))
49748
+ return null;
49749
+ const ms = timestampToMs(t);
49750
+ return ms == null ? null : weekOfYear(ms);
49751
+ }
49752
+ function calendarTimeTradingDay(t) {
49753
+ if (typeof t !== "number" || !Number.isFinite(t))
49754
+ return null;
49755
+ const ms = timestampToMs(t);
49756
+ return ms == null ? null : timeTradingDay(ms);
48120
49757
  }
48121
49758
  function calendarYear(t) {
48122
49759
  return utcPart(t, "year");
@@ -48550,7 +50187,8 @@ function interpretTree(tree, ohlcv, host) {
48550
50187
  open: num2(env.ctx.open) ?? undefined,
48551
50188
  high: num2(env.ctx.high) ?? undefined,
48552
50189
  low: num2(env.ctx.low) ?? undefined,
48553
- close: num2(env.ctx.close) ?? undefined
50190
+ close: num2(env.ctx.close) ?? undefined,
50191
+ time: num2(env.ctx.time) ?? undefined
48554
50192
  });
48555
50193
  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);
48556
50194
  try {
@@ -48881,6 +50519,27 @@ function seriesGet(env, id) {
48881
50519
  }
48882
50520
  return env.series.get(id);
48883
50521
  }
50522
+ var BARE_SERIES_NAMES2 = new Set([
50523
+ "open",
50524
+ "high",
50525
+ "low",
50526
+ "close",
50527
+ "volume",
50528
+ "hl2",
50529
+ "hlc3",
50530
+ "ohlc4",
50531
+ "hlcc4",
50532
+ "time",
50533
+ "time_close"
50534
+ ]);
50535
+ function isSeriesExpr(value, env) {
50536
+ if (value.kind === "Name") {
50537
+ if (BARE_SERIES_NAMES2.has(value.id))
50538
+ return true;
50539
+ return seriesGet(env, value.id) != null;
50540
+ }
50541
+ return false;
50542
+ }
48884
50543
  function bindName(env, id, value) {
48885
50544
  const stored = typeof value === "number" && !Number.isFinite(value) ? NA : value;
48886
50545
  const frame = activeFrame(env);
@@ -49503,6 +51162,20 @@ var MATH_CONSTANTS = {
49503
51162
  "plot.linestyle_solid": "linestyle_solid",
49504
51163
  "plot.linestyle_dashed": "linestyle_dashed",
49505
51164
  "plot.linestyle_dotted": "linestyle_dotted",
51165
+ "plot.style_line": "style_line",
51166
+ "plot.style_linebr": "style_linebr",
51167
+ "plot.style_stepline": "style_stepline",
51168
+ "plot.style_steplinebr": "style_steplinebr",
51169
+ "plot.style_stepline_diamond": "style_stepline_diamond",
51170
+ "plot.style_histogram": "style_histogram",
51171
+ "plot.style_columns": "style_columns",
51172
+ "plot.style_cross": "style_cross",
51173
+ "plot.style_area": "style_area",
51174
+ "plot.style_areabr": "style_areabr",
51175
+ "plot.style_circles": "style_circles",
51176
+ "alert.freq_once_per_bar": "once_per_bar",
51177
+ "alert.freq_once_per_bar_close": "once_per_bar_close",
51178
+ "alert.freq_all": "all",
49506
51179
  "dayofweek.sunday": 1,
49507
51180
  "dayofweek.monday": 2,
49508
51181
  "dayofweek.tuesday": 3,
@@ -49893,6 +51566,9 @@ function evalCall(node, env) {
49893
51566
  if (isRequestBuiltin(fname) || fname === "request.security" || fname === "security" || fname === "security_lower_tf") {
49894
51567
  return evalRequestCall(fname, node, env);
49895
51568
  }
51569
+ const fpCall = evalFootprintCall(fname, node, env);
51570
+ if (fpCall !== undefined)
51571
+ return fpCall;
49896
51572
  const arrVal = evalArrayCall(fname, node, env);
49897
51573
  if (arrVal !== undefined)
49898
51574
  return arrVal;
@@ -50081,7 +51757,8 @@ function evalCall(node, env) {
50081
51757
  price: mark == null || !Number.isFinite(mark) ? undefined : mark,
50082
51758
  time: num2(env.ctx.time) ?? undefined,
50083
51759
  oca_name: evalAsString(callArg(node.args, -1, ["oca_name"]), env),
50084
- oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env)
51760
+ oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env),
51761
+ deferMarket: true
50085
51762
  });
50086
51763
  return NA;
50087
51764
  }
@@ -50090,13 +51767,10 @@ function evalCall(node, env) {
50090
51767
  const mark = num2(env.ctx.close);
50091
51768
  const qtyExpr = callArg(node.args, 1, ["qty"]);
50092
51769
  const qtyRaw = qtyExpr == null ? undefined : unwrap2(evalExpr(qtyExpr, env));
50093
- if (env.book.position.qty !== 0 && mark != null) {
50094
- env.book.fillClose(env.barIndex, id, mark, {
50095
- time: num2(env.ctx.time) ?? undefined,
50096
- qty: qtyRaw ?? undefined
50097
- });
50098
- } else
50099
- env.book.close(env.barIndex, id);
51770
+ env.book.placeClose(env.barIndex, id, mark ?? undefined, {
51771
+ time: num2(env.ctx.time) ?? undefined,
51772
+ qty: qtyRaw ?? undefined
51773
+ });
50100
51774
  return NA;
50101
51775
  }
50102
51776
  if (fname === "strategy.exit") {
@@ -50116,17 +51790,12 @@ function evalCall(node, env) {
50116
51790
  trail_offset: unwrap2(evalExpr(callArg(node.args, 10, ["trail_offset"]), env)),
50117
51791
  price: num2(env.ctx.close) ?? undefined,
50118
51792
  time: num2(env.ctx.time) ?? undefined,
50119
- ohlc: {
50120
- open: num2(env.ctx.open) ?? undefined,
50121
- high: num2(env.ctx.high) ?? undefined,
50122
- low: num2(env.ctx.low) ?? undefined,
50123
- close: num2(env.ctx.close) ?? undefined
50124
- }
51793
+ deferMarket: true
50125
51794
  });
50126
51795
  return NA;
50127
51796
  }
50128
51797
  if (fname === "strategy.close_all") {
50129
- env.book.closeAll(env.barIndex, num2(env.ctx.close) ?? undefined);
51798
+ env.book.placeCloseAll(env.barIndex, num2(env.ctx.close) ?? undefined);
50130
51799
  return NA;
50131
51800
  }
50132
51801
  if (fname === "strategy.cancel") {
@@ -50148,7 +51817,8 @@ function evalCall(node, env) {
50148
51817
  price: num2(env.ctx.close) ?? undefined,
50149
51818
  time: num2(env.ctx.time) ?? undefined,
50150
51819
  oca_name: evalAsString(callArg(node.args, -1, ["oca_name"]), env),
50151
- oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env)
51820
+ oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env),
51821
+ deferMarket: true
50152
51822
  });
50153
51823
  return NA;
50154
51824
  }
@@ -50498,15 +52168,57 @@ function packFills(book) {
50498
52168
  function packDrawings(book) {
50499
52169
  return book.items.length === 0 ? undefined : book.items;
50500
52170
  }
50501
- function fireAlertCondition(env, title, message) {
50502
- const key = `alertcondition|${title}|${message}|once_per_bar`;
52171
+ var FREQ_ONCE_PER_BAR = "once_per_bar";
52172
+ var FREQ_ONCE_PER_BAR_CLOSE = "once_per_bar_close";
52173
+ var FREQ_ALL = "all";
52174
+ var ALERT_FREQ_ALIASES = {
52175
+ once_per_bar: FREQ_ONCE_PER_BAR,
52176
+ freq_once_per_bar: FREQ_ONCE_PER_BAR,
52177
+ "alert.freq_once_per_bar": FREQ_ONCE_PER_BAR,
52178
+ once_per_bar_close: FREQ_ONCE_PER_BAR_CLOSE,
52179
+ freq_once_per_bar_close: FREQ_ONCE_PER_BAR_CLOSE,
52180
+ "alert.freq_once_per_bar_close": FREQ_ONCE_PER_BAR_CLOSE,
52181
+ all: FREQ_ALL,
52182
+ freq_all: FREQ_ALL,
52183
+ "alert.freq_all": FREQ_ALL
52184
+ };
52185
+ function normalizeAlertFreq(freq) {
52186
+ if (freq == null)
52187
+ return FREQ_ONCE_PER_BAR;
52188
+ if (typeof freq === "number" && !Number.isFinite(freq))
52189
+ return FREQ_ONCE_PER_BAR;
52190
+ const s = String(freq).trim().toLowerCase().replace(/ /g, "_");
52191
+ return ALERT_FREQ_ALIASES[s] ?? (s ? s : FREQ_ONCE_PER_BAR);
52192
+ }
52193
+ function barIsConfirmed(_env) {
52194
+ return true;
52195
+ }
52196
+ function shouldFireAlert(env, source, title, message, freq) {
52197
+ const freqN = normalizeAlertFreq(freq);
52198
+ if (freqN === FREQ_ALL)
52199
+ return true;
52200
+ if (freqN === FREQ_ONCE_PER_BAR_CLOSE && !barIsConfirmed(env))
52201
+ return false;
52202
+ const key = `${source}|${title}|${message}|${freqN}`;
50503
52203
  if (env.alertFireBars.get(key) === env.barIndex)
50504
- return;
52204
+ return false;
50505
52205
  env.alertFireBars.set(key, env.barIndex);
52206
+ return true;
52207
+ }
52208
+ function emitAlert(env, message, freq, opts) {
52209
+ const source = opts?.source ?? "alert";
52210
+ const title = opts?.title ?? "";
52211
+ const freqN = normalizeAlertFreq(freq);
52212
+ if (!shouldFireAlert(env, source, title, message, freqN))
52213
+ return;
50506
52214
  env.drawings.alert(env.barIndex, message);
50507
52215
  const ev = env.drawings.items[env.drawings.items.length - 1];
50508
- if (ev != null)
50509
- ev.extra = { source: "alertcondition", title, freq: "once_per_bar" };
52216
+ if (ev == null)
52217
+ return;
52218
+ ev.extra = title ? { source, title, freq: freqN } : { source, freq: freqN };
52219
+ }
52220
+ function fireAlertCondition(env, title, message) {
52221
+ emitAlert(env, message, FREQ_ONCE_PER_BAR, { title, source: "alertcondition" });
50510
52222
  }
50511
52223
  function inputTitle(node) {
50512
52224
  const named = namedStringArg(node.args, "title");
@@ -50828,9 +52540,75 @@ function evalRequestCall(fname, node, env) {
50828
52540
  const v = resolveRequest(fname, host, { seed });
50829
52541
  return typeof v === "number" || v === null ? v : NA;
50830
52542
  }
52543
+ if (fname === "request.footprint") {
52544
+ const numTicks = unwrap2(evalExpr(callArg(node.args, 0, ["num_ticks"]), env));
52545
+ const va = unwrap2(evalExpr(callArg(node.args, 1, ["va_percentage"]), env));
52546
+ const v = resolveRequest(fname, host, {
52547
+ num_ticks: numTicks ?? 100,
52548
+ va_percentage: va ?? 70
52549
+ });
52550
+ return v instanceof Footprint ? v : NA;
52551
+ }
50831
52552
  const v = resolveRequest(fname, host, {});
50832
52553
  return typeof v === "number" || v === null ? v : NA;
50833
52554
  }
52555
+ function evalFootprintCall(fname, node, env) {
52556
+ if (fname == null)
52557
+ return;
52558
+ if (fname.startsWith("footprint.")) {
52559
+ const fp = evalExpr(callArg(node.args, 0, ["id", "footprint"]), env);
52560
+ switch (fname) {
52561
+ case "footprint.buy_volume":
52562
+ return footprintBuyVolume(fp);
52563
+ case "footprint.sell_volume":
52564
+ return footprintSellVolume(fp);
52565
+ case "footprint.delta":
52566
+ return footprintDelta(fp);
52567
+ case "footprint.total_volume":
52568
+ return footprintTotalVolume(fp);
52569
+ case "footprint.vah":
52570
+ return footprintVah(fp);
52571
+ case "footprint.val":
52572
+ return footprintVal(fp);
52573
+ case "footprint.poc":
52574
+ return footprintPoc(fp);
52575
+ case "footprint.rows": {
52576
+ const arr = new PineArray;
52577
+ for (const row of footprintRows(fp))
52578
+ arr.push(row);
52579
+ return arr;
52580
+ }
52581
+ case "footprint.get_row_by_price":
52582
+ return footprintGetRowByPrice(fp, unwrap2(evalExpr(callArg(node.args, 1, ["price"]), env)));
52583
+ default:
52584
+ return;
52585
+ }
52586
+ }
52587
+ if (fname.startsWith("volume_row.")) {
52588
+ const vr = evalExpr(callArg(node.args, 0, ["id", "volume_row"]), env);
52589
+ switch (fname) {
52590
+ case "volume_row.up_price":
52591
+ return volumeRowUpPrice(vr);
52592
+ case "volume_row.down_price":
52593
+ return volumeRowDownPrice(vr);
52594
+ case "volume_row.buy_volume":
52595
+ return volumeRowBuyVolume(vr);
52596
+ case "volume_row.sell_volume":
52597
+ return volumeRowSellVolume(vr);
52598
+ case "volume_row.delta":
52599
+ return volumeRowDelta(vr);
52600
+ case "volume_row.total_volume":
52601
+ return volumeRowTotalVolume(vr);
52602
+ case "volume_row.has_buy_imbalance":
52603
+ return volumeRowHasBuyImbalance(vr);
52604
+ case "volume_row.has_sell_imbalance":
52605
+ return volumeRowHasSellImbalance(vr);
52606
+ default:
52607
+ return;
52608
+ }
52609
+ }
52610
+ return;
52611
+ }
50834
52612
  function evalMathCall(fname, node, env) {
50835
52613
  if (fname === "math.abs" || fname === "abs") {
50836
52614
  return mathAbs(cellArg(node, env, 0, ["number", "x"]));
@@ -51445,11 +53223,11 @@ function evalExtraTa(fname, node, env, site) {
51445
53223
  }
51446
53224
  if (fname === "ta.engulfing" || fname === "engulfing") {
51447
53225
  const msg = "ta.engulfing() requires 4 arguments: open, high, low, close";
51448
- unwrap2(evalExpr(wave10aArg(0, ["open"], msg), env));
53226
+ const open = unwrap2(evalExpr(wave10aArg(0, ["open"], msg), env));
51449
53227
  unwrap2(evalExpr(wave10aArg(1, ["high"], msg), env));
51450
53228
  unwrap2(evalExpr(wave10aArg(2, ["low"], msg), env));
51451
- unwrap2(evalExpr(wave10aArg(3, ["close"], msg), env));
51452
- return env.ta.engulfing();
53229
+ const close = unwrap2(evalExpr(wave10aArg(3, ["close"], msg), env));
53230
+ return env.ta.engulfing(site, open, close);
51453
53231
  }
51454
53232
  if (fname === "ta.gap_detector" || fname === "gap_detector") {
51455
53233
  const msg = "ta.gap_detector() requires 3 arguments: high, low, prev_close";
@@ -51457,15 +53235,15 @@ function evalExtraTa(fname, node, env, site) {
51457
53235
  }
51458
53236
  if (fname === "ta.double_top_bottom" || fname === "double_top_bottom") {
51459
53237
  const msg = "ta.double_top_bottom() requires 3 arguments";
51460
- unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
51461
- unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
51462
- return env.ta.doubleTopBottom(unwrap2(evalExpr(wave10aArg(2, ["period", "length"], msg), env)));
53238
+ const high = unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
53239
+ const low = unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
53240
+ return env.ta.doubleTopBottom(site, high, low, unwrap2(evalExpr(wave10aArg(2, ["period", "length"], msg), env)));
51463
53241
  }
51464
53242
  if (fname === "ta.inside_bar_pattern" || fname === "inside_bar_pattern") {
51465
53243
  const msg = "ta.inside_bar_pattern() requires 2 arguments";
51466
- unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
51467
- unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
51468
- return env.ta.insideBarPattern();
53244
+ const high = unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
53245
+ const low = unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
53246
+ return env.ta.insideBarPattern(site, high, low);
51469
53247
  }
51470
53248
  if (fname === "ta.macd_signal" || fname === "macd_signal") {
51471
53249
  const msg = "ta.macd_signal() requires 2 arguments: macd_line, signal_line";
@@ -51477,7 +53255,7 @@ function evalExtraTa(fname, node, env, site) {
51477
53255
  }
51478
53256
  if (fname === "ta.stoch_smooth" || fname === "stoch_smooth") {
51479
53257
  const msg = "ta.stoch_smooth() requires 6 arguments: high, low, close, period, smooth_k, smooth_d";
51480
- return env.ta.stochSmooth(unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env)), unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env)), unwrap2(evalExpr(wave10aArg(2, ["close"], msg), env)), unwrap2(evalExpr(wave10aArg(3, ["period", "length"], msg), env)), unwrap2(evalExpr(wave10aArg(4, ["smooth_k", "k"], msg), env)), unwrap2(evalExpr(wave10aArg(5, ["smooth_d", "d"], msg), env)));
53258
+ return env.ta.stochSmooth(site, unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env)), unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env)), unwrap2(evalExpr(wave10aArg(2, ["close"], msg), env)), unwrap2(evalExpr(wave10aArg(3, ["period", "length"], msg), env)), unwrap2(evalExpr(wave10aArg(4, ["smooth_k", "k"], msg), env)), unwrap2(evalExpr(wave10aArg(5, ["smooth_d", "d"], msg), env)));
51481
53259
  }
51482
53260
  const wave10bList = (index, names) => {
51483
53261
  const raw = evalExpr(callArg(node.args, index, names), env);
@@ -51502,7 +53280,7 @@ function evalExtraTa(fname, node, env, site) {
51502
53280
  }
51503
53281
  if (fname === "ta.rsi_divergence" || fname === "rsi_divergence") {
51504
53282
  const period = unwrap2(evalExpr(callArg(node.args, 1, ["period", "length"]), env));
51505
- return env.ta.rsiDivergence(wave10bList(0, ["rsi_series", "series", "source"]), period ?? 0);
53283
+ return env.ta.rsiDivergence(site, seriesLastCell(evalExpr(callArg(node.args, 0, ["rsi_series", "series", "source"]), env)), period ?? 0);
51506
53284
  }
51507
53285
  if (fname === "ta.cumulative_delta" || fname === "cumulative_delta") {
51508
53286
  const period = unwrap2(evalExpr(callArg(node.args, 2, ["period", "length"]), env));
@@ -51524,6 +53302,188 @@ function evalExtraTa(fname, node, env, site) {
51524
53302
  const sens = unwrap2(evalExpr(callArg(node.args, 3, ["sensitivity"]), env));
51525
53303
  return env.ta.volumeThrust(site, unwrap2(evalExpr(callArg(node.args, 0, ["close", "source"]), env)), unwrap2(evalExpr(callArg(node.args, 1, ["volume"]), env)), unwrap2(evalExpr(callArg(node.args, 2, ["volume_sma", "vol_sma", "sma"]), env)), sens ?? 0.3);
51526
53304
  }
53305
+ const wave11 = (index, names, message) => unwrap2(evalExpr(wave10aArg(index, names, message), env));
53306
+ const wave11n = (index, names, message) => num2(wave11(index, names, message));
53307
+ if (fname === "ta.sma_weighted" || fname === "sma_weighted") {
53308
+ const msg = "ta.sma_weighted() requires at least 2 arguments: series, period";
53309
+ const weightArg = callArg(node.args, 2, ["weight_type", "weight"]);
53310
+ return env.ta.smaWeighted(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["period", "length"], msg), weightArg == null ? "linear" : evalExpr(weightArg, env));
53311
+ }
53312
+ if (fname === "ta.apo" || fname === "apo") {
53313
+ const msg = "ta.apo() requires 3 arguments: series, fast_period, slow_period";
53314
+ return env.ta.apo(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["fast_period", "fast"], msg), wave11n(2, ["slow_period", "slow"], msg));
53315
+ }
53316
+ if (fname === "ta.atr_normalized" || fname === "atr_normalized") {
53317
+ const msg = "ta.atr_normalized() requires 4 arguments: high, low, close, period";
53318
+ return env.ta.atrNormalized(site, wave11n(0, ["high"], msg), wave11n(1, ["low"], msg), wave11n(2, ["close"], msg), wave11n(3, ["period", "length"], msg));
53319
+ }
53320
+ if (fname === "ta.beta" || fname === "beta") {
53321
+ const msg = "ta.beta() requires 3 arguments: series1, series2, length";
53322
+ return env.ta.beta(site, wave11n(0, ["series1", "series", "source"], msg), wave11n(1, ["series2", "series_b", "other"], msg), wave11n(2, ["length", "period"], msg));
53323
+ }
53324
+ if (fname === "ta.r_squared" || fname === "r_squared") {
53325
+ const msg = "ta.r_squared() requires 3 arguments: series1, series2, length";
53326
+ return env.ta.rSquared(site, wave11n(0, ["series1", "series", "source"], msg), wave11n(1, ["series2", "series_b", "other"], msg), wave11n(2, ["length", "period"], msg));
53327
+ }
53328
+ if (fname === "ta.comovement" || fname === "comovement") {
53329
+ const msg = "ta.comovement() requires 3 arguments: series1, series2, length";
53330
+ return env.ta.comovement(site, wave11n(0, ["series1", "series", "source"], msg), wave11n(1, ["series2", "series_b", "other"], msg), wave11n(2, ["length", "period"], msg));
53331
+ }
53332
+ if (fname === "ta.skewness" || fname === "skewness") {
53333
+ const msg = "ta.skewness() requires 2 arguments: series, period";
53334
+ return env.ta.skewness(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["period", "length"], msg));
53335
+ }
53336
+ if (fname === "ta.kurtosis" || fname === "kurtosis") {
53337
+ const msg = "ta.kurtosis() requires 2 arguments: series, period";
53338
+ return env.ta.kurtosis(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["period", "length"], msg));
53339
+ }
53340
+ if (fname === "ta.volume_weighted_momentum" || fname === "volume_weighted_momentum") {
53341
+ const msg = "ta.volume_weighted_momentum() requires 3 arguments: series, volume, length";
53342
+ return env.ta.volumeWeightedMomentum(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["volume"], msg), wave11n(2, ["length", "period"], msg));
53343
+ }
53344
+ if (fname === "ta.parkinson" || fname === "parkinson") {
53345
+ const msg = "ta.parkinson() requires 2 arguments: high, low";
53346
+ const highArg = wave10aArg(0, ["high"], msg);
53347
+ const lowArg = wave10aArg(1, ["low"], msg);
53348
+ if (isSeriesExpr(highArg, env) || isSeriesExpr(lowArg, env))
53349
+ return NA;
53350
+ return env.ta.parkinson(num2(evalExpr(highArg, env)), num2(evalExpr(lowArg, env)));
53351
+ }
53352
+ if (fname === "ta.garman_klass" || fname === "garman_klass") {
53353
+ const msg = "ta.garman_klass() requires 4 arguments: high, low, close, open";
53354
+ const argsExpr = [
53355
+ wave10aArg(0, ["high"], msg),
53356
+ wave10aArg(1, ["low"], msg),
53357
+ wave10aArg(2, ["close"], msg),
53358
+ wave10aArg(3, ["open"], msg)
53359
+ ];
53360
+ if (argsExpr.some((a) => isSeriesExpr(a, env)))
53361
+ return NA;
53362
+ return env.ta.garmanKlass(num2(evalExpr(argsExpr[0], env)), num2(evalExpr(argsExpr[1], env)), num2(evalExpr(argsExpr[2], env)), num2(evalExpr(argsExpr[3], env)));
53363
+ }
53364
+ if (fname === "ta.mean_reversion_score" || fname === "mean_reversion_score") {
53365
+ const msg = "ta.mean_reversion_score() requires 4 arguments";
53366
+ return env.ta.meanReversionScore(site, wave11n(0, ["close", "source"], msg), wave11n(1, ["sma"], msg), wave11n(2, ["stdev", "std_dev"], msg), wave11n(3, ["period", "length"], msg));
53367
+ }
53368
+ if (fname === "ta.market_condition" || fname === "market_condition") {
53369
+ const msg = "ta.market_condition() requires 4 arguments";
53370
+ return env.ta.marketCondition(site, wave11n(0, ["close", "source"], msg), wave11n(1, ["atr"], msg), wave11n(2, ["sma_period", "sma_length"], msg), wave11n(3, ["stdev_period", "stdev_length"], msg));
53371
+ }
53372
+ if (fname === "ta.order_flow_imbalance" || fname === "order_flow_imbalance") {
53373
+ const msg = "ta.order_flow_imbalance() requires 5 arguments";
53374
+ return env.ta.orderFlowImbalance(site, wave11n(0, ["high"], msg), wave11n(1, ["low"], msg), wave11n(2, ["close"], msg), wave11n(3, ["volume"], msg), wave11n(4, ["period", "length"], msg));
53375
+ }
53376
+ if (fname === "ta.liquidity_score" || fname === "liquidity_score") {
53377
+ const msg = "ta.liquidity_score() requires 4 arguments";
53378
+ return env.ta.liquidityScore(site, wave11n(0, ["volume"], msg), wave11n(1, ["volatility"], msg), wave11n(2, ["spread"], msg), wave11n(3, ["period", "length"], msg));
53379
+ }
53380
+ if (fname === "ta.fear_greed_index" || fname === "fear_greed_index") {
53381
+ const msg = "ta.fear_greed_index() requires 4 arguments";
53382
+ return env.ta.fearGreedIndex(wave11n(0, ["rsi"], msg), wave11n(1, ["vix"], msg), wave11n(2, ["put_call", "put_call_ratio"], msg), wave11n(3, ["breadth"], msg));
53383
+ }
53384
+ if (fname === "ta.crowd_sentiment" || fname === "crowd_sentiment") {
53385
+ const msg = "ta.crowd_sentiment() requires 3 arguments";
53386
+ return env.ta.crowdSentiment(wave11n(0, ["price_agreement", "price"], msg), wave11n(1, ["volume_agreement", "volume"], msg), wave11n(2, ["time_agreement", "time"], msg));
53387
+ }
53388
+ if (fname === "ta.smart_money_flow" || fname === "smart_money_flow") {
53389
+ const msg = "ta.smart_money_flow() requires 4 arguments";
53390
+ return env.ta.smartMoneyFlow(wave11n(0, ["price_change"], msg), wave11n(1, ["volume"], msg), wave11n(2, ["time_since_high", "time_high"], msg), wave11n(3, ["time_since_low", "time_low"], msg));
53391
+ }
53392
+ if (fname === "ta.trend_confirmation_score" || fname === "trend_confirmation_score") {
53393
+ const msg = "ta.trend_confirmation_score() requires 6 arguments";
53394
+ wave11n(5, ["support_distance"], msg);
53395
+ return env.ta.trendConfirmationScore(wave11n(0, ["momentum"], msg), wave11n(1, ["trend_alignment"], msg), wave11n(2, ["strength"], msg), wave11n(3, ["rsi"], msg), wave11n(4, ["rsi_alignment"], msg));
53396
+ }
53397
+ if (fname === "ta.max_loss_level" || fname === "max_loss_level") {
53398
+ const msg = "ta.max_loss_level() requires 3 arguments";
53399
+ return env.ta.maxLossLevel(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["account", "account_size"], msg), wave11n(2, ["max_loss_pct", "max_loss_percent"], msg));
53400
+ }
53401
+ if (fname === "ta.profit_lock_level" || fname === "profit_lock_level") {
53402
+ const msg = "ta.profit_lock_level() requires 4 arguments";
53403
+ return env.ta.profitLockLevel(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["current", "current_price"], msg), wave11n(2, ["trail_pct", "trail_percent"], msg), wave11n(3, ["direction"], msg));
53404
+ }
53405
+ const wave12s = (index, names, message) => evalExpr(wave10aArg(index, names, message), env);
53406
+ if (fname === "ta.position_sizing" || fname === "position_sizing") {
53407
+ const msg = "ta.position_sizing() requires 4 arguments";
53408
+ return env.ta.positionSizing(wave11n(0, ["account", "account_size"], msg), wave11n(1, ["risk_pct", "risk_percent"], msg), wave11n(2, ["entry", "entry_price"], msg), wave11n(3, ["stop", "stop_price"], msg));
53409
+ }
53410
+ if (fname === "ta.kelly_criterion" || fname === "kelly_criterion") {
53411
+ const msg = "ta.kelly_criterion() requires 3 arguments";
53412
+ return env.ta.kellyCriterion(wave11n(0, ["win_rate"], msg), wave11n(1, ["avg_win"], msg), wave11n(2, ["avg_loss"], msg));
53413
+ }
53414
+ if (fname === "ta.risk_reward_ratio" || fname === "risk_reward_ratio") {
53415
+ const msg = "ta.risk_reward_ratio() requires 3 arguments";
53416
+ return env.ta.riskRewardRatio(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["stop", "stop_price"], msg), wave11n(2, ["target", "target_price"], msg));
53417
+ }
53418
+ if (fname === "ta.risk_reward_asymmetry" || fname === "risk_reward_asymmetry") {
53419
+ const msg = "ta.risk_reward_asymmetry() requires 4 arguments";
53420
+ return env.ta.riskRewardAsymmetry(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["stop", "stop_price"], msg), wave11n(2, ["target", "target_price"], msg), wave11n(3, ["win_rate"], msg));
53421
+ }
53422
+ if (fname === "ta.probability_of_movement" || fname === "probability_of_movement") {
53423
+ const msg = "ta.probability_of_movement() requires 4 arguments";
53424
+ return env.ta.probabilityOfMovement(wave11n(0, ["current", "current_price"], msg), wave11n(1, ["target", "target_price"], msg), wave11n(2, ["atr"], msg), wave11n(3, ["period", "length"], msg));
53425
+ }
53426
+ if (fname === "ta.trend_strength" || fname === "trend_strength") {
53427
+ const msg = "ta.trend_strength() requires 3 arguments";
53428
+ return env.ta.trendStrength(wave11n(0, ["price", "source"], msg), wave11n(1, ["adx"], msg), wave11n(2, ["rsi"], msg));
53429
+ }
53430
+ if (fname === "ta.breakeven_level" || fname === "breakeven_level") {
53431
+ const msg = "ta.breakeven_level() requires 5 arguments";
53432
+ return env.ta.breakevenLevel(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["quantity", "qty"], msg), wave11n(2, ["commission"], msg), wave11n(3, ["slippage"], msg), wave11n(4, ["direction"], msg));
53433
+ }
53434
+ if (fname === "ta.market_structure_pivot" || fname === "market_structure_pivot") {
53435
+ const msg = "ta.market_structure_pivot() requires 5 arguments";
53436
+ wave11n(0, ["high"], msg);
53437
+ wave11n(1, ["low"], msg);
53438
+ const close = wave11n(2, ["close"], msg);
53439
+ wave11n(3, ["left", "left_bars"], msg);
53440
+ wave11n(4, ["right", "right_bars"], msg);
53441
+ return env.ta.marketStructurePivot(close);
53442
+ }
53443
+ if (fname === "ta.position_sizing_score" || fname === "position_sizing_score") {
53444
+ const msg = "ta.position_sizing_score() requires 4 arguments";
53445
+ return env.ta.positionSizingScore(wave11n(0, ["account_risk", "risk"], msg), wave11n(1, ["volatility"], msg), wave11n(2, ["conviction"], msg), wave11n(3, ["correlation"], msg));
53446
+ }
53447
+ if (fname === "ta.trailing_exit_level" || fname === "trailing_exit_level") {
53448
+ const msg = "ta.trailing_exit_level() requires 5 arguments";
53449
+ return env.ta.trailingExitLevel(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["current", "current_price"], msg), wave11n(2, ["atr"], msg), wave11n(3, ["multiplier", "mult"], msg), wave11n(4, ["step"], msg));
53450
+ }
53451
+ if (fname === "ta.optimal_entry_zone" || fname === "optimal_entry_zone") {
53452
+ const msg = "ta.optimal_entry_zone() requires 4 arguments";
53453
+ wave11n(0, ["high"], msg);
53454
+ wave11n(1, ["low"], msg);
53455
+ const close = wave11n(2, ["close"], msg);
53456
+ wave11n(3, ["period", "length"], msg);
53457
+ return env.ta.optimalEntryZone(close);
53458
+ }
53459
+ if (fname === "ta.mean_reversion_entry" || fname === "mean_reversion_entry") {
53460
+ const msg = "ta.mean_reversion_entry() requires 5 arguments";
53461
+ return env.ta.meanReversionEntry(wave11n(0, ["price", "source"], msg), wave11n(1, ["sma"], msg), wave11n(2, ["stdev", "std_dev"], msg), wave11n(4, ["threshold"], msg));
53462
+ }
53463
+ if (fname === "ta.multi_timeframe_signal" || fname === "multi_timeframe_signal") {
53464
+ const msg = "ta.multi_timeframe_signal() requires 6 arguments";
53465
+ return env.ta.multiTimeframeSignal(wave11n(0, ["s1", "signal1"], msg), wave11n(1, ["s2", "signal2"], msg), wave11n(2, ["s3", "signal3"], msg), wave11n(3, ["w1", "weight1"], msg), wave11n(4, ["w2", "weight2"], msg), wave11n(5, ["w3", "weight3"], msg));
53466
+ }
53467
+ if (fname === "ta.market_timing_index" || fname === "market_timing_index") {
53468
+ const msg = "ta.market_timing_index() requires 4 arguments";
53469
+ return env.ta.marketTimingIndex(wave11n(0, ["trend"], msg), wave11n(1, ["momentum"], msg), wave11n(2, ["volatility"], msg), wave11n(3, ["sentiment"], msg));
53470
+ }
53471
+ if (fname === "ta.regime_adaptive_signal" || fname === "regime_adaptive_signal") {
53472
+ const msg = "ta.regime_adaptive_signal() requires 4 arguments";
53473
+ const strength = wave11n(0, ["signal_strength", "strength"], msg);
53474
+ const volRegime = wave12s(1, ["volatility_regime", "vol_regime"], msg);
53475
+ const trendRegime = wave12s(2, ["trend_regime"], msg);
53476
+ wave11n(3, ["period", "length"], msg);
53477
+ return env.ta.regimeAdaptiveSignal(strength, volRegime, trendRegime);
53478
+ }
53479
+ if (fname === "ta.strategy_score" || fname === "strategy_score") {
53480
+ const msg = "ta.strategy_score() requires 4 arguments";
53481
+ return env.ta.strategyScore(wave11n(0, ["rsi"], msg), wave11n(1, ["macd"], msg), wave11n(2, ["ema_cross"], msg), wave11n(3, ["trend"], msg));
53482
+ }
53483
+ if (fname === "ta.breakout_detection" || fname === "breakout_detection") {
53484
+ const msg = "ta.breakout_detection() requires 3 arguments";
53485
+ return env.ta.breakoutDetection(wave11n(0, ["close", "source"], msg), wave11n(1, ["resistance"], msg), wave11n(2, ["support"], msg));
53486
+ }
51527
53487
  return;
51528
53488
  }
51529
53489
  function hlc3(env) {
@@ -51534,6 +53494,14 @@ function hlc3(env) {
51534
53494
  return c ?? h ?? l;
51535
53495
  return (h + l + c) / 3;
51536
53496
  }
53497
+ function seriesLastCell(value) {
53498
+ if (value instanceof PineArray) {
53499
+ const n = value.size();
53500
+ return n > 0 ? value.get(n - 1) : null;
53501
+ }
53502
+ const v = unwrap2(value);
53503
+ return typeof v === "number" && Number.isFinite(v) ? v : null;
53504
+ }
51537
53505
  function asArray2(value) {
51538
53506
  if (value instanceof PineArray)
51539
53507
  return value;
@@ -52415,8 +54383,16 @@ function evalDrawingCall(fname, node, env) {
52415
54383
  return book.boxNew(env.barIndex, extra);
52416
54384
  }
52417
54385
  if (fname === "alert") {
54386
+ if (asArgs2(node.args).length === 0)
54387
+ return NA;
52418
54388
  const msg = evalAlertMessage(callArg(node.args, 0, ["message"]), env);
52419
- book.alert(env.barIndex, msg);
54389
+ const freqExpr = callArg(node.args, 1, ["freq"]);
54390
+ let freq = null;
54391
+ if (freqExpr != null) {
54392
+ const v = evalExpr(freqExpr, env);
54393
+ freq = typeof v === "string" ? v : unwrap2(v);
54394
+ }
54395
+ emitAlert(env, msg, freq, { source: "alert" });
52420
54396
  return NA;
52421
54397
  }
52422
54398
  if (fname === "table.new") {
@@ -52424,8 +54400,22 @@ function evalDrawingCall(fname, node, env) {
52424
54400
  const position = drawRaw(node, env, 0, ["position"]);
52425
54401
  if (position !== undefined)
52426
54402
  extra.position = position;
52427
- putFinite(extra, "rows", drawNum(node, env, 1, ["rows"]));
52428
- putFinite(extra, "columns", drawNum(node, env, 2, ["columns"]));
54403
+ putFinite(extra, "columns", drawNum(node, env, 1, ["columns"]));
54404
+ putFinite(extra, "rows", drawNum(node, env, 2, ["rows"]));
54405
+ const bgcolor = drawRaw(node, env, 3, ["bgcolor"]);
54406
+ if (bgcolor !== undefined)
54407
+ extra.bgcolor = bgcolor;
54408
+ const frameColor = drawRaw(node, env, 4, ["frame_color"]);
54409
+ if (frameColor !== undefined)
54410
+ extra.frame_color = frameColor;
54411
+ putFinite(extra, "frame_width", drawNum(node, env, 5, ["frame_width"]));
54412
+ const borderColor = drawRaw(node, env, 6, ["border_color"]);
54413
+ if (borderColor !== undefined)
54414
+ extra.border_color = borderColor;
54415
+ putFinite(extra, "border_width", drawNum(node, env, 7, ["border_width"]));
54416
+ const forceOverlay = drawRaw(node, env, 8, ["force_overlay"]);
54417
+ if (forceOverlay !== undefined)
54418
+ extra.force_overlay = forceOverlay;
52429
54419
  return book.tableNew(env.barIndex, extra);
52430
54420
  }
52431
54421
  if (fname === "polyline.new") {
@@ -53472,8 +55462,8 @@ function syminfoPrefix2(node, env) {
53472
55462
  function calendarMs(node, env) {
53473
55463
  const arg = callArg(node.args, 0, ["time", "timestamp"]);
53474
55464
  if (arg == null)
53475
- return num2(env.ctx.time);
53476
- return unwrap2(evalExpr(arg, env));
55465
+ return timestampToMs(num2(env.ctx.time));
55466
+ return timestampToMs(unwrap2(evalExpr(arg, env)));
53477
55467
  }
53478
55468
  function evalLibraryMemberCall(mod, attr, node, env) {
53479
55469
  const exp = mod.get(attr);