@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/CHANGELOG.md +30 -0
- package/README.md +7 -5
- package/dist/browser.js +66 -66
- package/dist/index.js +2009 -47
- package/package.json +1 -1
- package/src/cli/rich.ts +1 -1
- package/src/runtime/compile/collections.ts +4 -0
- package/src/runtime/compile/draw.ts +609 -19
- package/src/runtime/compile/emit.ts +98 -1
- package/src/runtime/compile/emit_call.ts +366 -10
- package/src/runtime/compile/runtime.ts +71 -1
- package/src/runtime/compile/strategy.ts +253 -1
- package/src/runtime/footprint.ts +272 -0
- package/src/runtime/interpret.ts +325 -8
- package/src/runtime/request.ts +19 -4
- package/src/runtime/ta.ts +392 -0
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 === "
|
|
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"], ["
|
|
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 === "
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
46184
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
46199
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
46286
|
-
|
|
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
|
-
|
|
49099
|
-
|
|
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
|
|
49106
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
53421
|
+
const xy = pointXY2(p);
|
|
51460
53422
|
book.boxSetRightBottom(id, xy.x, xy.y);
|
|
51461
53423
|
}
|
|
51462
53424
|
return NA;
|