@hoox-sh/pynets 0.5.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
  }
@@ -36320,6 +36328,13 @@ function mathRandom(a, b, rng = Math.random) {
36320
36328
  // src/runtime/time.ts
36321
36329
  var MIN_T = -62167219200;
36322
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
+ }
36323
36338
  function utcPartsFromMs(ms) {
36324
36339
  let t = Number.isFinite(ms) ? Math.trunc(ms / 1000) : 0;
36325
36340
  if (t < MIN_T)
@@ -37176,8 +37191,7 @@ function coerceFormatTimeMs(time) {
37176
37191
  if (typeof raw !== "number" || !Number.isFinite(raw))
37177
37192
  return null;
37178
37193
  let ts = Math.trunc(raw);
37179
- if (ts > 0 && ts < 10000000000)
37180
- ts *= 1000;
37194
+ ts = timestampToMs(ts) ?? ts;
37181
37195
  return ts;
37182
37196
  }
37183
37197
  function formatOffsetHours(offsetHours) {
@@ -37930,6 +37944,48 @@ class StrategyBook {
37930
37944
  bar: isFiniteNumber2(bar) ? bar : 0
37931
37945
  });
37932
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
+ }
37933
37989
  exit(bar, id, qty) {
37934
37990
  const event = {
37935
37991
  type: "exit",
@@ -37967,10 +38023,46 @@ class StrategyBook {
37967
38023
  placeEntry(bar, id, direction, qty, opts) {
37968
38024
  const limit = optLevel(opts?.limit);
37969
38025
  const stop = optLevel(opts?.stop);
38026
+ const b = isFiniteNumber2(bar) ? bar : 0;
38027
+ const oid = String(id ?? "");
37970
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
+ }
37971
38063
  if (isFiniteNumber2(opts?.price)) {
37972
38064
  const dir = mapDirection(direction);
37973
- const t = isFiniteNumber2(opts?.time) ? opts.time : bar;
38065
+ const t = isFiniteNumber2(opts?.time) ? opts.time : b;
37974
38066
  this.updateEquityExtremes(opts.price);
37975
38067
  if (!this.riskAllowsEntry(dir, t))
37976
38068
  return;
@@ -37981,8 +38073,6 @@ class StrategyBook {
37981
38073
  }
37982
38074
  const dir = mapDirection(direction);
37983
38075
  const absQty = isFiniteNumber2(qty) ? Math.abs(qty) : Number.NaN;
37984
- const b = isFiniteNumber2(bar) ? bar : 0;
37985
- const oid = String(id ?? "");
37986
38076
  this.entry(b, oid, dir, isFiniteNumber2(absQty) ? absQty : qty);
37987
38077
  if (!isFiniteNumber2(absQty) || absQty === 0)
37988
38078
  return;
@@ -38032,6 +38122,23 @@ class StrategyBook {
38032
38122
  return;
38033
38123
  const t = isFiniteNumber2(opts?.time) ? opts.time : b;
38034
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
+ }
38035
38142
  if (!isFiniteNumber2(opts?.price))
38036
38143
  return;
38037
38144
  this.reducePosition(b, oid, opts.price, qty, fromEntry, t, opts?.comment);
@@ -38102,13 +38209,24 @@ class StrategyBook {
38102
38209
  for (const order of this.pending.slice()) {
38103
38210
  if (!this.pending.some((p) => p.id === order.id))
38104
38211
  continue;
38212
+ if (order.bar === b)
38213
+ continue;
38105
38214
  if (order.kind === "exit" && isTrailOrder(order))
38106
38215
  updateTrailStop(order, high, low);
38107
- 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);
38108
38221
  if (px == null)
38109
38222
  continue;
38110
38223
  this.dropPending(order.id);
38111
- 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
+ });
38112
38230
  if (applied) {
38113
38231
  const q = Math.abs(this.fills.at(-1)?.qty ?? order.qty);
38114
38232
  this.ocaAfterFill(order, q, b);
@@ -38124,6 +38242,22 @@ class StrategyBook {
38124
38242
  }
38125
38243
  return filled;
38126
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
+ }
38127
38261
  fillEntry(bar, id, direction, qty, price, opts) {
38128
38262
  this.applyEntryFill(bar, id, direction, qty, price, true, opts);
38129
38263
  }
@@ -38246,9 +38380,9 @@ class StrategyBook {
38246
38380
  return { status: "invalid", qty: 0 };
38247
38381
  return { status: "ok", qty: Math.min(rawQty, target) };
38248
38382
  }
38249
- applyExitFill(bar, order, price) {
38383
+ applyExitFill(bar, order, price, time) {
38250
38384
  const t = isFiniteNumber2(bar) ? bar : 0;
38251
- 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);
38252
38386
  }
38253
38387
  closeLeg(ot, bar, exitPrice, qty, profit, commission, exitTime, exitComment) {
38254
38388
  const closed = {
@@ -40255,6 +40389,37 @@ function pushCap(window2, value, cap) {
40255
40389
  function finiteOut2(value) {
40256
40390
  return Number.isFinite(value) ? value : null;
40257
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
+ }
40258
40423
  var PERIOD_INT_EPS = 0.000000001;
40259
40424
  function pinePeriod(period) {
40260
40425
  if (!Number.isFinite(period) || period <= 0)
@@ -40353,6 +40518,22 @@ class TaEngine {
40353
40518
  emvSites = new Map;
40354
40519
  fractalSites = new Map;
40355
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;
40356
40537
  sma(site, source, period) {
40357
40538
  const n = pinePeriod(period);
40358
40539
  if (n === null)
@@ -40427,18 +40608,24 @@ class TaEngine {
40427
40608
  st = {
40428
40609
  period: n,
40429
40610
  prevClose: null,
40611
+ started: false,
40430
40612
  rma: { period: n, rma: null, seeded: false, started: false, seedBuf: [] }
40431
40613
  };
40432
40614
  this.atrSites.set(site, st);
40433
40615
  }
40434
- const prev = st.prevClose;
40435
- st.prevClose = finiteCell2(close);
40436
- if (prev === null)
40437
- return null;
40438
40616
  const h = finiteCell2(high);
40439
40617
  const l = finiteCell2(low);
40440
40618
  const c = finiteCell2(close);
40441
- 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)
40442
40629
  return null;
40443
40630
  const tr = Math.max(h - l, Math.abs(h - prev), Math.abs(l - prev));
40444
40631
  return rmaStep(st.rma, tr, n);
@@ -40604,7 +40791,7 @@ class TaEngine {
40604
40791
  }
40605
40792
  if (st.window.length < n || st.count !== n)
40606
40793
  return null;
40607
- let v = (st.sumsq - st.sum * st.sum / n) / (n - 1);
40794
+ let v = (st.sumsq - st.sum * st.sum / n) / n;
40608
40795
  if (v < 0)
40609
40796
  v = 0;
40610
40797
  return Math.sqrt(v);
@@ -41810,7 +41997,7 @@ class TaEngine {
41810
41997
  }
41811
41998
  if (st.window.length < n || st.count !== n)
41812
41999
  return null;
41813
- let v = (st.sumsq - st.sum * st.sum / n) / (n - 1);
42000
+ let v = (st.sumsq - st.sum * st.sum / n) / n;
41814
42001
  if (v < 0)
41815
42002
  v = 0;
41816
42003
  return v;
@@ -42414,20 +42601,17 @@ class TaEngine {
42414
42601
  st = { samples: [] };
42415
42602
  this.zigzagSites.set(site, st);
42416
42603
  }
42417
- pushCap(st.samples, finiteCell2(source), 1000);
42418
- const finite = [];
42419
- for (const v of st.samples) {
42420
- if (v !== null)
42421
- finite.push(v);
42422
- }
42423
- 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)
42424
42608
  return { high: null, low: null, dir: 0 };
42425
- const oldest = finite[0];
42426
- const second = finite[1];
42427
- const recentHigh = Math.max(oldest, second);
42428
- 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);
42429
42613
  const pct = recentLow !== 0 ? (recentHigh - recentLow) / recentLow * 100 : 0;
42430
- const direction = recentHigh === oldest ? 1 : -1;
42614
+ const direction = recentHigh === newest ? 1 : -1;
42431
42615
  return { high: recentHigh, low: recentLow, dir: pct > th ? 1 : direction };
42432
42616
  }
42433
42617
  accelSites = new Map;
@@ -42494,30 +42678,31 @@ class TaEngine {
42494
42678
  }
42495
42679
  accelerationFactor(site, source, period) {
42496
42680
  const p = this.coerceTaInt(period, "ta.acceleration_factor() requires 2 arguments");
42497
- 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);
42498
42685
  if (samples === undefined) {
42499
42686
  samples = [];
42500
- this.accelSites.set(site, samples);
42687
+ this.accelSites.set(key, samples);
42501
42688
  }
42502
- pushCap(samples, finiteCell2(source), 1000);
42503
- if (samples.length < p + 1 || p <= 0)
42689
+ pushCap(samples, finiteCell2(source), p + 1);
42690
+ if (samples.length < p + 1)
42504
42691
  return 0;
42505
- const oldest = samples.slice(0, p + 1);
42506
- const newestFirst = [];
42507
- for (let i = oldest.length - 1;i >= 0; i--) {
42508
- const v = oldest[i];
42692
+ const clean = [];
42693
+ for (const v of samples) {
42509
42694
  if (v !== null)
42510
- newestFirst.push(v);
42695
+ clean.push(v);
42511
42696
  }
42512
- if (newestFirst.length < 2)
42697
+ if (clean.length < 2)
42513
42698
  return 0;
42514
42699
  let oldSum = 0;
42515
- for (let i = 0;i < newestFirst.length - 1; i++)
42516
- oldSum += newestFirst[i];
42517
- 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];
42518
42704
  if (Math.abs(oldMom) < 0.0000000001)
42519
42705
  return 0;
42520
- const newMom = newestFirst[newestFirst.length - 1];
42521
42706
  let acc = (newMom - oldMom) / oldMom;
42522
42707
  if (acc < -2)
42523
42708
  acc = -2;
@@ -42525,32 +42710,141 @@ class TaEngine {
42525
42710
  acc = 2;
42526
42711
  return finiteOut2(acc);
42527
42712
  }
42528
- stochSmooth(high, low, close, period, smoothK, smoothD) {
42713
+ stochSmooth(site, high, low, close, period, smoothK, smoothD) {
42529
42714
  const p = this.coerceTaInt(period, "ta.stoch_smooth period must be integer");
42530
42715
  const k = this.coerceTaInt(smoothK, "ta.stoch_smooth smooth_k must be integer");
42531
42716
  const d = this.coerceTaInt(smoothD, "ta.stoch_smooth smooth_d must be integer");
42532
- if (p <= 0)
42533
- throw new Error("max() iterable argument is empty");
42534
- if (high === null || low === null || close === null) {
42535
- throw new Error("unsupported operand type(s) for /: 'float' and 'NoneType'");
42536
- }
42537
- if (k !== 1 || d !== 1)
42717
+ if (p < 1 || k < 1 || d < 1)
42538
42718
  return null;
42539
- const span = high - low;
42540
- const stoch = span !== 0 ? 100 * (close - low) / span : 50;
42541
- return finiteOut2(stoch);
42542
- }
42543
- engulfing() {
42544
- return taRec({ is_bullish: false, is_bearish: false, pattern_strength: 0 });
42545
- }
42546
- insideBarPattern() {
42547
- 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
+ });
42548
42777
  }
42549
- doubleTopBottom(period) {
42550
- if (period === null || !Number.isFinite(period)) {
42551
- 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;
42552
42793
  }
42553
- return taRec({ pattern_type: "none", strength: 0, breakout_level: 0 });
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;
42842
+ }
42843
+ return taRec({
42844
+ pattern_type: "double_top",
42845
+ strength: finiteOut2(strength) ?? 0,
42846
+ breakout_level: finiteOut2(minLow - avgPeak * 0.1) ?? 0
42847
+ });
42554
42848
  }
42555
42849
  cumDeltaSites = new Map;
42556
42850
  volMomSites = new Map;
@@ -42603,96 +42897,91 @@ class TaEngine {
42603
42897
  }
42604
42898
  return taRec({ is_oversold: rsi < os, is_overbought: rsi > ob, rsi });
42605
42899
  }
42606
- rsiDivergence(series, period) {
42900
+ rsiDivergence(site, value, period) {
42607
42901
  const p = this.asCount(period);
42608
- if (p === null || series.length === 0)
42609
- return null;
42610
- let last = 0;
42611
- for (let i = 0;i < series.length; i++) {
42612
- if (i < p) {
42613
- last = 0;
42614
- continue;
42615
- }
42616
- const start = Math.max(0, i - p);
42617
- const vals = [];
42618
- for (let j = start;j <= i; j++) {
42619
- const v = series[j];
42620
- if (v !== null && Number.isFinite(v))
42621
- vals.push(v);
42622
- }
42623
- if (vals.length < 2) {
42624
- last = 0;
42625
- continue;
42626
- }
42627
- let rsiMin = vals[0];
42628
- let rsiMax = vals[0];
42629
- for (const v of vals) {
42630
- if (v < rsiMin)
42631
- rsiMin = v;
42632
- if (v > rsiMax)
42633
- rsiMax = v;
42634
- }
42635
- const cur = series[i];
42636
- const range = rsiMax - rsiMin;
42637
- if (cur === null || !Number.isFinite(cur) || range <= 0) {
42638
- last = 0;
42639
- continue;
42640
- }
42641
- 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;
42642
42928
  }
42643
- return finiteOut2(last);
42929
+ const range = hi - lo;
42930
+ return range > 0 ? finiteOut2((x - lo) / range * 2 - 1) : 0;
42644
42931
  }
42645
42932
  cumulativeDelta(site, close, volume, period) {
42646
42933
  const n = this.asCount(period);
42647
- let st = this.cumDeltaSites.get(site);
42934
+ if (n === null || n <= 0)
42935
+ return 0;
42936
+ let st = this.cumDeltaSites.get(`${site}:${n}`);
42648
42937
  if (st === undefined) {
42649
- st = { close: [], volume: [] };
42650
- this.cumDeltaSites.set(site, st);
42938
+ st = { closes: [], volumes: [], count: 0 };
42939
+ this.cumDeltaSites.set(`${site}:${n}`, st);
42651
42940
  }
42652
- this.pushChrono(st.close, close);
42653
- this.pushChrono(st.volume, volume);
42654
- 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)
42655
42947
  return 0;
42656
42948
  let delta = 0;
42657
- for (let i = -n;i < 0; i++) {
42658
- const cRaw = this.nf(st.close, i);
42659
- const vRaw = this.nf(st.volume, i);
42660
- const c = cRaw !== null && Number.isFinite(cRaw) ? cRaw : 0;
42661
- const v = vRaw !== null && Number.isFinite(vRaw) ? vRaw : 0;
42662
- if (i > -n) {
42663
- const prevRaw = this.nf(st.close, i - 1);
42664
- const prev = prevRaw !== null && Number.isFinite(prevRaw) ? prevRaw : c;
42665
- if (c > prev)
42666
- delta += v;
42667
- else if (c < prev)
42668
- delta -= v;
42669
- }
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;
42670
42961
  }
42671
42962
  return finiteOut2(delta);
42672
42963
  }
42673
42964
  volumeMomentum(site, volume, period) {
42674
42965
  const n = this.asCount(period);
42675
- let st = this.volMomSites.get(site);
42676
- if (st === undefined) {
42677
- st = { volume: [] };
42678
- this.volMomSites.set(site, st);
42679
- }
42680
- this.pushChrono(st.volume, volume);
42681
- if (n === null || n <= 0 || st.volume.length < n + 1)
42966
+ if (n === null || n <= 0)
42682
42967
  return 0;
42683
- const clean = [];
42684
- for (let i = 0;i < n + 1; i++) {
42685
- const v = st.volume[i];
42686
- if (v !== null && Number.isFinite(v))
42687
- 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);
42688
42972
  }
42689
- 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)
42690
42976
  return 0;
42691
- const newVol = clean[0];
42692
- let sum = 0;
42693
- for (let i = 1;i < clean.length; i++)
42694
- sum += clean[i];
42695
- 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;
42696
42985
  if (oldVol === 0)
42697
42986
  return 0;
42698
42987
  let momentum = (newVol - oldVol) / oldVol * 100;
@@ -42702,6 +42991,667 @@ class TaEngine {
42702
42991
  momentum = -100;
42703
42992
  return finiteOut2(momentum);
42704
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
+ }
42705
43655
  volumeProfileHigh(prices, volumes) {
42706
43656
  if (prices.length === 0 || volumes.length === 0 || prices.length !== volumes.length)
42707
43657
  return 0;
@@ -42774,19 +43724,27 @@ class TaEngine {
42774
43724
  const sens = Number.isFinite(sensitivity) ? sensitivity : 0.3;
42775
43725
  let st = this.volThrustSites.get(site);
42776
43726
  if (st === undefined) {
42777
- st = { close: [], volume: [], sma: [] };
43727
+ st = { closes: [], volume: null, sma: null, nClose: 0, nVolume: 0, nSma: 0 };
42778
43728
  this.volThrustSites.set(site, st);
42779
43729
  }
42780
- this.pushChrono(st.close, close);
42781
- this.pushChrono(st.volume, volume);
42782
- this.pushChrono(st.sma, volSma);
42783
- 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)
42784
43743
  return 0;
42785
- const numOr = (v, fallback) => v !== null && Number.isFinite(v) ? v : fallback;
42786
- const cVal = numOr(this.nf(st.close, -1), 100);
42787
- const cPrev = st.close.length > 1 ? numOr(this.nf(st.close, -2), 100) : 100;
42788
- const vVal = numOr(this.nf(st.volume, -1), 1000);
42789
- 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;
42790
43748
  const spike = vVal > vsVal * (1 + sens);
42791
43749
  const move = cPrev !== 0 ? Math.abs(cVal - cPrev) / cPrev > 0.01 : false;
42792
43750
  return spike && move ? 1 : 0;
@@ -43279,7 +44237,45 @@ var TA_METHODS = new Set([
43279
44237
  "volume_momentum",
43280
44238
  "volume_profile_high",
43281
44239
  "volume_profile_low",
43282
- "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"
43283
44279
  ]);
43284
44280
  var TA_BARE_ATTRS = new Set([
43285
44281
  "accdist",
@@ -43624,6 +44620,23 @@ function hasArg(args, index, names) {
43624
44620
  }
43625
44621
  return index >= 0 && index < args.pos.length;
43626
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
+ }
43627
44640
  function hasAnyKw(args, names) {
43628
44641
  return names.some((n) => Object.hasOwn(args.kw, n));
43629
44642
  }
@@ -43639,6 +44652,9 @@ function cellOf(expr) {
43639
44652
  function cellList(expr) {
43640
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)]; })()`;
43641
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
+ }
43642
44658
  var DRAW_KINDS = new Set(["label", "line", "box", "table", "polyline", "linefill"]);
43643
44659
  var ARRAY_SIGS = {
43644
44660
  new: [["size"], ["initial_value", "initial"]],
@@ -44018,6 +45034,8 @@ function emitDraw(ctx, name, methodSrc, args) {
44018
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")})`;
44019
45035
  } else if (kind === "polyline") {
44020
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")})`;
44021
45039
  } else if (kind === "linefill") {
44022
45040
  const color = hasArg(args, 2, ["color"]) ? pick(args, 2, ["color"], "null") : "null";
44023
45041
  code = `__h.draw.linefill_new(__bar_idx, ${pick(args, 0, ["id1", "line1"], "null")}, ${pick(args, 1, ["id2", "line2"], "null")}, ${color})`;
@@ -44640,6 +45658,9 @@ function allocSite(ctx) {
44640
45658
  function taCall(method, site, parts) {
44641
45659
  return `__h.ta.${method}(${site}, ${parts.join(", ")})`;
44642
45660
  }
45661
+ function taPure(method, parts) {
45662
+ return `__h.ta.${method}(${parts.join(", ")})`;
45663
+ }
44643
45664
  function emitTa(ctx, method, args) {
44644
45665
  if (!TA_METHODS.has(method))
44645
45666
  return "null";
@@ -45063,16 +46084,30 @@ function emitTa(ctx, method, args) {
45063
46084
  ]);
45064
46085
  }
45065
46086
  if (method === "stoch_smooth") {
45066
- 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
+ ]);
45067
46095
  }
