@hoox-sh/pynets 0.3.0 → 0.5.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
@@ -34428,6 +34428,235 @@ function colorT(c) {
34428
34428
  return col ? alphaToTransp(col.a) : null;
34429
34429
  }
34430
34430
 
34431
+ // src/runtime/footprint.ts
34432
+ class VolumeRow {
34433
+ up_price;
34434
+ down_price;
34435
+ buy_volume;
34436
+ sell_volume;
34437
+ delta;
34438
+ is_imbalance;
34439
+ is_poc;
34440
+ is_vah;
34441
+ is_val;
34442
+ constructor(up_price = 0, down_price = 0, buy_volume = 0, sell_volume = 0, delta = 0, is_imbalance = false, is_poc = false, is_vah = false, is_val = false) {
34443
+ this.up_price = up_price;
34444
+ this.down_price = down_price;
34445
+ this.buy_volume = buy_volume;
34446
+ this.sell_volume = sell_volume;
34447
+ this.delta = delta;
34448
+ this.is_imbalance = is_imbalance;
34449
+ this.is_poc = is_poc;
34450
+ this.is_vah = is_vah;
34451
+ this.is_val = is_val;
34452
+ }
34453
+ }
34454
+
34455
+ class Footprint {
34456
+ num_ticks;
34457
+ va_percentage;
34458
+ buy_volume;
34459
+ sell_volume;
34460
+ delta;
34461
+ total_volume;
34462
+ vah_row;
34463
+ val_row;
34464
+ poc_row;
34465
+ rows;
34466
+ constructor(num_ticks = 100, va_percentage = 70, buy_volume = 0, sell_volume = 0, delta = 0, total_volume = 0, vah_row = null, val_row = null, poc_row = null, rows = []) {
34467
+ this.num_ticks = num_ticks;
34468
+ this.va_percentage = va_percentage;
34469
+ this.buy_volume = buy_volume;
34470
+ this.sell_volume = sell_volume;
34471
+ this.delta = delta;
34472
+ this.total_volume = total_volume;
34473
+ this.vah_row = vah_row;
34474
+ this.val_row = val_row;
34475
+ this.poc_row = poc_row;
34476
+ this.rows = rows;
34477
+ }
34478
+ }
34479
+ var N2 = 624;
34480
+ var M2 = 397;
34481
+ var MATRIX_A = 2567483615;
34482
+ var UPPER_MASK = 2147483648;
34483
+ var LOWER_MASK = 2147483647;
34484
+
34485
+ class PyRandom {
34486
+ mt = new Uint32Array(N2);
34487
+ index = N2 + 1;
34488
+ seed(a) {
34489
+ const n = Math.trunc(a);
34490
+ const abs = n < 0 ? -n : n;
34491
+ const key = [];
34492
+ if (abs === 0)
34493
+ key.push(0);
34494
+ else {
34495
+ let x = abs;
34496
+ while (x > 0) {
34497
+ key.push(x >>> 0);
34498
+ x = Math.floor(x / 4294967296);
34499
+ }
34500
+ }
34501
+ this.initByArray(key);
34502
+ }
34503
+ random() {
34504
+ const a = this.genrand() >>> 5;
34505
+ const b = this.genrand() >>> 6;
34506
+ return (a * 67108864 + b) * (1 / 9007199254740992);
34507
+ }
34508
+ initGenrand(s) {
34509
+ const mt = this.mt;
34510
+ mt[0] = s >>> 0;
34511
+ for (let mti = 1;mti < N2; mti++) {
34512
+ mt[mti] = Math.imul(1812433253, mt[mti - 1] ^ mt[mti - 1] >>> 30) + mti >>> 0;
34513
+ }
34514
+ this.index = N2;
34515
+ }
34516
+ initByArray(initKey) {
34517
+ const mt = this.mt;
34518
+ this.initGenrand(19650218);
34519
+ let i = 1;
34520
+ let j = 0;
34521
+ const keyLength = initKey.length;
34522
+ let k = N2 > keyLength ? N2 : keyLength;
34523
+ for (;k > 0; k--) {
34524
+ mt[i] = (mt[i] ^ Math.imul(mt[i - 1] ^ mt[i - 1] >>> 30, 1664525)) + initKey[j] + j >>> 0;
34525
+ i++;
34526
+ j++;
34527
+ if (i >= N2) {
34528
+ mt[0] = mt[N2 - 1];
34529
+ i = 1;
34530
+ }
34531
+ if (j >= keyLength)
34532
+ j = 0;
34533
+ }
34534
+ for (k = N2 - 1;k > 0; k--) {
34535
+ mt[i] = (mt[i] ^ Math.imul(mt[i - 1] ^ mt[i - 1] >>> 30, 1566083941)) - i >>> 0;
34536
+ i++;
34537
+ if (i >= N2) {
34538
+ mt[0] = mt[N2 - 1];
34539
+ i = 1;
34540
+ }
34541
+ }
34542
+ mt[0] = 2147483648;
34543
+ this.index = N2;
34544
+ }
34545
+ genrand() {
34546
+ const mt = this.mt;
34547
+ if (this.index >= N2) {
34548
+ for (let kk = 0;kk < N2 - M2; kk++) {
34549
+ const y = mt[kk] & UPPER_MASK | mt[kk + 1] & LOWER_MASK;
34550
+ mt[kk] = (mt[kk + M2] ^ y >>> 1 ^ (y & 1 ? MATRIX_A : 0)) >>> 0;
34551
+ }
34552
+ for (let kk = N2 - M2;kk < N2 - 1; kk++) {
34553
+ const y = mt[kk] & UPPER_MASK | mt[kk + 1] & LOWER_MASK;
34554
+ mt[kk] = (mt[kk + (M2 - N2)] ^ y >>> 1 ^ (y & 1 ? MATRIX_A : 0)) >>> 0;
34555
+ }
34556
+ const y = mt[N2 - 1] & UPPER_MASK | mt[0] & LOWER_MASK;
34557
+ mt[N2 - 1] = (mt[M2 - 1] ^ y >>> 1 ^ (y & 1 ? MATRIX_A : 0)) >>> 0;
34558
+ this.index = 0;
34559
+ }
34560
+ let y = mt[this.index++];
34561
+ y ^= y >>> 11;
34562
+ y ^= y << 7 & 2636928640;
34563
+ y ^= y << 15 & 4022730752;
34564
+ y ^= y >>> 18;
34565
+ return y >>> 0;
34566
+ }
34567
+ }
34568
+ var pyRng = null;
34569
+ function seedFootprintRng(seed) {
34570
+ pyRng = new PyRandom;
34571
+ pyRng.seed(seed);
34572
+ }
34573
+ function nextRandom() {
34574
+ return pyRng != null ? pyRng.random() : Math.random();
34575
+ }
34576
+ function asCount(value, fallback) {
34577
+ if (typeof value === "number" && Number.isFinite(value))
34578
+ return Math.trunc(value);
34579
+ return fallback;
34580
+ }
34581
+ function rowAt(rows, idx) {
34582
+ return idx >= 0 && idx < rows.length ? rows[idx] : null;
34583
+ }
34584
+ function createFootprint(numTicks = 100, vaPercentage = 70) {
34585
+ const n = asCount(numTicks, 100);
34586
+ const va = asCount(vaPercentage, 70);
34587
+ const rows = [];
34588
+ const basePrice = 100;
34589
+ const tickSize = 0.01;
34590
+ for (let i = 0;i < n; i++) {
34591
+ const priceLevel = basePrice + i * tickSize;
34592
+ rows.push(new VolumeRow(priceLevel + tickSize, priceLevel, 1000 + nextRandom() * 500, 900 + nextRandom() * 500, 100 + (nextRandom() * 200 - 100), nextRandom() < 0.1, i === Math.floor(n / 2), i === Math.trunc(n * 0.7), i === Math.trunc(n * 0.3)));
34593
+ }
34594
+ const totalBuy = rows.reduce((s, r) => s + r.buy_volume, 0);
34595
+ const totalSell = rows.reduce((s, r) => s + r.sell_volume, 0);
34596
+ return new Footprint(n, va, totalBuy, totalSell, totalBuy - totalSell, totalBuy + totalSell, rowAt(rows, Math.trunc(n * 0.7)), rowAt(rows, Math.trunc(n * 0.3)), rowAt(rows, Math.floor(n / 2)), rows);
34597
+ }
34598
+ function footprintBuyVolume(fp) {
34599
+ return fp instanceof Footprint ? fp.buy_volume : 0;
34600
+ }
34601
+ function footprintSellVolume(fp) {
34602
+ return fp instanceof Footprint ? fp.sell_volume : 0;
34603
+ }
34604
+ function footprintDelta(fp) {
34605
+ return fp instanceof Footprint ? fp.delta : 0;
34606
+ }
34607
+ function footprintTotalVolume(fp) {
34608
+ return fp instanceof Footprint ? fp.total_volume : 0;
34609
+ }
34610
+ function footprintVah(fp) {
34611
+ return fp instanceof Footprint ? fp.vah_row : null;
34612
+ }
34613
+ function footprintVal(fp) {
34614
+ return fp instanceof Footprint ? fp.val_row : null;
34615
+ }
34616
+ function footprintPoc(fp) {
34617
+ return fp instanceof Footprint ? fp.poc_row : null;
34618
+ }
34619
+ function footprintRows(fp) {
34620
+ return fp instanceof Footprint ? fp.rows.slice() : [];
34621
+ }
34622
+ function footprintGetRowByPrice(fp, price) {
34623
+ if (!(fp instanceof Footprint) || price == null)
34624
+ return null;
34625
+ if (typeof price !== "number" || !Number.isFinite(price))
34626
+ return null;
34627
+ for (const row of fp.rows) {
34628
+ const lo = Math.min(row.down_price, row.up_price);
34629
+ const hi = Math.max(row.down_price, row.up_price);
34630
+ if (lo <= price && price <= hi)
34631
+ return row;
34632
+ }
34633
+ return null;
34634
+ }
34635
+ function volumeRowUpPrice(vr) {
34636
+ return vr instanceof VolumeRow ? vr.up_price : 0;
34637
+ }
34638
+ function volumeRowDownPrice(vr) {
34639
+ return vr instanceof VolumeRow ? vr.down_price : 0;
34640
+ }
34641
+ function volumeRowBuyVolume(vr) {
34642
+ return vr instanceof VolumeRow ? vr.buy_volume : 0;
34643
+ }
34644
+ function volumeRowSellVolume(vr) {
34645
+ return vr instanceof VolumeRow ? vr.sell_volume : 0;
34646
+ }
34647
+ function volumeRowDelta(vr) {
34648
+ return vr instanceof VolumeRow ? vr.delta : 0;
34649
+ }
34650
+ function volumeRowTotalVolume(vr) {
34651
+ return vr instanceof VolumeRow ? vr.buy_volume + vr.sell_volume : 0;
34652
+ }
34653
+ function volumeRowHasBuyImbalance(vr) {
34654
+ return vr instanceof VolumeRow ? Boolean(vr.is_imbalance && vr.buy_volume > vr.sell_volume) : false;
34655
+ }
34656
+ function volumeRowHasSellImbalance(vr) {
34657
+ return vr instanceof VolumeRow ? Boolean(vr.is_imbalance && vr.sell_volume > vr.buy_volume) : false;
34658
+ }
34659
+
34431
34660
  // src/runtime/request.ts
