@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/CHANGELOG.md +13 -0
- package/README.md +3 -1
- package/dist/browser.js +63 -63
- package/dist/index.js +477 -9
- package/package.json +1 -1
- package/src/cli/rich.ts +1 -1
- package/src/runtime/compile/emit.ts +17 -0
- package/src/runtime/compile/emit_call.ts +54 -1
- package/src/runtime/compile/runtime.ts +51 -1
- package/src/runtime/footprint.ts +272 -0
- package/src/runtime/interpret.ts +174 -8
- package/src/runtime/request.ts +19 -4
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
|
-
|
|
50502
|
-
|
|
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
|
|
50509
|
-
|
|
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
|
-
|
|
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
package/src/cli/rich.ts
CHANGED
|
@@ -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
|
]);
|