@hoox-sh/pynets 0.4.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();
@@ -42933,7 +43172,9 @@ var NS = new Set([
42933
43172
  "session",
42934
43173
  "syminfo",
42935
43174
  "timenow",
42936
- "chart"
43175
+ "chart",
43176
+ "footprint",
43177
+ "volume_row"
42937
43178
  ]);
42938
43179
  var TA_METHODS = new Set([
42939
43180
  "sma",
@@ -43311,6 +43552,9 @@ function emitCall2(ctx, node, visit) {
43311
43552
  const req = emitRequest(ctx, name, args);
43312
43553
  if (req != null)
43313
43554
  return req;
43555
+ const fp = emitFootprint(name, args);
43556
+ if (fp != null)
43557
+ return fp;
43314
43558
  return "null";
43315
43559
  }
43316
43560
  function resolveCallee(func) {
@@ -43840,8 +44084,7 @@ var SECURITY_FUNCS = new Set([
43840
44084
  "security",
43841
44085
  "security_lower_tf",
43842
44086
  "request_security",
43843
- "request_security_lower_tf",
43844
- "request_seed"
44087
+ "request_security_lower_tf"
43845
44088
  ]);
43846
44089
  var SIMPLE_CHART_EXPR = new Set([
43847
44090
  "close",
@@ -43879,10 +44122,58 @@ function emitRequest(ctx, name, args) {
43879
44122
  if (name === "request_currency_rate" || name === "currency_rate") {
43880
44123
  return `__h.currencyRate(${pick(args, 0, ["from", "from_currency"], "null")}, ${pick(args, 1, ["to", "to_currency"], "null")})`;
43881
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
+ }
43882
44131
  if (name.startsWith("request_"))
43883
44132
  return "null";
43884
44133
  return null;
43885
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
+ }
43886
44177
  function isSimpleSecurityExpr(expr) {
43887
44178
  const e = expr.trim();
43888
44179
  if (!e)
@@ -45477,6 +45768,20 @@ var ATTR_CONSTANTS = {
45477
45768
  "plot.linestyle_solid": "linestyle_solid",
45478
45769
  "plot.linestyle_dashed": "linestyle_dashed",
45479
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",
45480
45785
  "dayofweek.sunday": 1,
45481
45786
  "dayofweek.monday": 2,
45482
45787
  "dayofweek.tuesday": 3,
@@ -45513,6 +45818,7 @@ var ATTR_CONST_NS = new Set([
45513
45818
  "position",
45514
45819
  "hline",
45515
45820
  "plot",
45821
+ "alert",
45516
45822
  "dayofweek",
45517
45823
  "month"
45518
45824
  ]);
@@ -48065,11 +48371,40 @@ function createCompileHelpers(opts) {
48065
48371
  udtSet,
48066
48372
  udtRegister,
48067
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
+ },
48068
48397
  runtimeError(msg) {
48069
48398
  throw new Error(String(msg));
48070
48399
  }
48071
48400
  };
48072
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
+ }
48073
48408
  function compileColorNew(color, transp) {
48074
48409
  const parsed = asColor(color);
48075
48410
  if (!parsed)
@@ -49503,6 +49838,20 @@ var MATH_CONSTANTS = {
49503
49838
  "plot.linestyle_solid": "linestyle_solid",
49504
49839
  "plot.linestyle_dashed": "linestyle_dashed",
49505
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",
49506
49855
  "dayofweek.sunday": 1,
49507
49856
  "dayofweek.monday": 2,
49508
49857
  "dayofweek.tuesday": 3,
@@ -49893,6 +50242,9 @@ function evalCall(node, env) {
49893
50242
  if (isRequestBuiltin(fname) || fname === "request.security" || fname === "security" || fname === "security_lower_tf") {
49894
50243
  return evalRequestCall(fname, node, env);
49895
50244
  }
50245
+ const fpCall = evalFootprintCall(fname, node, env);
50246
+ if (fpCall !== undefined)
50247
+ return fpCall;
49896
50248
  const arrVal = evalArrayCall(fname, node, env);
49897
50249
  if (arrVal !== undefined)
49898
50250
  return arrVal;
@@ -50498,15 +50850,57 @@ function packFills(book) {
50498
50850
  function packDrawings(book) {
50499
50851
  return book.items.length === 0 ? undefined : book.items;
50500
50852
  }
50501
- function fireAlertCondition(env, title, message) {
50502
- 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}`;
50503
50885
  if (env.alertFireBars.get(key) === env.barIndex)
50504
- return;
50886
+ return false;
50505
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;
50506
50896
  env.drawings.alert(env.barIndex, message);
50507
50897
  const ev = env.drawings.items[env.drawings.items.length - 1];
50508
- if (ev != null)
50509
- 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" });
50510
50904
  }
50511
50905
  function inputTitle(node) {
50512
50906
  const named = namedStringArg(node.args, "title");
@@ -50828,9 +51222,75 @@ function evalRequestCall(fname, node, env) {
50828
51222
  const v = resolveRequest(fname, host, { seed });
50829
51223
  return typeof v === "number" || v === null ? v : NA;
50830
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
+ }
50831
51234
  const v = resolveRequest(fname, host, {});
50832
51235
  return typeof v === "number" || v === null ? v : NA;
50833
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
+ }
50834
51294
  function evalMathCall(fname, node, env) {
50835
51295
  if (fname === "math.abs" || fname === "abs") {
50836
51296
  return mathAbs(cellArg(node, env, 0, ["number", "x"]));
@@ -52415,8 +52875,16 @@ function evalDrawingCall(fname, node, env) {
52415
52875
  return book.boxNew(env.barIndex, extra);
52416
52876
  }
52417
52877
  if (fname === "alert") {
52878
+ if (asArgs2(node.args).length === 0)
52879
+ return NA;
52418
52880
  const msg = evalAlertMessage(callArg(node.args, 0, ["message"]), env);
52419
- 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" });
52420
52888
  return NA;
52421
52889
  }
52422
52890
  if (fname === "table.new") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hoox-sh/pynets",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "author": "jango_blockchained",
package/src/cli/rich.ts CHANGED
@@ -12,7 +12,7 @@ const MUTED = [203, 204, 189] as const;
12
12
  const FAIL = [231, 0, 11] as const;
13
13
  const WARN = [235, 169, 65] as const;
14
14
 
15
- export const VERSION = "0.4.0";
15
+ export const VERSION = "0.5.0";
16
16
 
17
17
  type Rgb = readonly [number, number, number];
18
18
 
@@ -707,6 +707,22 @@ const ATTR_CONSTANTS: Record<string, string | number | boolean> = {
707
707
  "plot.linestyle_solid": "linestyle_solid",
708
708
  "plot.linestyle_dashed": "linestyle_dashed",
709
709
  "plot.linestyle_dotted": "linestyle_dotted",
710
+ // Python plotting.py plot.style_* (dispatch tag 0 strings).
711
+ "plot.style_line": "style_line",
712
+ "plot.style_linebr": "style_linebr",
713
+ "plot.style_stepline": "style_stepline",
714
+ "plot.style_steplinebr": "style_steplinebr",
715
+ "plot.style_stepline_diamond": "style_stepline_diamond",
716
+ "plot.style_histogram": "style_histogram",
717
+ "plot.style_columns": "style_columns",
718
+ "plot.style_cross": "style_cross",
719
+ "plot.style_area": "style_area",
720
+ "plot.style_areabr": "style_areabr",
721
+ "plot.style_circles": "style_circles",
722
+ // Python alerts.py FREQ_* tokens.
723
+ "alert.freq_once_per_bar": "once_per_bar",
724
+ "alert.freq_once_per_bar_close": "once_per_bar_close",
725
+ "alert.freq_all": "all",
710
726
  "dayofweek.sunday": 1,
711
727
  "dayofweek.monday": 2,
712
728
  "dayofweek.tuesday": 3,
@@ -744,6 +760,7 @@ const ATTR_CONST_NS = new Set([
744
760
  "position",
745
761
  "hline",
746
762
  "plot",
763
+ "alert",
747
764
  "dayofweek",
748
765
  "month",
749
766
  ]);