34432
34661
  var REQUEST_FNS = new Set([
34433
34662
  "request.security",
@@ -34547,6 +34776,7 @@ function resolveCurrencyRate(from, to) {
34547
34776
  }
34548
34777
  function resolveSeed(seed) {
34549
34778
  lastSeed = coerceSeed(seed ?? 0);
34779
+ seedFootprintRng(lastSeed);
34550
34780
  return null;
34551
34781
  }
34552
34782
  function resolveRequest(fname, host, args = {}) {
@@ -34565,6 +34795,10 @@ function resolveRequest(fname, host, args = {}) {
34565
34795
  if (fname === "request.seed") {
34566
34796
  return resolveSeed(seedFromArgs(args));
34567
34797
  }
34798
+ if (fname === "request.footprint") {
34799
+ const [numTicks, va] = footprintFromArgs(args);
34800
+ return createFootprint(numTicks, va);
34801
+ }
34568
34802
  return resolveForeignNa();
34569
34803
  }
34570
34804
  function isNamedArgs(args) {
@@ -34603,6 +34837,11 @@ function seedFromArgs(args) {
34603
34837
  return args[0] ?? 0;
34604
34838
  return args.seed ?? 0;
34605
34839
  }
34840
+ function footprintFromArgs(args) {
34841
+ if (!isNamedArgs(args))
34842
+ return [args[0] ?? 100, args[1] ?? 70];
34843
+ return [args.num_ticks ?? 100, args.va_percentage ?? 70];
34844
+ }
34606
34845
  function currencyPair(from, to) {
34607
34846
  const a = (from ?? "").trim().toUpperCase();
34608
34847
  const b = (to ?? "").trim().toUpperCase();
@@ -42191,6 +42430,367 @@ class TaEngine {
42191
42430
  const direction = recentHigh === oldest ? 1 : -1;
42192
42431
  return { high: recentHigh, low: recentLow, dir: pct > th ? 1 : direction };
42193
42432
  }
42433
+ accelSites = new Map;
42434
+ coerceTaInt(value, message) {
42435
+ if (value === null || !Number.isFinite(value))
42436
+ throw new Error(`${message}. Got: na`);
42437
+ const nearest = Math.round(value);
42438
+ if (Math.abs(value - nearest) <= PERIOD_INT_EPS)
42439
+ return nearest;
42440
+ return Math.floor(value);
42441
+ }
42442
+ hammer(open, high, low, close) {
42443
+ if (open === null || high === null || low === null || close === null) {
42444
+ throw new Error("bad operand type for abs(): 'NoneType'");
42445
+ }
42446
+ const body = Math.abs(close - open);
42447
+ const range = high - low;
42448
+ const lower = Math.min(open, close) - low;
42449
+ const upper = high - Math.max(open, close);
42450
+ const isDoji = body < range * 0.1;
42451
+ const isHammer = body > 0 && lower > body * 2 && upper < body;
42452
+ let strength = 0;
42453
+ if (isDoji)
42454
+ strength = 1 - body / (range + 0.0001);
42455
+ else if (isHammer)
42456
+ strength = Math.min(1, lower / (range + 0.0001));
42457
+ return taRec({
42458
+ is_hammer: isHammer,
42459
+ is_doji: isDoji,
42460
+ pattern_strength: Number.isFinite(strength) ? strength : null
42461
+ });
42462
+ }
42463
+ gapDetector(high, low, prevClose) {
42464
+ const none = taRec({ gap_size: 0, gap_type: 0, gap_percent: 0 });
42465
+ if (prevClose === null)
42466
+ return none;
42467
+ if (high === null || low === null) {
42468
+ throw new Error("unsupported operand type(s) for -: 'float' and 'NoneType'");
42469
+ }
42470
+ const upside = Math.max(0, low - prevClose);
42471
+ const downside = Math.max(0, prevClose - high);
42472
+ if (upside > downside) {
42473
+ const pct = prevClose !== 0 ? upside / prevClose * 100 : 0;
42474
+ return taRec({
42475
+ gap_size: upside,
42476
+ gap_type: 1,
42477
+ gap_percent: Number.isFinite(pct) ? pct : null
42478
+ });
42479
+ }
42480
+ if (downside > 0) {
42481
+ const pct = prevClose !== 0 ? downside / prevClose * 100 : 0;
42482
+ return taRec({
42483
+ gap_size: downside,
42484
+ gap_type: -1,
42485
+ gap_percent: Number.isFinite(pct) ? pct : null
42486
+ });
42487
+ }
42488
+ return none;
42489
+ }
42490
+ macdSignal(macdLine, signalLine) {
42491
+ if (macdLine === null || signalLine === null)
42492
+ return null;
42493
+ return finiteOut2(macdLine - signalLine);
42494
+ }
42495
+ accelerationFactor(site, source, period) {
42496
+ const p = this.coerceTaInt(period, "ta.acceleration_factor() requires 2 arguments");
42497
+ let samples = this.accelSites.get(site);
42498
+ if (samples === undefined) {
42499
+ samples = [];
42500
+ this.accelSites.set(site, samples);
42501
+ }
42502
+ pushCap(samples, finiteCell2(source), 1000);
42503
+ if (samples.length < p + 1 || p <= 0)
42504
+ 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];
42509
+ if (v !== null)
42510
+ newestFirst.push(v);
42511
+ }
42512
+ if (newestFirst.length < 2)
42513
+ return 0;
42514
+ let oldSum = 0;
42515
+ for (let i = 0;i < newestFirst.length - 1; i++)
42516
+ oldSum += newestFirst[i];
42517
+ const oldMom = oldSum / (newestFirst.length - 1);
42518
+ if (Math.abs(oldMom) < 0.0000000001)
42519
+ return 0;
42520
+ const newMom = newestFirst[newestFirst.length - 1];
42521
+ let acc = (newMom - oldMom) / oldMom;
42522
+ if (acc < -2)
42523
+ acc = -2;
42524
+ if (acc > 2)
42525
+ acc = 2;
42526
+ return finiteOut2(acc);
42527
+ }
42528
+ stochSmooth(high, low, close, period, smoothK, smoothD) {
42529
+ const p = this.coerceTaInt(period, "ta.stoch_smooth period must be integer");
42530
+ const k = this.coerceTaInt(smoothK, "ta.stoch_smooth smooth_k must be integer");
42531
+ 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)
42538
+ 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;
42548
+ }
42549
+ doubleTopBottom(period) {
42550
+ if (period === null || !Number.isFinite(period)) {
42551
+ throw new Error("period must be integer. Got: na");
42552
+ }
42553
+ return taRec({ pattern_type: "none", strength: 0, breakout_level: 0 });
42554
+ }
42555
+ cumDeltaSites = new Map;
42556
+ volMomSites = new Map;
42557
+ volProfileLowSites = new Map;
42558
+ volThrustSites = new Map;
42559
+ asCount(value) {
42560
+ if (!Number.isFinite(value))
42561
+ return null;
42562
+ const nearest = Math.round(value);
42563
+ return Math.abs(value - nearest) <= PERIOD_INT_EPS ? nearest : Math.floor(value);
42564
+ }
42565
+ pushChrono(buf, value) {
42566
+ buf.push(value !== null && Number.isFinite(value) ? value : null);
42567
+ if (buf.length > 1000)
42568
+ buf.shift();
42569
+ }
42570
+ nf(buf, i) {
42571
+ const v = buf[-i - 1];
42572
+ return v === undefined ? null : v;
42573
+ }
42574
+ voi(buy, sell) {
42575
+ const b = buy !== null && Number.isFinite(buy) ? buy : 0;
42576
+ const s = sell !== null && Number.isFinite(sell) ? sell : 0;
42577
+ const total = b + s;
42578
+ if (total === 0)
42579
+ return 0;
42580
+ return finiteOut2((b - s) / total);
42581
+ }
42582
+ bidAskImbalance(bidSize, askSize, bidPrice, askPrice) {
42583
+ const bid = bidSize !== null && Number.isFinite(bidSize) ? bidSize : 0;
42584
+ const ask = askSize !== null && Number.isFinite(askSize) ? askSize : 0;
42585
+ const bidPx = bidPrice !== null && Number.isFinite(bidPrice) ? bidPrice : 0;
42586
+ const askPx = askPrice !== null && Number.isFinite(askPrice) ? askPrice : 0;
42587
+ const total = bid + ask;
42588
+ if (total === 0)
42589
+ return taRec({ imbalance_ratio: 0, spread: 0 });
42590
+ return taRec({
42591
+ imbalance_ratio: finiteOut2((bid - ask) / total),
42592
+ spread: finiteOut2(bidPx > 0 ? askPx - bidPx : 0)
42593
+ });
42594
+ }
42595
+ rsiOversoldOverbought(rsi, oversold, overbought) {
42596
+ if (rsi === null || !Number.isFinite(rsi)) {
42597
+ return taRec({ is_oversold: false, is_overbought: false, rsi: null });
42598
+ }
42599
+ const os = this.asCount(oversold);
42600
+ const ob = this.asCount(overbought);
42601
+ if (os === null || ob === null) {
42602
+ return taRec({ is_oversold: false, is_overbought: false, rsi });
42603
+ }
42604
+ return taRec({ is_oversold: rsi < os, is_overbought: rsi > ob, rsi });
42605
+ }
42606
+ rsiDivergence(series, period) {
42607
+ 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;
42642
+ }
42643
+ return finiteOut2(last);
42644
+ }
42645
+ cumulativeDelta(site, close, volume, period) {
42646
+ const n = this.asCount(period);
42647
+ let st = this.cumDeltaSites.get(site);
42648
+ if (st === undefined) {
42649
+ st = { close: [], volume: [] };
42650
+ this.cumDeltaSites.set(site, st);
42651
+ }
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)
42655
+ return 0;
42656
+ 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
+ }
42670
+ }
42671
+ return finiteOut2(delta);
42672
+ }
42673
+ volumeMomentum(site, volume, period) {
42674
+ 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)
42682
+ 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);
42688
+ }
42689
+ if (clean.length < 2)
42690
+ 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);
42696
+ if (oldVol === 0)
42697
+ return 0;
42698
+ let momentum = (newVol - oldVol) / oldVol * 100;
42699
+ if (momentum > 100)
42700
+ momentum = 100;
42701
+ if (momentum < -100)
42702
+ momentum = -100;
42703
+ return finiteOut2(momentum);
42704
+ }
42705
+ volumeProfileHigh(prices, volumes) {
42706
+ if (prices.length === 0 || volumes.length === 0 || prices.length !== volumes.length)
42707
+ return 0;
42708
+ let maxVol = 0;
42709
+ let maxPrice = 0;
42710
+ for (let i = 0;i < prices.length; i++) {
42711
+ const v = volumes[i];
42712
+ if (v === null || !Number.isFinite(v) || !(v > maxVol))
42713
+ continue;
42714
+ maxVol = v;
42715
+ const p = prices[i];
42716
+ maxPrice = p !== null && Number.isFinite(p) ? p : 0;
42717
+ }
42718
+ return finiteOut2(maxPrice);
42719
+ }
42720
+ volumeProfileLow(site, close, volume, period, levels) {
42721
+ const p = this.asCount(period);
42722
+ const lv = this.asCount(levels);
42723
+ let st = this.volProfileLowSites.get(site);
42724
+ if (st === undefined) {
42725
+ st = { close: [], volume: [] };
42726
+ this.volProfileLowSites.set(site, st);
42727
+ }
42728
+ this.pushChrono(st.close, close);
42729
+ this.pushChrono(st.volume, volume);
42730
+ const oldest = st.close.length > 0 ? st.close[0] : null;
42731
+ const fallback = st.close.length === 0 ? 100 : oldest !== null && Number.isFinite(oldest) ? oldest : null;
42732
+ if (p === null || lv === null || p <= 0 || lv <= 0 || st.close.length < p)
42733
+ return fallback;
42734
+ const prices = [];
42735
+ const vols = [];
42736
+ for (let i = -p;i < 0; i++) {
42737
+ const c = this.nf(st.close, i);
42738
+ const v = this.nf(st.volume, i);
42739
+ if (c !== null && Number.isFinite(c) && v !== null && Number.isFinite(v)) {
42740
+ prices.push(c);
42741
+ vols.push(v);
42742
+ }
42743
+ }
42744
+ if (prices.length === 0)
42745
+ return fallback;
42746
+ let minP = prices[0];
42747
+ let maxP = prices[0];
42748
+ for (const c of prices) {
42749
+ if (c < minP)
42750
+ minP = c;
42751
+ if (c > maxP)
42752
+ maxP = c;
42753
+ }
42754
+ if (minP === maxP)
42755
+ return minP;
42756
+ const bucket = (maxP - minP) / lv;
42757
+ const buckets = new Array(lv).fill(0);
42758
+ for (let k = 0;k < prices.length; k++) {
42759
+ let idx = Math.trunc((prices[k] - minP) / bucket);
42760
+ if (idx > lv - 1)
42761
+ idx = lv - 1;
42762
+ if (idx < 0)
42763
+ idx = 0;
42764
+ buckets[idx] = (buckets[idx] ?? 0) + vols[k];
42765
+ }
42766
+ let minIdx = 0;
42767
+ for (let i = 1;i < lv; i++) {
42768
+ if ((buckets[i] ?? 0) < (buckets[minIdx] ?? 0))
42769
+ minIdx = i;
42770
+ }
42771
+ return finiteOut2(minP + minIdx * bucket);
42772
+ }
42773
+ volumeThrust(site, close, volume, volSma, sensitivity) {
42774
+ const sens = Number.isFinite(sensitivity) ? sensitivity : 0.3;
42775
+ let st = this.volThrustSites.get(site);
42776
+ if (st === undefined) {
42777
+ st = { close: [], volume: [], sma: [] };
42778
+ this.volThrustSites.set(site, st);
42779
+ }
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)
42784
+ 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);
42790
+ const spike = vVal > vsVal * (1 + sens);
42791
+ const move = cPrev !== 0 ? Math.abs(cVal - cPrev) / cPrev > 0.01 : false;
42792
+ return spike && move ? 1 : 0;
42793
+ }
42194
42794
  }