45068
46096
  if (method === "engulfing") {
45069
- 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); })()`;
45070
46098
  }
45071
46099
  if (method === "inside_bar_pattern") {
45072
- 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
+ ]);
45073
46104
  }
45074
46105
  if (method === "double_top_bottom") {
45075
- 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
+ ]);
45076
46111
  }
45077
46112
  if (method === "voi") {
45078
46113
  return `__h.ta.voi(${cellOf(pick(args, 0, ["buy_volume", "buy"], "null"))}, ${cellOf(pick(args, 1, ["sell_volume", "sell"], "null"))})`;
@@ -45085,7 +46120,10 @@ function emitTa(ctx, method, args) {
45085
46120
  }
45086
46121
  if (method === "rsi_divergence") {
45087
46122
  const period = `((__n) => (__n == null ? 0 : __n))(${cellOf(pick(args, 1, ["period", "length"], "null"))})`;
45088
- 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
+ ]);
45089
46127
  }
45090
46128
  if (method === "cumulative_delta") {
45091
46129
  return taCall("cumulativeDelta", site, [
@@ -45120,6 +46158,237 @@ function emitTa(ctx, method, args) {
45120
46158
  `((__n) => (__n == null ? 0.3 : __n))(${sens})`
45121
46159
  ]);
45122
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
+ }
45123
46392
  return "null";
45124
46393
  }
45125
46394
 
@@ -46588,6 +47857,8 @@ function naNum(v) {
46588
47857
  function hold(v) {
46589
47858
  if (v != null && typeof v === "object")
46590
47859
  return v;
47860
+ if (typeof v === "string")
47861
+ return v;
46591
47862
  return naNum(v);
46592
47863
  }
46593
47864
  function pineEq(a, b) {
@@ -47280,8 +48551,23 @@ class CompileDraw {
47280
48551
  putNum(extra, "bottom", bottom);
47281
48552
  return this.book.boxNew(n3(bar, 0), Object.keys(extra).length ? extra : undefined);
47282
48553
  }
47283
- table_new(bar) {
47284
- 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);
47285
48571
  }
47286
48572
  polyline_new(bar, points) {
47287
48573
  const pts = pointsOf(points);
@@ -47915,7 +49201,8 @@ class CompileStrategy {
47915
49201
  open: num(open, this.mark),
47916
49202
  high: num(high, this.mark),
47917
49203
  low: num(low, this.mark),
47918
- close: this.mark
49204
+ close: this.mark,
49205
+ time: this.time
47919
49206
  };
47920
49207
  this.ohlc = ohlc;
47921
49208
  this.book.processPending(this.bar, ohlc);
@@ -47931,17 +49218,18 @@ class CompileStrategy {
47931
49218
  stop: opts?.stop,
47932
49219
  comment: opts?.comment,
47933
49220
  oca_name: opts?.oca_name,
47934
- oca_type: opts?.oca_type
49221
+ oca_type: opts?.oca_type,
49222
+ deferMarket: true
47935
49223
  });
47936
49224
  }
47937
49225
  close(id, qty) {
47938
- this.book.fillClose(this.bar, str(id, ""), this.mark, {
49226
+ this.book.placeClose(this.bar, str(id, ""), this.mark, {
47939
49227
  time: this.time,
47940
49228
  qty: optNum(qty)
47941
49229
  });
47942
49230
  }
47943
49231
  close_all(_comment) {
47944
- this.book.closeAll(this.bar, this.mark);
49232
+ this.book.placeCloseAll(this.bar, this.mark);
47945
49233
  }
47946
49234
  order(id, direction, qty, opts) {
47947
49235
  this.entry(id, direction, qty, opts);
@@ -47958,7 +49246,8 @@ class CompileStrategy {
47958
49246
  ...parsed,
47959
49247
  price: this.mark,
47960
49248
  time: this.time,
47961
- ohlc: this.ohlc
49249
+ ohlc: this.ohlc,
49250
+ deferMarket: true
47962
49251
  });
47963
49252
  }
47964
49253
  position_size() {
@@ -48326,8 +49615,8 @@ function createCompileHelpers(opts) {
48326
49615
  second: calendarSecond,
48327
49616
  dayofweek: calendarDayofweek,
48328
49617
  timestamp,
48329
- weekOfYear,
48330
- timeTradingDay,
49618
+ weekOfYear: calendarWeekOfYear,
49619
+ timeTradingDay: calendarTimeTradingDay,
48331
49620
  timeframeInSeconds: timeframeInSecondsOrDaily,
48332
49621
  timeframeChange,
48333
49622
  timeClose,
@@ -48451,7 +49740,20 @@ function NA_FN(v) {
48451
49740
  function utcPart(t, key) {
48452
49741
  if (typeof t !== "number" || !Number.isFinite(t))
48453
49742
  return null;
48454
- 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);
48455
49757
  }
48456
49758
  function calendarYear(t) {
48457
49759
  return utcPart(t, "year");
@@ -48885,7 +50187,8 @@ function interpretTree(tree, ohlcv, host) {
48885
50187
  open: num2(env.ctx.open) ?? undefined,
48886
50188
  high: num2(env.ctx.high) ?? undefined,
48887
50189
  low: num2(env.ctx.low) ?? undefined,
48888
- close: num2(env.ctx.close) ?? undefined
50190
+ close: num2(env.ctx.close) ?? undefined,
50191
+ time: num2(env.ctx.time) ?? undefined
48889
50192
  });
48890
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);
48891
50194
  try {
@@ -49216,6 +50519,27 @@ function seriesGet(env, id) {
49216
50519
  }
49217
50520
  return env.series.get(id);
49218
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
+ }
49219
50543
  function bindName(env, id, value) {
49220
50544
  const stored = typeof value === "number" && !Number.isFinite(value) ? NA : value;
49221
50545
  const frame = activeFrame(env);
@@ -50433,7 +51757,8 @@ function evalCall(node, env) {
50433
51757
  price: mark == null || !Number.isFinite(mark) ? undefined : mark,
50434
51758
  time: num2(env.ctx.time) ?? undefined,
50435
51759
  oca_name: evalAsString(callArg(node.args, -1, ["oca_name"]), env),
50436
- oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env)
51760
+ oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env),
51761
+ deferMarket: true
50437
51762
  });
50438
51763
  return NA;
50439
51764
  }
@@ -50442,13 +51767,10 @@ function evalCall(node, env) {
50442
51767
  const mark = num2(env.ctx.close);
50443
51768
  const qtyExpr = callArg(node.args, 1, ["qty"]);
50444
51769
  const qtyRaw = qtyExpr == null ? undefined : unwrap2(evalExpr(qtyExpr, env));
50445
- if (env.book.position.qty !== 0 && mark != null) {
50446
- env.book.fillClose(env.barIndex, id, mark, {
50447
- time: num2(env.ctx.time) ?? undefined,
50448
- qty: qtyRaw ?? undefined
50449
- });
50450
- } else
50451
- 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
+ });
50452
51774
  return NA;
50453
51775
  }
50454
51776
  if (fname === "strategy.exit") {
@@ -50468,17 +51790,12 @@ function evalCall(node, env) {
50468
51790
  trail_offset: unwrap2(evalExpr(callArg(node.args, 10, ["trail_offset"]), env)),
50469
51791
  price: num2(env.ctx.close) ?? undefined,
50470
51792
  time: num2(env.ctx.time) ?? undefined,
50471
- ohlc: {
50472
- open: num2(env.ctx.open) ?? undefined,
50473
- high: num2(env.ctx.high) ?? undefined,
50474
- low: num2(env.ctx.low) ?? undefined,
50475
- close: num2(env.ctx.close) ?? undefined
50476
- }
51793
+ deferMarket: true
50477
51794
  });
50478
51795
  return NA;
50479
51796
  }
50480
51797
  if (fname === "strategy.close_all") {
50481
- env.book.closeAll(env.barIndex, num2(env.ctx.close) ?? undefined);
51798
+ env.book.placeCloseAll(env.barIndex, num2(env.ctx.close) ?? undefined);
50482
51799
  return NA;
50483
51800
  }
50484
51801
  if (fname === "strategy.cancel") {
@@ -50500,7 +51817,8 @@ function evalCall(node, env) {
50500
51817
  price: num2(env.ctx.close) ?? undefined,
50501
51818
  time: num2(env.ctx.time) ?? undefined,
50502
51819
  oca_name: evalAsString(callArg(node.args, -1, ["oca_name"]), env),
50503
- oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env)
51820
+ oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env),
51821
+ deferMarket: true
50504
51822
  });
50505
51823
  return NA;
50506
51824
  }
@@ -51905,11 +53223,11 @@ function evalExtraTa(fname, node, env, site) {
51905
53223
  }
51906
53224
  if (fname === "ta.engulfing" || fname === "engulfing") {
51907
53225
  const msg = "ta.engulfing() requires 4 arguments: open, high, low, close";
51908
- unwrap2(evalExpr(wave10aArg(0, ["open"], msg), env));
53226
+ const open = unwrap2(evalExpr(wave10aArg(0, ["open"], msg), env));
51909
53227
  unwrap2(evalExpr(wave10aArg(1, ["high"], msg), env));
51910
53228
  unwrap2(evalExpr(wave10aArg(2, ["low"], msg), env));
51911
- unwrap2(evalExpr(wave10aArg(3, ["close"], msg), env));
51912
- return env.ta.engulfing();
53229
+ const close = unwrap2(evalExpr(wave10aArg(3, ["close"], msg), env));
53230
+ return env.ta.engulfing(site, open, close);
51913
53231
  }
51914
53232
  if (fname === "ta.gap_detector" || fname === "gap_detector") {
51915
53233
  const msg = "ta.gap_detector() requires 3 arguments: high, low, prev_close";
@@ -51917,15 +53235,15 @@ function evalExtraTa(fname, node, env, site) {
51917
53235
  }
51918
53236
  if (fname === "ta.double_top_bottom" || fname === "double_top_bottom") {
51919
53237
  const msg = "ta.double_top_bottom() requires 3 arguments";
51920
- unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
51921
- unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
51922
- 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)));
51923
53241
  }
51924
53242
  if (fname === "ta.inside_bar_pattern" || fname === "inside_bar_pattern") {
51925
53243
  const msg = "ta.inside_bar_pattern() requires 2 arguments";
51926
- unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
51927
- unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
51928
- 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);
51929
53247
  }
51930
53248
  if (fname === "ta.macd_signal" || fname === "macd_signal") {
51931
53249
  const msg = "ta.macd_signal() requires 2 arguments: macd_line, signal_line";
@@ -51937,7 +53255,7 @@ function evalExtraTa(fname, node, env, site) {
51937
53255
  }
51938
53256
  if (fname === "ta.stoch_smooth" || fname === "stoch_smooth") {
51939
53257
  const msg = "ta.stoch_smooth() requires 6 arguments: high, low, close, period, smooth_k, smooth_d";
51940
- 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)));
51941
53259
  }
51942
53260
  const wave10bList = (index, names) => {
51943
53261
  const raw = evalExpr(callArg(node.args, index, names), env);
@@ -51962,7 +53280,7 @@ function evalExtraTa(fname, node, env, site) {
51962
53280
  }
51963
53281
  if (fname === "ta.rsi_divergence" || fname === "rsi_divergence") {
51964
53282
  const period = unwrap2(evalExpr(callArg(node.args, 1, ["period", "length"]), env));
51965
- 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);
51966
53284
  }
51967
53285
  if (fname === "ta.cumulative_delta" || fname === "cumulative_delta") {
51968
53286
  const period = unwrap2(evalExpr(callArg(node.args, 2, ["period", "length"]), env));
@@ -51984,6 +53302,188 @@ function evalExtraTa(fname, node, env, site) {
51984
53302
  const sens = unwrap2(evalExpr(callArg(node.args, 3, ["sensitivity"]), env));
51985
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);
51986
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
+ }
51987
53487
  return;
51988
53488
  }
51989
53489
  function hlc3(env) {
@@ -51994,6 +53494,14 @@ function hlc3(env) {
51994
53494
  return c ?? h ?? l;
51995
53495
  return (h + l + c) / 3;
51996
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
+ }
51997
53505
  function asArray2(value) {
51998
53506
  if (value instanceof PineArray)
51999
53507
  return value;
@@ -52892,8 +54400,22 @@ function evalDrawingCall(fname, node, env) {
52892
54400
  const position = drawRaw(node, env, 0, ["position"]);
52893
54401
  if (position !== undefined)
52894
54402
  extra.position = position;
52895
- putFinite(extra, "rows", drawNum(node, env, 1, ["rows"]));
52896
- 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;
52897
54419
  return book.tableNew(env.barIndex, extra);
52898
54420
  }
52899
54421
  if (fname === "polyline.new") {
@@ -53940,8 +55462,8 @@ function syminfoPrefix2(node, env) {
53940
55462
  function calendarMs(node, env) {
53941
55463
  const arg = callArg(node.args, 0, ["time", "timestamp"]);
53942
55464
  if (arg == null)
53943
- return num2(env.ctx.time);
53944
- return unwrap2(evalExpr(arg, env));
55465
+ return timestampToMs(num2(env.ctx.time));
55466
+ return timestampToMs(unwrap2(evalExpr(arg, env)));
53945
55467
  }
53946
55468
  function evalLibraryMemberCall(mod, attr, node, env) {
53947
55469
  const exp = mod.get(attr);