42195
42795
  function spearmanRho(vals) {
42196
42796
  const n = vals.length;
@@ -42572,7 +43172,9 @@ var NS = new Set([
42572
43172
  "session",
42573
43173
  "syminfo",
42574
43174
  "timenow",
42575
- "chart"
43175
+ "chart",
43176
+ "footprint",
43177
+ "volume_row"
42576
43178
  ]);
42577
43179
  var TA_METHODS = new Set([
42578
43180
  "sma",
@@ -42660,7 +43262,24 @@ var TA_METHODS = new Set([
42660
43262
  "emv",
42661
43263
  "fractal",
42662
43264
  "atr_stop",
42663
- "zigzag"
43265
+ "zigzag",
43266
+ "hammer",
43267
+ "gap_detector",
43268
+ "macd_signal",
43269
+ "acceleration_factor",
43270
+ "stoch_smooth",
43271
+ "engulfing",
43272
+ "inside_bar_pattern",
43273
+ "double_top_bottom",
43274
+ "voi",
43275
+ "bid_ask_imbalance",
43276
+ "rsi_oversold_overbought",
43277
+ "rsi_divergence",
43278
+ "cumulative_delta",
43279
+ "volume_momentum",
43280
+ "volume_profile_high",
43281
+ "volume_profile_low",
43282
+ "volume_thrust"
42664
43283
  ]);
42665
43284
  var TA_BARE_ATTRS = new Set([
42666
43285
  "accdist",
@@ -42862,8 +43481,17 @@ function emitCall2(ctx, node, visit) {
42862
43481
  const msg = pick(args, 0, ["message", "msg"], `"runtime.error"`);
42863
43482
  return `(() => { throw new Error(String(${msg})); })()`;
42864
43483
  }
42865
- if (name === "alertcondition")
43484
+ if (name === "max_bars_back")
42866
43485
  return "null";
43486
+ if (name === "timenow")
43487
+ return "__h.timenow(time_arr)";
43488
+ if (name === "alertcondition") {
43489
+ ctx.usesDrawings = true;
43490
+ const cond = pick(args, 0, ["condition"], "null");
43491
+ const title = hasArg(args, 1, ["title"]) ? pick(args, 1, ["title"], `"Alert"`) : `"Alert"`;
43492
+ const message = hasArg(args, 2, ["message"]) ? pick(args, 2, ["message"], `"Alert"`) : `"Alert"`;
43493
+ return `__h.draw.alertcondition(__bar_idx, ${cond}, ${title}, ${message})`;
43494
+ }
42867
43495
  if (name === "str_tostring" || name === "tostring") {
42868
43496
  const x = pick(args, 0, ["value", "source", "x"], "null");
42869
43497
  return `String(${x} ?? "")`;
@@ -42924,6 +43552,9 @@ function emitCall2(ctx, node, visit) {
42924
43552
  const req = emitRequest(ctx, name, args);
42925
43553
  if (req != null)
42926
43554
  return req;
43555
+ const fp = emitFootprint(name, args);
43556
+ if (fp != null)
43557
+ return fp;
42927
43558
  return "null";
42928
43559
  }
42929
43560
  function resolveCallee(func) {
@@ -43002,6 +43633,12 @@ function periodGate(expr, fb) {
43002
43633
  function finiteOr2(expr, fb) {
43003
43634
  return `((__v) => (__v != null && Number.isFinite(__v) ? __v : ${fb}))(${expr})`;
43004
43635
  }
43636
+ function cellOf(expr) {
43637
+ return `((__c) => (__c == null ? null : typeof __c === "boolean" ? (__c ? 1 : 0) : (typeof __c === "number" && Number.isFinite(__c) ? __c : null)))(${expr})`;
43638
+ }
43639
+ function cellList(expr) {
43640
+ 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
+ }
43005
43642
  var DRAW_KINDS = new Set(["label", "line", "box", "table", "polyline", "linefill"]);
43006
43643
  var ARRAY_SIGS = {
43007
43644
  new: [["size"], ["initial_value", "initial"]],
@@ -43172,6 +43809,10 @@ function emitArray(name, args) {
43172
43809
  const raw = nsMethod(name, "array_");
43173
43810
  if (raw == null)
43174
43811
  return null;
43812
+ if (raw === "from") {
43813
+ const parts = args.pos.length > 0 ? args.pos : Object.values(args.kw);
43814
+ return `__h.array.from([${parts.join(", ")}])`;
43815
+ }
43175
43816
  const method = ctorMethod(raw);
43176
43817
  const params = ARRAY_SIGS[method];
43177
43818
  if (params == null)
@@ -43216,11 +43857,24 @@ var DRAW_METHODS = {
43216
43857
  label: {
43217
43858
  set_text: [["id"], ["text"]],
43218
43859
  set_xy: [["id"], ["x"], ["y"]],
43860
+ set_x: [["id"], ["x"]],
43861
+ set_y: [["id"], ["y"]],
43219
43862
  set_color: [["id"], ["color"]],
43220
43863
  set_style: [["id"], ["style"]],
43221
43864
  set_size: [["id"], ["size"]],
43222
43865
  set_tooltip: [["id"], ["tooltip"]],
43223
43866
  set_textalign: [["id"], ["textalign"]],
43867
+ set_textcolor: [["id"], ["color", "textcolor"]],
43868
+ set_text_font_family: [["id"], ["font_family", "text_font_family"]],
43869
+ set_text_halign: [["id"], ["halign", "text_halign"]],
43870
+ set_text_valign: [["id"], ["valign", "text_valign"]],
43871
+ set_text_size: [["id"], ["size", "text_size"]],
43872
+ set_text_formatting: [["id"], ["formatting", "text_formatting"]],
43873
+ set_border_color: [["id"], ["color"]],
43874
+ set_border_width: [["id"], ["width"]],
43875
+ set_border_style: [["id"], ["style"]],
43876
+ set_xloc: [["id"], ["xloc"]],
43877
+ set_yloc: [["id"], ["yloc"]],
43224
43878
  delete: [["id"]],
43225
43879
  get_text: [["id"]],
43226
43880
  get_x: [["id"]],
@@ -43228,12 +43882,17 @@ var DRAW_METHODS = {
43228
43882
  },
43229
43883
  line: {
43230
43884
  set_xy: [["id"], ["x1"], ["y1"], ["x2"], ["y2"]],
43231
- set_xy1: [["id"], ["x1"], ["y1"]],
43232
- set_xy2: [["id"], ["x2"], ["y2"]],
43885
+ set_xy1: [["id"], ["x1", "x"], ["y1", "y"]],
43886
+ set_xy2: [["id"], ["x2", "x"], ["y2", "y"]],
43887
+ set_x1: [["id"], ["x1", "x"]],
43888
+ set_y1: [["id"], ["y1", "y"]],
43889
+ set_x2: [["id"], ["x2", "x"]],
43890
+ set_y2: [["id"], ["y2", "y"]],
43233
43891
  set_color: [["id"], ["color"]],
43234
43892
  set_width: [["id"], ["width"]],
43235
43893
  set_style: [["id"], ["style"]],
43236
43894
  set_extend: [["id"], ["extend"]],
43895
+ set_xloc: [["id"], ["xloc"]],
43237
43896
  delete: [["id"]],
43238
43897
  get_price: [["id"], ["x"]],
43239
43898
  get_x1: [["id"]],
@@ -43244,44 +43903,137 @@ var DRAW_METHODS = {
43244
43903
  box: {
43245
43904
  set_corners: [["id"], ["left", "x1"], ["top", "y1"], ["right", "x2"], ["bottom", "y2"]],
43246
43905
  set_lefttop: [["id"], ["left", "x1"], ["top", "y1"], ["right", "x2"], ["bottom", "y2"]],
43906
+ set_left: [["id"], ["left"]],
43907
+ set_right: [["id"], ["right"]],
43908
+ set_top: [["id"], ["top"]],
43909
+ set_bottom: [["id"], ["bottom"]],
43247
43910
  set_bgcolor: [["id"], ["bgcolor", "color"]],
43248
43911
  set_border_color: [["id"], ["color", "border_color"]],
43912
+ set_border_width: [["id"], ["width"]],
43913
+ set_border_style: [["id"], ["style"]],
43249
43914
  set_text: [["id"], ["text"]],
43915
+ set_text_color: [["id"], ["color", "text_color"]],
43916
+ set_text_font_family: [["id"], ["font_family"]],
43917
+ set_text_halign: [["id"], ["halign"]],
43918
+ set_text_valign: [["id"], ["valign"]],
43919
+ set_text_size: [["id"], ["size"]],
43920
+ set_text_formatting: [["id"], ["formatting"]],
43921
+ set_text_wrap: [["id"], ["wrap"]],
43250
43922
  set_extend: [["id"], ["extend"]],
43923
+ set_closed: [["id"], ["closed"]],
43924
+ set_rightbottom: [["id"], ["right"], ["bottom"]],
43925
+ get_left: [["id"]],
43926
+ get_right: [["id"]],
43927
+ get_top: [["id"]],
43928
+ get_bottom: [["id"]],
43251
43929
  delete: [["id"]]
43252
43930
  },
43253
43931
  table: {
43254
43932
  cell: [["id"], ["column", "col"], ["row"], ["text"]],
43255
- cell_set_text: [["id"], ["column", "col"], ["row"], ["text"]],
43933
+ cell_set_text: [["id"], ["row"], ["column", "col"], ["text"]],
43934
+ cell_get_text: [["id"], ["row"], ["column", "col"]],
43935
+ cell_set_text_color: [["id"], ["row"], ["column", "col"], ["color", "text"]],
43936
+ cell_set_bgcolor: [["id"], ["row"], ["column", "col"], ["color"]],
43937
+ cell_set_border_color: [["id"], ["row"], ["column", "col"], ["color"]],
43938
+ cell_set_border_width: [["id"], ["row"], ["column", "col"], ["width"]],
43939
+ cell_set_tooltip: [["id"], ["row"], ["column", "col"], ["tooltip", "text"]],
43940
+ cell_set_width: [["id"], ["column", "col"], ["row"], ["width"]],
43941
+ cell_set_height: [["id"], ["column", "col"], ["row"], ["height"]],
43942
+ cell_set_text_halign: [["id"], ["column", "col"], ["row"], ["halign"]],
43943
+ cell_set_text_valign: [["id"], ["column", "col"], ["row"], ["valign"]],
43944
+ cell_set_text_size: [["id"], ["column", "col"], ["row"], ["size"]],
43945
+ cell_set_text_font_family: [["id"], ["column", "col"], ["row"], ["font_family"]],
43946
+ cell_set_text_formatting: [["id"], ["column", "col"], ["row"], ["formatting"]],
43256
43947
  set_position: [["id"], ["position"]],
43948
+ set_bgcolor: [["id"], ["color", "bgcolor"]],
43949
+ set_border_color: [["id"], ["color"]],
43950
+ set_border_width: [["id"], ["width"]],
43951
+ set_frame_color: [["id"], ["color"]],
43952
+ set_frame_width: [["id"], ["width"]],
43953
+ merge_cells: [["id"], ["start_row"], ["start_column", "start_col"], ["end_row"], ["end_column", "end_col"]],
43257
43954
  delete: [["id"]]
43258
43955
  },
43259
43956
  polyline: {
43260
- delete: [["id"]]
43957
+ delete: [["id"]],
43958
+ get_points: [["id"]],
43959
+ set_points: [["id"], ["points"]],
43960
+ set_line_color: [["id"], ["color"]],
43961
+ set_line_width: [["id"], ["width"]],
43962
+ set_line_style: [["id"], ["style"]],
43963
+ set_fill_color: [["id"], ["fill_color", "color"]],
43964
+ set_curved: [["id"], ["curved"]],
43965
+ set_force_overlay: [["id"], ["force_overlay"]],
43966
+ set_closed: [["id"], ["closed"]],
43967
+ set_xloc: [["id"], ["xloc"]]
43261
43968
  },
43262
43969
  linefill: {
43263
43970
  set_color: [["id"], ["color"]],
43264
- delete: [["id"]]
43971
+ delete: [["id"]],
43972
+ get_line1: [["id"]],
43973
+ get_line2: [["id"]]
43265
43974
  }
43266
43975
  };
43976
+ function emitChartPoint(name, args) {
43977
+ const meth = name.slice("chart_point_".length);
43978
+ if (meth === "new" || meth === "from_time") {
43979
+ return `__h.draw.point_new(${pick(args, 0, ["time"], "null")}, ${pick(args, 1, ["price"], "0")})`;
43980
+ }
43981
+ if (meth === "from_index") {
43982
+ return `__h.draw.point_from_index(${pick(args, 0, ["index"], "null")}, ${pick(args, 1, ["price"], "0")})`;
43983
+ }
43984
+ if (meth === "now") {
43985
+ return `__h.draw.point_now(__bar_idx, time, ${pick(args, 0, ["price"], "0")})`;
43986
+ }
43987
+ if (meth === "copy") {
43988
+ return `__h.draw.point_copy(${pick(args, 0, ["point"], "null")})`;
43989
+ }
43990
+ return null;
43991
+ }
43267
43992
  function emitDraw(ctx, name, methodSrc, args) {
43268
43993
  if (name === "alert" && methodSrc == null) {
43269
43994
  ctx.usesDrawings = true;
43270
43995
  return `__h.draw.alert(__bar_idx, ${pick(args, 0, ["message"], "null")})`;
43271
43996
  }
43997
+ if (name.startsWith("chart_point_")) {
43998
+ const point = emitChartPoint(name, args);
43999
+ if (point != null)
44000
+ ctx.usesDrawings = true;
44001
+ return point;
44002
+ }
43272
44003
  const parsed = drawKindAndMethod(name, methodSrc);
43273
44004
  if (parsed == null)
43274
44005
  return null;
43275
44006
  const { kind, method } = parsed;
43276
44007
  let code = null;
43277
- if (method === "new") {
44008
+ if (method === "all") {
44009
+ code = `__h.draw.all(${JSON.stringify(kind)})`;
44010
+ } else if (method === "copy" && (kind === "line" || kind === "label" || kind === "box" || kind === "polyline")) {
44011
+ code = `__h.draw.copy(${pick(args, 0, ["id"], "null")})`;
44012
+ } else if (method === "new") {
43278
44013
  if (kind === "label") {
43279
- code = `__h.draw.label_new(__bar_idx, ${pick(args, 2, ["text"], "null")})`;
44014
+ code = `__h.draw.label_new(__bar_idx, ${pick(args, 2, ["text"], "null")}, ${pick(args, 0, ["x"], "0")}, ${pick(args, 1, ["y"], "0")})`;
44015
+ } else if (kind === "line") {
44016
+ code = `__h.draw.line_new(__bar_idx, ${pick(args, 0, ["x1"], "0")}, ${pick(args, 1, ["y1"], "0")}, ${pick(args, 2, ["x2"], "0")}, ${pick(args, 3, ["y2"], "0")})`;
44017
+ } else if (kind === "box") {
44018
+ 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
+ } else if (kind === "polyline") {
44020
+ code = `__h.draw.polyline_new(__bar_idx, ${pick(args, 0, ["points"], "null")})`;
43280
44021
  } else if (kind === "linefill") {
43281
- code = `__h.draw.linefill_new(__bar_idx, ${pick(args, 0, ["id1"], "null")}, ${pick(args, 1, ["id2"], "null")})`;
44022
+ const color = hasArg(args, 2, ["color"]) ? pick(args, 2, ["color"], "null") : "null";
44023
+ code = `__h.draw.linefill_new(__bar_idx, ${pick(args, 0, ["id1", "line1"], "null")}, ${pick(args, 1, ["id2", "line2"], "null")}, ${color})`;
43282
44024
  } else if (DRAW_KINDS.has(kind)) {
43283
44025
  code = `__h.draw.${kind}_new(__bar_idx)`;
43284
44026
  }
44027
+ } else if (kind === "line" && method === "fill") {
44028
+ const color = hasArg(args, 2, ["color"]) ? pick(args, 2, ["color"], "null") : "null";
44029
+ code = `__h.draw.linefill_new(__bar_idx, ${pick(args, 0, ["id1", "line1"], "null")}, ${pick(args, 1, ["id2", "line2"], "null")}, ${color})`;
44030
+ } else if (kind === "line" && (method === "set_first_point" || method === "set_second_point") || kind === "label" && method === "set_point" || kind === "box" && (method === "set_top_left_point" || method === "set_bottom_right_point")) {
44031
+ code = `__h.draw.${kind}_${method}(${pick(args, 0, ["id"], "null")}, ${pick(args, 1, ["point"], "null")})`;
44032
+ } else if (kind === "box" && method === "set_xloc") {
44033
+ code = `__h.draw.box_set_xloc(${pick(args, 0, ["id"], "null")}, ${pick(args, 1, ["left"], "null")}, ${pick(args, 2, ["right"], "null")}, ${pick(args, 3, ["xloc"], "null")})`;
44034
+ } else if (kind === "table" && method === "clear") {
44035
+ const id = pick(args, 0, ["id", "table_id"], "null");
44036
+ code = hasArg(args, 1, ["start_row"]) ? `__h.draw.table_clear(${id}, ${pick(args, 1, ["start_row"], "null")}, ${pick(args, 2, ["start_column", "start_col"], "null")}, ${pick(args, 3, ["end_row"], "null")}, ${pick(args, 4, ["end_column", "end_col"], "null")})` : `__h.draw.table_clear(${id})`;
43285
44037
  } else {
43286
44038
  const aliased = kind === "box" && method === "set_lefttop" ? "set_corners" : method;
43287
44039
  const params = DRAW_METHODS[kind]?.[method] ?? DRAW_METHODS[kind]?.[aliased];
@@ -43330,9 +44082,9 @@ function emitUdt(ctx, name, methodSrc, args) {
43330
44082
  }
43331
44083
  var SECURITY_FUNCS = new Set([
43332
44084
  "security",
44085
+ "security_lower_tf",
43333
44086
  "request_security",
43334
- "request_security_lower_tf",
43335
- "request_seed"
44087
+ "request_security_lower_tf"
43336
44088
  ]);
43337
44089
  var SIMPLE_CHART_EXPR = new Set([
43338
44090
  "close",
@@ -43370,10 +44122,58 @@ function emitRequest(ctx, name, args) {
43370
44122
  if (name === "request_currency_rate" || name === "currency_rate") {
43371
44123
  return `__h.currencyRate(${pick(args, 0, ["from", "from_currency"], "null")}, ${pick(args, 1, ["to", "to_currency"], "null")})`;
43372
44124
  }
44125
+ if (name === "request_seed") {
44126
+ return `__h.requestSeed(${pick(args, 0, ["seed"], "0")})`;
44127
+ }
44128
+ if (name === "request_footprint") {
44129
+ return `__h.requestFootprint(${pick(args, 0, ["num_ticks"], "100")}, ${pick(args, 1, ["va_percentage"], "70")})`;
44130
+ }
43373
44131
  if (name.startsWith("request_"))
43374
44132
  return "null";
43375
44133
  return null;
43376
44134
  }
44135
+ function emitFootprint(name, args) {
44136
+ const fp = pick(args, 0, ["id", "footprint"], "null");
44137
+ const vr = pick(args, 0, ["id", "volume_row"], "null");
44138
+ switch (name) {
44139
+ case "footprint_buy_volume":
44140
+ return `__h.footprint.buy_volume(${fp})`;
44141
+ case "footprint_sell_volume":
44142
+ return `__h.footprint.sell_volume(${fp})`;
44143
+ case "footprint_delta":
44144
+ return `__h.footprint.delta(${fp})`;
44145
+ case "footprint_total_volume":
44146
+ return `__h.footprint.total_volume(${fp})`;
44147
+ case "footprint_vah":
44148
+ return `__h.footprint.vah(${fp})`;
44149
+ case "footprint_val":
44150
+ return `__h.footprint.val(${fp})`;
44151
+ case "footprint_poc":
44152
+ return `__h.footprint.poc(${fp})`;
44153
+ case "footprint_rows":
44154
+ return `__h.footprint.rows(${fp})`;
44155
+ case "footprint_get_row_by_price":
44156
+ return `__h.footprint.get_row_by_price(${fp}, ${pick(args, 1, ["price"], "null")})`;
44157
+ case "volume_row_up_price":
44158
+ return `__h.footprint.volume_row.up_price(${vr})`;
44159
+ case "volume_row_down_price":
44160
+ return `__h.footprint.volume_row.down_price(${vr})`;
44161
+ case "volume_row_buy_volume":
44162
+ return `__h.footprint.volume_row.buy_volume(${vr})`;
44163
+ case "volume_row_sell_volume":
44164
+ return `__h.footprint.volume_row.sell_volume(${vr})`;
44165
+ case "volume_row_delta":
44166
+ return `__h.footprint.volume_row.delta(${vr})`;
44167
+ case "volume_row_total_volume":
44168
+ return `__h.footprint.volume_row.total_volume(${vr})`;
44169
+ case "volume_row_has_buy_imbalance":
44170
+ return `__h.footprint.volume_row.has_buy_imbalance(${vr})`;
44171
+ case "volume_row_has_sell_imbalance":
44172
+ return `__h.footprint.volume_row.has_sell_imbalance(${vr})`;
44173
+ default:
44174
+ return null;
44175
+ }
44176
+ }
43377
44177
  function isSimpleSecurityExpr(expr) {
43378
44178
  const e = expr.trim();
43379
44179
  if (!e)
@@ -43480,6 +44280,7 @@ function emitStrategyDecl(ctx, args) {
43480
44280
  add(["default_qty_type"], "default_qty_type");
43481
44281
  add(["default_qty_value"], "default_qty_value");
43482
44282
  add(["initial_capital"], "initial_capital");
44283
+ add(["currency"], "currency");
43483
44284
  return `__h.strategy.configure({${fields.join(", ")}})`;
43484
44285
  }
43485
44286
  function emitStrategyEntry(method, args) {
@@ -43550,8 +44351,48 @@ function emitStrategy(ctx, name, args) {
43550
44351
  case "margin_liquidation_price":
43551
44352
  case "position_avg_price":
43552
44353
  case "initial_capital":
44354
+ case "cash":
44355
+ case "position_entry_name":
44356
+ case "account_currency":
44357
+ case "max_contracts_held_all":
44358
+ case "max_contracts_held_long":
44359
+ case "max_contracts_held_short":
44360
+ case "wintrades":
44361
+ case "losstrades":
44362
+ case "eventrades":
44363
+ case "grossprofit":
44364
+ case "grossloss":
44365
+ case "avg_trade":
44366
+ case "avg_winning_trade":
44367
+ case "avg_losing_trade":
44368
+ case "netprofit_percent":
44369
+ case "openprofit_percent":
44370
+ case "grossprofit_percent":
44371
+ case "grossloss_percent":
44372
+ case "avg_trade_percent":
44373
+ case "avg_winning_trade_percent":
44374
+ case "avg_losing_trade_percent":
44375
+ case "max_drawdown":
44376
+ case "max_drawdown_percent":
44377
+ case "max_runup":
44378
+ case "max_runup_percent":
44379
+ case "percent_profitable":
44380
+ case "winrate":
44381
+ case "profitfactor":
44382
+ case "profit_factor":
44383
+ case "capital_held":
44384
+ case "closedtrades_first_index":
43553
44385
  ctx.usesStrategy = true;
43554
44386
  return `__h.strategy.${method}()`;
44387
+ case "commission":
44388
+ return "0";
44389
+ case "default_entry_qty":
44390
+ ctx.usesStrategy = true;
44391
+ return hasArg(args, 0, ["percent_equity"]) ? `__h.strategy.default_entry_qty(${pick(args, 0, ["percent_equity"], "null")})` : `__h.strategy.default_entry_qty()`;
44392
+ case "convert_to_account":
44393
+ case "convert_to_symbol":
44394
+ ctx.usesStrategy = true;
44395
+ return hasArg(args, 0, ["value"]) ? `__h.strategy.convert_to(${pick(args, 0, ["value"], "null")})` : "1";
43555
44396
  case "risk_allow_entry_in":
43556
44397
  ctx.usesStrategy = true;
43557
44398
  return `__h.strategy.risk_allow_entry_in(${pick(args, 0, ["value"], "null")})`;
@@ -43561,10 +44402,36 @@ function emitStrategy(ctx, name, args) {
43561
44402
  case "risk_max_drawdown":
43562
44403
  ctx.usesStrategy = true;
43563
44404
  return `__h.strategy.risk_max_drawdown(${pick(args, 0, ["value"], "null")}, ${pick(args, 1, ["type"], "null")})`;
43564
- default:
44405
+ default: {
44406
+ if (method.startsWith("direction_")) {
44407
+ const tail = method.slice("direction_".length);
44408
+ if (tail === "long" || tail === "short" || tail === "all")
44409
+ return JSON.stringify(tail);
44410
+ }
44411
+ if (method.startsWith("oca_")) {
44412
+ const tail = method.slice("oca_".length);
44413
+ if (tail === "none" || tail === "cancel" || tail === "reduce")
44414
+ return JSON.stringify(tail);
44415
+ }
44416
+ if (method.startsWith("commission_")) {
44417
+ const tail = method.slice("commission_".length);
44418
+ if (tail === "percent" || tail === "cash_per_order" || tail === "cash_per_contract") {
44419
+ return JSON.stringify(tail);
44420
+ }
44421
+ }
44422
+ if (method.startsWith("closedtrades_") || method.startsWith("opentrades_")) {
44423
+ ctx.usesStrategy = true;
44424
+ if (method === "opentrades_capital_held")
44425
+ return "__h.strategy.capital_held()";
44426
+ if (method === "closedtrades_first_index")
44427
+ return "__h.strategy.closedtrades_first_index()";
44428
+ const idx = hasArg(args, 0, ["trade_num", "trade_index", "index"]) ? pick(args, 0, ["trade_num", "trade_index", "index"], "0") : "0";
44429
+ return `__h.strategy.${method}(${idx})`;
44430
+ }
43565
44431
  if (isStrategyAction(name, method))
43566
44432
  ctx.usesStrategy = true;
43567
44433
  return "null";
44434
+ }
43568
44435
  }
43569
44436
  }
43570
44437
  function seriesNameRef(ctx, id) {
@@ -43624,7 +44491,7 @@ function emitPlot(ctx, fname, args) {
43624
44491
  const series = ohlc ? pick(args, 3, ["close"], "null") : pick(args, 0, ["series", "source", "price"], "null");
43625
44492
  const i = ctx.plots.length;
43626
44493
  ctx.plots.push({ title });
43627
- return `plot_${i}[__bar_idx] = __h.naNum(${series})`;
44494
+ return `plot_${i}[__bar_idx] = __h.plotNum(${series})`;
43628
44495
  }
43629
44496
  function emitColor(name, args) {
43630
44497
  if (name === "color_r")
@@ -44180,6 +45047,79 @@ function emitTa(ctx, method, args) {
44180
45047
  ]);
44181
45048
  return `(() => { const __r = ${call}; return [__r.high, __r.low, __r.dir]; })()`;
44182
45049
  }
45050
+ if (method === "hammer") {
45051
+ return `__h.ta.hammer(${cellOf(pick(args, 0, ["open"], "null"))}, ${cellOf(pick(args, 1, ["high"], "null"))}, ${cellOf(pick(args, 2, ["low"], "null"))}, ${cellOf(pick(args, 3, ["close"], "null"))})`;
45052
+ }
45053
+ if (method === "gap_detector") {
45054
+ return `__h.ta.gapDetector(${cellOf(pick(args, 0, ["high"], "null"))}, ${cellOf(pick(args, 1, ["low"], "null"))}, ${cellOf(pick(args, 2, ["prev_close", "prev"], "null"))})`;
45055
+ }
45056
+ if (method === "macd_signal") {
45057
+ return `__h.ta.macdSignal(${cellOf(pick(args, 0, ["macd_line", "macd"], "null"))}, ${cellOf(pick(args, 1, ["signal_line", "signal"], "null"))})`;
45058
+ }
45059
+ if (method === "acceleration_factor") {
45060
+ return taCall("accelerationFactor", site, [
45061
+ cellOf(pick(args, 0, ["momentum_list", "momentum", "source", "series"], "null")),
45062
+ cellOf(pick(args, 1, ["period", "length"], "null"))
45063
+ ]);
45064
+ }
45065
+ 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"))})`;
45067
+ }
45068
+ 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(); })()`;
45070
+ }
45071
+ if (method === "inside_bar_pattern") {
45072
+ return `(() => { ${cellOf(pick(args, 0, ["high"], "null"))}; ${cellOf(pick(args, 1, ["low"], "null"))}; return __h.ta.insideBarPattern(); })()`;
45073
+ }
45074
+ 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"))}); })()`;
45076
+ }
45077
+ if (method === "voi") {
45078
+ return `__h.ta.voi(${cellOf(pick(args, 0, ["buy_volume", "buy"], "null"))}, ${cellOf(pick(args, 1, ["sell_volume", "sell"], "null"))})`;
45079
+ }
45080
+ if (method === "bid_ask_imbalance") {
45081
+ return `__h.ta.bidAskImbalance(${cellOf(pick(args, 0, ["bid_size", "bid"], "null"))}, ${cellOf(pick(args, 1, ["ask_size", "ask"], "null"))}, ${cellOf(pick(args, 2, ["bid_price"], "null"))}, ${cellOf(pick(args, 3, ["ask_price"], "null"))})`;
45082
+ }
45083
+ if (method === "rsi_oversold_overbought") {
45084
+ return `__h.ta.rsiOversoldOverbought(${cellOf(pick(args, 0, ["rsi_series", "rsi", "source"], "null"))}, ${cellOf(pick(args, 1, ["oversold_level", "oversold"], "null"))}, ${cellOf(pick(args, 2, ["overbought_level", "overbought"], "null"))})`;
45085
+ }
45086
+ if (method === "rsi_divergence") {
45087
+ 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})`;
45089
+ }
45090
+ if (method === "cumulative_delta") {
45091
+ return taCall("cumulativeDelta", site, [
45092
+ cellOf(pick(args, 0, ["close", "source"], "null")),
45093
+ cellOf(pick(args, 1, ["volume"], "null")),
45094
+ cellOf(pick(args, 2, ["period", "length"], "null"))
45095
+ ]);
45096
+ }
45097
+ if (method === "volume_momentum") {
45098
+ return taCall("volumeMomentum", site, [
45099
+ cellOf(pick(args, 0, ["volume", "source"], "null")),
45100
+ cellOf(pick(args, 1, ["period", "length"], "null"))
45101
+ ]);
45102
+ }
45103
+ if (method === "volume_profile_high") {
45104
+ return `__h.ta.volumeProfileHigh(${cellList(pick(args, 0, ["close", "price", "source", "series"], "null"))}, ${cellList(pick(args, 1, ["volume"], "null"))})`;
45105
+ }
45106
+ if (method === "volume_profile_low") {
45107
+ return taCall("volumeProfileLow", site, [
45108
+ cellOf(pick(args, 0, ["close", "source"], "null")),
45109
+ cellOf(pick(args, 1, ["volume"], "null")),
45110
+ cellOf(pick(args, 2, ["period", "length"], "null")),
45111
+ cellOf(pick(args, 3, ["levels"], "null"))
45112
+ ]);
45113
+ }
45114
+ if (method === "volume_thrust") {
45115
+ const sens = cellOf(pick(args, 3, ["sensitivity"], "null"));
45116
+ return taCall("volumeThrust", site, [
45117
+ cellOf(pick(args, 0, ["close", "source"], "null")),
45118
+ cellOf(pick(args, 1, ["volume"], "null")),
45119
+ cellOf(pick(args, 2, ["volume_sma", "vol_sma", "sma"], "null")),
45120
+ `((__n) => (__n == null ? 0.3 : __n))(${sens})`
45121
+ ]);
45122
+ }
44183
45123
  return "null";
44184
45124
  }
44185
45125
 
@@ -44557,6 +45497,8 @@ function emitName(state, node) {
44557
45497
  return id;
44558
45498
  if (state.ctx.enumTypes.has(id))
44559
45499
  return JSON.stringify(id);
45500
+ if (id === "timenow")
45501
+ return "__h.timenow(time_arr)";
44560
45502
  return safeIdent2(id);
44561
45503
  }
44562
45504
  function emitConstant2(node) {
@@ -44673,8 +45615,53 @@ var STRATEGY_QUERY_ATTRS = new Set([
44673
45615
  "leverage",
44674
45616
  "margin_liquidation_price",
44675
45617
  "position_avg_price",
44676
- "initial_capital"
45618
+ "initial_capital",
45619
+ "cash",
45620
+ "position_entry_name",
45621
+ "account_currency",
45622
+ "default_entry_qty",
45623
+ "max_contracts_held_all",
45624
+ "max_contracts_held_long",
45625
+ "max_contracts_held_short",
45626
+ "wintrades",
45627
+ "losstrades",
45628
+ "eventrades",
45629
+ "grossprofit",
45630
+ "grossloss",
45631
+ "avg_trade",
45632
+ "avg_winning_trade",
45633
+ "avg_losing_trade",
45634
+ "netprofit_percent",
45635
+ "openprofit_percent",
45636
+ "grossprofit_percent",
45637
+ "grossloss_percent",
45638
+ "avg_trade_percent",
45639
+ "avg_winning_trade_percent",
45640
+ "avg_losing_trade_percent",
45641
+ "max_drawdown",
45642
+ "max_drawdown_percent",
45643
+ "max_runup",
45644
+ "max_runup_percent",
45645
+ "percent_profitable",
45646
+ "winrate",
45647
+ "profitfactor",
45648
+ "profit_factor"
44677
45649
  ]);
45650
+ var STRATEGY_NESTED_CONSTS = {
45651
+ "strategy.direction.long": "long",
45652
+ "strategy.direction.short": "short",
45653
+ "strategy.direction.all": "all",
45654
+ "strategy.oca.none": "none",
45655
+ "strategy.oca.cancel": "cancel",
45656
+ "strategy.oca.reduce": "reduce",
45657
+ "strategy.commission.percent": "percent",
45658
+ "strategy.commission.cash_per_order": "cash_per_order",
45659
+ "strategy.commission.cash_per_contract": "cash_per_contract"
45660
+ };
45661
+ var STRATEGY_NESTED_CALLS = {
45662
+ "strategy.closedtrades.first_index": "closedtrades_first_index",
45663
+ "strategy.opentrades.capital_held": "capital_held"
45664
+ };
44678
45665
  var ATTR_NAMESPACES = new Set([
44679
45666
  "ta",
44680
45667
  "math",
@@ -44778,6 +45765,23 @@ var ATTR_CONSTANTS = {
44778
45765
  "hline.style_solid": "solid",
44779
45766
  "hline.style_dashed": "dashed",
44780
45767
  "hline.style_dotted": "dotted",
45768
+ "plot.linestyle_solid": "linestyle_solid",
45769
+ "plot.linestyle_dashed": "linestyle_dashed",
45770
+ "plot.linestyle_dotted": "linestyle_dotted",
45771
+ "plot.style_line": "style_line",
45772
+ "plot.style_linebr": "style_linebr",
45773
+ "plot.style_stepline": "style_stepline",
45774
+ "plot.style_steplinebr": "style_steplinebr",
45775
+ "plot.style_stepline_diamond": "style_stepline_diamond",
45776
+ "plot.style_histogram": "style_histogram",
45777
+ "plot.style_columns": "style_columns",
45778
+ "plot.style_cross": "style_cross",
45779
+ "plot.style_area": "style_area",
45780
+ "plot.style_areabr": "style_areabr",
45781
+ "plot.style_circles": "style_circles",
45782
+ "alert.freq_once_per_bar": "once_per_bar",
45783
+ "alert.freq_once_per_bar_close": "once_per_bar_close",
45784
+ "alert.freq_all": "all",
44781
45785
  "dayofweek.sunday": 1,
44782
45786
  "dayofweek.monday": 2,
44783
45787
  "dayofweek.tuesday": 3,
@@ -44813,6 +45817,8 @@ var ATTR_CONST_NS = new Set([
44813
45817
  "display",
44814
45818
  "position",
44815
45819
  "hline",
45820
+ "plot",
45821
+ "alert",
44816
45822
  "dayofweek",
44817
45823
  "month"
44818
45824
  ]);
@@ -44959,16 +45965,24 @@ function emitAttribute(state, node) {
44959
45965
  return `"futures"`;
44960
45966
  if (attr === "avg_price_inverse")
44961
45967
  return `"inverse"`;
44962
- if (attr === "cash")
44963
- return `"cash"`;
44964
45968
  if (attr === "fixed")
44965
45969
  return `"fixed"`;
44966
45970
  if (attr === "percent_of_equity")
44967
45971
  return `"percent_of_equity"`;
45972
+ if (attr === "commission")
45973
+ return "0";
44968
45974
  if (STRATEGY_QUERY_ATTRS.has(attr)) {
44969
45975
  state.ctx.usesStrategy = true;
44970
45976
  return `__h.strategy.${attr}()`;
44971
45977
  }
45978
+ return "null";
45979
+ }
45980
+ if (node.attr === "all" && node.value.kind === "Name") {
45981
+ const kind = node.value.id;
45982
+ if (kind === "line" || kind === "label" || kind === "box" || kind === "table" || kind === "polyline" || kind === "linefill") {
45983
+ state.ctx.usesDrawings = true;
45984
+ return `__h.draw.all(${JSON.stringify(kind)})`;
45985
+ }
44972
45986
  }
44973
45987
  if (node.value.kind === "Name") {
44974
45988
  const members = state.ctx.enumTypes.get(node.value.id);
@@ -44978,6 +45992,16 @@ function emitAttribute(state, node) {
44978
45992
  }
44979
45993
  const qn = attrQualifiedName(node);
44980
45994
  if (qn != null) {
45995
+ const nested = STRATEGY_NESTED_CONSTS[qn];
45996
+ if (nested !== undefined)
45997
+ return JSON.stringify(nested);
45998
+ const nestedCall = STRATEGY_NESTED_CALLS[qn];
45999
+ if (nestedCall != null) {
46000
+ state.ctx.usesStrategy = true;
46001
+ return `__h.strategy.${nestedCall}()`;
46002
+ }
46003
+ if (qn.startsWith("strategy.") && qn.split(".").length > 2)
46004
+ return "null";
44981
46005
  const dot = qn.indexOf(".");
44982
46006
  const root = dot < 0 ? qn : qn.slice(0, dot);
44983
46007
  if (ATTR_CONST_NS.has(root)) {
@@ -45737,6 +46761,9 @@ var compileArray = {
45737
46761
  new(size, initial) {
45738
46762
  return new PineArray(n2(size, 0), store(initial));
45739
46763
  },
46764
+ from(values) {
46765
+ return wrapCells(Array.isArray(values) ? values : []) ?? new PineArray;
46766
+ },
45740
46767
  get(id, index) {
45741
46768
  return asArray(id)?.get(n2(index, 0)) ?? null;
45742
46769
  },
@@ -46177,26 +47204,114 @@ function n3(v, fallback = 0) {
46177
47204
  function idOf(v) {
46178
47205
  return n3(v, -1);
46179
47206
  }
47207
+ function idNum(v) {
47208
+ if (typeof v === "boolean")
47209
+ return v ? 1 : 0;
47210
+ if (typeof v === "number" && Number.isFinite(v))
47211
+ return Math.trunc(v);
47212
+ return null;
47213
+ }
47214
+ function putNum(extra, key, v) {
47215
+ const x = naNum(v);
47216
+ if (x != null)
47217
+ extra[key] = x;
47218
+ }
47219
+ function pointsOf(v) {
47220
+ if (v instanceof PineArray)
47221
+ return v.toValues().filter((p) => p != null);
47222
+ if (Array.isArray(v))
47223
+ return v.filter((p) => p != null);
47224
+ return [];
47225
+ }
47226
+ function isPoint(v) {
47227
+ return typeof v === "object" && v !== null && v.__chartPoint === true;
47228
+ }
47229
+ function makePoint(index, time, price) {
47230
+ return { __chartPoint: true, index, time, x: index ?? time, y: price, price };
47231
+ }
47232
+ function pointXY(v) {
47233
+ if (!isPoint(v))
47234
+ return null;
47235
+ return { x: v.index ?? v.time ?? v.x ?? 0, y: v.price ?? v.y ?? 0 };
47236
+ }
47237
+ function truthy(v) {
47238
+ if (typeof v === "boolean")
47239
+ return v;
47240
+ if (typeof v === "number")
47241
+ return Number.isFinite(v) && v !== 0;
47242
+ return false;
47243
+ }
47244
+ function alertText(v, fallback) {
47245
+ if (v == null)
47246
+ return fallback;
47247
+ if (typeof v === "string")
47248
+ return v;
47249
+ if (typeof v === "boolean")
47250
+ return v ? "1" : "0";
47251
+ if (typeof v === "number")
47252
+ return Number.isFinite(v) ? String(v) : fallback;
47253
+ return fallback;
47254
+ }
47255
+ var DRAW_KINDS2 = new Set(["line", "label", "box", "table", "polyline", "linefill"]);
46180
47256
 
46181
47257
  class CompileDraw {
46182
47258
  book = new DrawingBook;
46183
- label_new(bar, text) {
46184
- return this.book.labelNew(n3(bar, 0), text == null ? undefined : String(text));
47259
+ alertKeys = new Map;
47260
+ label_new(bar, text, x, y) {
47261
+ const extra = {};
47262
+ putNum(extra, "x", x);
47263
+ putNum(extra, "y", y);
47264
+ const t = text == null ? "" : String(text);
47265
+ return this.book.labelNew(n3(bar, 0), t, Object.keys(extra).length ? extra : undefined);
46185
47266
  }
46186
- line_new(bar) {
46187
- return this.book.lineNew(n3(bar, 0));
47267
+ line_new(bar, x1, y1, x2, y2) {
47268
+ const extra = {};
47269
+ putNum(extra, "x1", x1);
47270
+ putNum(extra, "y1", y1);
47271
+ putNum(extra, "x2", x2);
47272
+ putNum(extra, "y2", y2);
47273
+ return this.book.lineNew(n3(bar, 0), Object.keys(extra).length ? extra : undefined);
46188
47274
  }
46189
- box_new(bar) {
46190
- return this.book.boxNew(n3(bar, 0));
47275
+ box_new(bar, left, top, right, bottom) {
47276
+ const extra = {};
47277
+ putNum(extra, "left", left);
47278
+ putNum(extra, "top", top);
47279
+ putNum(extra, "right", right);
47280
+ putNum(extra, "bottom", bottom);
47281
+ return this.book.boxNew(n3(bar, 0), Object.keys(extra).length ? extra : undefined);
46191
47282
  }
46192
47283
  table_new(bar) {
46193
47284
  return this.book.tableNew(n3(bar, 0));
46194
47285
  }
46195
- polyline_new(bar) {
46196
- return this.book.polylineNew(n3(bar, 0));
47286
+ polyline_new(bar, points) {
47287
+ const pts = pointsOf(points);
47288
+ return this.book.polylineNew(n3(bar, 0), pts.length ? { points: pts } : undefined);
47289
+ }
47290
+ linefill_new(bar, id1, id2, color) {
47291
+ const extra = {};
47292
+ const a = idNum(id1);
47293
+ const b = idNum(id2);
47294
+ if (a != null)
47295
+ extra.id1 = a;
47296
+ if (b != null)
47297
+ extra.id2 = b;
47298
+ if (color != null)
47299
+ extra.color = color;
47300
+ return this.book.linefillNew(n3(bar, 0), Object.keys(extra).length ? extra : undefined);
47301
+ }
47302
+ all(kind) {
47303
+ const arr = new PineArray;
47304
+ if (typeof kind === "string" && DRAW_KINDS2.has(kind)) {
47305
+ for (const id of this.book.allIds(kind))
47306
+ arr.push(id);
47307
+ }
47308
+ return arr;
46197
47309
  }
46198
- linefill_new(bar, extra) {
46199
- return this.book.linefillNew(n3(bar, 0), extra);
47310
+ copy(id) {
47311
+ const i = idNum(id);
47312
+ if (i == null)
47313
+ return null;
47314
+ return this.book.copy(i);
46200
47315
  }
46201
47316
  label_set_text(id, text) {
46202
47317
  this.book.labelSetText(idOf(id), text == null ? "" : String(text));
@@ -46250,13 +47365,38 @@ class CompileDraw {
46250
47365
  this.book.labelSetTooltip(idOf(id), tooltip);
46251
47366
  }
46252
47367
  label_get_x(id) {
46253
- return this.book.labelGetX(idOf(id));
47368
+ const i = idNum(id);
47369
+ if (i == null)
47370
+ return 0;
47371
+ return this.book.labelGetX(i) ?? 0;
46254
47372
  }
46255
47373
  label_get_y(id) {
46256
- return this.book.labelGetY(idOf(id));
47374
+ const i = idNum(id);
47375
+ if (i == null)
47376
+ return 0;
47377
+ return this.book.labelGetY(i) ?? 0;
46257
47378
  }
46258
47379
  label_get_text(id) {
46259
- return this.book.labelGetText(idOf(id));
47380
+ const i = idNum(id);
47381
+ if (i == null)
47382
+ return "";
47383
+ return this.book.labelGetText(i) ?? "";
47384
+ }
47385
+ line_get_x1(id) {
47386
+ const i = idNum(id);
47387
+ return i == null ? null : this.book.lineGetX1(i);
47388
+ }
47389
+ line_get_y1(id) {
47390
+ const i = idNum(id);
47391
+ return i == null ? null : this.book.lineGetY1(i);
47392
+ }
47393
+ line_get_x2(id) {
47394
+ const i = idNum(id);
47395
+ return i == null ? null : this.book.lineGetX2(i);
47396
+ }
47397
+ line_get_y2(id) {
47398
+ const i = idNum(id);
47399
+ return i == null ? null : this.book.lineGetY2(i);
46260
47400
  }
46261
47401
  box_delete(id) {
46262
47402
  this.book.boxDelete(idOf(id));
@@ -46282,8 +47422,18 @@ class CompileDraw {
46282
47422
  table_cell(id, column, row, text) {
46283
47423
  this.book.tableCell(idOf(id), column, row, text);
46284
47424
  }
46285
- table_cell_set_text(id, column, row, text) {
46286
- this.book.tableCellSetText(idOf(id), column, row, text);
47425
+ table_cell_set_text(id, row, column, text) {
47426
+ const i = idNum(id);
47427
+ if (i == null)
47428
+ return null;
47429
+ this.book.tableCellSetText(i, column, row, text == null ? "" : String(text));
47430
+ return null;
47431
+ }
47432
+ table_cell_get_text(id, row, column) {
47433
+ const i = idNum(id);
47434
+ if (i == null)
47435
+ return "";
47436
+ return this.book.tableCellGetText(i, column, row) ?? "";
46287
47437
  }
46288
47438
  table_set_position(id, position) {
46289
47439
  this.book.tableSetPosition(idOf(id), position);
@@ -46294,6 +47444,361 @@ class CompileDraw {
46294
47444
  alert(bar, message) {
46295
47445
  this.book.alert(n3(bar, 0), message == null ? "" : String(message));
46296
47446
  }
47447
+ alertcondition(bar, condition, title, message) {
47448
+ if (!truthy(condition))
47449
+ return null;
47450
+ const t = alertText(title, "Alert");
47451
+ const m = alertText(message, "Alert");
47452
+ const b = n3(bar, 0);
47453
+ const key = `alertcondition|${t}|${m}|once_per_bar`;
47454
+ if (this.alertKeys.get(key) === b)
47455
+ return null;
47456
+ this.alertKeys.set(key, b);
47457
+ this.book.alert(b, m);
47458
+ const ev = this.book.items[this.book.items.length - 1];
47459
+ if (ev != null)
47460
+ ev.extra = { source: "alertcondition", title: t, freq: "once_per_bar" };
47461
+ return null;
47462
+ }
47463
+ line_set_x1(id, x) {
47464
+ return this.kindNum("lineSetX1", id, x);
47465
+ }
47466
+ line_set_y1(id, y) {
47467
+ return this.kindNum("lineSetY1", id, y);
47468
+ }
47469
+ line_set_x2(id, x) {
47470
+ return this.kindNum("lineSetX2", id, x);
47471
+ }
47472
+ line_set_y2(id, y) {
47473
+ return this.kindNum("lineSetY2", id, y);
47474
+ }
47475
+ line_set_xloc(id, xloc) {
47476
+ return this.kindAny("lineSetXloc", id, xloc);
47477
+ }
47478
+ line_set_first_point(id, point) {
47479
+ const i = idNum(id);
47480
+ const xy = pointXY(point);
47481
+ if (i != null && xy)
47482
+ this.book.lineSetXy1(i, xy.x, xy.y);
47483
+ return null;
47484
+ }
47485
+ line_set_second_point(id, point) {
47486
+ const i = idNum(id);
47487
+ const xy = pointXY(point);
47488
+ if (i != null && xy)
47489
+ this.book.lineSetXy2(i, xy.x, xy.y);
47490
+ return null;
47491
+ }
47492
+ label_set_x(id, x) {
47493
+ return this.kindAny("labelSetX", id, x);
47494
+ }
47495
+ label_set_y(id, y) {
47496
+ return this.kindAny("labelSetY", id, y);
47497
+ }
47498
+ label_set_textcolor(id, color) {
47499
+ return this.kindAny("labelSetTextcolor", id, color);
47500
+ }
47501
+ label_set_text_font_family(id, font) {
47502
+ return this.kindAny("labelSetTextFontFamily", id, font);
47503
+ }
47504
+ label_set_text_halign(id, halign) {
47505
+ return this.kindAny("labelSetTextHalign", id, halign);
47506
+ }
47507
+ label_set_text_valign(id, valign) {
47508
+ return this.kindAny("labelSetTextValign", id, valign);
47509
+ }
47510
+ label_set_text_size(id, size) {
47511
+ return this.kindAny("labelSetTextSize", id, size);
47512
+ }
47513
+ label_set_text_formatting(id, formatting) {
47514
+ return this.kindAny("labelSetTextFormatting", id, formatting);
47515
+ }
47516
+ label_set_border_color(id, color) {
47517
+ return this.kindAny("labelSetBorderColor", id, color);
47518
+ }
47519
+ label_set_border_width(id, width) {
47520
+ return this.kindAny("labelSetBorderWidth", id, width);
47521
+ }
47522
+ label_set_border_style(id, style) {
47523
+ return this.kindAny("labelSetBorderStyle", id, style);
47524
+ }
47525
+ label_set_xloc(id, xloc) {
47526
+ return this.kindAny("labelSetXloc", id, xloc);
47527
+ }
47528
+ label_set_yloc(id, yloc) {
47529
+ return this.kindAny("labelSetYloc", id, yloc);
47530
+ }
47531
+ label_set_point(id, point) {
47532
+ const i = idNum(id);
47533
+ const xy = pointXY(point);
47534
+ if (i != null && xy)
47535
+ this.book.labelSetXy(i, xy.x, xy.y);
47536
+ return null;
47537
+ }
47538
+ box_get_left(id) {
47539
+ return this.boxGet("boxGetLeft", id);
47540
+ }
47541
+ box_get_right(id) {
47542
+ return this.boxGet("boxGetRight", id);
47543
+ }
47544
+ box_get_top(id) {
47545
+ return this.boxGet("boxGetTop", id);
47546
+ }
47547
+ box_get_bottom(id) {
47548
+ return this.boxGet("boxGetBottom", id);
47549
+ }
47550
+ box_set_left(id, left) {
47551
+ return this.kindAny("boxSetLeft", id, left);
47552
+ }
47553
+ box_set_right(id, right) {
47554
+ return this.kindAny("boxSetRight", id, right);
47555
+ }
47556
+ box_set_top(id, top) {
47557
+ return this.kindAny("boxSetTop", id, top);
47558
+ }
47559
+ box_set_bottom(id, bottom) {
47560
+ return this.kindAny("boxSetBottom", id, bottom);
47561
+ }
47562
+ box_set_border_width(id, width) {
47563
+ return this.kindAny("boxSetBorderWidth", id, width);
47564
+ }
47565
+ box_set_border_style(id, style) {
47566
+ return this.kindAny("boxSetBorderStyle", id, style);
47567
+ }
47568
+ box_set_closed(id, closed) {
47569
+ return this.kindAny("boxSetClosed", id, closed);
47570
+ }
47571
+ box_set_rightbottom(id, right, bottom) {
47572
+ const i = idNum(id);
47573
+ if (i != null)
47574
+ this.book.boxSetRightBottom(i, right, bottom);
47575
+ return null;
47576
+ }
47577
+ box_set_text_color(id, color) {
47578
+ return this.kindAny("boxSetTextColor", id, color);
47579
+ }
47580
+ box_set_text_font_family(id, font) {
47581
+ return this.kindAny("boxSetTextFontFamily", id, font);
47582
+ }
47583
+ box_set_text_halign(id, halign) {
47584
+ return this.kindAny("boxSetTextHalign", id, halign);
47585
+ }
47586
+ box_set_text_valign(id, valign) {
47587
+ return this.kindAny("boxSetTextValign", id, valign);
47588
+ }
47589
+ box_set_text_size(id, size) {
47590
+ return this.kindAny("boxSetTextSize", id, size);
47591
+ }
47592
+ box_set_text_formatting(id, formatting) {
47593
+ return this.kindAny("boxSetTextFormatting", id, formatting);
47594
+ }
47595
+ box_set_text_wrap(id, wrap) {
47596
+ return this.kindAny("boxSetTextWrap", id, wrap);
47597
+ }
47598
+ box_set_xloc(id, left, right, xloc) {
47599
+ const i = idNum(id);
47600
+ if (i == null)
47601
+ return null;
47602
+ this.book.boxSetLeft(i, left);
47603
+ this.book.boxSetRight(i, right);
47604
+ this.book.boxSetXloc(i, xloc);
47605
+ return null;
47606
+ }
47607
+ box_set_top_left_point(id, point) {
47608
+ const i = idNum(id);
47609
+ const xy = pointXY(point);
47610
+ if (i != null && xy)
47611
+ this.book.boxSetLeftTop(i, xy.x, xy.y);
47612
+ return null;
47613
+ }
47614
+ box_set_bottom_right_point(id, point) {
47615
+ const i = idNum(id);
47616
+ const xy = pointXY(point);
47617
+ if (i != null && xy)
47618
+ this.book.boxSetRightBottom(i, xy.x, xy.y);
47619
+ return null;
47620
+ }
47621
+ table_delete(id) {
47622
+ const i = idNum(id);
47623
+ if (i != null)
47624
+ this.book.tableDelete(i);
47625
+ return null;
47626
+ }
47627
+ table_set_bgcolor(id, color) {
47628
+ return this.kindAny("tableSetBgcolor", id, color);
47629
+ }
47630
+ table_set_border_color(id, color) {
47631
+ return this.kindAny("tableSetBorderColor", id, color);
47632
+ }
47633
+ table_set_border_width(id, width) {
47634
+ return this.kindAny("tableSetBorderWidth", id, width);
47635
+ }
47636
+ table_set_frame_color(id, color) {
47637
+ return this.kindAny("tableSetFrameColor", id, color);
47638
+ }
47639
+ table_set_frame_width(id, width) {
47640
+ return this.kindAny("tableSetFrameWidth", id, width);
47641
+ }
47642
+ table_clear(id, startRow, startCol, endRow, endCol) {
47643
+ const i = idNum(id);
47644
+ if (i == null)
47645
+ return null;
47646
+ if (arguments.length < 2)
47647
+ this.book.tableClear(i);
47648
+ else
47649
+ this.book.tableClear(i, startRow, startCol, endRow, endCol);
47650
+ return null;
47651
+ }
47652
+ table_merge_cells(id, startRow, startCol, endRow, endCol) {
47653
+ const i = idNum(id);
47654
+ if (i != null)
47655
+ this.book.tableMergeCells(i, startRow, startCol, endRow, endCol);
47656
+ return null;
47657
+ }
47658
+ table_cell_set_text_color(id, row, column, value) {
47659
+ return this.cellField(id, column, row, "text_color", value);
47660
+ }
47661
+ table_cell_set_bgcolor(id, row, column, value) {
47662
+ return this.cellField(id, column, row, "bgcolor", value);
47663
+ }
47664
+ table_cell_set_border_color(id, row, column, value) {
47665
+ return this.cellField(id, column, row, "border_color", value);
47666
+ }
47667
+ table_cell_set_border_width(id, row, column, value) {
47668
+ return this.cellField(id, column, row, "border_width", value);
47669
+ }
47670
+ table_cell_set_tooltip(id, row, column, value) {
47671
+ return this.cellField(id, column, row, "tooltip", value);
47672
+ }
47673
+ table_cell_set_width(id, column, row, value) {
47674
+ return this.cellField(id, column, row, "width", value);
47675
+ }
47676
+ table_cell_set_height(id, column, row, value) {
47677
+ return this.cellField(id, column, row, "height", value);
47678
+ }
47679
+ table_cell_set_text_halign(id, column, row, value) {
47680
+ return this.cellField(id, column, row, "text_halign", value);
47681
+ }
47682
+ table_cell_set_text_valign(id, column, row, value) {
47683
+ return this.cellField(id, column, row, "text_valign", value);
47684
+ }
47685
+ table_cell_set_text_size(id, column, row, value) {
47686
+ return this.cellField(id, column, row, "text_size", value);
47687
+ }
47688
+ table_cell_set_text_font_family(id, column, row, value) {
47689
+ return this.cellField(id, column, row, "text_font_family", value);
47690
+ }
47691
+ table_cell_set_text_formatting(id, column, row, value) {
47692
+ return this.cellField(id, column, row, "text_formatting", value);
47693
+ }
47694
+ polyline_delete(id) {
47695
+ const i = idNum(id);
47696
+ if (i != null)
47697
+ this.book.polylineDelete(i);
47698
+ return null;
47699
+ }
47700
+ polyline_get_points(id) {
47701
+ const arr = new PineArray;
47702
+ const i = idNum(id);
47703
+ if (i == null)
47704
+ return arr;
47705
+ for (const p of this.book.polylineGetPoints(i))
47706
+ arr.push(p);
47707
+ return arr;
47708
+ }
47709
+ polyline_set_points(id, points) {
47710
+ const i = idNum(id);
47711
+ if (i != null)
47712
+ this.book.polylineSetPoints(i, pointsOf(points));
47713
+ return null;
47714
+ }
47715
+ polyline_set_line_color(id, color) {
47716
+ return this.kindAny("polylineSetLineColor", id, color);
47717
+ }
47718
+ polyline_set_line_width(id, width) {
47719
+ return this.kindAny("polylineSetLineWidth", id, width);
47720
+ }
47721
+ polyline_set_line_style(id, style) {
47722
+ return this.kindAny("polylineSetLineStyle", id, style);
47723
+ }
47724
+ polyline_set_fill_color(id, color) {
47725
+ return this.kindAny("polylineSetFillColor", id, color);
47726
+ }
47727
+ polyline_set_curved(id, curved) {
47728
+ return this.kindAny("polylineSetCurved", id, curved);
47729
+ }
47730
+ polyline_set_force_overlay(id, force) {
47731
+ return this.kindAny("polylineSetForceOverlay", id, force);
47732
+ }
47733
+ polyline_set_closed(id, closed) {
47734
+ return this.kindAny("polylineSetClosed", id, closed);
47735
+ }
47736
+ polyline_set_xloc(id, xloc) {
47737
+ return this.kindAny("polylineSetXloc", id, xloc);
47738
+ }
47739
+ linefill_delete(id) {
47740
+ const i = idNum(id);
47741
+ if (i != null)
47742
+ this.book.linefillDelete(i);
47743
+ return null;
47744
+ }
47745
+ linefill_get_line1(id) {
47746
+ const i = idNum(id);
47747
+ return i == null ? null : this.book.linefillGetLine1(i);
47748
+ }
47749
+ linefill_get_line2(id) {
47750
+ const i = idNum(id);
47751
+ return i == null ? null : this.book.linefillGetLine2(i);
47752
+ }
47753
+ point_new(time, price) {
47754
+ const p = naNum(price);
47755
+ if (p == null)
47756
+ return null;
47757
+ return makePoint(null, naNum(time), p);
47758
+ }
47759
+ point_from_index(index, price) {
47760
+ const ix = naNum(index);
47761
+ const p = naNum(price);
47762
+ if (ix == null || p == null)
47763
+ return null;
47764
+ return makePoint(Math.trunc(ix), null, p);
47765
+ }
47766
+ point_now(bar, time, price) {
47767
+ const p = naNum(price);
47768
+ if (p == null)
47769
+ return null;
47770
+ const ix = naNum(bar);
47771
+ return makePoint(ix == null ? null : Math.trunc(ix), naNum(time), p);
47772
+ }
47773
+ point_copy(raw) {
47774
+ if (isPoint(raw))
47775
+ return makePoint(raw.index, raw.time, raw.price);
47776
+ return makePoint(null, null, 0);
47777
+ }
47778
+ kindNum(method, id, value) {
47779
+ const i = idNum(id);
47780
+ if (i != null)
47781
+ this.book[method](i, value);
47782
+ return null;
47783
+ }
47784
+ kindAny(method, id, value) {
47785
+ const i = idNum(id);
47786
+ if (i != null)
47787
+ this.book[method](i, value);
47788
+ return null;
47789
+ }
47790
+ boxGet(method, id) {
47791
+ const i = idNum(id);
47792
+ if (i == null)
47793
+ return 0;
47794
+ return this.book[method](i) ?? 0;
47795
+ }
47796
+ cellField(id, column, row, field, value) {
47797
+ const i = idNum(id);
47798
+ if (i != null)
47799
+ this.book.tableCellSetField(i, column, row, field, value);
47800
+ return null;
47801
+ }
46297
47802
  extras() {
46298
47803
  return { __drawings: this.book.items.slice() };
46299
47804
  }
@@ -46388,11 +47893,14 @@ class CompileStrategy {
46388
47893
  const ms = optNum(rec.margin_short);
46389
47894
  if (ms != null)
46390
47895
  broker.margin_short = ms;
46391
- if (typeof rec.default_qty_type === "string")
47896
+ if (typeof rec.default_qty_type === "string" || isStrategyCashAmount(rec.default_qty_type)) {
46392
47897
  broker.default_qty_type = rec.default_qty_type;
47898
+ }
46393
47899
  const dqv = optNum(rec.default_qty_value);
46394
47900
  if (dqv != null)
46395
47901
  broker.default_qty_value = dqv;
47902
+ if (typeof rec.currency === "string" && rec.currency !== "")
47903
+ broker.currency = rec.currency;
46396
47904
  if (Object.keys(broker).length)
46397
47905
  this.book.configure(broker);
46398
47906
  const capital = optNum(rec.initial_capital);
@@ -46487,6 +47995,192 @@ class CompileStrategy {
46487
47995
  initial_capital() {
46488
47996
  return this.book.initialCapital;
46489
47997
  }
47998
+ cash() {
47999
+ return strategyCashAmount(this.book.cash(this.mark));
48000
+ }
48001
+ position_entry_name() {
48002
+ return this.book.position_entry_name;
48003
+ }
48004
+ account_currency() {
48005
+ return this.book.account_currency;
48006
+ }
48007
+ default_entry_qty(percent) {
48008
+ const pct = arguments.length === 0 || percent === undefined ? 100 : naNum(percent);
48009
+ if (pct == null)
48010
+ return null;
48011
+ return this.book.initialCapital * (pct / 100) / 100;
48012
+ }
48013
+ convert_to(value) {
48014
+ if (arguments.length === 0 || value === undefined)
48015
+ return 1;
48016
+ return naNum(value);
48017
+ }
48018
+ max_contracts_held_all() {
48019
+ return this.book.maxContractsHeldAll();
48020
+ }
48021
+ max_contracts_held_long() {
48022
+ return this.book.maxContractsHeldLong();
48023
+ }
48024
+ max_contracts_held_short() {
48025
+ return this.book.maxContractsHeldShort();
48026
+ }
48027
+ capital_held() {
48028
+ return this.book.capitalHeld();
48029
+ }
48030
+ closedtrades_first_index() {
48031
+ return this.book.closedtrades_first_index;
48032
+ }
48033
+ wintrades() {
48034
+ return this.book.wintrades;
48035
+ }
48036
+ losstrades() {
48037
+ return this.book.losstrades;
48038
+ }
48039
+ eventrades() {
48040
+ return this.book.eventrades;
48041
+ }
48042
+ grossprofit() {
48043
+ return this.book.grossprofit;
48044
+ }
48045
+ grossloss() {
48046
+ return this.book.grossloss;
48047
+ }
48048
+ avg_trade() {
48049
+ return this.book.avgTrade();
48050
+ }
48051
+ avg_winning_trade() {
48052
+ return this.book.avgWinningTrade();
48053
+ }
48054
+ avg_losing_trade() {
48055
+ return this.book.avgLosingTrade();
48056
+ }
48057
+ netprofit_percent() {
48058
+ return this.book.netprofitPercent(this.mark);
48059
+ }
48060
+ openprofit_percent() {
48061
+ return this.book.openprofitPercent(this.mark);
48062
+ }
48063
+ grossprofit_percent() {
48064
+ return this.book.grossprofitPercent();
48065
+ }
48066
+ grossloss_percent() {
48067
+ return this.book.grosslossPercent();
48068
+ }
48069
+ avg_trade_percent() {
48070
+ return this.book.avgTradePercent();
48071
+ }
48072
+ avg_winning_trade_percent() {
48073
+ return this.book.avgWinningTradePercent();
48074
+ }
48075
+ avg_losing_trade_percent() {
48076
+ return this.book.avgLosingTradePercent();
48077
+ }
48078
+ max_drawdown() {
48079
+ return this.book.maxDrawdown();
48080
+ }
48081
+ max_drawdown_percent() {
48082
+ return this.book.maxDrawdownPercent();
48083
+ }
48084
+ max_runup() {
48085
+ return this.book.maxRunup();
48086
+ }
48087
+ max_runup_percent() {
48088
+ return this.book.maxRunupPercent();
48089
+ }
48090
+ percent_profitable() {
48091
+ return this.book.percentProfitable();
48092
+ }
48093
+ winrate() {
48094
+ return this.book.percentProfitable();
48095
+ }
48096
+ profitfactor() {
48097
+ return this.book.profitFactor();
48098
+ }
48099
+ profit_factor() {
48100
+ return this.book.profitFactor();
48101
+ }
48102
+ closedtrades_entry_bar_index(i) {
48103
+ return this.book.closedEntryBar(this.idx(i)) ?? 0;
48104
+ }
48105
+ closedtrades_entry_price(i) {
48106
+ return this.book.closedEntryPrice(this.idx(i)) ?? 0;
48107
+ }
48108
+ closedtrades_exit_bar_index(i) {
48109
+ return this.book.closedExitBar(this.idx(i)) ?? 0;
48110
+ }
48111
+ closedtrades_exit_price(i) {
48112
+ return this.book.closedExitPrice(this.idx(i)) ?? 0;
48113
+ }
48114
+ closedtrades_profit(i) {
48115
+ return this.book.closedProfit(this.idx(i)) ?? 0;
48116
+ }
48117
+ closedtrades_size(i) {
48118
+ return this.book.closedSize(this.idx(i)) ?? 0;
48119
+ }
48120
+ closedtrades_entry_id(i) {
48121
+ return this.book.closedId(this.idx(i)) ?? "";
48122
+ }
48123
+ closedtrades_exit_id(i) {
48124
+ return this.book.closedId(this.idx(i)) ?? "";
48125
+ }
48126
+ closedtrades_commission(i) {
48127
+ return this.book.closedCommission(this.idx(i)) ?? 0;
48128
+ }
48129
+ closedtrades_entry_time(i) {
48130
+ return this.book.closedEntryTime(this.idx(i));
48131
+ }
48132
+ closedtrades_exit_time(i) {
48133
+ return this.book.closedExitTime(this.idx(i));
48134
+ }
48135
+ closedtrades_entry_comment(i) {
48136
+ return this.book.closedEntryComment(this.idx(i));
48137
+ }
48138
+ closedtrades_exit_comment(i) {
48139
+ return this.book.closedExitComment(this.idx(i));
48140
+ }
48141
+ closedtrades_max_drawdown(i) {
48142
+ return this.book.closedMaxDrawdown(this.idx(i));
48143
+ }
48144
+ closedtrades_max_runup(i) {
48145
+ return this.book.closedMaxRunup(this.idx(i));
48146
+ }
48147
+ opentrades_entry_bar_index(i) {
48148
+ return this.book.openEntryBar(this.idx(i)) ?? 0;
48149
+ }
48150
+ opentrades_entry_price(i) {
48151
+ return this.book.openEntryPrice(this.idx(i)) ?? 0;
48152
+ }
48153
+ opentrades_size(i) {
48154
+ return this.book.openSize(this.idx(i)) ?? 0;
48155
+ }
48156
+ opentrades_entry_id(i) {
48157
+ return this.book.openId(this.idx(i)) ?? "";
48158
+ }
48159
+ opentrades_profit(i) {
48160
+ return this.book.openProfit(this.idx(i), this.mark) ?? 0;
48161
+ }
48162
+ opentrades_entry_time(i) {
48163
+ return this.book.openEntryTime(this.idx(i));
48164
+ }
48165
+ opentrades_entry_comment(i) {
48166
+ return this.book.openEntryComment(this.idx(i));
48167
+ }
48168
+ opentrades_commission(i) {
48169
+ return this.book.openCommission(this.idx(i));
48170
+ }
48171
+ opentrades_max_drawdown(i) {
48172
+ return this.book.openMaxDrawdown(this.idx(i));
48173
+ }
48174
+ opentrades_max_runup(i) {
48175
+ return this.book.openMaxRunup(this.idx(i));
48176
+ }
48177
+ idx(i) {
48178
+ if (typeof i === "boolean")
48179
+ return i ? 1 : 0;
48180
+ if (typeof i === "number" && Number.isFinite(i))
48181
+ return Math.trunc(i);
48182
+ return 0;
48183
+ }
46490
48184
  risk_allow_entry_in(value) {
46491
48185
  this.book.riskAllowEntryIn(value);
46492
48186
  }
@@ -46556,6 +48250,8 @@ function createCompileHelpers(opts) {
46556
48250
  na: NA_FN,
46557
48251
  nz,
46558
48252
  naNum,
48253
+ plotNum,
48254
+ timenow,
46559
48255
  isNa: isNaCell,
46560
48256
  eq: pineEq,
46561
48257
  ne: pineNe,
@@ -46675,11 +48371,40 @@ function createCompileHelpers(opts) {
46675
48371
  udtSet,
46676
48372
  udtRegister,
46677
48373
  currencyRate: resolveCurrencyRate,
48374
+ requestSeed: resolveSeed,
48375
+ requestFootprint: createFootprint,
48376
+ footprint: {
48377
+ buy_volume: footprintBuyVolume,
48378
+ sell_volume: footprintSellVolume,
48379
+ delta: footprintDelta,
48380
+ total_volume: footprintTotalVolume,
48381
+ vah: footprintVah,
48382
+ val: footprintVal,
48383
+ poc: footprintPoc,
48384
+ rows: compileFootprintRows,
48385
+ get_row_by_price: footprintGetRowByPrice,
48386
+ volume_row: {
48387
+ up_price: volumeRowUpPrice,
48388
+ down_price: volumeRowDownPrice,
48389
+ buy_volume: volumeRowBuyVolume,
48390
+ sell_volume: volumeRowSellVolume,
48391
+ delta: volumeRowDelta,
48392
+ total_volume: volumeRowTotalVolume,
48393
+ has_buy_imbalance: volumeRowHasBuyImbalance,
48394
+ has_sell_imbalance: volumeRowHasSellImbalance
48395
+ }
48396
+ },
46678
48397
  runtimeError(msg) {
46679
48398
  throw new Error(String(msg));
46680
48399
  }
46681
48400
  };
46682
48401
  }
48402
+ function compileFootprintRows(fp) {
48403
+ const arr = new PineArray;
48404
+ for (const row of footprintRows(fp))
48405
+ arr.push(row);
48406
+ return arr;
48407
+ }
46683
48408
  function compileColorNew(color, transp) {
46684
48409
  const parsed = asColor(color);
46685
48410
  if (!parsed)
@@ -46705,6 +48430,19 @@ function iff(cond, thenV, elseV) {
46705
48430
  return cond ? thenV : elseV;
46706
48431
  return mathIff(cond, thenV, elseV);
46707
48432
  }
48433
+ function plotNum(v) {
48434
+ if (isStrategyCashAmount(v))
48435
+ return Number.isFinite(v.value) ? v.value : null;
48436
+ return naNum(v);
48437
+ }
48438
+ function timenow(timeArr) {
48439
+ if (!Array.isArray(timeArr) || timeArr.length === 0)
48440
+ return 0;
48441
+ const last = timeArr[timeArr.length - 1];
48442
+ if (typeof last === "number" && Number.isFinite(last))
48443
+ return last;
48444
+ return (timeArr.length - 1) * 60000;
48445
+ }
46708
48446
  function NA_FN(v) {
46709
48447
  if (arguments.length === 0)
46710
48448
  return null;
@@ -48100,6 +49838,20 @@ var MATH_CONSTANTS = {
48100
49838
  "plot.linestyle_solid": "linestyle_solid",
48101
49839
  "plot.linestyle_dashed": "linestyle_dashed",
48102
49840
  "plot.linestyle_dotted": "linestyle_dotted",
49841
+ "plot.style_line": "style_line",
49842
+ "plot.style_linebr": "style_linebr",
49843
+ "plot.style_stepline": "style_stepline",
49844
+ "plot.style_steplinebr": "style_steplinebr",
49845
+ "plot.style_stepline_diamond": "style_stepline_diamond",
49846
+ "plot.style_histogram": "style_histogram",
49847
+ "plot.style_columns": "style_columns",
49848
+ "plot.style_cross": "style_cross",
49849
+ "plot.style_area": "style_area",
49850
+ "plot.style_areabr": "style_areabr",
49851
+ "plot.style_circles": "style_circles",
49852
+ "alert.freq_once_per_bar": "once_per_bar",
49853
+ "alert.freq_once_per_bar_close": "once_per_bar_close",
49854
+ "alert.freq_all": "all",
48103
49855
  "dayofweek.sunday": 1,
48104
49856
  "dayofweek.monday": 2,
48105
49857
  "dayofweek.tuesday": 3,
@@ -48490,6 +50242,9 @@ function evalCall(node, env) {
48490
50242
  if (isRequestBuiltin(fname) || fname === "request.security" || fname === "security" || fname === "security_lower_tf") {
48491
50243
  return evalRequestCall(fname, node, env);
48492
50244
  }
50245
+ const fpCall = evalFootprintCall(fname, node, env);
50246
+ if (fpCall !== undefined)
50247
+ return fpCall;
48493
50248
  const arrVal = evalArrayCall(fname, node, env);
48494
50249
  if (arrVal !== undefined)
48495
50250
  return arrVal;
@@ -49095,15 +50850,57 @@ function packFills(book) {
49095
50850
  function packDrawings(book) {
49096
50851
  return book.items.length === 0 ? undefined : book.items;
49097
50852
  }
49098
- function fireAlertCondition(env, title, message) {
49099
- const key = `alertcondition|${title}|${message}|once_per_bar`;
50853
+ var FREQ_ONCE_PER_BAR = "once_per_bar";
50854
+ var FREQ_ONCE_PER_BAR_CLOSE = "once_per_bar_close";
50855
+ var FREQ_ALL = "all";
50856
+ var ALERT_FREQ_ALIASES = {
50857
+ once_per_bar: FREQ_ONCE_PER_BAR,
50858
+ freq_once_per_bar: FREQ_ONCE_PER_BAR,
50859
+ "alert.freq_once_per_bar": FREQ_ONCE_PER_BAR,
50860
+ once_per_bar_close: FREQ_ONCE_PER_BAR_CLOSE,
50861
+ freq_once_per_bar_close: FREQ_ONCE_PER_BAR_CLOSE,
50862
+ "alert.freq_once_per_bar_close": FREQ_ONCE_PER_BAR_CLOSE,
50863
+ all: FREQ_ALL,
50864
+ freq_all: FREQ_ALL,
50865
+ "alert.freq_all": FREQ_ALL
50866
+ };
50867
+ function normalizeAlertFreq(freq) {
50868
+ if (freq == null)
50869
+ return FREQ_ONCE_PER_BAR;
50870
+ if (typeof freq === "number" && !Number.isFinite(freq))
50871
+ return FREQ_ONCE_PER_BAR;
50872
+ const s = String(freq).trim().toLowerCase().replace(/ /g, "_");
50873
+ return ALERT_FREQ_ALIASES[s] ?? (s ? s : FREQ_ONCE_PER_BAR);
50874
+ }
50875
+ function barIsConfirmed(_env) {
50876
+ return true;
50877
+ }
50878
+ function shouldFireAlert(env, source, title, message, freq) {
50879
+ const freqN = normalizeAlertFreq(freq);
50880
+ if (freqN === FREQ_ALL)
50881
+ return true;
50882
+ if (freqN === FREQ_ONCE_PER_BAR_CLOSE && !barIsConfirmed(env))
50883
+ return false;
50884
+ const key = `${source}|${title}|${message}|${freqN}`;
49100
50885
  if (env.alertFireBars.get(key) === env.barIndex)
49101
- return;
50886
+ return false;
49102
50887
  env.alertFireBars.set(key, env.barIndex);
50888
+ return true;
50889
+ }
50890
+ function emitAlert(env, message, freq, opts) {
50891
+ const source = opts?.source ?? "alert";
50892
+ const title = opts?.title ?? "";
50893
+ const freqN = normalizeAlertFreq(freq);
50894
+ if (!shouldFireAlert(env, source, title, message, freqN))
50895
+ return;
49103
50896
  env.drawings.alert(env.barIndex, message);
49104
50897
  const ev = env.drawings.items[env.drawings.items.length - 1];
49105
- if (ev != null)
49106
- ev.extra = { source: "alertcondition", title, freq: "once_per_bar" };
50898
+ if (ev == null)
50899
+ return;
50900
+ ev.extra = title ? { source, title, freq: freqN } : { source, freq: freqN };
50901
+ }
50902
+ function fireAlertCondition(env, title, message) {
50903
+ emitAlert(env, message, FREQ_ONCE_PER_BAR, { title, source: "alertcondition" });
49107
50904
  }
49108
50905
  function inputTitle(node) {
49109
50906
  const named = namedStringArg(node.args, "title");
@@ -49425,9 +51222,75 @@ function evalRequestCall(fname, node, env) {
49425
51222
  const v = resolveRequest(fname, host, { seed });
49426
51223
  return typeof v === "number" || v === null ? v : NA;
49427
51224
  }
51225
+ if (fname === "request.footprint") {
51226
+ const numTicks = unwrap2(evalExpr(callArg(node.args, 0, ["num_ticks"]), env));
51227
+ const va = unwrap2(evalExpr(callArg(node.args, 1, ["va_percentage"]), env));
51228
+ const v = resolveRequest(fname, host, {
51229
+ num_ticks: numTicks ?? 100,
51230
+ va_percentage: va ?? 70
51231
+ });
51232
+ return v instanceof Footprint ? v : NA;
51233
+ }
49428
51234
  const v = resolveRequest(fname, host, {});
49429
51235
  return typeof v === "number" || v === null ? v : NA;
49430
51236
  }
51237
+ function evalFootprintCall(fname, node, env) {
51238
+ if (fname == null)
51239
+ return;
51240
+ if (fname.startsWith("footprint.")) {
51241
+ const fp = evalExpr(callArg(node.args, 0, ["id", "footprint"]), env);
51242
+ switch (fname) {
51243
+ case "footprint.buy_volume":
51244
+ return footprintBuyVolume(fp);
51245
+ case "footprint.sell_volume":
51246
+ return footprintSellVolume(fp);
51247
+ case "footprint.delta":
51248
+ return footprintDelta(fp);
51249
+ case "footprint.total_volume":
51250
+ return footprintTotalVolume(fp);
51251
+ case "footprint.vah":
51252
+ return footprintVah(fp);
51253
+ case "footprint.val":
51254
+ return footprintVal(fp);
51255
+ case "footprint.poc":
51256
+ return footprintPoc(fp);
51257
+ case "footprint.rows": {
51258
+ const arr = new PineArray;
51259
+ for (const row of footprintRows(fp))
51260
+ arr.push(row);
51261
+ return arr;
51262
+ }
51263
+ case "footprint.get_row_by_price":
51264
+ return footprintGetRowByPrice(fp, unwrap2(evalExpr(callArg(node.args, 1, ["price"]), env)));
51265
+ default:
51266
+ return;
51267
+ }
51268
+ }
51269
+ if (fname.startsWith("volume_row.")) {
51270
+ const vr = evalExpr(callArg(node.args, 0, ["id", "volume_row"]), env);
51271
+ switch (fname) {
51272
+ case "volume_row.up_price":
51273
+ return volumeRowUpPrice(vr);
51274
+ case "volume_row.down_price":
51275
+ return volumeRowDownPrice(vr);
51276
+ case "volume_row.buy_volume":
51277
+ return volumeRowBuyVolume(vr);
51278
+ case "volume_row.sell_volume":
51279
+ return volumeRowSellVolume(vr);
51280
+ case "volume_row.delta":
51281
+ return volumeRowDelta(vr);
51282
+ case "volume_row.total_volume":
51283
+ return volumeRowTotalVolume(vr);
51284
+ case "volume_row.has_buy_imbalance":
51285
+ return volumeRowHasBuyImbalance(vr);
51286
+ case "volume_row.has_sell_imbalance":
51287
+ return volumeRowHasSellImbalance(vr);
51288
+ default:
51289
+ return;
51290
+ }
51291
+ }
51292
+ return;
51293
+ }
49431
51294
  function evalMathCall(fname, node, env) {
49432
51295
  if (fname === "math.abs" || fname === "abs") {
49433
51296
  return mathAbs(cellArg(node, env, 0, ["number", "x"]));
@@ -50030,6 +51893,97 @@ function evalExtraTa(fname, node, env, site) {
50030
51893
  const z = env.ta.zigzag(site, srcArg(node, env), th);
50031
51894
  return tupleOf([z.high, z.low, z.dir]);
50032
51895
  }
51896
+ const wave10aArg = (index, names, message) => {
51897
+ const arg = callArg(node.args, index, names);
51898
+ if (arg == null)
51899
+ runtimeError(message);
51900
+ return arg;
51901
+ };
51902
+ if (fname === "ta.hammer" || fname === "hammer") {
51903
+ const msg = "ta.hammer() requires 4 arguments: open, high, low, close";
51904
+ return env.ta.hammer(unwrap2(evalExpr(wave10aArg(0, ["open"], msg), env)), unwrap2(evalExpr(wave10aArg(1, ["high"], msg), env)), unwrap2(evalExpr(wave10aArg(2, ["low"], msg), env)), unwrap2(evalExpr(wave10aArg(3, ["close"], msg), env)));
51905
+ }
51906
+ if (fname === "ta.engulfing" || fname === "engulfing") {
51907
+ const msg = "ta.engulfing() requires 4 arguments: open, high, low, close";
51908
+ unwrap2(evalExpr(wave10aArg(0, ["open"], msg), env));
51909
+ unwrap2(evalExpr(wave10aArg(1, ["high"], msg), env));
51910
+ unwrap2(evalExpr(wave10aArg(2, ["low"], msg), env));
51911
+ unwrap2(evalExpr(wave10aArg(3, ["close"], msg), env));
51912
+ return env.ta.engulfing();
51913
+ }
51914
+ if (fname === "ta.gap_detector" || fname === "gap_detector") {
51915
+ const msg = "ta.gap_detector() requires 3 arguments: high, low, prev_close";
51916
+ return env.ta.gapDetector(unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env)), unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env)), unwrap2(evalExpr(wave10aArg(2, ["prev_close", "prev"], msg), env)));
51917
+ }
51918
+ if (fname === "ta.double_top_bottom" || fname === "double_top_bottom") {
51919
+ 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)));
51923
+ }
51924
+ if (fname === "ta.inside_bar_pattern" || fname === "inside_bar_pattern") {
51925
+ 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();
51929
+ }
51930
+ if (fname === "ta.macd_signal" || fname === "macd_signal") {
51931
+ const msg = "ta.macd_signal() requires 2 arguments: macd_line, signal_line";
51932
+ return env.ta.macdSignal(unwrap2(evalExpr(wave10aArg(0, ["macd_line", "macd"], msg), env)), unwrap2(evalExpr(wave10aArg(1, ["signal_line", "signal"], msg), env)));
51933
+ }
51934
+ if (fname === "ta.acceleration_factor" || fname === "acceleration_factor") {
51935
+ const msg = "ta.acceleration_factor() requires 2 arguments";
51936
+ return env.ta.accelerationFactor(site, unwrap2(evalExpr(wave10aArg(0, ["momentum_list", "momentum", "source", "series"], msg), env)), unwrap2(evalExpr(wave10aArg(1, ["period", "length"], msg), env)));
51937
+ }
51938
+ if (fname === "ta.stoch_smooth" || fname === "stoch_smooth") {
51939
+ 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)));
51941
+ }
51942
+ const wave10bList = (index, names) => {
51943
+ const raw = evalExpr(callArg(node.args, index, names), env);
51944
+ const arr = asArray2(raw);
51945
+ if (arr == null)
51946
+ return [unwrap2(raw)];
51947
+ const out = [];
51948
+ for (let i = 0;i < arr.size(); i++)
51949
+ out.push(arr.get(i));
51950
+ return out;
51951
+ };
51952
+ if (fname === "ta.voi" || fname === "voi") {
51953
+ return env.ta.voi(unwrap2(evalExpr(callArg(node.args, 0, ["buy_volume", "buy"]), env)), unwrap2(evalExpr(callArg(node.args, 1, ["sell_volume", "sell"]), env)));
51954
+ }
51955
+ if (fname === "ta.bid_ask_imbalance" || fname === "bid_ask_imbalance") {
51956
+ return env.ta.bidAskImbalance(unwrap2(evalExpr(callArg(node.args, 0, ["bid_size", "bid"]), env)), unwrap2(evalExpr(callArg(node.args, 1, ["ask_size", "ask"]), env)), unwrap2(evalExpr(callArg(node.args, 2, ["bid_price"]), env)), unwrap2(evalExpr(callArg(node.args, 3, ["ask_price"]), env)));
51957
+ }
51958
+ if (fname === "ta.rsi_oversold_overbought" || fname === "rsi_oversold_overbought") {
51959
+ const os = unwrap2(evalExpr(callArg(node.args, 1, ["oversold_level", "oversold"]), env));
51960
+ const ob = unwrap2(evalExpr(callArg(node.args, 2, ["overbought_level", "overbought"]), env));
51961
+ return env.ta.rsiOversoldOverbought(unwrap2(evalExpr(callArg(node.args, 0, ["rsi_series", "rsi", "source"]), env)), os ?? Number.NaN, ob ?? Number.NaN);
51962
+ }
51963
+ if (fname === "ta.rsi_divergence" || fname === "rsi_divergence") {
51964
+ const period = unwrap2(evalExpr(callArg(node.args, 1, ["period", "length"]), env));
51965
+ return env.ta.rsiDivergence(wave10bList(0, ["rsi_series", "series", "source"]), period ?? 0);
51966
+ }
51967
+ if (fname === "ta.cumulative_delta" || fname === "cumulative_delta") {
51968
+ const period = unwrap2(evalExpr(callArg(node.args, 2, ["period", "length"]), env));
51969
+ return env.ta.cumulativeDelta(site, unwrap2(evalExpr(callArg(node.args, 0, ["close", "source"]), env)), unwrap2(evalExpr(callArg(node.args, 1, ["volume"]), env)), period ?? 0);
51970
+ }
51971
+ if (fname === "ta.volume_momentum" || fname === "volume_momentum") {
51972
+ const period = unwrap2(evalExpr(callArg(node.args, 1, ["period", "length"]), env));
51973
+ return env.ta.volumeMomentum(site, unwrap2(evalExpr(callArg(node.args, 0, ["volume", "source"]), env)), period ?? 0);
51974
+ }
51975
+ if (fname === "ta.volume_profile_high" || fname === "volume_profile_high") {
51976
+ return env.ta.volumeProfileHigh(wave10bList(0, ["close", "price", "source", "series"]), wave10bList(1, ["volume"]));
51977
+ }
51978
+ if (fname === "ta.volume_profile_low" || fname === "volume_profile_low") {
51979
+ const period = unwrap2(evalExpr(callArg(node.args, 2, ["period", "length"]), env));
51980
+ const levels = unwrap2(evalExpr(callArg(node.args, 3, ["levels"]), env));
51981
+ return env.ta.volumeProfileLow(site, unwrap2(evalExpr(callArg(node.args, 0, ["close", "source"]), env)), unwrap2(evalExpr(callArg(node.args, 1, ["volume"]), env)), period ?? 0, levels ?? 0);
51982
+ }
51983
+ if (fname === "ta.volume_thrust" || fname === "volume_thrust") {
51984
+ const sens = unwrap2(evalExpr(callArg(node.args, 3, ["sensitivity"]), env));
51985
+ 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
+ }
50033
51987
  return;
50034
51988
  }
50035
51989
  function hlc3(env) {
@@ -50842,7 +52796,7 @@ function optionalCoord(node, env, index, names, fallback) {
50842
52796
  return fallback;
50843
52797
  return unwrap2(evalExpr(e, env));
50844
52798
  }
50845
- function pointXY(p) {
52799
+ function pointXY2(p) {
50846
52800
  const x = p.index ?? p.time ?? p.x ?? 0;
50847
52801
  const y = p.price ?? p.y ?? 0;
50848
52802
  return { x: x ?? 0, y: y ?? 0 };
@@ -50889,7 +52843,7 @@ function evalDrawingCall(fname, node, env) {
50889
52843
  const extra = {};
50890
52844
  let text;
50891
52845
  if (isChartPoint(v0)) {
50892
- const xy = pointXY(v0);
52846
+ const xy = pointXY2(v0);
50893
52847
  extra.x = xy.x;
50894
52848
  extra.y = xy.y;
50895
52849
  text = drawText(node, env, pointKw != null ? 0 : 1, ["text"]);
@@ -50921,8 +52875,16 @@ function evalDrawingCall(fname, node, env) {
50921
52875
  return book.boxNew(env.barIndex, extra);
50922
52876
  }
50923
52877
  if (fname === "alert") {
52878
+ if (asArgs2(node.args).length === 0)
52879
+ return NA;
50924
52880
  const msg = evalAlertMessage(callArg(node.args, 0, ["message"]), env);
50925
- book.alert(env.barIndex, msg);
52881
+ const freqExpr = callArg(node.args, 1, ["freq"]);
52882
+ let freq = null;
52883
+ if (freqExpr != null) {
52884
+ const v = evalExpr(freqExpr, env);
52885
+ freq = typeof v === "string" ? v : unwrap2(v);
52886
+ }
52887
+ emitAlert(env, msg, freq, { source: "alert" });
50926
52888
  return NA;
50927
52889
  }
50928
52890
  if (fname === "table.new") {
@@ -51170,7 +53132,7 @@ function evalDrawingCall(fname, node, env) {
51170
53132
  const id = drawId(node, env);
51171
53133
  const p = evalExpr(callArg(node.args, 1, ["point"]), env);
51172
53134
  if (id != null && isChartPoint(p)) {
51173
- const xy = pointXY(p);
53135
+ const xy = pointXY2(p);
51174
53136
  book.lineSetXy1(id, xy.x, xy.y);
51175
53137
  }
51176
53138
  return NA;
@@ -51179,7 +53141,7 @@ function evalDrawingCall(fname, node, env) {
51179
53141
  const id = drawId(node, env);
51180
53142
  const p = evalExpr(callArg(node.args, 1, ["point"]), env);
51181
53143
  if (id != null && isChartPoint(p)) {
51182
- const xy = pointXY(p);
53144
+ const xy = pointXY2(p);
51183
53145
  book.lineSetXy2(id, xy.x, xy.y);
51184
53146
  }
51185
53147
  return NA;
@@ -51308,7 +53270,7 @@ function evalDrawingCall(fname, node, env) {
51308
53270
  const id = drawId(node, env);
51309
53271
  const p = evalExpr(callArg(node.args, 1, ["point"]), env);
51310
53272
  if (id != null && isChartPoint(p)) {
51311
- const xy = pointXY(p);
53273
+ const xy = pointXY2(p);
51312
53274
  book.labelSetXy(id, xy.x, xy.y);
51313
53275
  }
51314
53276
  return NA;
@@ -51447,7 +53409,7 @@ function evalDrawingCall(fname, node, env) {
51447
53409
  const id = drawId(node, env);
51448
53410
  const p = evalExpr(callArg(node.args, 1, ["point"]), env);
51449
53411
  if (id != null && isChartPoint(p)) {
51450
- const xy = pointXY(p);
53412
+ const xy = pointXY2(p);
51451
53413
  book.boxSetLeftTop(id, xy.x, xy.y);
51452
53414
  }
51453
53415
  return NA;
@@ -51456,7 +53418,7 @@ function evalDrawingCall(fname, node, env) {
51456
53418
  const id = drawId(node, env);
51457
53419
  const p = evalExpr(callArg(node.args, 1, ["point"]), env);
51458
53420
  if (id != null && isChartPoint(p)) {
51459
- const xy = pointXY(p);
53421
+ const xy = pointXY2(p);
51460
53422
  book.boxSetRightBottom(id, xy.x, xy.y);
51461
53423
  }
51462
53424
  return NA;