@hoox-sh/pynets 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.md +9 -5
- package/dist/browser.js +68 -68
- package/dist/index.js +2196 -206
- package/package.json +1 -1
- package/src/cli/rich.ts +1 -1
- package/src/generated/PinescriptLexerBase.ts +22 -4
- package/src/parser/LexerBase.ts +22 -4
- package/src/runtime/compile/draw.ts +26 -2
- package/src/runtime/compile/emit.ts +17 -0
- package/src/runtime/compile/emit_call.ts +378 -7
- package/src/runtime/compile/helpers.ts +2 -1
- package/src/runtime/compile/runtime.ts +71 -6
- package/src/runtime/compile/strategy.ts +5 -2
- package/src/runtime/footprint.ts +272 -0
- package/src/runtime/interpret.ts +621 -36
- package/src/runtime/request.ts +19 -4
- package/src/runtime/str.ts +3 -2
- package/src/runtime/strategy.ts +164 -12
- package/src/runtime/ta.ts +1090 -149
- package/src/runtime/time.ts +12 -0
package/dist/index.js
CHANGED
|
@@ -6287,6 +6287,7 @@ class PinescriptLexerBase extends cn {
|
|
|
6287
6287
|
_lastPendingTokenType = 0;
|
|
6288
6288
|
_lastPendingTokenTypeFromDefaultChannel = 0;
|
|
6289
6289
|
_numOpens = 0;
|
|
6290
|
+
_numSqBrackets = 0;
|
|
6290
6291
|
_indentLengthStack = [];
|
|
6291
6292
|
_inputStarted = false;
|
|
6292
6293
|
constructor(input) {
|
|
@@ -6340,6 +6341,7 @@ class PinescriptLexerBase extends cn {
|
|
|
6340
6341
|
this._lastPendingTokenType = 0;
|
|
6341
6342
|
this._lastPendingTokenTypeFromDefaultChannel = 0;
|
|
6342
6343
|
this._numOpens = 0;
|
|
6344
|
+
this._numSqBrackets = 0;
|
|
6343
6345
|
this._indentLengthStack = [];
|
|
6344
6346
|
this._inputStarted = false;
|
|
6345
6347
|
}
|
|
@@ -6356,11 +6358,17 @@ class PinescriptLexerBase extends cn {
|
|
|
6356
6358
|
const tok = this._currentToken;
|
|
6357
6359
|
const tokType = tok.type;
|
|
6358
6360
|
const C = this.C;
|
|
6359
|
-
if (tokType === C.LPAR
|
|
6361
|
+
if (tokType === C.LPAR) {
|
|
6360
6362
|
this._numOpens += 1;
|
|
6361
6363
|
this._addPendingToken(tok);
|
|
6362
|
-
} else if (tokType === C.
|
|
6363
|
-
this.
|
|
6364
|
+
} else if (tokType === C.LSQB) {
|
|
6365
|
+
this._numSqBrackets += 1;
|
|
6366
|
+
this._addPendingToken(tok);
|
|
6367
|
+
} else if (tokType === C.RPAR) {
|
|
6368
|
+
this._numOpens = Math.max(0, this._numOpens - 1);
|
|
6369
|
+
this._addPendingToken(tok);
|
|
6370
|
+
} else if (tokType === C.RSQB) {
|
|
6371
|
+
this._numSqBrackets = Math.max(0, this._numSqBrackets - 1);
|
|
6364
6372
|
this._addPendingToken(tok);
|
|
6365
6373
|
} else if (tokType === C.NEWLINE) {
|
|
6366
6374
|
this._handleNEWLINEToken();
|
|
@@ -6452,7 +6460,7 @@ class PinescriptLexerBase extends cn {
|
|
|
6452
6460
|
return tok;
|
|
6453
6461
|
}
|
|
6454
6462
|
_handleNEWLINEToken() {
|
|
6455
|
-
if (this._numOpens > 0 || this._operators.has(this._lastPendingTokenTypeFromDefaultChannel)) {
|
|
6463
|
+
if (this._numOpens > 0 || this._numSqBrackets > 0 || this._operators.has(this._lastPendingTokenTypeFromDefaultChannel)) {
|
|
6456
6464
|
this._hideAndAddPendingToken(this._currentToken);
|
|
6457
6465
|
return;
|
|
6458
6466
|
}
|
|
@@ -34428,6 +34436,235 @@ function colorT(c) {
|
|
|
34428
34436
|
return col ? alphaToTransp(col.a) : null;
|
|
34429
34437
|
}
|
|
34430
34438
|
|
|
34439
|
+
// src/runtime/footprint.ts
|
|
34440
|
+
class VolumeRow {
|
|
34441
|
+
up_price;
|
|
34442
|
+
down_price;
|
|
34443
|
+
buy_volume;
|
|
34444
|
+
sell_volume;
|
|
34445
|
+
delta;
|
|
34446
|
+
is_imbalance;
|
|
34447
|
+
is_poc;
|
|
34448
|
+
is_vah;
|
|
34449
|
+
is_val;
|
|
34450
|
+
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) {
|
|
34451
|
+
this.up_price = up_price;
|
|
34452
|
+
this.down_price = down_price;
|
|
34453
|
+
this.buy_volume = buy_volume;
|
|
34454
|
+
this.sell_volume = sell_volume;
|
|
34455
|
+
this.delta = delta;
|
|
34456
|
+
this.is_imbalance = is_imbalance;
|
|
34457
|
+
this.is_poc = is_poc;
|
|
34458
|
+
this.is_vah = is_vah;
|
|
34459
|
+
this.is_val = is_val;
|
|
34460
|
+
}
|
|
34461
|
+
}
|
|
34462
|
+
|
|
34463
|
+
class Footprint {
|
|
34464
|
+
num_ticks;
|
|
34465
|
+
va_percentage;
|
|
34466
|
+
buy_volume;
|
|
34467
|
+
sell_volume;
|
|
34468
|
+
delta;
|
|
34469
|
+
total_volume;
|
|
34470
|
+
vah_row;
|
|
34471
|
+
val_row;
|
|
34472
|
+
poc_row;
|
|
34473
|
+
rows;
|
|
34474
|
+
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 = []) {
|
|
34475
|
+
this.num_ticks = num_ticks;
|
|
34476
|
+
this.va_percentage = va_percentage;
|
|
34477
|
+
this.buy_volume = buy_volume;
|
|
34478
|
+
this.sell_volume = sell_volume;
|
|
34479
|
+
this.delta = delta;
|
|
34480
|
+
this.total_volume = total_volume;
|
|
34481
|
+
this.vah_row = vah_row;
|
|
34482
|
+
this.val_row = val_row;
|
|
34483
|
+
this.poc_row = poc_row;
|
|
34484
|
+
this.rows = rows;
|
|
34485
|
+
}
|
|
34486
|
+
}
|
|
34487
|
+
var N2 = 624;
|
|
34488
|
+
var M2 = 397;
|
|
34489
|
+
var MATRIX_A = 2567483615;
|
|
34490
|
+
var UPPER_MASK = 2147483648;
|
|
34491
|
+
var LOWER_MASK = 2147483647;
|
|
34492
|
+
|
|
34493
|
+
class PyRandom {
|
|
34494
|
+
mt = new Uint32Array(N2);
|
|
34495
|
+
index = N2 + 1;
|
|
34496
|
+
seed(a) {
|
|
34497
|
+
const n = Math.trunc(a);
|
|
34498
|
+
const abs = n < 0 ? -n : n;
|
|
34499
|
+
const key = [];
|
|
34500
|
+
if (abs === 0)
|
|
34501
|
+
key.push(0);
|
|
34502
|
+
else {
|
|
34503
|
+
let x = abs;
|
|
34504
|
+
while (x > 0) {
|
|
34505
|
+
key.push(x >>> 0);
|
|
34506
|
+
x = Math.floor(x / 4294967296);
|
|
34507
|
+
}
|
|
34508
|
+
}
|
|
34509
|
+
this.initByArray(key);
|
|
34510
|
+
}
|
|
34511
|
+
random() {
|
|
34512
|
+
const a = this.genrand() >>> 5;
|
|
34513
|
+
const b = this.genrand() >>> 6;
|
|
34514
|
+
return (a * 67108864 + b) * (1 / 9007199254740992);
|
|
34515
|
+
}
|
|
34516
|
+
initGenrand(s) {
|
|
34517
|
+
const mt = this.mt;
|
|
34518
|
+
mt[0] = s >>> 0;
|
|
34519
|
+
for (let mti = 1;mti < N2; mti++) {
|
|
34520
|
+
mt[mti] = Math.imul(1812433253, mt[mti - 1] ^ mt[mti - 1] >>> 30) + mti >>> 0;
|
|
34521
|
+
}
|
|
34522
|
+
this.index = N2;
|
|
34523
|
+
}
|
|
34524
|
+
initByArray(initKey) {
|
|
34525
|
+
const mt = this.mt;
|
|
34526
|
+
this.initGenrand(19650218);
|
|
34527
|
+
let i = 1;
|
|
34528
|
+
let j = 0;
|
|
34529
|
+
const keyLength = initKey.length;
|
|
34530
|
+
let k = N2 > keyLength ? N2 : keyLength;
|
|
34531
|
+
for (;k > 0; k--) {
|
|
34532
|
+
mt[i] = (mt[i] ^ Math.imul(mt[i - 1] ^ mt[i - 1] >>> 30, 1664525)) + initKey[j] + j >>> 0;
|
|
34533
|
+
i++;
|
|
34534
|
+
j++;
|
|
34535
|
+
if (i >= N2) {
|
|
34536
|
+
mt[0] = mt[N2 - 1];
|
|
34537
|
+
i = 1;
|
|
34538
|
+
}
|
|
34539
|
+
if (j >= keyLength)
|
|
34540
|
+
j = 0;
|
|
34541
|
+
}
|
|
34542
|
+
for (k = N2 - 1;k > 0; k--) {
|
|
34543
|
+
mt[i] = (mt[i] ^ Math.imul(mt[i - 1] ^ mt[i - 1] >>> 30, 1566083941)) - i >>> 0;
|
|
34544
|
+
i++;
|
|
34545
|
+
if (i >= N2) {
|
|
34546
|
+
mt[0] = mt[N2 - 1];
|
|
34547
|
+
i = 1;
|
|
34548
|
+
}
|
|
34549
|
+
}
|
|
34550
|
+
mt[0] = 2147483648;
|
|
34551
|
+
this.index = N2;
|
|
34552
|
+
}
|
|
34553
|
+
genrand() {
|
|
34554
|
+
const mt = this.mt;
|
|
34555
|
+
if (this.index >= N2) {
|
|
34556
|
+
for (let kk = 0;kk < N2 - M2; kk++) {
|
|
34557
|
+
const y = mt[kk] & UPPER_MASK | mt[kk + 1] & LOWER_MASK;
|
|
34558
|
+
mt[kk] = (mt[kk + M2] ^ y >>> 1 ^ (y & 1 ? MATRIX_A : 0)) >>> 0;
|
|
34559
|
+
}
|
|
34560
|
+
for (let kk = N2 - M2;kk < N2 - 1; kk++) {
|
|
34561
|
+
const y = mt[kk] & UPPER_MASK | mt[kk + 1] & LOWER_MASK;
|
|
34562
|
+
mt[kk] = (mt[kk + (M2 - N2)] ^ y >>> 1 ^ (y & 1 ? MATRIX_A : 0)) >>> 0;
|
|
34563
|
+
}
|
|
34564
|
+
const y = mt[N2 - 1] & UPPER_MASK | mt[0] & LOWER_MASK;
|
|
34565
|
+
mt[N2 - 1] = (mt[M2 - 1] ^ y >>> 1 ^ (y & 1 ? MATRIX_A : 0)) >>> 0;
|
|
34566
|
+
this.index = 0;
|
|
34567
|
+
}
|
|
34568
|
+
let y = mt[this.index++];
|
|
34569
|
+
y ^= y >>> 11;
|
|
34570
|
+
y ^= y << 7 & 2636928640;
|
|
34571
|
+
y ^= y << 15 & 4022730752;
|
|
34572
|
+
y ^= y >>> 18;
|
|
34573
|
+
return y >>> 0;
|
|
34574
|
+
}
|
|
34575
|
+
}
|
|
34576
|
+
var pyRng = null;
|
|
34577
|
+
function seedFootprintRng(seed) {
|
|
34578
|
+
pyRng = new PyRandom;
|
|
34579
|
+
pyRng.seed(seed);
|
|
34580
|
+
}
|
|
34581
|
+
function nextRandom() {
|
|
34582
|
+
return pyRng != null ? pyRng.random() : Math.random();
|
|
34583
|
+
}
|
|
34584
|
+
function asCount(value, fallback) {
|
|
34585
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
34586
|
+
return Math.trunc(value);
|
|
34587
|
+
return fallback;
|
|
34588
|
+
}
|
|
34589
|
+
function rowAt(rows, idx) {
|
|
34590
|
+
return idx >= 0 && idx < rows.length ? rows[idx] : null;
|
|
34591
|
+
}
|
|
34592
|
+
function createFootprint(numTicks = 100, vaPercentage = 70) {
|
|
34593
|
+
const n = asCount(numTicks, 100);
|
|
34594
|
+
const va = asCount(vaPercentage, 70);
|
|
34595
|
+
const rows = [];
|
|
34596
|
+
const basePrice = 100;
|
|
34597
|
+
const tickSize = 0.01;
|
|
34598
|
+
for (let i = 0;i < n; i++) {
|
|
34599
|
+
const priceLevel = basePrice + i * tickSize;
|
|
34600
|
+
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)));
|
|
34601
|
+
}
|
|
34602
|
+
const totalBuy = rows.reduce((s, r) => s + r.buy_volume, 0);
|
|
34603
|
+
const totalSell = rows.reduce((s, r) => s + r.sell_volume, 0);
|
|
34604
|
+
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);
|
|
34605
|
+
}
|
|
34606
|
+
function footprintBuyVolume(fp) {
|
|
34607
|
+
return fp instanceof Footprint ? fp.buy_volume : 0;
|
|
34608
|
+
}
|
|
34609
|
+
function footprintSellVolume(fp) {
|
|
34610
|
+
return fp instanceof Footprint ? fp.sell_volume : 0;
|
|
34611
|
+
}
|
|
34612
|
+
function footprintDelta(fp) {
|
|
34613
|
+
return fp instanceof Footprint ? fp.delta : 0;
|
|
34614
|
+
}
|
|
34615
|
+
function footprintTotalVolume(fp) {
|
|
34616
|
+
return fp instanceof Footprint ? fp.total_volume : 0;
|
|
34617
|
+
}
|
|
34618
|
+
function footprintVah(fp) {
|
|
34619
|
+
return fp instanceof Footprint ? fp.vah_row : null;
|
|
34620
|
+
}
|
|
34621
|
+
function footprintVal(fp) {
|
|
34622
|
+
return fp instanceof Footprint ? fp.val_row : null;
|
|
34623
|
+
}
|
|
34624
|
+
function footprintPoc(fp) {
|
|
34625
|
+
return fp instanceof Footprint ? fp.poc_row : null;
|
|
34626
|
+
}
|
|
34627
|
+
function footprintRows(fp) {
|
|
34628
|
+
return fp instanceof Footprint ? fp.rows.slice() : [];
|
|
34629
|
+
}
|
|
34630
|
+
function footprintGetRowByPrice(fp, price) {
|
|
34631
|
+
if (!(fp instanceof Footprint) || price == null)
|
|
34632
|
+
return null;
|
|
34633
|
+
if (typeof price !== "number" || !Number.isFinite(price))
|
|
34634
|
+
return null;
|
|
34635
|
+
for (const row of fp.rows) {
|
|
34636
|
+
const lo = Math.min(row.down_price, row.up_price);
|
|
34637
|
+
const hi = Math.max(row.down_price, row.up_price);
|
|
34638
|
+
if (lo <= price && price <= hi)
|
|
34639
|
+
return row;
|
|
34640
|
+
}
|
|
34641
|
+
return null;
|
|
34642
|
+
}
|
|
34643
|
+
function volumeRowUpPrice(vr) {
|
|
34644
|
+
return vr instanceof VolumeRow ? vr.up_price : 0;
|
|
34645
|
+
}
|
|
34646
|
+
function volumeRowDownPrice(vr) {
|
|
34647
|
+
return vr instanceof VolumeRow ? vr.down_price : 0;
|
|
34648
|
+
}
|
|
34649
|
+
function volumeRowBuyVolume(vr) {
|
|
34650
|
+
return vr instanceof VolumeRow ? vr.buy_volume : 0;
|
|
34651
|
+
}
|
|
34652
|
+
function volumeRowSellVolume(vr) {
|
|
34653
|
+
return vr instanceof VolumeRow ? vr.sell_volume : 0;
|
|
34654
|
+
}
|
|
34655
|
+
function volumeRowDelta(vr) {
|
|
34656
|
+
return vr instanceof VolumeRow ? vr.delta : 0;
|
|
34657
|
+
}
|
|
34658
|
+
function volumeRowTotalVolume(vr) {
|
|
34659
|
+
return vr instanceof VolumeRow ? vr.buy_volume + vr.sell_volume : 0;
|
|
34660
|
+
}
|
|
34661
|
+
function volumeRowHasBuyImbalance(vr) {
|
|
34662
|
+
return vr instanceof VolumeRow ? Boolean(vr.is_imbalance && vr.buy_volume > vr.sell_volume) : false;
|
|
34663
|
+
}
|
|
34664
|
+
function volumeRowHasSellImbalance(vr) {
|
|
34665
|
+
return vr instanceof VolumeRow ? Boolean(vr.is_imbalance && vr.sell_volume > vr.buy_volume) : false;
|
|
34666
|
+
}
|
|
34667
|
+
|
|
34431
34668
|
// src/runtime/request.ts
|
|
34432
34669
|
var REQUEST_FNS = new Set([
|
|
34433
34670
|
"request.security",
|
|
@@ -34547,6 +34784,7 @@ function resolveCurrencyRate(from, to) {
|
|
|
34547
34784
|
}
|
|
34548
34785
|
function resolveSeed(seed) {
|
|
34549
34786
|
lastSeed = coerceSeed(seed ?? 0);
|
|
34787
|
+
seedFootprintRng(lastSeed);
|
|
34550
34788
|
return null;
|
|
34551
34789
|
}
|
|
34552
34790
|
function resolveRequest(fname, host, args = {}) {
|
|
@@ -34565,6 +34803,10 @@ function resolveRequest(fname, host, args = {}) {
|
|
|
34565
34803
|
if (fname === "request.seed") {
|
|
34566
34804
|
return resolveSeed(seedFromArgs(args));
|
|
34567
34805
|
}
|
|
34806
|
+
if (fname === "request.footprint") {
|
|
34807
|
+
const [numTicks, va] = footprintFromArgs(args);
|
|
34808
|
+
return createFootprint(numTicks, va);
|
|
34809
|
+
}
|
|
34568
34810
|
return resolveForeignNa();
|
|
34569
34811
|
}
|
|
34570
34812
|
function isNamedArgs(args) {
|
|
@@ -34603,6 +34845,11 @@ function seedFromArgs(args) {
|
|
|
34603
34845
|
return args[0] ?? 0;
|
|
34604
34846
|
return args.seed ?? 0;
|
|
34605
34847
|
}
|
|
34848
|
+
function footprintFromArgs(args) {
|
|
34849
|
+
if (!isNamedArgs(args))
|
|
34850
|
+
return [args[0] ?? 100, args[1] ?? 70];
|
|
34851
|
+
return [args.num_ticks ?? 100, args.va_percentage ?? 70];
|
|
34852
|
+
}
|
|
34606
34853
|
function currencyPair(from, to) {
|
|
34607
34854
|
const a = (from ?? "").trim().toUpperCase();
|
|
34608
34855
|
const b = (to ?? "").trim().toUpperCase();
|
|
@@ -36081,6 +36328,13 @@ function mathRandom(a, b, rng = Math.random) {
|
|
|
36081
36328
|
// src/runtime/time.ts
|
|
36082
36329
|
var MIN_T = -62167219200;
|
|
36083
36330
|
var MAX_T = 253402300799;
|
|
36331
|
+
function timestampToMs(ts) {
|
|
36332
|
+
if (ts == null || !Number.isFinite(ts))
|
|
36333
|
+
return null;
|
|
36334
|
+
if (Math.abs(ts) < 100000000000)
|
|
36335
|
+
return ts * 1000;
|
|
36336
|
+
return ts;
|
|
36337
|
+
}
|
|
36084
36338
|
function utcPartsFromMs(ms) {
|
|
36085
36339
|
let t = Number.isFinite(ms) ? Math.trunc(ms / 1000) : 0;
|
|
36086
36340
|
if (t < MIN_T)
|
|
@@ -36937,8 +37191,7 @@ function coerceFormatTimeMs(time) {
|
|
|
36937
37191
|
if (typeof raw !== "number" || !Number.isFinite(raw))
|
|
36938
37192
|
return null;
|
|
36939
37193
|
let ts = Math.trunc(raw);
|
|
36940
|
-
|
|
36941
|
-
ts *= 1000;
|
|
37194
|
+
ts = timestampToMs(ts) ?? ts;
|
|
36942
37195
|
return ts;
|
|
36943
37196
|
}
|
|
36944
37197
|
function formatOffsetHours(offsetHours) {
|
|
@@ -37691,6 +37944,48 @@ class StrategyBook {
|
|
|
37691
37944
|
bar: isFiniteNumber2(bar) ? bar : 0
|
|
37692
37945
|
});
|
|
37693
37946
|
}
|
|
37947
|
+
placeClose(bar, id, price, opts) {
|
|
37948
|
+
const b = isFiniteNumber2(bar) ? bar : 0;
|
|
37949
|
+
const oid = String(id ?? "");
|
|
37950
|
+
this.ensureSanePosition();
|
|
37951
|
+
if (this.position.qty !== 0) {
|
|
37952
|
+
const absPos = Math.abs(this.position.qty);
|
|
37953
|
+
const rawQty = opts?.qty;
|
|
37954
|
+
const q = isFiniteNumber2(rawQty) && rawQty >= 0 ? Math.min(Math.abs(rawQty), absPos) : absPos;
|
|
37955
|
+
if (q > 0) {
|
|
37956
|
+
this.upsertPending({
|
|
37957
|
+
id: `${oid}:close`,
|
|
37958
|
+
direction: this.position.qty > 0 ? "short" : "long",
|
|
37959
|
+
qty: q,
|
|
37960
|
+
limit: null,
|
|
37961
|
+
stop: null,
|
|
37962
|
+
bar: b,
|
|
37963
|
+
kind: "close",
|
|
37964
|
+
deferred: true,
|
|
37965
|
+
comment: opts?.comment
|
|
37966
|
+
});
|
|
37967
|
+
}
|
|
37968
|
+
}
|
|
37969
|
+
this.close(b, oid);
|
|
37970
|
+
}
|
|
37971
|
+
placeCloseAll(bar, price, opts) {
|
|
37972
|
+
const b = isFiniteNumber2(bar) ? bar : 0;
|
|
37973
|
+
this.ensureSanePosition();
|
|
37974
|
+
if (this.position.qty !== 0) {
|
|
37975
|
+
this.upsertPending({
|
|
37976
|
+
id: "close_all",
|
|
37977
|
+
direction: this.position.qty > 0 ? "short" : "long",
|
|
37978
|
+
qty: Math.abs(this.position.qty),
|
|
37979
|
+
limit: null,
|
|
37980
|
+
stop: null,
|
|
37981
|
+
bar: b,
|
|
37982
|
+
kind: "close_all",
|
|
37983
|
+
deferred: true,
|
|
37984
|
+
comment: opts?.comment
|
|
37985
|
+
});
|
|
37986
|
+
}
|
|
37987
|
+
this.events.push({ type: "close_all", id: "", bar: b });
|
|
37988
|
+
}
|
|
37694
37989
|
exit(bar, id, qty) {
|
|
37695
37990
|
const event = {
|
|
37696
37991
|
type: "exit",
|
|
@@ -37728,10 +38023,46 @@ class StrategyBook {
|
|
|
37728
38023
|
placeEntry(bar, id, direction, qty, opts) {
|
|
37729
38024
|
const limit = optLevel(opts?.limit);
|
|
37730
38025
|
const stop = optLevel(opts?.stop);
|
|
38026
|
+
const b = isFiniteNumber2(bar) ? bar : 0;
|
|
38027
|
+
const oid = String(id ?? "");
|
|
37731
38028
|
if (limit == null && stop == null) {
|
|
38029
|
+
if (opts?.deferMarket === true) {
|
|
38030
|
+
const dir = mapDirection(direction);
|
|
38031
|
+
const absQty = isFiniteNumber2(qty) ? Math.abs(qty) : Number.NaN;
|
|
38032
|
+
if (!isFiniteNumber2(absQty) || absQty <= 0)
|
|
38033
|
+
return;
|
|
38034
|
+
const t = isFiniteNumber2(opts?.time) ? opts.time : b;
|
|
38035
|
+
if (!this.riskAllowsEntry(dir, t))
|
|
38036
|
+
return;
|
|
38037
|
+
const mark = isFiniteNumber2(opts?.price) ? opts.price : 0;
|
|
38038
|
+
const capped = this.capQtyByMaxPosition(absQty, mark);
|
|
38039
|
+
if (!isFiniteNumber2(capped) || capped <= 0)
|
|
38040
|
+
return;
|
|
38041
|
+
const signed = dir === "long" ? capped : -capped;
|
|
38042
|
+
if (this.position.qty !== 0 && Math.sign(this.position.qty) === Math.sign(signed)) {
|
|
38043
|
+
const maxEntries = this.pyramiding !== undefined ? this.pyramiding + 1 : 1;
|
|
38044
|
+
const allowed = this.pyramiding !== undefined && this.pyramiding > 0 && this.opentrades < maxEntries;
|
|
38045
|
+
if (!allowed)
|
|
38046
|
+
return;
|
|
38047
|
+
}
|
|
38048
|
+
this.upsertPending({
|
|
38049
|
+
id: oid,
|
|
38050
|
+
direction: dir,
|
|
38051
|
+
qty: capped,
|
|
38052
|
+
limit: null,
|
|
38053
|
+
stop: null,
|
|
38054
|
+
bar: b,
|
|
38055
|
+
kind: "entry",
|
|
38056
|
+
is_entry: true,
|
|
38057
|
+
deferred: true,
|
|
38058
|
+
comment: opts?.comment
|
|
38059
|
+
});
|
|
38060
|
+
this.events.push({ type: "order", id: oid, direction: dir, qty: capped, bar: b });
|
|
38061
|
+
return;
|
|
38062
|
+
}
|
|
37732
38063
|
if (isFiniteNumber2(opts?.price)) {
|
|
37733
38064
|
const dir = mapDirection(direction);
|
|
37734
|
-
const t = isFiniteNumber2(opts?.time) ? opts.time :
|
|
38065
|
+
const t = isFiniteNumber2(opts?.time) ? opts.time : b;
|
|
37735
38066
|
this.updateEquityExtremes(opts.price);
|
|
37736
38067
|
if (!this.riskAllowsEntry(dir, t))
|
|
37737
38068
|
return;
|
|
@@ -37742,8 +38073,6 @@ class StrategyBook {
|
|
|
37742
38073
|
}
|
|
37743
38074
|
const dir = mapDirection(direction);
|
|
37744
38075
|
const absQty = isFiniteNumber2(qty) ? Math.abs(qty) : Number.NaN;
|
|
37745
|
-
const b = isFiniteNumber2(bar) ? bar : 0;
|
|
37746
|
-
const oid = String(id ?? "");
|
|
37747
38076
|
this.entry(b, oid, dir, isFiniteNumber2(absQty) ? absQty : qty);
|
|
37748
38077
|
if (!isFiniteNumber2(absQty) || absQty === 0)
|
|
37749
38078
|
return;
|
|
@@ -37793,6 +38122,23 @@ class StrategyBook {
|
|
|
37793
38122
|
return;
|
|
37794
38123
|
const t = isFiniteNumber2(opts?.time) ? opts.time : b;
|
|
37795
38124
|
if (limitP == null && stopP == null && !hasTrail) {
|
|
38125
|
+
if (opts?.deferMarket === true) {
|
|
38126
|
+
const closeDir = isLong ? "short" : "long";
|
|
38127
|
+
this.upsertPending({
|
|
38128
|
+
id: `${oid}:close`,
|
|
38129
|
+
direction: closeDir,
|
|
38130
|
+
qty,
|
|
38131
|
+
limit: null,
|
|
38132
|
+
stop: null,
|
|
38133
|
+
bar: b,
|
|
38134
|
+
kind: "exit",
|
|
38135
|
+
from_entry: fromEntry,
|
|
38136
|
+
deferred: true,
|
|
38137
|
+
comment: opts?.comment
|
|
38138
|
+
});
|
|
38139
|
+
this.events.push({ type: "order", id: oid, direction: closeDir, qty, bar: b });
|
|
38140
|
+
return;
|
|
38141
|
+
}
|
|
37796
38142
|
if (!isFiniteNumber2(opts?.price))
|
|
37797
38143
|
return;
|
|
37798
38144
|
this.reducePosition(b, oid, opts.price, qty, fromEntry, t, opts?.comment);
|
|
@@ -37863,13 +38209,24 @@ class StrategyBook {
|
|
|
37863
38209
|
for (const order of this.pending.slice()) {
|
|
37864
38210
|
if (!this.pending.some((p) => p.id === order.id))
|
|
37865
38211
|
continue;
|
|
38212
|
+
if (order.bar === b)
|
|
38213
|
+
continue;
|
|
37866
38214
|
if (order.kind === "exit" && isTrailOrder(order))
|
|
37867
38215
|
updateTrailStop(order, high, low);
|
|
37868
|
-
|
|
38216
|
+
let px;
|
|
38217
|
+
if (order.limit == null && order.stop == null)
|
|
38218
|
+
px = open;
|
|
38219
|
+
else
|
|
38220
|
+
px = triggerPrice(order, open, high, low);
|
|
37869
38221
|
if (px == null)
|
|
37870
38222
|
continue;
|
|
37871
38223
|
this.dropPending(order.id);
|
|
37872
|
-
const
|
|
38224
|
+
const emitEntry = order.kind === "entry" || order.deferred === true;
|
|
38225
|
+
const barTime = isFiniteNumber2(ohlc.time) ? ohlc.time : undefined;
|
|
38226
|
+
const applied = order.kind === "exit" ? this.applyExitFill(b, order, px, barTime) : order.kind === "close" || order.kind === "close_all" ? this.applyCloseFill(b, order, px, barTime) : this.applyEntryFill(b, order.id, order.direction, order.qty, px, emitEntry, {
|
|
38227
|
+
comment: order.comment,
|
|
38228
|
+
time: barTime
|
|
38229
|
+
});
|
|
37873
38230
|
if (applied) {
|
|
37874
38231
|
const q = Math.abs(this.fills.at(-1)?.qty ?? order.qty);
|
|
37875
38232
|
this.ocaAfterFill(order, q, b);
|
|
@@ -37885,6 +38242,22 @@ class StrategyBook {
|
|
|
37885
38242
|
}
|
|
37886
38243
|
return filled;
|
|
37887
38244
|
}
|
|
38245
|
+
applyCloseFill(bar, order, price, time) {
|
|
38246
|
+
this.ensureSanePosition();
|
|
38247
|
+
if (this.position.qty === 0 || !isFiniteNumber2(price))
|
|
38248
|
+
return false;
|
|
38249
|
+
const absPos = Math.abs(this.position.qty);
|
|
38250
|
+
const rawQty = order.qty;
|
|
38251
|
+
const q = isFiniteNumber2(rawQty) && rawQty > 0 ? Math.min(Math.abs(rawQty), absPos) : absPos;
|
|
38252
|
+
if (!(q > 0))
|
|
38253
|
+
return false;
|
|
38254
|
+
if (q < absPos - 0.000000000001) {
|
|
38255
|
+
this.reducePosition(bar, order.id, price, q, order.from_entry ?? null, time, order.comment);
|
|
38256
|
+
} else {
|
|
38257
|
+
this.flattenAt(bar, order.id, price, time, order.comment);
|
|
38258
|
+
}
|
|
38259
|
+
return true;
|
|
38260
|
+
}
|
|
37888
38261
|
fillEntry(bar, id, direction, qty, price, opts) {
|
|
37889
38262
|
this.applyEntryFill(bar, id, direction, qty, price, true, opts);
|
|
37890
38263
|
}
|
|
@@ -38007,9 +38380,9 @@ class StrategyBook {
|
|
|
38007
38380
|
return { status: "invalid", qty: 0 };
|
|
38008
38381
|
return { status: "ok", qty: Math.min(rawQty, target) };
|
|
38009
38382
|
}
|
|
38010
|
-
applyExitFill(bar, order, price) {
|
|
38383
|
+
applyExitFill(bar, order, price, time) {
|
|
38011
38384
|
const t = isFiniteNumber2(bar) ? bar : 0;
|
|
38012
|
-
return this.reducePosition(t, order.id, price, order.qty, order.from_entry ?? null,
|
|
38385
|
+
return this.reducePosition(t, order.id, price, order.qty, order.from_entry ?? null, time);
|
|
38013
38386
|
}
|
|
38014
38387
|
closeLeg(ot, bar, exitPrice, qty, profit, commission, exitTime, exitComment) {
|
|
38015
38388
|
const closed = {
|
|
@@ -40016,6 +40389,37 @@ function pushCap(window2, value, cap) {
|
|
|
40016
40389
|
function finiteOut2(value) {
|
|
40017
40390
|
return Number.isFinite(value) ? value : null;
|
|
40018
40391
|
}
|
|
40392
|
+
function smaOf(series, period) {
|
|
40393
|
+
if (period <= 0 || series.length < period)
|
|
40394
|
+
return null;
|
|
40395
|
+
const window2 = series.slice(series.length - period);
|
|
40396
|
+
let sum = 0;
|
|
40397
|
+
for (const v of window2) {
|
|
40398
|
+
if (v === null)
|
|
40399
|
+
return null;
|
|
40400
|
+
sum += v;
|
|
40401
|
+
}
|
|
40402
|
+
return sum / period;
|
|
40403
|
+
}
|
|
40404
|
+
function stdevOf(series, period) {
|
|
40405
|
+
if (period <= 1 || series.length < period)
|
|
40406
|
+
return null;
|
|
40407
|
+
const window2 = series.slice(series.length - period);
|
|
40408
|
+
const vals = [];
|
|
40409
|
+
for (const v of window2) {
|
|
40410
|
+
if (v === null)
|
|
40411
|
+
return null;
|
|
40412
|
+
vals.push(v);
|
|
40413
|
+
}
|
|
40414
|
+
let mean = 0;
|
|
40415
|
+
for (const v of vals)
|
|
40416
|
+
mean += v;
|
|
40417
|
+
mean /= period;
|
|
40418
|
+
let sumSq = 0;
|
|
40419
|
+
for (const v of vals)
|
|
40420
|
+
sumSq += (v - mean) ** 2;
|
|
40421
|
+
return Math.sqrt(sumSq / period);
|
|
40422
|
+
}
|
|
40019
40423
|
var PERIOD_INT_EPS = 0.000000001;
|
|
40020
40424
|
function pinePeriod(period) {
|
|
40021
40425
|
if (!Number.isFinite(period) || period <= 0)
|
|
@@ -40114,6 +40518,22 @@ class TaEngine {
|
|
|
40114
40518
|
emvSites = new Map;
|
|
40115
40519
|
fractalSites = new Map;
|
|
40116
40520
|
zigzagSites = new Map;
|
|
40521
|
+
engulfingSites = new Map;
|
|
40522
|
+
insideBarSites = new Map;
|
|
40523
|
+
doubleTopBottomSites = new Map;
|
|
40524
|
+
rsiDivergenceSites = new Map;
|
|
40525
|
+
stochSmoothSites = new Map;
|
|
40526
|
+
smaWeightedSites = new Map;
|
|
40527
|
+
betaSites = new Map;
|
|
40528
|
+
rSquaredSites = new Map;
|
|
40529
|
+
comovementSites = new Map;
|
|
40530
|
+
skewnessSites = new Map;
|
|
40531
|
+
kurtosisSites = new Map;
|
|
40532
|
+
vwmSites = new Map;
|
|
40533
|
+
meanReversionSites = new Map;
|
|
40534
|
+
marketConditionSites = new Map;
|
|
40535
|
+
orderFlowSites = new Map;
|
|
40536
|
+
liquiditySites = new Map;
|
|
40117
40537
|
sma(site, source, period) {
|
|
40118
40538
|
const n = pinePeriod(period);
|
|
40119
40539
|
if (n === null)
|
|
@@ -40188,18 +40608,24 @@ class TaEngine {
|
|
|
40188
40608
|
st = {
|
|
40189
40609
|
period: n,
|
|
40190
40610
|
prevClose: null,
|
|
40611
|
+
started: false,
|
|
40191
40612
|
rma: { period: n, rma: null, seeded: false, started: false, seedBuf: [] }
|
|
40192
40613
|
};
|
|
40193
40614
|
this.atrSites.set(site, st);
|
|
40194
40615
|
}
|
|
40195
|
-
const prev = st.prevClose;
|
|
40196
|
-
st.prevClose = finiteCell2(close);
|
|
40197
|
-
if (prev === null)
|
|
40198
|
-
return null;
|
|
40199
40616
|
const h = finiteCell2(high);
|
|
40200
40617
|
const l = finiteCell2(low);
|
|
40201
40618
|
const c = finiteCell2(close);
|
|
40202
|
-
if (
|
|
40619
|
+
if (!st.started) {
|
|
40620
|
+
st.started = true;
|
|
40621
|
+
st.prevClose = c;
|
|
40622
|
+
if (h === null || l === null)
|
|
40623
|
+
return null;
|
|
40624
|
+
return rmaStep(st.rma, h - l, n);
|
|
40625
|
+
}
|
|
40626
|
+
const prev = st.prevClose;
|
|
40627
|
+
st.prevClose = c;
|
|
40628
|
+
if (prev === null || h === null || l === null || c === null)
|
|
40203
40629
|
return null;
|
|
40204
40630
|
const tr = Math.max(h - l, Math.abs(h - prev), Math.abs(l - prev));
|
|
40205
40631
|
return rmaStep(st.rma, tr, n);
|
|
@@ -40365,7 +40791,7 @@ class TaEngine {
|
|
|
40365
40791
|
}
|
|
40366
40792
|
if (st.window.length < n || st.count !== n)
|
|
40367
40793
|
return null;
|
|
40368
|
-
let v = (st.sumsq - st.sum * st.sum / n) /
|
|
40794
|
+
let v = (st.sumsq - st.sum * st.sum / n) / n;
|
|
40369
40795
|
if (v < 0)
|
|
40370
40796
|
v = 0;
|
|
40371
40797
|
return Math.sqrt(v);
|
|
@@ -41571,7 +41997,7 @@ class TaEngine {
|
|
|
41571
41997
|
}
|
|
41572
41998
|
if (st.window.length < n || st.count !== n)
|
|
41573
41999
|
return null;
|
|
41574
|
-
let v = (st.sumsq - st.sum * st.sum / n) /
|
|
42000
|
+
let v = (st.sumsq - st.sum * st.sum / n) / n;
|
|
41575
42001
|
if (v < 0)
|
|
41576
42002
|
v = 0;
|
|
41577
42003
|
return v;
|
|
@@ -42175,20 +42601,17 @@ class TaEngine {
|
|
|
42175
42601
|
st = { samples: [] };
|
|
42176
42602
|
this.zigzagSites.set(site, st);
|
|
42177
42603
|
}
|
|
42178
|
-
|
|
42179
|
-
|
|
42180
|
-
|
|
42181
|
-
|
|
42182
|
-
finite.push(v);
|
|
42183
|
-
}
|
|
42184
|
-
if (finite.length < 2)
|
|
42604
|
+
const x = finiteCell2(source);
|
|
42605
|
+
if (x !== null)
|
|
42606
|
+
pushCap(st.samples, x, 2);
|
|
42607
|
+
if (st.samples.length < 2)
|
|
42185
42608
|
return { high: null, low: null, dir: 0 };
|
|
42186
|
-
const oldest =
|
|
42187
|
-
const
|
|
42188
|
-
const recentHigh = Math.max(oldest,
|
|
42189
|
-
const recentLow = Math.min(oldest,
|
|
42609
|
+
const oldest = st.samples[0];
|
|
42610
|
+
const newest = st.samples[1];
|
|
42611
|
+
const recentHigh = Math.max(oldest, newest);
|
|
42612
|
+
const recentLow = Math.min(oldest, newest);
|
|
42190
42613
|
const pct = recentLow !== 0 ? (recentHigh - recentLow) / recentLow * 100 : 0;
|
|
42191
|
-
const direction = recentHigh ===
|
|
42614
|
+
const direction = recentHigh === newest ? 1 : -1;
|
|
42192
42615
|
return { high: recentHigh, low: recentLow, dir: pct > th ? 1 : direction };
|
|
42193
42616
|
}
|
|
42194
42617
|
accelSites = new Map;
|
|
@@ -42255,30 +42678,31 @@ class TaEngine {
|
|
|
42255
42678
|
}
|
|
42256
42679
|
accelerationFactor(site, source, period) {
|
|
42257
42680
|
const p = this.coerceTaInt(period, "ta.acceleration_factor() requires 2 arguments");
|
|
42258
|
-
|
|
42681
|
+
if (p <= 0)
|
|
42682
|
+
return 0;
|
|
42683
|
+
const key = `${site}:${p}`;
|
|
42684
|
+
let samples = this.accelSites.get(key);
|
|
42259
42685
|
if (samples === undefined) {
|
|
42260
42686
|
samples = [];
|
|
42261
|
-
this.accelSites.set(
|
|
42687
|
+
this.accelSites.set(key, samples);
|
|
42262
42688
|
}
|
|
42263
|
-
pushCap(samples, finiteCell2(source),
|
|
42264
|
-
if (samples.length < p + 1
|
|
42689
|
+
pushCap(samples, finiteCell2(source), p + 1);
|
|
42690
|
+
if (samples.length < p + 1)
|
|
42265
42691
|
return 0;
|
|
42266
|
-
const
|
|
42267
|
-
const
|
|
42268
|
-
for (let i = oldest.length - 1;i >= 0; i--) {
|
|
42269
|
-
const v = oldest[i];
|
|
42692
|
+
const clean = [];
|
|
42693
|
+
for (const v of samples) {
|
|
42270
42694
|
if (v !== null)
|
|
42271
|
-
|
|
42695
|
+
clean.push(v);
|
|
42272
42696
|
}
|
|
42273
|
-
if (
|
|
42697
|
+
if (clean.length < 2)
|
|
42274
42698
|
return 0;
|
|
42275
42699
|
let oldSum = 0;
|
|
42276
|
-
for (let i = 0;i <
|
|
42277
|
-
oldSum +=
|
|
42278
|
-
const oldMom = oldSum / (
|
|
42700
|
+
for (let i = 0;i < clean.length - 1; i++)
|
|
42701
|
+
oldSum += clean[i];
|
|
42702
|
+
const oldMom = oldSum / (clean.length - 1);
|
|
42703
|
+
const newMom = clean[clean.length - 1];
|
|
42279
42704
|
if (Math.abs(oldMom) < 0.0000000001)
|
|
42280
42705
|
return 0;
|
|
42281
|
-
const newMom = newestFirst[newestFirst.length - 1];
|
|
42282
42706
|
let acc = (newMom - oldMom) / oldMom;
|
|
42283
42707
|
if (acc < -2)
|
|
42284
42708
|
acc = -2;
|
|
@@ -42286,32 +42710,141 @@ class TaEngine {
|
|
|
42286
42710
|
acc = 2;
|
|
42287
42711
|
return finiteOut2(acc);
|
|
42288
42712
|
}
|
|
42289
|
-
stochSmooth(high, low, close, period, smoothK, smoothD) {
|
|
42713
|
+
stochSmooth(site, high, low, close, period, smoothK, smoothD) {
|
|
42290
42714
|
const p = this.coerceTaInt(period, "ta.stoch_smooth period must be integer");
|
|
42291
42715
|
const k = this.coerceTaInt(smoothK, "ta.stoch_smooth smooth_k must be integer");
|
|
42292
42716
|
const d = this.coerceTaInt(smoothD, "ta.stoch_smooth smooth_d must be integer");
|
|
42293
|
-
if (p
|
|
42294
|
-
throw new Error("max() iterable argument is empty");
|
|
42295
|
-
if (high === null || low === null || close === null) {
|
|
42296
|
-
throw new Error("unsupported operand type(s) for /: 'float' and 'NoneType'");
|
|
42297
|
-
}
|
|
42298
|
-
if (k !== 1 || d !== 1)
|
|
42717
|
+
if (p < 1 || k < 1 || d < 1)
|
|
42299
42718
|
return null;
|
|
42300
|
-
const
|
|
42301
|
-
|
|
42302
|
-
|
|
42303
|
-
|
|
42304
|
-
|
|
42305
|
-
|
|
42306
|
-
|
|
42307
|
-
|
|
42308
|
-
|
|
42719
|
+
const key = `${site}:${p}:${k}:${d}`;
|
|
42720
|
+
let st = this.stochSmoothSites.get(key);
|
|
42721
|
+
if (st === undefined) {
|
|
42722
|
+
st = { highs: [], lows: [] };
|
|
42723
|
+
this.stochSmoothSites.set(key, st);
|
|
42724
|
+
}
|
|
42725
|
+
pushCap(st.highs, finiteCell2(high), p);
|
|
42726
|
+
pushCap(st.lows, finiteCell2(low), p);
|
|
42727
|
+
const c = finiteCell2(close);
|
|
42728
|
+
let stoch = null;
|
|
42729
|
+
if (c !== null && !st.highs.includes(null) && !st.lows.includes(null)) {
|
|
42730
|
+
let hh = -Infinity;
|
|
42731
|
+
let ll = Infinity;
|
|
42732
|
+
for (const v of st.highs) {
|
|
42733
|
+
if (v > hh)
|
|
42734
|
+
hh = v;
|
|
42735
|
+
}
|
|
42736
|
+
for (const v of st.lows) {
|
|
42737
|
+
if (v < ll)
|
|
42738
|
+
ll = v;
|
|
42739
|
+
}
|
|
42740
|
+
stoch = hh === ll ? 50 : 100 * (c - ll) / (hh - ll);
|
|
42741
|
+
}
|
|
42742
|
+
const kVal = this.ema(`${site}:k`, stoch, k);
|
|
42743
|
+
return this.ema(`${site}:d`, kVal, d);
|
|
42744
|
+
}
|
|
42745
|
+
engulfing(site, open, close) {
|
|
42746
|
+
const off = taRec({ is_bullish: false, is_bearish: false, pattern_strength: 0 });
|
|
42747
|
+
let st = this.engulfingSites.get(site);
|
|
42748
|
+
if (st === undefined) {
|
|
42749
|
+
st = { prevOpen: null, prevClose: null, count: 0 };
|
|
42750
|
+
this.engulfingSites.set(site, st);
|
|
42751
|
+
}
|
|
42752
|
+
const o = finiteCell2(open);
|
|
42753
|
+
const c = finiteCell2(close);
|
|
42754
|
+
st.count += 1;
|
|
42755
|
+
const prevO = st.prevOpen;
|
|
42756
|
+
const prevC = st.prevClose;
|
|
42757
|
+
if (st.count < 2 || prevO === null || prevC === null || o === null || c === null) {
|
|
42758
|
+
st.prevOpen = o;
|
|
42759
|
+
st.prevClose = c;
|
|
42760
|
+
return off;
|
|
42761
|
+
}
|
|
42762
|
+
const isBullish = o < prevC && c > prevO && c > o;
|
|
42763
|
+
const isBearish = o > prevC && c < prevO && c < o;
|
|
42764
|
+
let engulf = 0;
|
|
42765
|
+
if (isBullish) {
|
|
42766
|
+
engulf = Math.max(0, Math.min(1, (c - prevO) / Math.abs(prevO - prevC + 0.0001)));
|
|
42767
|
+
} else if (isBearish) {
|
|
42768
|
+
engulf = Math.max(0, Math.min(1, (prevO - c) / Math.abs(prevC - prevO + 0.0001)));
|
|
42769
|
+
}
|
|
42770
|
+
st.prevOpen = o;
|
|
42771
|
+
st.prevClose = c;
|
|
42772
|
+
return taRec({
|
|
42773
|
+
is_bullish: isBullish,
|
|
42774
|
+
is_bearish: isBearish,
|
|
42775
|
+
pattern_strength: finiteOut2(engulf) ?? 0
|
|
42776
|
+
});
|
|
42309
42777
|
}
|
|
42310
|
-
|
|
42311
|
-
|
|
42312
|
-
|
|
42778
|
+
insideBarPattern(site, high, low) {
|
|
42779
|
+
let st = this.insideBarSites.get(site);
|
|
42780
|
+
if (st === undefined) {
|
|
42781
|
+
st = { prevHigh: null, prevLow: null, count: 0 };
|
|
42782
|
+
this.insideBarSites.set(site, st);
|
|
42783
|
+
}
|
|
42784
|
+
const currH = high !== null && Number.isFinite(high) ? high : 0;
|
|
42785
|
+
const currL = low !== null && Number.isFinite(low) ? low : 0;
|
|
42786
|
+
st.count += 1;
|
|
42787
|
+
const prevH = st.prevHigh;
|
|
42788
|
+
const prevL = st.prevLow;
|
|
42789
|
+
if (st.count < 2 || prevH === null || prevL === null) {
|
|
42790
|
+
st.prevHigh = currH;
|
|
42791
|
+
st.prevLow = currL;
|
|
42792
|
+
return false;
|
|
42793
|
+
}
|
|
42794
|
+
const val = currH < prevH && currL > prevL;
|
|
42795
|
+
st.prevHigh = currH;
|
|
42796
|
+
st.prevLow = currL;
|
|
42797
|
+
return val;
|
|
42798
|
+
}
|
|
42799
|
+
doubleTopBottom(site, high, low, period) {
|
|
42800
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
42801
|
+
const off = taRec({ pattern_type: "none", strength: 0, breakout_level: 0 });
|
|
42802
|
+
if (n < 1)
|
|
42803
|
+
return off;
|
|
42804
|
+
const key = `${site}:${n}`;
|
|
42805
|
+
let st = this.doubleTopBottomSites.get(key);
|
|
42806
|
+
if (st === undefined) {
|
|
42807
|
+
st = { highs: [], lows: [], count: 0 };
|
|
42808
|
+
this.doubleTopBottomSites.set(key, st);
|
|
42809
|
+
}
|
|
42810
|
+
pushCap(st.highs, finiteCell2(high), n);
|
|
42811
|
+
pushCap(st.lows, finiteCell2(low), n);
|
|
42812
|
+
st.count += 1;
|
|
42813
|
+
if (st.count < n)
|
|
42814
|
+
return off;
|
|
42815
|
+
const recentHigh = [];
|
|
42816
|
+
for (const v of st.highs) {
|
|
42817
|
+
if (v !== null)
|
|
42818
|
+
recentHigh.push(v);
|
|
42819
|
+
}
|
|
42820
|
+
const recentLow = [];
|
|
42821
|
+
for (const v of st.lows) {
|
|
42822
|
+
if (v !== null)
|
|
42823
|
+
recentLow.push(v);
|
|
42824
|
+
}
|
|
42825
|
+
if (recentHigh.length < 3 || recentLow.length === 0)
|
|
42826
|
+
return off;
|
|
42827
|
+
const peaks = [recentHigh[0]];
|
|
42828
|
+
for (let i = 1;i < recentHigh.length - 1; i++) {
|
|
42829
|
+
if (recentHigh[i] > recentHigh[i - 1] && recentHigh[i] > recentHigh[i + 1]) {
|
|
42830
|
+
peaks.push(recentHigh[i]);
|
|
42831
|
+
}
|
|
42832
|
+
}
|
|
42833
|
+
if (peaks.length < 2)
|
|
42834
|
+
return off;
|
|
42835
|
+
const peakDiff = Math.abs(peaks[peaks.length - 1] - peaks[peaks.length - 2]);
|
|
42836
|
+
const avgPeak = (peaks[peaks.length - 1] + peaks[peaks.length - 2]) / 2;
|
|
42837
|
+
const strength = avgPeak > 0 ? 1 - Math.min(1, peakDiff / avgPeak) : 0;
|
|
42838
|
+
let minLow = recentLow[0];
|
|
42839
|
+
for (const v of recentLow) {
|
|
42840
|
+
if (v < minLow)
|
|
42841
|
+
minLow = v;
|
|
42313
42842
|
}
|
|
42314
|
-
return taRec({
|
|
42843
|
+
return taRec({
|
|
42844
|
+
pattern_type: "double_top",
|
|
42845
|
+
strength: finiteOut2(strength) ?? 0,
|
|
42846
|
+
breakout_level: finiteOut2(minLow - avgPeak * 0.1) ?? 0
|
|
42847
|
+
});
|
|
42315
42848
|
}
|
|
42316
42849
|
cumDeltaSites = new Map;
|
|
42317
42850
|
volMomSites = new Map;
|
|
@@ -42364,96 +42897,91 @@ class TaEngine {
|
|
|
42364
42897
|
}
|
|
42365
42898
|
return taRec({ is_oversold: rsi < os, is_overbought: rsi > ob, rsi });
|
|
42366
42899
|
}
|
|
42367
|
-
rsiDivergence(
|
|
42900
|
+
rsiDivergence(site, value, period) {
|
|
42368
42901
|
const p = this.asCount(period);
|
|
42369
|
-
if (p === null ||
|
|
42370
|
-
return
|
|
42371
|
-
let
|
|
42372
|
-
|
|
42373
|
-
|
|
42374
|
-
|
|
42375
|
-
|
|
42376
|
-
|
|
42377
|
-
|
|
42378
|
-
|
|
42379
|
-
|
|
42380
|
-
|
|
42381
|
-
|
|
42382
|
-
|
|
42383
|
-
|
|
42384
|
-
|
|
42385
|
-
|
|
42386
|
-
|
|
42387
|
-
|
|
42388
|
-
|
|
42389
|
-
|
|
42390
|
-
|
|
42391
|
-
|
|
42392
|
-
|
|
42393
|
-
|
|
42394
|
-
|
|
42395
|
-
}
|
|
42396
|
-
const cur = series[i];
|
|
42397
|
-
const range = rsiMax - rsiMin;
|
|
42398
|
-
if (cur === null || !Number.isFinite(cur) || range <= 0) {
|
|
42399
|
-
last = 0;
|
|
42400
|
-
continue;
|
|
42401
|
-
}
|
|
42402
|
-
last = (cur - rsiMin) / range * 2 - 1;
|
|
42902
|
+
if (p === null || p < 1)
|
|
42903
|
+
return 0;
|
|
42904
|
+
let st = this.rsiDivergenceSites.get(`${site}:${p}`);
|
|
42905
|
+
if (st === undefined) {
|
|
42906
|
+
st = { window: [], count: 0 };
|
|
42907
|
+
this.rsiDivergenceSites.set(`${site}:${p}`, st);
|
|
42908
|
+
}
|
|
42909
|
+
const x = finiteCell2(value);
|
|
42910
|
+
pushCap(st.window, x, p + 1);
|
|
42911
|
+
st.count += 1;
|
|
42912
|
+
if (st.count <= p)
|
|
42913
|
+
return 0;
|
|
42914
|
+
const vals = [];
|
|
42915
|
+
for (const v of st.window) {
|
|
42916
|
+
if (v !== null)
|
|
42917
|
+
vals.push(v);
|
|
42918
|
+
}
|
|
42919
|
+
if (vals.length < 2 || x === null)
|
|
42920
|
+
return 0;
|
|
42921
|
+
let lo = vals[0];
|
|
42922
|
+
let hi = vals[0];
|
|
42923
|
+
for (const v of vals) {
|
|
42924
|
+
if (v < lo)
|
|
42925
|
+
lo = v;
|
|
42926
|
+
if (v > hi)
|
|
42927
|
+
hi = v;
|
|
42403
42928
|
}
|
|
42404
|
-
|
|
42929
|
+
const range = hi - lo;
|
|
42930
|
+
return range > 0 ? finiteOut2((x - lo) / range * 2 - 1) : 0;
|
|
42405
42931
|
}
|
|
42406
42932
|
cumulativeDelta(site, close, volume, period) {
|
|
42407
42933
|
const n = this.asCount(period);
|
|
42408
|
-
|
|
42934
|
+
if (n === null || n <= 0)
|
|
42935
|
+
return 0;
|
|
42936
|
+
let st = this.cumDeltaSites.get(`${site}:${n}`);
|
|
42409
42937
|
if (st === undefined) {
|
|
42410
|
-
st = {
|
|
42411
|
-
this.cumDeltaSites.set(site
|
|
42938
|
+
st = { closes: [], volumes: [], count: 0 };
|
|
42939
|
+
this.cumDeltaSites.set(`${site}:${n}`, st);
|
|
42412
42940
|
}
|
|
42413
|
-
|
|
42414
|
-
|
|
42415
|
-
|
|
42941
|
+
const c = finiteCell2(close);
|
|
42942
|
+
const v = volume !== null && Number.isFinite(volume) ? volume : 0;
|
|
42943
|
+
pushCap(st.closes, c, n + 1);
|
|
42944
|
+
pushCap(st.volumes, v, n);
|
|
42945
|
+
st.count += 1;
|
|
42946
|
+
if (st.count < n)
|
|
42416
42947
|
return 0;
|
|
42417
42948
|
let delta = 0;
|
|
42418
|
-
|
|
42419
|
-
|
|
42420
|
-
const
|
|
42421
|
-
const
|
|
42422
|
-
const
|
|
42423
|
-
|
|
42424
|
-
|
|
42425
|
-
|
|
42426
|
-
|
|
42427
|
-
|
|
42428
|
-
|
|
42429
|
-
|
|
42430
|
-
}
|
|
42949
|
+
const offset = st.closes.length - st.volumes.length;
|
|
42950
|
+
for (let j = 0;j < st.volumes.length; j++) {
|
|
42951
|
+
const idx = offset + j;
|
|
42952
|
+
const cRaw = st.closes[idx] ?? null;
|
|
42953
|
+
const cur = cRaw ?? 0;
|
|
42954
|
+
const prevRaw = idx === 0 ? null : st.closes[idx - 1] ?? null;
|
|
42955
|
+
const prev = prevRaw ?? cur;
|
|
42956
|
+
const vol = st.volumes[j];
|
|
42957
|
+
if (cur > prev)
|
|
42958
|
+
delta += vol;
|
|
42959
|
+
else if (cur < prev)
|
|
42960
|
+
delta -= vol;
|
|
42431
42961
|
}
|
|
42432
42962
|
return finiteOut2(delta);
|
|
42433
42963
|
}
|
|
42434
42964
|
volumeMomentum(site, volume, period) {
|
|
42435
42965
|
const n = this.asCount(period);
|
|
42436
|
-
|
|
42437
|
-
if (st === undefined) {
|
|
42438
|
-
st = { volume: [] };
|
|
42439
|
-
this.volMomSites.set(site, st);
|
|
42440
|
-
}
|
|
42441
|
-
this.pushChrono(st.volume, volume);
|
|
42442
|
-
if (n === null || n <= 0 || st.volume.length < n + 1)
|
|
42966
|
+
if (n === null || n <= 0)
|
|
42443
42967
|
return 0;
|
|
42444
|
-
|
|
42445
|
-
|
|
42446
|
-
|
|
42447
|
-
|
|
42448
|
-
clean.push(v);
|
|
42968
|
+
let st = this.volMomSites.get(`${site}:${n}`);
|
|
42969
|
+
if (st === undefined) {
|
|
42970
|
+
st = { window: [] };
|
|
42971
|
+
this.volMomSites.set(`${site}:${n}`, st);
|
|
42449
42972
|
}
|
|
42450
|
-
if (
|
|
42973
|
+
if (volume !== null && Number.isFinite(volume))
|
|
42974
|
+
pushCap(st.window, volume, n + 1);
|
|
42975
|
+
if (st.window.length < n + 1)
|
|
42451
42976
|
return 0;
|
|
42452
|
-
|
|
42453
|
-
let
|
|
42454
|
-
|
|
42455
|
-
|
|
42456
|
-
|
|
42977
|
+
let oldSum = 0;
|
|
42978
|
+
for (let i = 0;i < n; i++)
|
|
42979
|
+
oldSum += st.window[i];
|
|
42980
|
+
let newSum = 0;
|
|
42981
|
+
for (let i = 1;i <= n; i++)
|
|
42982
|
+
newSum += st.window[i];
|
|
42983
|
+
const oldVol = oldSum / n;
|
|
42984
|
+
const newVol = newSum / n;
|
|
42457
42985
|
if (oldVol === 0)
|
|
42458
42986
|
return 0;
|
|
42459
42987
|
let momentum = (newVol - oldVol) / oldVol * 100;
|
|
@@ -42463,6 +42991,667 @@ class TaEngine {
|
|
|
42463
42991
|
momentum = -100;
|
|
42464
42992
|
return finiteOut2(momentum);
|
|
42465
42993
|
}
|
|
42994
|
+
smaWeighted(site, source, period, weightType) {
|
|
42995
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
42996
|
+
const kind = typeof weightType === "string" ? weightType : "linear";
|
|
42997
|
+
if (n < 1)
|
|
42998
|
+
return null;
|
|
42999
|
+
const key = `${site}:${n}:${kind}`;
|
|
43000
|
+
let st = this.smaWeightedSites.get(key);
|
|
43001
|
+
if (st === undefined) {
|
|
43002
|
+
const weights = [];
|
|
43003
|
+
for (let i = 0;i < n; i++) {
|
|
43004
|
+
if (kind === "quadratic")
|
|
43005
|
+
weights.push((i + 1) ** 2);
|
|
43006
|
+
else if (kind === "sqrt")
|
|
43007
|
+
weights.push((i + 1) ** 0.5);
|
|
43008
|
+
else
|
|
43009
|
+
weights.push(i + 1);
|
|
43010
|
+
}
|
|
43011
|
+
st = { window: [], weights, wsum: weights.reduce((a, b) => a + b, 0) };
|
|
43012
|
+
this.smaWeightedSites.set(key, st);
|
|
43013
|
+
}
|
|
43014
|
+
pushCap(st.window, finiteCell2(source), n);
|
|
43015
|
+
if (st.window.length < n || st.window.includes(null) || st.wsum <= 0)
|
|
43016
|
+
return null;
|
|
43017
|
+
let total = 0;
|
|
43018
|
+
for (let i = 0;i < n; i++)
|
|
43019
|
+
total += st.window[i] * st.weights[i];
|
|
43020
|
+
return finiteOut2(total / st.wsum);
|
|
43021
|
+
}
|
|
43022
|
+
apo(site, source, fast, slow) {
|
|
43023
|
+
const f = this.coerceTaInt(fast, "ta.apo fast_period must be integer");
|
|
43024
|
+
const s = this.coerceTaInt(slow, "ta.apo slow_period must be integer");
|
|
43025
|
+
const fastV = this.ema(`${site}:fast`, source, f);
|
|
43026
|
+
const slowV = this.ema(`${site}:slow`, source, s);
|
|
43027
|
+
if (fastV === null || slowV === null)
|
|
43028
|
+
return null;
|
|
43029
|
+
return finiteOut2(fastV - slowV);
|
|
43030
|
+
}
|
|
43031
|
+
atrNormalized(site, high, low, close, period) {
|
|
43032
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43033
|
+
const atr = this.atr(`${site}:atr`, high, low, close, n);
|
|
43034
|
+
const c = finiteCell2(close);
|
|
43035
|
+
if (c === null || c === 0 || atr === null)
|
|
43036
|
+
return null;
|
|
43037
|
+
return finiteOut2(atr / c * 100);
|
|
43038
|
+
}
|
|
43039
|
+
pairWindow(sites, site, a, b, length) {
|
|
43040
|
+
const n = this.coerceTaInt(length, "length must be integer");
|
|
43041
|
+
if (n < 1)
|
|
43042
|
+
return null;
|
|
43043
|
+
const key = `${site}:${n}`;
|
|
43044
|
+
let st = sites.get(key);
|
|
43045
|
+
if (st === undefined) {
|
|
43046
|
+
st = { a: [], b: [] };
|
|
43047
|
+
sites.set(key, st);
|
|
43048
|
+
}
|
|
43049
|
+
pushCap(st.a, finiteCell2(a), n);
|
|
43050
|
+
pushCap(st.b, finiteCell2(b), n);
|
|
43051
|
+
if (st.a.length < n || st.b.length < n)
|
|
43052
|
+
return null;
|
|
43053
|
+
const left = [];
|
|
43054
|
+
const right = [];
|
|
43055
|
+
for (let i = 0;i < n; i++) {
|
|
43056
|
+
const av = st.a[i];
|
|
43057
|
+
const bv = st.b[i];
|
|
43058
|
+
if (av === null || bv === null)
|
|
43059
|
+
return null;
|
|
43060
|
+
left.push(av);
|
|
43061
|
+
right.push(bv);
|
|
43062
|
+
}
|
|
43063
|
+
return { a: left, b: right };
|
|
43064
|
+
}
|
|
43065
|
+
beta(site, a, b, length) {
|
|
43066
|
+
const pair = this.pairWindow(this.betaSites, site, a, b, length);
|
|
43067
|
+
if (pair === null)
|
|
43068
|
+
return null;
|
|
43069
|
+
const n = pair.a.length;
|
|
43070
|
+
let meanA = 0;
|
|
43071
|
+
let meanB = 0;
|
|
43072
|
+
for (let i = 0;i < n; i++) {
|
|
43073
|
+
meanA += pair.a[i];
|
|
43074
|
+
meanB += pair.b[i];
|
|
43075
|
+
}
|
|
43076
|
+
meanA /= n;
|
|
43077
|
+
meanB /= n;
|
|
43078
|
+
let covariance = 0;
|
|
43079
|
+
let varianceB = 0;
|
|
43080
|
+
for (let i = 0;i < n; i++) {
|
|
43081
|
+
covariance += (pair.a[i] - meanA) * (pair.b[i] - meanB);
|
|
43082
|
+
varianceB += (pair.b[i] - meanB) ** 2;
|
|
43083
|
+
}
|
|
43084
|
+
covariance /= n;
|
|
43085
|
+
varianceB /= n;
|
|
43086
|
+
if (varianceB === 0)
|
|
43087
|
+
return 0;
|
|
43088
|
+
return finiteOut2(covariance / varianceB);
|
|
43089
|
+
}
|
|
43090
|
+
rSquared(site, a, b, length) {
|
|
43091
|
+
const pair = this.pairWindow(this.rSquaredSites, site, a, b, length);
|
|
43092
|
+
if (pair === null)
|
|
43093
|
+
return null;
|
|
43094
|
+
const n = pair.a.length;
|
|
43095
|
+
let meanA = 0;
|
|
43096
|
+
let meanB = 0;
|
|
43097
|
+
for (let i = 0;i < n; i++) {
|
|
43098
|
+
meanA += pair.a[i];
|
|
43099
|
+
meanB += pair.b[i];
|
|
43100
|
+
}
|
|
43101
|
+
meanA /= n;
|
|
43102
|
+
meanB /= n;
|
|
43103
|
+
let covariance = 0;
|
|
43104
|
+
let varA = 0;
|
|
43105
|
+
let varB = 0;
|
|
43106
|
+
for (let i = 0;i < n; i++) {
|
|
43107
|
+
covariance += (pair.a[i] - meanA) * (pair.b[i] - meanB);
|
|
43108
|
+
varA += (pair.a[i] - meanA) ** 2;
|
|
43109
|
+
varB += (pair.b[i] - meanB) ** 2;
|
|
43110
|
+
}
|
|
43111
|
+
covariance /= n;
|
|
43112
|
+
varA /= n;
|
|
43113
|
+
varB /= n;
|
|
43114
|
+
if (varA === 0 || varB === 0)
|
|
43115
|
+
return 0;
|
|
43116
|
+
const corr = covariance / Math.sqrt(varA * varB);
|
|
43117
|
+
return finiteOut2(Math.max(0, Math.min(1, corr ** 2)));
|
|
43118
|
+
}
|
|
43119
|
+
comovement(site, a, b, length) {
|
|
43120
|
+
const pair = this.pairWindow(this.comovementSites, site, a, b, length);
|
|
43121
|
+
if (pair === null)
|
|
43122
|
+
return null;
|
|
43123
|
+
const n = pair.a.length;
|
|
43124
|
+
if (n <= 1)
|
|
43125
|
+
return 0;
|
|
43126
|
+
let same = 0;
|
|
43127
|
+
for (let i = 1;i < n; i++) {
|
|
43128
|
+
if ((pair.a[i] - pair.a[i - 1]) * (pair.b[i] - pair.b[i - 1]) > 0)
|
|
43129
|
+
same += 1;
|
|
43130
|
+
}
|
|
43131
|
+
return finiteOut2(same / (n - 1) * 100);
|
|
43132
|
+
}
|
|
43133
|
+
skewness(site, source, period) {
|
|
43134
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43135
|
+
if (n < 1)
|
|
43136
|
+
return null;
|
|
43137
|
+
const key = `${site}:${n}`;
|
|
43138
|
+
let st = this.skewnessSites.get(key);
|
|
43139
|
+
if (st === undefined) {
|
|
43140
|
+
st = { window: [] };
|
|
43141
|
+
this.skewnessSites.set(key, st);
|
|
43142
|
+
}
|
|
43143
|
+
pushCap(st.window, finiteCell2(source), n);
|
|
43144
|
+
if (st.window.length < n || st.window.includes(null))
|
|
43145
|
+
return null;
|
|
43146
|
+
const vals = st.window;
|
|
43147
|
+
let mean = 0;
|
|
43148
|
+
for (const v of vals)
|
|
43149
|
+
mean += v;
|
|
43150
|
+
mean /= n;
|
|
43151
|
+
let variance = 0;
|
|
43152
|
+
for (const v of vals)
|
|
43153
|
+
variance += (v - mean) ** 2;
|
|
43154
|
+
variance /= n;
|
|
43155
|
+
const std = Math.sqrt(variance);
|
|
43156
|
+
if (std === 0)
|
|
43157
|
+
return 0;
|
|
43158
|
+
let third = 0;
|
|
43159
|
+
for (const v of vals)
|
|
43160
|
+
third += (v - mean) ** 3;
|
|
43161
|
+
return finiteOut2(third / (n * std ** 3));
|
|
43162
|
+
}
|
|
43163
|
+
kurtosis(site, source, period) {
|
|
43164
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43165
|
+
if (n < 1)
|
|
43166
|
+
return null;
|
|
43167
|
+
const key = `${site}:${n}`;
|
|
43168
|
+
let st = this.kurtosisSites.get(key);
|
|
43169
|
+
if (st === undefined) {
|
|
43170
|
+
st = { window: [] };
|
|
43171
|
+
this.kurtosisSites.set(key, st);
|
|
43172
|
+
}
|
|
43173
|
+
pushCap(st.window, finiteCell2(source), n);
|
|
43174
|
+
if (st.window.length < n || st.window.includes(null))
|
|
43175
|
+
return null;
|
|
43176
|
+
const vals = st.window;
|
|
43177
|
+
let mean = 0;
|
|
43178
|
+
for (const v of vals)
|
|
43179
|
+
mean += v;
|
|
43180
|
+
mean /= n;
|
|
43181
|
+
let variance = 0;
|
|
43182
|
+
for (const v of vals)
|
|
43183
|
+
variance += (v - mean) ** 2;
|
|
43184
|
+
variance /= n;
|
|
43185
|
+
const std = Math.sqrt(variance);
|
|
43186
|
+
if (std === 0)
|
|
43187
|
+
return 0;
|
|
43188
|
+
let fourth = 0;
|
|
43189
|
+
for (const v of vals)
|
|
43190
|
+
fourth += (v - mean) ** 4;
|
|
43191
|
+
fourth /= n;
|
|
43192
|
+
return finiteOut2(fourth / std ** 4 - 3);
|
|
43193
|
+
}
|
|
43194
|
+
volumeWeightedMomentum(site, source, volume, length) {
|
|
43195
|
+
const n = this.coerceTaInt(length, "length must be integer");
|
|
43196
|
+
if (n < 1)
|
|
43197
|
+
return null;
|
|
43198
|
+
const key = `${site}:${n}`;
|
|
43199
|
+
let st = this.vwmSites.get(key);
|
|
43200
|
+
if (st === undefined) {
|
|
43201
|
+
st = { prices: [], volumes: [] };
|
|
43202
|
+
this.vwmSites.set(key, st);
|
|
43203
|
+
}
|
|
43204
|
+
pushCap(st.prices, finiteCell2(source), n + 1);
|
|
43205
|
+
pushCap(st.volumes, finiteCell2(volume), n);
|
|
43206
|
+
if (st.volumes.length < n)
|
|
43207
|
+
return null;
|
|
43208
|
+
const ps = st.prices;
|
|
43209
|
+
const vs = st.volumes;
|
|
43210
|
+
let momentumSum = 0;
|
|
43211
|
+
let volumeSum = 0;
|
|
43212
|
+
for (let i = 0;i < n; i++) {
|
|
43213
|
+
const pEnd = ps.length - 1 - i;
|
|
43214
|
+
const pPrev = pEnd - 1;
|
|
43215
|
+
if (pPrev < 0)
|
|
43216
|
+
break;
|
|
43217
|
+
const pv = ps[pEnd] ?? null;
|
|
43218
|
+
const pp = ps[pPrev] ?? null;
|
|
43219
|
+
if (pv === null || pp === null)
|
|
43220
|
+
return null;
|
|
43221
|
+
const vol = vs[vs.length - 1 - i] ?? 0;
|
|
43222
|
+
momentumSum += (pv - pp) * vol;
|
|
43223
|
+
volumeSum += vol;
|
|
43224
|
+
}
|
|
43225
|
+
return finiteOut2(volumeSum > 0 ? momentumSum / volumeSum : 0);
|
|
43226
|
+
}
|
|
43227
|
+
parkinson(high, low) {
|
|
43228
|
+
const h = finiteCell2(high);
|
|
43229
|
+
const l = finiteCell2(low);
|
|
43230
|
+
if (h === null || l === null || h <= l)
|
|
43231
|
+
return null;
|
|
43232
|
+
const ratio = h / l;
|
|
43233
|
+
if (ratio <= 0)
|
|
43234
|
+
return null;
|
|
43235
|
+
return finiteOut2(Math.sqrt(Math.log(ratio) ** 2 / (4 * Math.log(2))));
|
|
43236
|
+
}
|
|
43237
|
+
garmanKlass(high, low, close, open) {
|
|
43238
|
+
const h = finiteCell2(high);
|
|
43239
|
+
const l = finiteCell2(low);
|
|
43240
|
+
const c = finiteCell2(close);
|
|
43241
|
+
const o = finiteCell2(open);
|
|
43242
|
+
if (h === null || l === null || c === null || o === null)
|
|
43243
|
+
return null;
|
|
43244
|
+
if (h <= l || h <= 0 || c <= 0)
|
|
43245
|
+
return null;
|
|
43246
|
+
const term1 = 0.5 * Math.log(h / l) ** 2;
|
|
43247
|
+
const term2 = (2 * Math.log(2) - 1) * Math.log(c / o) ** 2;
|
|
43248
|
+
return finiteOut2(Math.sqrt(term1 - term2));
|
|
43249
|
+
}
|
|
43250
|
+
meanReversionScore(site, close, sma, stdev, period) {
|
|
43251
|
+
const n = this.coerceTaInt(period, "ta.mean_reversion_score() requires 4 arguments");
|
|
43252
|
+
if (n <= 0)
|
|
43253
|
+
return 50;
|
|
43254
|
+
let st = this.meanReversionSites.get(`${site}:${n}`);
|
|
43255
|
+
if (st === undefined) {
|
|
43256
|
+
st = { countClose: 0, countSma: 0 };
|
|
43257
|
+
this.meanReversionSites.set(`${site}:${n}`, st);
|
|
43258
|
+
}
|
|
43259
|
+
st.countClose += 1;
|
|
43260
|
+
st.countSma += 1;
|
|
43261
|
+
if (st.countClose < n || st.countSma < n)
|
|
43262
|
+
return 50;
|
|
43263
|
+
const c = finiteCell2(close) ?? 100;
|
|
43264
|
+
const s = finiteCell2(sma) ?? 100;
|
|
43265
|
+
const sd = finiteCell2(stdev) ?? 1;
|
|
43266
|
+
if (sd === 0)
|
|
43267
|
+
return 50;
|
|
43268
|
+
return Math.max(0, Math.min(100, Math.min(100, Math.abs(c - s) / sd * 20)));
|
|
43269
|
+
}
|
|
43270
|
+
marketCondition(site, close, atr, smaPeriod, stdevPeriod) {
|
|
43271
|
+
const smaN = this.coerceTaInt(smaPeriod, "sma period must be integer");
|
|
43272
|
+
const stdevN = this.coerceTaInt(stdevPeriod, "stdev period must be integer");
|
|
43273
|
+
if (smaN <= 0 || stdevN <= 0)
|
|
43274
|
+
return "ranging";
|
|
43275
|
+
const win = Math.max(smaN, stdevN);
|
|
43276
|
+
const key = `${site}:${smaN}:${stdevN}`;
|
|
43277
|
+
let st = this.marketConditionSites.get(key);
|
|
43278
|
+
if (st === undefined) {
|
|
43279
|
+
st = { window: [], atr: null };
|
|
43280
|
+
this.marketConditionSites.set(key, st);
|
|
43281
|
+
}
|
|
43282
|
+
pushCap(st.window, finiteCell2(close), win);
|
|
43283
|
+
st.atr = finiteCell2(atr);
|
|
43284
|
+
if (st.window.length < win)
|
|
43285
|
+
return "ranging";
|
|
43286
|
+
const cLast = st.window[st.window.length - 1] ?? null;
|
|
43287
|
+
const currentClose = cLast ?? 0;
|
|
43288
|
+
const currentAtr = st.atr ?? 1;
|
|
43289
|
+
const currentSma = smaOf(st.window, smaN) ?? currentClose;
|
|
43290
|
+
const stdevVal = stdevOf(st.window, stdevN);
|
|
43291
|
+
if (stdevVal !== null && stdevVal > currentAtr * 1.5)
|
|
43292
|
+
return "volatile";
|
|
43293
|
+
if (currentClose > currentSma && currentAtr > 0.5)
|
|
43294
|
+
return "trending_up";
|
|
43295
|
+
if (currentClose < currentSma && currentAtr > 0.5)
|
|
43296
|
+
return "trending_down";
|
|
43297
|
+
return "ranging";
|
|
43298
|
+
}
|
|
43299
|
+
orderFlowImbalance(site, high, low, close, volume, period) {
|
|
43300
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43301
|
+
if (n <= 0)
|
|
43302
|
+
return 0;
|
|
43303
|
+
const key = `${site}:${n}`;
|
|
43304
|
+
let st = this.orderFlowSites.get(key);
|
|
43305
|
+
if (st === undefined) {
|
|
43306
|
+
st = { highs: [], lows: [], closes: [], volumes: [] };
|
|
43307
|
+
this.orderFlowSites.set(key, st);
|
|
43308
|
+
}
|
|
43309
|
+
pushCap(st.highs, finiteCell2(high), n);
|
|
43310
|
+
pushCap(st.lows, finiteCell2(low), n);
|
|
43311
|
+
pushCap(st.closes, finiteCell2(close), n);
|
|
43312
|
+
pushCap(st.volumes, finiteCell2(volume), n);
|
|
43313
|
+
if (st.highs.length < n || st.lows.length < n)
|
|
43314
|
+
return 0;
|
|
43315
|
+
let buy = 0;
|
|
43316
|
+
let sell = 0;
|
|
43317
|
+
for (let i = 0;i < n; i++) {
|
|
43318
|
+
const h = st.highs[i] ?? 0;
|
|
43319
|
+
const l = st.lows[i] ?? 0;
|
|
43320
|
+
const c = st.closes[i] ?? 0;
|
|
43321
|
+
const v = st.volumes[i] ?? 0;
|
|
43322
|
+
if (h > l) {
|
|
43323
|
+
const mid = (h + l) / 2;
|
|
43324
|
+
if (c > mid)
|
|
43325
|
+
buy += v;
|
|
43326
|
+
else
|
|
43327
|
+
sell += v;
|
|
43328
|
+
}
|
|
43329
|
+
}
|
|
43330
|
+
const total = buy + sell;
|
|
43331
|
+
if (total === 0)
|
|
43332
|
+
return 0;
|
|
43333
|
+
return finiteOut2((buy - sell) / total) ?? 0;
|
|
43334
|
+
}
|
|
43335
|
+
liquidityScore(site, volume, volatility, spread, period) {
|
|
43336
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43337
|
+
if (n <= 0)
|
|
43338
|
+
return 50;
|
|
43339
|
+
const key = `${site}:${n}`;
|
|
43340
|
+
let st = this.liquiditySites.get(key);
|
|
43341
|
+
if (st === undefined) {
|
|
43342
|
+
st = { volume: [], volatility: [], spread: [] };
|
|
43343
|
+
this.liquiditySites.set(key, st);
|
|
43344
|
+
}
|
|
43345
|
+
pushCap(st.volume, finiteCell2(volume), n);
|
|
43346
|
+
pushCap(st.volatility, finiteCell2(volatility), n);
|
|
43347
|
+
pushCap(st.spread, finiteCell2(spread), n);
|
|
43348
|
+
if (st.volume.length < n || st.volatility.length < n || st.spread.length < n)
|
|
43349
|
+
return 50;
|
|
43350
|
+
let volSum = 0;
|
|
43351
|
+
for (const v of st.volume)
|
|
43352
|
+
if (v !== null)
|
|
43353
|
+
volSum += v;
|
|
43354
|
+
let volaSum = 0;
|
|
43355
|
+
for (const v of st.volatility)
|
|
43356
|
+
if (v !== null)
|
|
43357
|
+
volaSum += v;
|
|
43358
|
+
let spreadSum = 0;
|
|
43359
|
+
for (const v of st.spread)
|
|
43360
|
+
if (v !== null)
|
|
43361
|
+
spreadSum += v;
|
|
43362
|
+
const volScore = Math.min(100, volSum / n / 100);
|
|
43363
|
+
const volatilityScore = Math.max(0, 100 - volaSum / n * 50);
|
|
43364
|
+
const spreadScore = Math.max(0, 100 - spreadSum / n * 100);
|
|
43365
|
+
const liquidity = volScore * 0.4 + volatilityScore * 0.3 + spreadScore * 0.3;
|
|
43366
|
+
return Math.max(0, Math.min(100, liquidity));
|
|
43367
|
+
}
|
|
43368
|
+
fearGreedIndex(rsi, vix, putCall, breadth) {
|
|
43369
|
+
const r = finiteCell2(rsi) ?? 50;
|
|
43370
|
+
const v = finiteCell2(vix) ?? 2;
|
|
43371
|
+
const pc = finiteCell2(putCall) ?? 1;
|
|
43372
|
+
const b = finiteCell2(breadth) ?? 0.5;
|
|
43373
|
+
const index = ((r - 50) * 1 + (v - 2) * 10 + (1 - pc) * 50 + (b - 0.5) * 100) / 4;
|
|
43374
|
+
return Math.max(-100, Math.min(100, index));
|
|
43375
|
+
}
|
|
43376
|
+
crowdSentiment(priceAgreement, volumeAgreement, timeAgreement) {
|
|
43377
|
+
const p = finiteCell2(priceAgreement) ?? 0.5;
|
|
43378
|
+
const v = finiteCell2(volumeAgreement) ?? 0.5;
|
|
43379
|
+
const t = finiteCell2(timeAgreement) ?? 0.5;
|
|
43380
|
+
return Math.max(0, Math.min(100, (p + v + t) / 3 * 100));
|
|
43381
|
+
}
|
|
43382
|
+
smartMoneyFlow(priceChange, volume, timeHigh, timeLow) {
|
|
43383
|
+
const p = finiteCell2(priceChange) ?? 0;
|
|
43384
|
+
const v = finiteCell2(volume) ?? 1000;
|
|
43385
|
+
const th = finiteCell2(timeHigh) ?? 10;
|
|
43386
|
+
const tl = finiteCell2(timeLow) ?? 10;
|
|
43387
|
+
const volFactor = Math.min(1, v / 5000);
|
|
43388
|
+
let flow = 0;
|
|
43389
|
+
if (p > 0 && th < tl)
|
|
43390
|
+
flow = volFactor * 0.8;
|
|
43391
|
+
else if (p < 0 && tl < th)
|
|
43392
|
+
flow = -volFactor * 0.8;
|
|
43393
|
+
return Math.max(-1, Math.min(1, flow));
|
|
43394
|
+
}
|
|
43395
|
+
trendConfirmationScore(momentum, trendAlignment, strength, rsi, rsiAlignment) {
|
|
43396
|
+
const m = finiteCell2(momentum) ?? 0;
|
|
43397
|
+
const t = finiteCell2(trendAlignment) ?? 0;
|
|
43398
|
+
const s = finiteCell2(strength) ?? 1;
|
|
43399
|
+
const r = finiteCell2(rsi) ?? 50;
|
|
43400
|
+
const a = finiteCell2(rsiAlignment) ?? 0;
|
|
43401
|
+
const momentumScore = Math.min(100, Math.abs(m) * 20);
|
|
43402
|
+
const trendScore = Math.max(0, (t + 1) / 2 * 100);
|
|
43403
|
+
const strengthScore = Math.min(100, s * 50);
|
|
43404
|
+
const rsiScore = Math.abs(r - 50) > 10 ? Math.min(100, Math.abs(r - 50) * 2) : 40;
|
|
43405
|
+
const alignmentBonus = Math.abs(a) > 0.5 ? 20 : 0;
|
|
43406
|
+
const total = momentumScore * 0.25 + trendScore * 0.3 + strengthScore * 0.25 + rsiScore * 0.15 + alignmentBonus;
|
|
43407
|
+
return Math.max(0, Math.min(100, total));
|
|
43408
|
+
}
|
|
43409
|
+
maxLossLevel(entry, account, maxLossPct) {
|
|
43410
|
+
const e = finiteCell2(entry) ?? 100;
|
|
43411
|
+
const a = finiteCell2(account) ?? 1e4;
|
|
43412
|
+
const p = finiteCell2(maxLossPct) ?? 1;
|
|
43413
|
+
const maxLossAmount = a * (p / 100);
|
|
43414
|
+
if (e <= 0)
|
|
43415
|
+
return 0;
|
|
43416
|
+
const shares = a / e;
|
|
43417
|
+
const stop = shares > 0 ? e - maxLossAmount / shares : 0;
|
|
43418
|
+
return Math.max(0, stop);
|
|
43419
|
+
}
|
|
43420
|
+
profitLockLevel(entry, current, trailPct, direction) {
|
|
43421
|
+
const e = finiteCell2(entry) ?? 100;
|
|
43422
|
+
const c = finiteCell2(current) ?? 100;
|
|
43423
|
+
const t = Math.max(0, Math.min(1, finiteCell2(trailPct) ?? 0.05));
|
|
43424
|
+
const d = finiteCell2(direction) ?? 1;
|
|
43425
|
+
return d > 0 ? Math.max(e * 0.9, c - c * t) : Math.min(e * 1.1, c + c * t);
|
|
43426
|
+
}
|
|
43427
|
+
positionSizing(account, riskPct, entry, stop) {
|
|
43428
|
+
const a = finiteCell2(account) ?? 1e4;
|
|
43429
|
+
const r = finiteCell2(riskPct) ?? 0.01;
|
|
43430
|
+
const e = finiteCell2(entry) ?? 100;
|
|
43431
|
+
const s = finiteCell2(stop) ?? 95;
|
|
43432
|
+
const riskAmount = a * (r / 100);
|
|
43433
|
+
const distance = e - s;
|
|
43434
|
+
if (Math.abs(distance) < 0.0000000001)
|
|
43435
|
+
return 0;
|
|
43436
|
+
return Math.max(0, riskAmount / Math.abs(distance));
|
|
43437
|
+
}
|
|
43438
|
+
kellyCriterion(winRate, avgWin, avgLoss) {
|
|
43439
|
+
const wr = Math.max(0, Math.min(1, finiteCell2(winRate) ?? 0.5));
|
|
43440
|
+
const win = finiteCell2(avgWin) ?? 1;
|
|
43441
|
+
const loss = finiteCell2(avgLoss) ?? 1;
|
|
43442
|
+
if (Math.abs(win) < 0.0000000001)
|
|
43443
|
+
return 0;
|
|
43444
|
+
const kelly = (wr * win - (1 - wr) * loss) / win;
|
|
43445
|
+
return Math.max(0, kelly);
|
|
43446
|
+
}
|
|
43447
|
+
riskRewardRatio(entry, stop, target) {
|
|
43448
|
+
const e = finiteCell2(entry) ?? 0;
|
|
43449
|
+
const s = finiteCell2(stop) ?? 0;
|
|
43450
|
+
const t = finiteCell2(target) ?? 0;
|
|
43451
|
+
const risk = e - s;
|
|
43452
|
+
if (Math.abs(risk) < 0.0000000001)
|
|
43453
|
+
return null;
|
|
43454
|
+
return finiteOut2((t - e) / risk);
|
|
43455
|
+
}
|
|
43456
|
+
riskRewardAsymmetry(entry, stop, target, winRate) {
|
|
43457
|
+
const e = finiteCell2(entry) ?? 0;
|
|
43458
|
+
const s = finiteCell2(stop) ?? 0;
|
|
43459
|
+
const t = finiteCell2(target) ?? 0;
|
|
43460
|
+
const wr = finiteCell2(winRate) ?? 0.5;
|
|
43461
|
+
const risk = Math.abs(e - s);
|
|
43462
|
+
const reward = Math.abs(t - e);
|
|
43463
|
+
const ratio = risk > 0 ? reward / risk : 0;
|
|
43464
|
+
const ev = wr * reward - (1 - wr) * risk;
|
|
43465
|
+
const kelly = ratio > 0 ? wr - (1 - wr) / ratio : 0;
|
|
43466
|
+
return taRec({
|
|
43467
|
+
ratio: finiteOut2(ratio) ?? 0,
|
|
43468
|
+
expected_value: finiteOut2(ev) ?? 0,
|
|
43469
|
+
kelly_percent: finiteOut2(kelly * 100) ?? 0,
|
|
43470
|
+
is_favorable: ev > 0,
|
|
43471
|
+
risk_reward_ratio: finiteOut2(ratio) ?? 0,
|
|
43472
|
+
kelly_percentage: finiteOut2(kelly * 100) ?? 0
|
|
43473
|
+
});
|
|
43474
|
+
}
|
|
43475
|
+
probabilityOfMovement(current, target, atr, period) {
|
|
43476
|
+
const c = finiteCell2(current) ?? 100;
|
|
43477
|
+
const t = finiteCell2(target) ?? 100;
|
|
43478
|
+
const a = finiteCell2(atr) ?? 1;
|
|
43479
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43480
|
+
if (Math.abs(c) < 0.0000000001 || Math.abs(a) < 0.0000000001)
|
|
43481
|
+
return 0.5;
|
|
43482
|
+
const distance = Math.abs(t - c);
|
|
43483
|
+
const expected = a * Math.sqrt(n);
|
|
43484
|
+
if (expected === 0)
|
|
43485
|
+
return 0.5;
|
|
43486
|
+
return Math.max(0, Math.min(1, Math.min(1, distance / expected) * 0.8 + 0.1));
|
|
43487
|
+
}
|
|
43488
|
+
trendStrength(price, adx, rsi) {
|
|
43489
|
+
const a = finiteCell2(adx) ?? 20;
|
|
43490
|
+
const r = finiteCell2(rsi) ?? 50;
|
|
43491
|
+
const adxNorm = Math.min(100, Math.max(0, a));
|
|
43492
|
+
const rsiExtremeness = Math.abs(r - 50) / 50;
|
|
43493
|
+
return Math.min(100, Math.max(0, adxNorm * 0.6 + rsiExtremeness * 40));
|
|
43494
|
+
}
|
|
43495
|
+
breakevenLevel(entry, qty, commission, slippage, direction) {
|
|
43496
|
+
const e = finiteCell2(entry) ?? 0;
|
|
43497
|
+
const q = finiteCell2(qty) ?? 0;
|
|
43498
|
+
const comm = finiteCell2(commission) ?? 0;
|
|
43499
|
+
const slip = finiteCell2(slippage) ?? 0;
|
|
43500
|
+
const d = finiteCell2(direction) ?? 1;
|
|
43501
|
+
const cost = comm + slip * q;
|
|
43502
|
+
const impact = q > 0 ? cost / q : 0;
|
|
43503
|
+
const breakeven = d >= 0 ? e + impact : e - impact;
|
|
43504
|
+
const move = e > 0 ? Math.abs(breakeven - e) / e * 100 : 0;
|
|
43505
|
+
return taRec({
|
|
43506
|
+
breakeven_price: finiteOut2(breakeven) ?? 0,
|
|
43507
|
+
total_cost: finiteOut2(cost) ?? 0,
|
|
43508
|
+
move_required_percent: finiteOut2(move) ?? 0
|
|
43509
|
+
});
|
|
43510
|
+
}
|
|
43511
|
+
marketStructurePivot(close) {
|
|
43512
|
+
const c = finiteCell2(close) ?? 0;
|
|
43513
|
+
return taRec({ pivot_price: c, structure: "fractal", type: "high" });
|
|
43514
|
+
}
|
|
43515
|
+
positionSizingScore(risk, volatility, conviction, correlation) {
|
|
43516
|
+
const r = finiteCell2(risk) ?? 0;
|
|
43517
|
+
const v = finiteCell2(volatility) ?? 0;
|
|
43518
|
+
const c = finiteCell2(conviction) ?? 0;
|
|
43519
|
+
const corr = finiteCell2(correlation) ?? 0;
|
|
43520
|
+
let score = r / (v + 0.1) * c * (1 - corr);
|
|
43521
|
+
score = Math.max(0, Math.min(1, score * 0.1));
|
|
43522
|
+
return taRec({
|
|
43523
|
+
score: finiteOut2(score * 100) ?? 0,
|
|
43524
|
+
position_size_ratio: finiteOut2(score) ?? 0,
|
|
43525
|
+
kelly_fraction: finiteOut2(score * 0.5) ?? 0,
|
|
43526
|
+
correlation_adjustment: finiteOut2(1 - corr) ?? 0
|
|
43527
|
+
});
|
|
43528
|
+
}
|
|
43529
|
+
trailingExitLevel(entry, current, atr, mult, step) {
|
|
43530
|
+
const e = finiteCell2(entry) ?? 0;
|
|
43531
|
+
const c = finiteCell2(current) ?? 0;
|
|
43532
|
+
const a = finiteCell2(atr) ?? 0;
|
|
43533
|
+
const m = finiteCell2(mult) ?? 0;
|
|
43534
|
+
finiteCell2(step);
|
|
43535
|
+
const trail = c > e ? Math.max(e * 1.001, c - a * m) : c + a * m;
|
|
43536
|
+
return taRec({
|
|
43537
|
+
trail_stop: finiteOut2(trail) ?? 0,
|
|
43538
|
+
protected_profit: c > e ? finiteOut2(Math.max(0, c - e)) ?? 0 : 0,
|
|
43539
|
+
risk_reward_current: a > 0 ? finiteOut2(Math.abs(c - e) / a) ?? 0 : 0
|
|
43540
|
+
});
|
|
43541
|
+
}
|
|
43542
|
+
optimalEntryZone(close) {
|
|
43543
|
+
const c = finiteCell2(close) ?? 0;
|
|
43544
|
+
return taRec({
|
|
43545
|
+
min: finiteOut2(c * 0.99) ?? 0,
|
|
43546
|
+
max: finiteOut2(c * 1.01) ?? 0,
|
|
43547
|
+
optimal: c,
|
|
43548
|
+
entry_zone_low: finiteOut2(c * 0.99) ?? 0,
|
|
43549
|
+
entry_zone_high: finiteOut2(c * 1.01) ?? 0,
|
|
43550
|
+
best_entry: c,
|
|
43551
|
+
zone_strength: 85
|
|
43552
|
+
});
|
|
43553
|
+
}
|
|
43554
|
+
meanReversionEntry(price, sma, stdev, threshold) {
|
|
43555
|
+
const p = finiteCell2(price) ?? 0;
|
|
43556
|
+
const s = finiteCell2(sma) ?? 0;
|
|
43557
|
+
const sd = finiteCell2(stdev) ?? 1;
|
|
43558
|
+
const th = finiteCell2(threshold) ?? 0;
|
|
43559
|
+
const z = sd !== 0 ? (p - s) / sd : 0;
|
|
43560
|
+
return taRec({
|
|
43561
|
+
entry_price: 100,
|
|
43562
|
+
stop_loss: 95,
|
|
43563
|
+
take_profit: 105,
|
|
43564
|
+
probability: 0.7,
|
|
43565
|
+
reversion_probability: 0.75,
|
|
43566
|
+
target_price: 105,
|
|
43567
|
+
z_score: finiteOut2(z) ?? 0,
|
|
43568
|
+
is_mean_reversion_setup: Math.abs(z) > th
|
|
43569
|
+
});
|
|
43570
|
+
}
|
|
43571
|
+
multiTimeframeSignal(s1, s2, s3, w1, w2, w3) {
|
|
43572
|
+
const score = (finiteCell2(s1) ?? 0) * (finiteCell2(w1) ?? 0) + (finiteCell2(s2) ?? 0) * (finiteCell2(w2) ?? 0) + (finiteCell2(s3) ?? 0) * (finiteCell2(w3) ?? 0);
|
|
43573
|
+
return taRec({ score: finiteOut2(score) ?? 0, signal: score > 0.5 ? "buy" : "sell", agreement: true });
|
|
43574
|
+
}
|
|
43575
|
+
marketTimingIndex(trend, momentum, volatility, sentiment) {
|
|
43576
|
+
const t = finiteCell2(trend) ?? 0;
|
|
43577
|
+
const m = finiteCell2(momentum) ?? 0;
|
|
43578
|
+
const v = finiteCell2(volatility) ?? 0;
|
|
43579
|
+
const s = finiteCell2(sentiment) ?? 0;
|
|
43580
|
+
const score = t * 0.3 + m * 0.3 + v * 0.2 + s * 0.2;
|
|
43581
|
+
let recommendation = "hold";
|
|
43582
|
+
if (score > 80)
|
|
43583
|
+
recommendation = "strong_buy";
|
|
43584
|
+
else if (score > 60)
|
|
43585
|
+
recommendation = "buy";
|
|
43586
|
+
else if (score < 20)
|
|
43587
|
+
recommendation = "strong_sell";
|
|
43588
|
+
else if (score < 40)
|
|
43589
|
+
recommendation = "sell";
|
|
43590
|
+
return taRec({
|
|
43591
|
+
score: finiteOut2(score) ?? 0,
|
|
43592
|
+
recommendation,
|
|
43593
|
+
regime: Math.abs(t) > 50 ? "trending" : "ranging",
|
|
43594
|
+
timing_index: finiteOut2(score) ?? 0,
|
|
43595
|
+
market_condition: score > 80 ? "optimal_long" : "neutral",
|
|
43596
|
+
confidence: 0.85
|
|
43597
|
+
});
|
|
43598
|
+
}
|
|
43599
|
+
regimeAdaptiveSignal(strength, volRegime, trendRegime) {
|
|
43600
|
+
const vol = typeof volRegime === "string" ? volRegime : "";
|
|
43601
|
+
const trend = typeof trendRegime === "string" ? trendRegime : "";
|
|
43602
|
+
let adapted = finiteCell2(strength) ?? 0;
|
|
43603
|
+
let fit = 1;
|
|
43604
|
+
if (vol === "high") {
|
|
43605
|
+
adapted *= 0.8;
|
|
43606
|
+
fit *= 0.8;
|
|
43607
|
+
}
|
|
43608
|
+
if (trend === "ranging") {
|
|
43609
|
+
adapted *= 0.5;
|
|
43610
|
+
fit *= 0.5;
|
|
43611
|
+
}
|
|
43612
|
+
return taRec({
|
|
43613
|
+
signal: adapted > 0.5 ? "buy" : "sell",
|
|
43614
|
+
strength: finiteOut2(adapted) ?? 0,
|
|
43615
|
+
confidence: finiteOut2(adapted * 100) ?? 0,
|
|
43616
|
+
adapted_signal: finiteOut2(adapted) ?? 0,
|
|
43617
|
+
regime_fit: finiteOut2(fit) ?? 0,
|
|
43618
|
+
strategy_recommendation: trend === "trending" ? "trend_following" : "mean_reversion",
|
|
43619
|
+
signal_confidence: finiteOut2(adapted) ?? 0
|
|
43620
|
+
});
|
|
43621
|
+
}
|
|
43622
|
+
strategyScore(rsi, macd, emaCross, trend) {
|
|
43623
|
+
const r = finiteCell2(rsi) ?? 50;
|
|
43624
|
+
const m = finiteCell2(macd) ?? 0;
|
|
43625
|
+
const cross = emaCross != null && emaCross !== 0;
|
|
43626
|
+
const t = finiteCell2(trend) ?? 50;
|
|
43627
|
+
const rsiNorm = (r - 50) / 50 * 25;
|
|
43628
|
+
const macdNorm = Math.max(-25, Math.min(25, m * 50));
|
|
43629
|
+
const emaBonus = cross ? 25 : -25;
|
|
43630
|
+
const trendNorm = (t - 50) / 50 * 25;
|
|
43631
|
+
return Math.max(-100, Math.min(100, rsiNorm + macdNorm + emaBonus + trendNorm));
|
|
43632
|
+
}
|
|
43633
|
+
breakoutDetection(close, resistance, support) {
|
|
43634
|
+
const c = finiteCell2(close) ?? 0;
|
|
43635
|
+
const r = finiteCell2(resistance) ?? 0;
|
|
43636
|
+
const s = finiteCell2(support) ?? 0;
|
|
43637
|
+
if (c > r) {
|
|
43638
|
+
const strength = r > 0 ? (c - r) / r * 100 : 0;
|
|
43639
|
+
return taRec({
|
|
43640
|
+
is_breakout: true,
|
|
43641
|
+
breakout_type: "resistance",
|
|
43642
|
+
breakout_strength: finiteOut2(strength) ?? 0
|
|
43643
|
+
});
|
|
43644
|
+
}
|
|
43645
|
+
if (c < s) {
|
|
43646
|
+
const strength = s > 0 ? (s - c) / s * 100 : 0;
|
|
43647
|
+
return taRec({
|
|
43648
|
+
is_breakout: true,
|
|
43649
|
+
breakout_type: "support",
|
|
43650
|
+
breakout_strength: finiteOut2(strength) ?? 0
|
|
43651
|
+
});
|
|
43652
|
+
}
|
|
43653
|
+
return taRec({ is_breakout: false, breakout_type: "none", breakout_strength: 0 });
|
|
43654
|
+
}
|
|
42466
43655
|
volumeProfileHigh(prices, volumes) {
|
|
42467
43656
|
if (prices.length === 0 || volumes.length === 0 || prices.length !== volumes.length)
|
|
42468
43657
|
return 0;
|
|
@@ -42535,19 +43724,27 @@ class TaEngine {
|
|
|
42535
43724
|
const sens = Number.isFinite(sensitivity) ? sensitivity : 0.3;
|
|
42536
43725
|
let st = this.volThrustSites.get(site);
|
|
42537
43726
|
if (st === undefined) {
|
|
42538
|
-
st = {
|
|
43727
|
+
st = { closes: [], volume: null, sma: null, nClose: 0, nVolume: 0, nSma: 0 };
|
|
42539
43728
|
this.volThrustSites.set(site, st);
|
|
42540
43729
|
}
|
|
42541
|
-
|
|
42542
|
-
|
|
42543
|
-
|
|
42544
|
-
|
|
43730
|
+
if (!(close === null && st.nClose === 0)) {
|
|
43731
|
+
pushCap(st.closes, finiteCell2(close), 2);
|
|
43732
|
+
st.nClose += 1;
|
|
43733
|
+
}
|
|
43734
|
+
if (!(volume === null && st.nVolume === 0)) {
|
|
43735
|
+
st.volume = finiteCell2(volume);
|
|
43736
|
+
st.nVolume += 1;
|
|
43737
|
+
}
|
|
43738
|
+
if (!(volSma === null && st.nSma === 0)) {
|
|
43739
|
+
st.sma = finiteCell2(volSma);
|
|
43740
|
+
st.nSma += 1;
|
|
43741
|
+
}
|
|
43742
|
+
if (st.nClose < 1 || st.nVolume < 1 || st.nSma < 1)
|
|
42545
43743
|
return 0;
|
|
42546
|
-
const
|
|
42547
|
-
const
|
|
42548
|
-
const
|
|
42549
|
-
const
|
|
42550
|
-
const vsVal = numOr(this.nf(st.sma, -1), 1000);
|
|
43744
|
+
const cVal = st.closes[st.closes.length - 1] ?? 100;
|
|
43745
|
+
const cPrev = st.closes.length > 1 ? st.closes[st.closes.length - 2] ?? 100 : 100;
|
|
43746
|
+
const vVal = st.volume ?? 1000;
|
|
43747
|
+
const vsVal = st.sma ?? 1000;
|
|
42551
43748
|
const spike = vVal > vsVal * (1 + sens);
|
|
42552
43749
|
const move = cPrev !== 0 ? Math.abs(cVal - cPrev) / cPrev > 0.01 : false;
|
|
42553
43750
|
return spike && move ? 1 : 0;
|
|
@@ -42933,7 +44130,9 @@ var NS = new Set([
|
|
|
42933
44130
|
"session",
|
|
42934
44131
|
"syminfo",
|
|
42935
44132
|
"timenow",
|
|
42936
|
-
"chart"
|
|
44133
|
+
"chart",
|
|
44134
|
+
"footprint",
|
|
44135
|
+
"volume_row"
|
|
42937
44136
|
]);
|
|
42938
44137
|
var TA_METHODS = new Set([
|
|
42939
44138
|
"sma",
|
|
@@ -43038,7 +44237,45 @@ var TA_METHODS = new Set([
|
|
|
43038
44237
|
"volume_momentum",
|
|
43039
44238
|
"volume_profile_high",
|
|
43040
44239
|
"volume_profile_low",
|
|
43041
|
-
"volume_thrust"
|
|
44240
|
+
"volume_thrust",
|
|
44241
|
+
"sma_weighted",
|
|
44242
|
+
"apo",
|
|
44243
|
+
"atr_normalized",
|
|
44244
|
+
"beta",
|
|
44245
|
+
"r_squared",
|
|
44246
|
+
"comovement",
|
|
44247
|
+
"skewness",
|
|
44248
|
+
"kurtosis",
|
|
44249
|
+
"volume_weighted_momentum",
|
|
44250
|
+
"parkinson",
|
|
44251
|
+
"garman_klass",
|
|
44252
|
+
"mean_reversion_score",
|
|
44253
|
+
"market_condition",
|
|
44254
|
+
"order_flow_imbalance",
|
|
44255
|
+
"liquidity_score",
|
|
44256
|
+
"fear_greed_index",
|
|
44257
|
+
"crowd_sentiment",
|
|
44258
|
+
"smart_money_flow",
|
|
44259
|
+
"trend_confirmation_score",
|
|
44260
|
+
"max_loss_level",
|
|
44261
|
+
"profit_lock_level",
|
|
44262
|
+
"position_sizing",
|
|
44263
|
+
"kelly_criterion",
|
|
44264
|
+
"risk_reward_ratio",
|
|
44265
|
+
"risk_reward_asymmetry",
|
|
44266
|
+
"probability_of_movement",
|
|
44267
|
+
"trend_strength",
|
|
44268
|
+
"breakeven_level",
|
|
44269
|
+
"market_structure_pivot",
|
|
44270
|
+
"position_sizing_score",
|
|
44271
|
+
"trailing_exit_level",
|
|
44272
|
+
"optimal_entry_zone",
|
|
44273
|
+
"mean_reversion_entry",
|
|
44274
|
+
"multi_timeframe_signal",
|
|
44275
|
+
"market_timing_index",
|
|
44276
|
+
"regime_adaptive_signal",
|
|
44277
|
+
"strategy_score",
|
|
44278
|
+
"breakout_detection"
|
|
43042
44279
|
]);
|
|
43043
44280
|
var TA_BARE_ATTRS = new Set([
|
|
43044
44281
|
"accdist",
|
|
@@ -43311,6 +44548,9 @@ function emitCall2(ctx, node, visit) {
|
|
|
43311
44548
|
const req = emitRequest(ctx, name, args);
|
|
43312
44549
|
if (req != null)
|
|
43313
44550
|
return req;
|
|
44551
|
+
const fp = emitFootprint(name, args);
|
|
44552
|
+
if (fp != null)
|
|
44553
|
+
return fp;
|
|
43314
44554
|
return "null";
|
|
43315
44555
|
}
|
|
43316
44556
|
function resolveCallee(func) {
|
|
@@ -43380,6 +44620,23 @@ function hasArg(args, index, names) {
|
|
|
43380
44620
|
}
|
|
43381
44621
|
return index >= 0 && index < args.pos.length;
|
|
43382
44622
|
}
|
|
44623
|
+
var BARE_SERIES_NAMES = new Set([
|
|
44624
|
+
"open",
|
|
44625
|
+
"high",
|
|
44626
|
+
"low",
|
|
44627
|
+
"close",
|
|
44628
|
+
"volume",
|
|
44629
|
+
"hl2",
|
|
44630
|
+
"hlc3",
|
|
44631
|
+
"ohlc4",
|
|
44632
|
+
"hlcc4",
|
|
44633
|
+
"time",
|
|
44634
|
+
"time_close"
|
|
44635
|
+
]);
|
|
44636
|
+
function hasSeriesArg(args) {
|
|
44637
|
+
const isSeries = (n) => n.kind === "Name" && BARE_SERIES_NAMES.has(n.id);
|
|
44638
|
+
return args.posNodes.some(isSeries) || Object.values(args.kwNodes).some(isSeries);
|
|
44639
|
+
}
|
|
43383
44640
|
function hasAnyKw(args, names) {
|
|
43384
44641
|
return names.some((n) => Object.hasOwn(args.kw, n));
|
|
43385
44642
|
}
|
|
@@ -43395,6 +44652,9 @@ function cellOf(expr) {
|
|
|
43395
44652
|
function cellList(expr) {
|
|
43396
44653
|
return `(() => { const __v = ${expr}; const __cell = (e) => (e == null ? null : typeof e === "boolean" ? (e ? 1 : 0) : (typeof e === "number" && Number.isFinite(e) ? e : null)); if (__v != null && typeof __v.size === "function" && typeof __v.get === "function") { const __n = __v.size(); const __o = []; for (let __i = 0; __i < __n; __i++) __o.push(__cell(__v.get(__i))); return __o; } return [__cell(__v)]; })()`;
|
|
43397
44654
|
}
|
|
44655
|
+
function cellLast(expr) {
|
|
44656
|
+
return `(() => { const __v = ${expr}; const __cell = (e) => (e == null ? null : typeof e === "boolean" ? (e ? 1 : 0) : (typeof e === "number" && Number.isFinite(e) ? e : null)); if (__v != null && typeof __v.size === "function" && typeof __v.get === "function") { const __n = __v.size(); return __n === 0 ? null : __cell(__v.get(__n - 1)); } return __cell(__v); })()`;
|
|
44657
|
+
}
|
|
43398
44658
|
var DRAW_KINDS = new Set(["label", "line", "box", "table", "polyline", "linefill"]);
|
|
43399
44659
|
var ARRAY_SIGS = {
|
|
43400
44660
|
new: [["size"], ["initial_value", "initial"]],
|
|
@@ -43774,6 +45034,8 @@ function emitDraw(ctx, name, methodSrc, args) {
|
|
|
43774
45034
|
code = `__h.draw.box_new(__bar_idx, ${pick(args, 0, ["left"], "0")}, ${pick(args, 1, ["top"], "0")}, ${pick(args, 2, ["right"], "0")}, ${pick(args, 3, ["bottom"], "0")})`;
|
|
43775
45035
|
} else if (kind === "polyline") {
|
|
43776
45036
|
code = `__h.draw.polyline_new(__bar_idx, ${pick(args, 0, ["points"], "null")})`;
|
|
45037
|
+
} else if (kind === "table") {
|
|
45038
|
+
code = `__h.draw.table_new(__bar_idx, ${pick(args, 0, ["position"], "null")}, ${pick(args, 1, ["columns"], "null")}, ${pick(args, 2, ["rows"], "null")}, ${pick(args, 3, ["bgcolor"], "null")}, ${pick(args, 4, ["frame_color"], "null")}, ${pick(args, 5, ["frame_width"], "null")}, ${pick(args, 6, ["border_color"], "null")}, ${pick(args, 7, ["border_width"], "null")}, ${pick(args, 8, ["force_overlay"], "null")})`;
|
|
43777
45039
|
} else if (kind === "linefill") {
|
|
43778
45040
|
const color = hasArg(args, 2, ["color"]) ? pick(args, 2, ["color"], "null") : "null";
|
|
43779
45041
|
code = `__h.draw.linefill_new(__bar_idx, ${pick(args, 0, ["id1", "line1"], "null")}, ${pick(args, 1, ["id2", "line2"], "null")}, ${color})`;
|
|
@@ -43840,8 +45102,7 @@ var SECURITY_FUNCS = new Set([
|
|
|
43840
45102
|
"security",
|
|
43841
45103
|
"security_lower_tf",
|
|
43842
45104
|
"request_security",
|
|
43843
|
-
"request_security_lower_tf"
|
|
43844
|
-
"request_seed"
|
|
45105
|
+
"request_security_lower_tf"
|
|
43845
45106
|
]);
|
|
43846
45107
|
var SIMPLE_CHART_EXPR = new Set([
|
|
43847
45108
|
"close",
|
|
@@ -43879,10 +45140,58 @@ function emitRequest(ctx, name, args) {
|
|
|
43879
45140
|
if (name === "request_currency_rate" || name === "currency_rate") {
|
|
43880
45141
|
return `__h.currencyRate(${pick(args, 0, ["from", "from_currency"], "null")}, ${pick(args, 1, ["to", "to_currency"], "null")})`;
|
|
43881
45142
|
}
|
|
45143
|
+
if (name === "request_seed") {
|
|
45144
|
+
return `__h.requestSeed(${pick(args, 0, ["seed"], "0")})`;
|
|
45145
|
+
}
|
|
45146
|
+
if (name === "request_footprint") {
|
|
45147
|
+
return `__h.requestFootprint(${pick(args, 0, ["num_ticks"], "100")}, ${pick(args, 1, ["va_percentage"], "70")})`;
|
|
45148
|
+
}
|
|
43882
45149
|
if (name.startsWith("request_"))
|
|
43883
45150
|
return "null";
|
|
43884
45151
|
return null;
|
|
43885
45152
|
}
|
|
45153
|
+
function emitFootprint(name, args) {
|
|
45154
|
+
const fp = pick(args, 0, ["id", "footprint"], "null");
|
|
45155
|
+
const vr = pick(args, 0, ["id", "volume_row"], "null");
|
|
45156
|
+
switch (name) {
|
|
45157
|
+
case "footprint_buy_volume":
|
|
45158
|
+
return `__h.footprint.buy_volume(${fp})`;
|
|
45159
|
+
case "footprint_sell_volume":
|
|
45160
|
+
return `__h.footprint.sell_volume(${fp})`;
|
|
45161
|
+
case "footprint_delta":
|
|
45162
|
+
return `__h.footprint.delta(${fp})`;
|
|
45163
|
+
case "footprint_total_volume":
|
|
45164
|
+
return `__h.footprint.total_volume(${fp})`;
|
|
45165
|
+
case "footprint_vah":
|
|
45166
|
+
return `__h.footprint.vah(${fp})`;
|
|
45167
|
+
case "footprint_val":
|
|
45168
|
+
return `__h.footprint.val(${fp})`;
|
|
45169
|
+
case "footprint_poc":
|
|
45170
|
+
return `__h.footprint.poc(${fp})`;
|
|
45171
|
+
case "footprint_rows":
|
|
45172
|
+
return `__h.footprint.rows(${fp})`;
|
|
45173
|
+
case "footprint_get_row_by_price":
|
|
45174
|
+
return `__h.footprint.get_row_by_price(${fp}, ${pick(args, 1, ["price"], "null")})`;
|
|
45175
|
+
case "volume_row_up_price":
|
|
45176
|
+
return `__h.footprint.volume_row.up_price(${vr})`;
|
|
45177
|
+
case "volume_row_down_price":
|
|
45178
|
+
return `__h.footprint.volume_row.down_price(${vr})`;
|
|
45179
|
+
case "volume_row_buy_volume":
|
|
45180
|
+
return `__h.footprint.volume_row.buy_volume(${vr})`;
|
|
45181
|
+
case "volume_row_sell_volume":
|
|
45182
|
+
return `__h.footprint.volume_row.sell_volume(${vr})`;
|
|
45183
|
+
case "volume_row_delta":
|
|
45184
|
+
return `__h.footprint.volume_row.delta(${vr})`;
|
|
45185
|
+
case "volume_row_total_volume":
|
|
45186
|
+
return `__h.footprint.volume_row.total_volume(${vr})`;
|
|
45187
|
+
case "volume_row_has_buy_imbalance":
|
|
45188
|
+
return `__h.footprint.volume_row.has_buy_imbalance(${vr})`;
|
|
45189
|
+
case "volume_row_has_sell_imbalance":
|
|
45190
|
+
return `__h.footprint.volume_row.has_sell_imbalance(${vr})`;
|
|
45191
|
+
default:
|
|
45192
|
+
return null;
|
|
45193
|
+
}
|
|
45194
|
+
}
|
|
43886
45195
|
function isSimpleSecurityExpr(expr) {
|
|
43887
45196
|
const e = expr.trim();
|
|
43888
45197
|
if (!e)
|
|
@@ -44349,6 +45658,9 @@ function allocSite(ctx) {
|
|
|
44349
45658
|
function taCall(method, site, parts) {
|
|
44350
45659
|
return `__h.ta.${method}(${site}, ${parts.join(", ")})`;
|
|
44351
45660
|
}
|
|
45661
|
+
function taPure(method, parts) {
|
|
45662
|
+
return `__h.ta.${method}(${parts.join(", ")})`;
|
|
45663
|
+
}
|
|
44352
45664
|
function emitTa(ctx, method, args) {
|
|
44353
45665
|
if (!TA_METHODS.has(method))
|
|
44354
45666
|
return "null";
|
|
@@ -44772,16 +46084,30 @@ function emitTa(ctx, method, args) {
|
|
|
44772
46084
|
]);
|
|
44773
46085
|
}
|
|
44774
46086
|
if (method === "stoch_smooth") {
|
|
44775
|
-
return
|
|
46087
|
+
return taCall("stochSmooth", site, [
|
|
46088
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
46089
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
46090
|
+
cellOf(pick(args, 2, ["close"], "null")),
|
|
46091
|
+
cellOf(pick(args, 3, ["period", "length"], "null")),
|
|
46092
|
+
cellOf(pick(args, 4, ["smooth_k", "k"], "null")),
|
|
46093
|
+
cellOf(pick(args, 5, ["smooth_d", "d"], "null"))
|
|
46094
|
+
]);
|
|
44776
46095
|
}
|
|
44777
46096
|
if (method === "engulfing") {
|
|
44778
|
-
return `(() => { ${cellOf(pick(args, 0, ["open"], "null"))}; ${cellOf(pick(args, 1, ["high"], "null"))}; ${cellOf(pick(args, 2, ["low"], "null"))}; ${cellOf(pick(args, 3, ["close"], "null"))}; return __h.ta.engulfing(); })()`;
|
|
46097
|
+
return `(() => { const __o = ${cellOf(pick(args, 0, ["open"], "null"))}; ${cellOf(pick(args, 1, ["high"], "null"))}; ${cellOf(pick(args, 2, ["low"], "null"))}; const __c = ${cellOf(pick(args, 3, ["close"], "null"))}; return __h.ta.engulfing(${site}, __o, __c); })()`;
|
|
44779
46098
|
}
|
|
44780
46099
|
if (method === "inside_bar_pattern") {
|
|
44781
|
-
return
|
|
46100
|
+
return taCall("insideBarPattern", site, [
|
|
46101
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
46102
|
+
cellOf(pick(args, 1, ["low"], "null"))
|
|
46103
|
+
]);
|
|
44782
46104
|
}
|
|
44783
46105
|
if (method === "double_top_bottom") {
|
|
44784
|
-
return
|
|
46106
|
+
return taCall("doubleTopBottom", site, [
|
|
46107
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
46108
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
46109
|
+
cellOf(pick(args, 2, ["period", "length"], "null"))
|
|
46110
|
+
]);
|
|
44785
46111
|
}
|
|
44786
46112
|
if (method === "voi") {
|
|
44787
46113
|
return `__h.ta.voi(${cellOf(pick(args, 0, ["buy_volume", "buy"], "null"))}, ${cellOf(pick(args, 1, ["sell_volume", "sell"], "null"))})`;
|
|
@@ -44794,7 +46120,10 @@ function emitTa(ctx, method, args) {
|
|
|
44794
46120
|
}
|
|
44795
46121
|
if (method === "rsi_divergence") {
|
|
44796
46122
|
const period = `((__n) => (__n == null ? 0 : __n))(${cellOf(pick(args, 1, ["period", "length"], "null"))})`;
|
|
44797
|
-
return
|
|
46123
|
+
return taCall("rsiDivergence", site, [
|
|
46124
|
+
cellLast(pick(args, 0, ["rsi_series", "series", "source"], "null")),
|
|
46125
|
+
period
|
|
46126
|
+
]);
|
|
44798
46127
|
}
|
|
44799
46128
|
if (method === "cumulative_delta") {
|
|
44800
46129
|
return taCall("cumulativeDelta", site, [
|
|
@@ -44829,6 +46158,237 @@ function emitTa(ctx, method, args) {
|
|
|
44829
46158
|
`((__n) => (__n == null ? 0.3 : __n))(${sens})`
|
|
44830
46159
|
]);
|
|
44831
46160
|
}
|
|
46161
|
+
if (method === "sma_weighted") {
|
|
46162
|
+
return taCall("smaWeighted", site, [
|
|
46163
|
+
cellOf(pick(args, 0, ["series", "source"], "null")),
|
|
46164
|
+
cellOf(pick(args, 1, ["period", "length"], "null")),
|
|
46165
|
+
pick(args, 2, ["weight_type", "weight"], '"linear"')
|
|
46166
|
+
]);
|
|
46167
|
+
}
|
|
46168
|
+
if (method === "apo") {
|
|
46169
|
+
return taCall("apo", site, [
|
|
46170
|
+
cellOf(pick(args, 0, ["series", "source"], "null")),
|
|
46171
|
+
cellOf(pick(args, 1, ["fast_period", "fast"], "null")),
|
|
46172
|
+
cellOf(pick(args, 2, ["slow_period", "slow"], "null"))
|
|
46173
|
+
]);
|
|
46174
|
+
}
|
|
46175
|
+
if (method === "atr_normalized") {
|
|
46176
|
+
return taCall("atrNormalized", site, [
|
|
46177
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
46178
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
46179
|
+
cellOf(pick(args, 2, ["close"], "null")),
|
|
46180
|
+
cellOf(pick(args, 3, ["period", "length"], "null"))
|
|
46181
|
+
]);
|
|
46182
|
+
}
|
|
46183
|
+
if (method === "beta" || method === "r_squared" || method === "comovement") {
|
|
46184
|
+
const fn = method === "beta" ? "beta" : method === "r_squared" ? "rSquared" : "comovement";
|
|
46185
|
+
return taCall(fn, site, [
|
|
46186
|
+
cellOf(pick(args, 0, ["series1", "series", "source"], "null")),
|
|
46187
|
+
cellOf(pick(args, 1, ["series2", "series_b", "other"], "null")),
|
|
46188
|
+
cellOf(pick(args, 2, ["length", "period"], "null"))
|
|
46189
|
+
]);
|
|
46190
|
+
}
|
|
46191
|
+
if (method === "skewness" || method === "kurtosis") {
|
|
46192
|
+
return taCall(method, site, [
|
|
46193
|
+
cellOf(pick(args, 0, ["series", "source"], "null")),
|
|
46194
|
+
cellOf(pick(args, 1, ["period", "length"], "null"))
|
|
46195
|
+
]);
|
|
46196
|
+
}
|
|
46197
|
+
if (method === "volume_weighted_momentum") {
|
|
46198
|
+
return taCall("volumeWeightedMomentum", site, [
|
|
46199
|
+
cellOf(pick(args, 0, ["series", "source"], "null")),
|
|
46200
|
+
cellOf(pick(args, 1, ["volume"], "null")),
|
|
46201
|
+
cellOf(pick(args, 2, ["length", "period"], "null"))
|
|
46202
|
+
]);
|
|
46203
|
+
}
|
|
46204
|
+
if (method === "parkinson") {
|
|
46205
|
+
if (hasSeriesArg(args))
|
|
46206
|
+
return "null";
|
|
46207
|
+
return `__h.ta.parkinson(${cellOf(pick(args, 0, ["high"], "null"))}, ${cellOf(pick(args, 1, ["low"], "null"))})`;
|
|
46208
|
+
}
|
|
46209
|
+
if (method === "garman_klass") {
|
|
46210
|
+
if (hasSeriesArg(args))
|
|
46211
|
+
return "null";
|
|
46212
|
+
return `__h.ta.garmanKlass(${cellOf(pick(args, 0, ["high"], "null"))}, ${cellOf(pick(args, 1, ["low"], "null"))}, ${cellOf(pick(args, 2, ["close"], "null"))}, ${cellOf(pick(args, 3, ["open"], "null"))})`;
|
|
46213
|
+
}
|
|
46214
|
+
if (method === "mean_reversion_score") {
|
|
46215
|
+
return taCall("meanReversionScore", site, [
|
|
46216
|
+
cellOf(pick(args, 0, ["close", "source"], "null")),
|
|
46217
|
+
cellOf(pick(args, 1, ["sma"], "null")),
|
|
46218
|
+
cellOf(pick(args, 2, ["stdev", "std_dev"], "null")),
|
|
46219
|
+
cellOf(pick(args, 3, ["period", "length"], "null"))
|
|
46220
|
+
]);
|
|
46221
|
+
}
|
|
46222
|
+
if (method === "market_condition") {
|
|
46223
|
+
return taCall("marketCondition", site, [
|
|
46224
|
+
cellOf(pick(args, 0, ["close", "source"], "null")),
|
|
46225
|
+
cellOf(pick(args, 1, ["atr"], "null")),
|
|
46226
|
+
cellOf(pick(args, 2, ["sma_period", "sma_length"], "null")),
|
|
46227
|
+
cellOf(pick(args, 3, ["stdev_period", "stdev_length"], "null"))
|
|
46228
|
+
]);
|
|
46229
|
+
}
|
|
46230
|
+
if (method === "order_flow_imbalance") {
|
|
46231
|
+
return taCall("orderFlowImbalance", site, [
|
|
46232
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
46233
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
46234
|
+
cellOf(pick(args, 2, ["close"], "null")),
|
|
46235
|
+
cellOf(pick(args, 3, ["volume"], "null")),
|
|
46236
|
+
cellOf(pick(args, 4, ["period", "length"], "null"))
|
|
46237
|
+
]);
|
|
46238
|
+
}
|
|
46239
|
+
if (method === "liquidity_score") {
|
|
46240
|
+
return taCall("liquidityScore", site, [
|
|
46241
|
+
cellOf(pick(args, 0, ["volume"], "null")),
|
|
46242
|
+
cellOf(pick(args, 1, ["volatility"], "null")),
|
|
46243
|
+
cellOf(pick(args, 2, ["spread"], "null")),
|
|
46244
|
+
cellOf(pick(args, 3, ["period", "length"], "null"))
|
|
46245
|
+
]);
|
|
46246
|
+
}
|
|
46247
|
+
if (method === "fear_greed_index") {
|
|
46248
|
+
return `__h.ta.fearGreedIndex(${cellOf(pick(args, 0, ["rsi"], "null"))}, ${cellOf(pick(args, 1, ["vix"], "null"))}, ${cellOf(pick(args, 2, ["put_call", "put_call_ratio"], "null"))}, ${cellOf(pick(args, 3, ["breadth"], "null"))})`;
|
|
46249
|
+
}
|
|
46250
|
+
if (method === "crowd_sentiment") {
|
|
46251
|
+
return `__h.ta.crowdSentiment(${cellOf(pick(args, 0, ["price_agreement", "price"], "null"))}, ${cellOf(pick(args, 1, ["volume_agreement", "volume"], "null"))}, ${cellOf(pick(args, 2, ["time_agreement", "time"], "null"))})`;
|
|
46252
|
+
}
|
|
46253
|
+
if (method === "smart_money_flow") {
|
|
46254
|
+
return `__h.ta.smartMoneyFlow(${cellOf(pick(args, 0, ["price_change"], "null"))}, ${cellOf(pick(args, 1, ["volume"], "null"))}, ${cellOf(pick(args, 2, ["time_since_high", "time_high"], "null"))}, ${cellOf(pick(args, 3, ["time_since_low", "time_low"], "null"))})`;
|
|
46255
|
+
}
|
|
46256
|
+
if (method === "trend_confirmation_score") {
|
|
46257
|
+
return `__h.ta.trendConfirmationScore(${cellOf(pick(args, 0, ["momentum"], "null"))}, ${cellOf(pick(args, 1, ["trend_alignment"], "null"))}, ${cellOf(pick(args, 2, ["strength"], "null"))}, ${cellOf(pick(args, 3, ["rsi"], "null"))}, ${cellOf(pick(args, 4, ["rsi_alignment"], "null"))})`;
|
|
46258
|
+
}
|
|
46259
|
+
if (method === "max_loss_level") {
|
|
46260
|
+
return `__h.ta.maxLossLevel(${cellOf(pick(args, 0, ["entry", "entry_price"], "null"))}, ${cellOf(pick(args, 1, ["account", "account_size"], "null"))}, ${cellOf(pick(args, 2, ["max_loss_pct", "max_loss_percent"], "null"))})`;
|
|
46261
|
+
}
|
|
46262
|
+
if (method === "profit_lock_level") {
|
|
46263
|
+
return `__h.ta.profitLockLevel(${cellOf(pick(args, 0, ["entry", "entry_price"], "null"))}, ${cellOf(pick(args, 1, ["current", "current_price"], "null"))}, ${cellOf(pick(args, 2, ["trail_pct", "trail_percent"], "null"))}, ${cellOf(pick(args, 3, ["direction"], "null"))})`;
|
|
46264
|
+
}
|
|
46265
|
+
if (method === "position_sizing") {
|
|
46266
|
+
return taPure("positionSizing", [
|
|
46267
|
+
cellOf(pick(args, 0, ["account", "account_size"], "null")),
|
|
46268
|
+
cellOf(pick(args, 1, ["risk_pct", "risk_percent"], "null")),
|
|
46269
|
+
cellOf(pick(args, 2, ["entry", "entry_price"], "null")),
|
|
46270
|
+
cellOf(pick(args, 3, ["stop", "stop_price"], "null"))
|
|
46271
|
+
]);
|
|
46272
|
+
}
|
|
46273
|
+
if (method === "kelly_criterion") {
|
|
46274
|
+
return taPure("kellyCriterion", [
|
|
46275
|
+
cellOf(pick(args, 0, ["win_rate"], "null")),
|
|
46276
|
+
cellOf(pick(args, 1, ["avg_win"], "null")),
|
|
46277
|
+
cellOf(pick(args, 2, ["avg_loss"], "null"))
|
|
46278
|
+
]);
|
|
46279
|
+
}
|
|
46280
|
+
if (method === "risk_reward_ratio") {
|
|
46281
|
+
return taPure("riskRewardRatio", [
|
|
46282
|
+
cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
|
|
46283
|
+
cellOf(pick(args, 1, ["stop", "stop_price"], "null")),
|
|
46284
|
+
cellOf(pick(args, 2, ["target", "target_price"], "null"))
|
|
46285
|
+
]);
|
|
46286
|
+
}
|
|
46287
|
+
if (method === "risk_reward_asymmetry") {
|
|
46288
|
+
return taPure("riskRewardAsymmetry", [
|
|
46289
|
+
cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
|
|
46290
|
+
cellOf(pick(args, 1, ["stop", "stop_price"], "null")),
|
|
46291
|
+
cellOf(pick(args, 2, ["target", "target_price"], "null")),
|
|
46292
|
+
cellOf(pick(args, 3, ["win_rate"], "null"))
|
|
46293
|
+
]);
|
|
46294
|
+
}
|
|
46295
|
+
if (method === "probability_of_movement") {
|
|
46296
|
+
return taPure("probabilityOfMovement", [
|
|
46297
|
+
cellOf(pick(args, 0, ["current", "current_price"], "null")),
|
|
46298
|
+
cellOf(pick(args, 1, ["target", "target_price"], "null")),
|
|
46299
|
+
cellOf(pick(args, 2, ["atr"], "null")),
|
|
46300
|
+
cellOf(pick(args, 3, ["period", "length"], "null"))
|
|
46301
|
+
]);
|
|
46302
|
+
}
|
|
46303
|
+
if (method === "trend_strength") {
|
|
46304
|
+
return taPure("trendStrength", [
|
|
46305
|
+
cellOf(pick(args, 0, ["price", "source"], "null")),
|
|
46306
|
+
cellOf(pick(args, 1, ["adx"], "null")),
|
|
46307
|
+
cellOf(pick(args, 2, ["rsi"], "null"))
|
|
46308
|
+
]);
|
|
46309
|
+
}
|
|
46310
|
+
if (method === "breakeven_level") {
|
|
46311
|
+
return taPure("breakevenLevel", [
|
|
46312
|
+
cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
|
|
46313
|
+
cellOf(pick(args, 1, ["quantity", "qty"], "null")),
|
|
46314
|
+
cellOf(pick(args, 2, ["commission"], "null")),
|
|
46315
|
+
cellOf(pick(args, 3, ["slippage"], "null")),
|
|
46316
|
+
cellOf(pick(args, 4, ["direction"], "null"))
|
|
46317
|
+
]);
|
|
46318
|
+
}
|
|
46319
|
+
if (method === "market_structure_pivot") {
|
|
46320
|
+
return taPure("marketStructurePivot", [
|
|
46321
|
+
cellOf(pick(args, 2, ["close"], "null"))
|
|
46322
|
+
]);
|
|
46323
|
+
}
|
|
46324
|
+
if (method === "position_sizing_score") {
|
|
46325
|
+
return taPure("positionSizingScore", [
|
|
46326
|
+
cellOf(pick(args, 0, ["account_risk", "risk"], "null")),
|
|
46327
|
+
cellOf(pick(args, 1, ["volatility"], "null")),
|
|
46328
|
+
cellOf(pick(args, 2, ["conviction"], "null")),
|
|
46329
|
+
cellOf(pick(args, 3, ["correlation"], "null"))
|
|
46330
|
+
]);
|
|
46331
|
+
}
|
|
46332
|
+
if (method === "trailing_exit_level") {
|
|
46333
|
+
return taPure("trailingExitLevel", [
|
|
46334
|
+
cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
|
|
46335
|
+
cellOf(pick(args, 1, ["current", "current_price"], "null")),
|
|
46336
|
+
cellOf(pick(args, 2, ["atr"], "null")),
|
|
46337
|
+
cellOf(pick(args, 3, ["multiplier", "mult"], "null")),
|
|
46338
|
+
cellOf(pick(args, 4, ["step"], "null"))
|
|
46339
|
+
]);
|
|
46340
|
+
}
|
|
46341
|
+
if (method === "optimal_entry_zone") {
|
|
46342
|
+
return taPure("optimalEntryZone", [cellOf(pick(args, 2, ["close"], "null"))]);
|
|
46343
|
+
}
|
|
46344
|
+
if (method === "mean_reversion_entry") {
|
|
46345
|
+
return taPure("meanReversionEntry", [
|
|
46346
|
+
cellOf(pick(args, 0, ["price", "source"], "null")),
|
|
46347
|
+
cellOf(pick(args, 1, ["sma"], "null")),
|
|
46348
|
+
cellOf(pick(args, 2, ["stdev", "std_dev"], "null")),
|
|
46349
|
+
cellOf(pick(args, 4, ["threshold"], "null"))
|
|
46350
|
+
]);
|
|
46351
|
+
}
|
|
46352
|
+
if (method === "multi_timeframe_signal") {
|
|
46353
|
+
return taPure("multiTimeframeSignal", [
|
|
46354
|
+
cellOf(pick(args, 0, ["s1", "signal1"], "null")),
|
|
46355
|
+
cellOf(pick(args, 1, ["s2", "signal2"], "null")),
|
|
46356
|
+
cellOf(pick(args, 2, ["s3", "signal3"], "null")),
|
|
46357
|
+
cellOf(pick(args, 3, ["w1", "weight1"], "null")),
|
|
46358
|
+
cellOf(pick(args, 4, ["w2", "weight2"], "null")),
|
|
46359
|
+
cellOf(pick(args, 5, ["w3", "weight3"], "null"))
|
|
46360
|
+
]);
|
|
46361
|
+
}
|
|
46362
|
+
if (method === "market_timing_index") {
|
|
46363
|
+
return taPure("marketTimingIndex", [
|
|
46364
|
+
cellOf(pick(args, 0, ["trend"], "null")),
|
|
46365
|
+
cellOf(pick(args, 1, ["momentum"], "null")),
|
|
46366
|
+
cellOf(pick(args, 2, ["volatility"], "null")),
|
|
46367
|
+
cellOf(pick(args, 3, ["sentiment"], "null"))
|
|
46368
|
+
]);
|
|
46369
|
+
}
|
|
46370
|
+
if (method === "regime_adaptive_signal") {
|
|
46371
|
+
return taPure("regimeAdaptiveSignal", [
|
|
46372
|
+
cellOf(pick(args, 0, ["signal_strength", "strength"], "null")),
|
|
46373
|
+
pick(args, 1, ["volatility_regime", "vol_regime"], '""'),
|
|
46374
|
+
pick(args, 2, ["trend_regime"], '""')
|
|
46375
|
+
]);
|
|
46376
|
+
}
|
|
46377
|
+
if (method === "strategy_score") {
|
|
46378
|
+
return taPure("strategyScore", [
|
|
46379
|
+
cellOf(pick(args, 0, ["rsi"], "null")),
|
|
46380
|
+
cellOf(pick(args, 1, ["macd"], "null")),
|
|
46381
|
+
cellOf(pick(args, 2, ["ema_cross"], "null")),
|
|
46382
|
+
cellOf(pick(args, 3, ["trend"], "null"))
|
|
46383
|
+
]);
|
|
46384
|
+
}
|
|
46385
|
+
if (method === "breakout_detection") {
|
|
46386
|
+
return taPure("breakoutDetection", [
|
|
46387
|
+
cellOf(pick(args, 0, ["close", "source"], "null")),
|
|
46388
|
+
cellOf(pick(args, 1, ["resistance"], "null")),
|
|
46389
|
+
cellOf(pick(args, 2, ["support"], "null"))
|
|
46390
|
+
]);
|
|
46391
|
+
}
|
|
44832
46392
|
return "null";
|
|
44833
46393
|
}
|
|
44834
46394
|
|
|
@@ -45477,6 +47037,20 @@ var ATTR_CONSTANTS = {
|
|
|
45477
47037
|
"plot.linestyle_solid": "linestyle_solid",
|
|
45478
47038
|
"plot.linestyle_dashed": "linestyle_dashed",
|
|
45479
47039
|
"plot.linestyle_dotted": "linestyle_dotted",
|
|
47040
|
+
"plot.style_line": "style_line",
|
|
47041
|
+
"plot.style_linebr": "style_linebr",
|
|
47042
|
+
"plot.style_stepline": "style_stepline",
|
|
47043
|
+
"plot.style_steplinebr": "style_steplinebr",
|
|
47044
|
+
"plot.style_stepline_diamond": "style_stepline_diamond",
|
|
47045
|
+
"plot.style_histogram": "style_histogram",
|
|
47046
|
+
"plot.style_columns": "style_columns",
|
|
47047
|
+
"plot.style_cross": "style_cross",
|
|
47048
|
+
"plot.style_area": "style_area",
|
|
47049
|
+
"plot.style_areabr": "style_areabr",
|
|
47050
|
+
"plot.style_circles": "style_circles",
|
|
47051
|
+
"alert.freq_once_per_bar": "once_per_bar",
|
|
47052
|
+
"alert.freq_once_per_bar_close": "once_per_bar_close",
|
|
47053
|
+
"alert.freq_all": "all",
|
|
45480
47054
|
"dayofweek.sunday": 1,
|
|
45481
47055
|
"dayofweek.monday": 2,
|
|
45482
47056
|
"dayofweek.tuesday": 3,
|
|
@@ -45513,6 +47087,7 @@ var ATTR_CONST_NS = new Set([
|
|
|
45513
47087
|
"position",
|
|
45514
47088
|
"hline",
|
|
45515
47089
|
"plot",
|
|
47090
|
+
"alert",
|
|
45516
47091
|
"dayofweek",
|
|
45517
47092
|
"month"
|
|
45518
47093
|
]);
|
|
@@ -46282,6 +47857,8 @@ function naNum(v) {
|
|
|
46282
47857
|
function hold(v) {
|
|
46283
47858
|
if (v != null && typeof v === "object")
|
|
46284
47859
|
return v;
|
|
47860
|
+
if (typeof v === "string")
|
|
47861
|
+
return v;
|
|
46285
47862
|
return naNum(v);
|
|
46286
47863
|
}
|
|
46287
47864
|
function pineEq(a, b) {
|
|
@@ -46974,8 +48551,23 @@ class CompileDraw {
|
|
|
46974
48551
|
putNum(extra, "bottom", bottom);
|
|
46975
48552
|
return this.book.boxNew(n3(bar, 0), Object.keys(extra).length ? extra : undefined);
|
|
46976
48553
|
}
|
|
46977
|
-
table_new(bar) {
|
|
46978
|
-
|
|
48554
|
+
table_new(bar, position, columns, rows, bgcolor, frameColor, frameWidth, borderColor, borderWidth, forceOverlay) {
|
|
48555
|
+
const extra = {};
|
|
48556
|
+
if (position != null)
|
|
48557
|
+
extra.position = position;
|
|
48558
|
+
putNum(extra, "columns", columns);
|
|
48559
|
+
putNum(extra, "rows", rows);
|
|
48560
|
+
if (bgcolor != null)
|
|
48561
|
+
extra.bgcolor = bgcolor;
|
|
48562
|
+
if (frameColor != null)
|
|
48563
|
+
extra.frame_color = frameColor;
|
|
48564
|
+
putNum(extra, "frame_width", frameWidth);
|
|
48565
|
+
if (borderColor != null)
|
|
48566
|
+
extra.border_color = borderColor;
|
|
48567
|
+
putNum(extra, "border_width", borderWidth);
|
|
48568
|
+
if (forceOverlay != null)
|
|
48569
|
+
extra.force_overlay = forceOverlay;
|
|
48570
|
+
return this.book.tableNew(n3(bar, 0), Object.keys(extra).length ? extra : undefined);
|
|
46979
48571
|
}
|
|
46980
48572
|
polyline_new(bar, points) {
|
|
46981
48573
|
const pts = pointsOf(points);
|
|
@@ -47609,7 +49201,8 @@ class CompileStrategy {
|
|
|
47609
49201
|
open: num(open, this.mark),
|
|
47610
49202
|
high: num(high, this.mark),
|
|
47611
49203
|
low: num(low, this.mark),
|
|
47612
|
-
close: this.mark
|
|
49204
|
+
close: this.mark,
|
|
49205
|
+
time: this.time
|
|
47613
49206
|
};
|
|
47614
49207
|
this.ohlc = ohlc;
|
|
47615
49208
|
this.book.processPending(this.bar, ohlc);
|
|
@@ -47625,17 +49218,18 @@ class CompileStrategy {
|
|
|
47625
49218
|
stop: opts?.stop,
|
|
47626
49219
|
comment: opts?.comment,
|
|
47627
49220
|
oca_name: opts?.oca_name,
|
|
47628
|
-
oca_type: opts?.oca_type
|
|
49221
|
+
oca_type: opts?.oca_type,
|
|
49222
|
+
deferMarket: true
|
|
47629
49223
|
});
|
|
47630
49224
|
}
|
|
47631
49225
|
close(id, qty) {
|
|
47632
|
-
this.book.
|
|
49226
|
+
this.book.placeClose(this.bar, str(id, ""), this.mark, {
|
|
47633
49227
|
time: this.time,
|
|
47634
49228
|
qty: optNum(qty)
|
|
47635
49229
|
});
|
|
47636
49230
|
}
|
|
47637
49231
|
close_all(_comment) {
|
|
47638
|
-
this.book.
|
|
49232
|
+
this.book.placeCloseAll(this.bar, this.mark);
|
|
47639
49233
|
}
|
|
47640
49234
|
order(id, direction, qty, opts) {
|
|
47641
49235
|
this.entry(id, direction, qty, opts);
|
|
@@ -47652,7 +49246,8 @@ class CompileStrategy {
|
|
|
47652
49246
|
...parsed,
|
|
47653
49247
|
price: this.mark,
|
|
47654
49248
|
time: this.time,
|
|
47655
|
-
ohlc: this.ohlc
|
|
49249
|
+
ohlc: this.ohlc,
|
|
49250
|
+
deferMarket: true
|
|
47656
49251
|
});
|
|
47657
49252
|
}
|
|
47658
49253
|
position_size() {
|
|
@@ -48020,8 +49615,8 @@ function createCompileHelpers(opts) {
|
|
|
48020
49615
|
second: calendarSecond,
|
|
48021
49616
|
dayofweek: calendarDayofweek,
|
|
48022
49617
|
timestamp,
|
|
48023
|
-
weekOfYear,
|
|
48024
|
-
timeTradingDay,
|
|
49618
|
+
weekOfYear: calendarWeekOfYear,
|
|
49619
|
+
timeTradingDay: calendarTimeTradingDay,
|
|
48025
49620
|
timeframeInSeconds: timeframeInSecondsOrDaily,
|
|
48026
49621
|
timeframeChange,
|
|
48027
49622
|
timeClose,
|
|
@@ -48065,11 +49660,40 @@ function createCompileHelpers(opts) {
|
|
|
48065
49660
|
udtSet,
|
|
48066
49661
|
udtRegister,
|
|
48067
49662
|
currencyRate: resolveCurrencyRate,
|
|
49663
|
+
requestSeed: resolveSeed,
|
|
49664
|
+
requestFootprint: createFootprint,
|
|
49665
|
+
footprint: {
|
|
49666
|
+
buy_volume: footprintBuyVolume,
|
|
49667
|
+
sell_volume: footprintSellVolume,
|
|
49668
|
+
delta: footprintDelta,
|
|
49669
|
+
total_volume: footprintTotalVolume,
|
|
49670
|
+
vah: footprintVah,
|
|
49671
|
+
val: footprintVal,
|
|
49672
|
+
poc: footprintPoc,
|
|
49673
|
+
rows: compileFootprintRows,
|
|
49674
|
+
get_row_by_price: footprintGetRowByPrice,
|
|
49675
|
+
volume_row: {
|
|
49676
|
+
up_price: volumeRowUpPrice,
|
|
49677
|
+
down_price: volumeRowDownPrice,
|
|
49678
|
+
buy_volume: volumeRowBuyVolume,
|
|
49679
|
+
sell_volume: volumeRowSellVolume,
|
|
49680
|
+
delta: volumeRowDelta,
|
|
49681
|
+
total_volume: volumeRowTotalVolume,
|
|
49682
|
+
has_buy_imbalance: volumeRowHasBuyImbalance,
|
|
49683
|
+
has_sell_imbalance: volumeRowHasSellImbalance
|
|
49684
|
+
}
|
|
49685
|
+
},
|
|
48068
49686
|
runtimeError(msg) {
|
|
48069
49687
|
throw new Error(String(msg));
|
|
48070
49688
|
}
|
|
48071
49689
|
};
|
|
48072
49690
|
}
|
|
49691
|
+
function compileFootprintRows(fp) {
|
|
49692
|
+
const arr = new PineArray;
|
|
49693
|
+
for (const row of footprintRows(fp))
|
|
49694
|
+
arr.push(row);
|
|
49695
|
+
return arr;
|
|
49696
|
+
}
|
|
48073
49697
|
function compileColorNew(color, transp) {
|
|
48074
49698
|
const parsed = asColor(color);
|
|
48075
49699
|
if (!parsed)
|
|
@@ -48116,7 +49740,20 @@ function NA_FN(v) {
|
|
|
48116
49740
|
function utcPart(t, key) {
|
|
48117
49741
|
if (typeof t !== "number" || !Number.isFinite(t))
|
|
48118
49742
|
return null;
|
|
48119
|
-
|
|
49743
|
+
const ms = timestampToMs(t);
|
|
49744
|
+
return ms == null ? null : utcPartsFromMs(ms)[key];
|
|
49745
|
+
}
|
|
49746
|
+
function calendarWeekOfYear(t) {
|
|
49747
|
+
if (typeof t !== "number" || !Number.isFinite(t))
|
|
49748
|
+
return null;
|
|
49749
|
+
const ms = timestampToMs(t);
|
|
49750
|
+
return ms == null ? null : weekOfYear(ms);
|
|
49751
|
+
}
|
|
49752
|
+
function calendarTimeTradingDay(t) {
|
|
49753
|
+
if (typeof t !== "number" || !Number.isFinite(t))
|
|
49754
|
+
return null;
|
|
49755
|
+
const ms = timestampToMs(t);
|
|
49756
|
+
return ms == null ? null : timeTradingDay(ms);
|
|
48120
49757
|
}
|
|
48121
49758
|
function calendarYear(t) {
|
|
48122
49759
|
return utcPart(t, "year");
|
|
@@ -48550,7 +50187,8 @@ function interpretTree(tree, ohlcv, host) {
|
|
|
48550
50187
|
open: num2(env.ctx.open) ?? undefined,
|
|
48551
50188
|
high: num2(env.ctx.high) ?? undefined,
|
|
48552
50189
|
low: num2(env.ctx.low) ?? undefined,
|
|
48553
|
-
close: num2(env.ctx.close) ?? undefined
|
|
50190
|
+
close: num2(env.ctx.close) ?? undefined,
|
|
50191
|
+
time: num2(env.ctx.time) ?? undefined
|
|
48554
50192
|
});
|
|
48555
50193
|
env.book.markOpenTrades(num2(env.ctx.high) ?? num2(env.ctx.close) ?? 0, num2(env.ctx.low) ?? num2(env.ctx.close) ?? 0, num2(env.ctx.close) ?? 0);
|
|
48556
50194
|
try {
|
|
@@ -48881,6 +50519,27 @@ function seriesGet(env, id) {
|
|
|
48881
50519
|
}
|
|
48882
50520
|
return env.series.get(id);
|
|
48883
50521
|
}
|
|
50522
|
+
var BARE_SERIES_NAMES2 = new Set([
|
|
50523
|
+
"open",
|
|
50524
|
+
"high",
|
|
50525
|
+
"low",
|
|
50526
|
+
"close",
|
|
50527
|
+
"volume",
|
|
50528
|
+
"hl2",
|
|
50529
|
+
"hlc3",
|
|
50530
|
+
"ohlc4",
|
|
50531
|
+
"hlcc4",
|
|
50532
|
+
"time",
|
|
50533
|
+
"time_close"
|
|
50534
|
+
]);
|
|
50535
|
+
function isSeriesExpr(value, env) {
|
|
50536
|
+
if (value.kind === "Name") {
|
|
50537
|
+
if (BARE_SERIES_NAMES2.has(value.id))
|
|
50538
|
+
return true;
|
|
50539
|
+
return seriesGet(env, value.id) != null;
|
|
50540
|
+
}
|
|
50541
|
+
return false;
|
|
50542
|
+
}
|
|
48884
50543
|
function bindName(env, id, value) {
|
|
48885
50544
|
const stored = typeof value === "number" && !Number.isFinite(value) ? NA : value;
|
|
48886
50545
|
const frame = activeFrame(env);
|
|
@@ -49503,6 +51162,20 @@ var MATH_CONSTANTS = {
|
|
|
49503
51162
|
"plot.linestyle_solid": "linestyle_solid",
|
|
49504
51163
|
"plot.linestyle_dashed": "linestyle_dashed",
|
|
49505
51164
|
"plot.linestyle_dotted": "linestyle_dotted",
|
|
51165
|
+
"plot.style_line": "style_line",
|
|
51166
|
+
"plot.style_linebr": "style_linebr",
|
|
51167
|
+
"plot.style_stepline": "style_stepline",
|
|
51168
|
+
"plot.style_steplinebr": "style_steplinebr",
|
|
51169
|
+
"plot.style_stepline_diamond": "style_stepline_diamond",
|
|
51170
|
+
"plot.style_histogram": "style_histogram",
|
|
51171
|
+
"plot.style_columns": "style_columns",
|
|
51172
|
+
"plot.style_cross": "style_cross",
|
|
51173
|
+
"plot.style_area": "style_area",
|
|
51174
|
+
"plot.style_areabr": "style_areabr",
|
|
51175
|
+
"plot.style_circles": "style_circles",
|
|
51176
|
+
"alert.freq_once_per_bar": "once_per_bar",
|
|
51177
|
+
"alert.freq_once_per_bar_close": "once_per_bar_close",
|
|
51178
|
+
"alert.freq_all": "all",
|
|
49506
51179
|
"dayofweek.sunday": 1,
|
|
49507
51180
|
"dayofweek.monday": 2,
|
|
49508
51181
|
"dayofweek.tuesday": 3,
|
|
@@ -49893,6 +51566,9 @@ function evalCall(node, env) {
|
|
|
49893
51566
|
if (isRequestBuiltin(fname) || fname === "request.security" || fname === "security" || fname === "security_lower_tf") {
|
|
49894
51567
|
return evalRequestCall(fname, node, env);
|
|
49895
51568
|
}
|
|
51569
|
+
const fpCall = evalFootprintCall(fname, node, env);
|
|
51570
|
+
if (fpCall !== undefined)
|
|
51571
|
+
return fpCall;
|
|
49896
51572
|
const arrVal = evalArrayCall(fname, node, env);
|
|
49897
51573
|
if (arrVal !== undefined)
|
|
49898
51574
|
return arrVal;
|
|
@@ -50081,7 +51757,8 @@ function evalCall(node, env) {
|
|
|
50081
51757
|
price: mark == null || !Number.isFinite(mark) ? undefined : mark,
|
|
50082
51758
|
time: num2(env.ctx.time) ?? undefined,
|
|
50083
51759
|
oca_name: evalAsString(callArg(node.args, -1, ["oca_name"]), env),
|
|
50084
|
-
oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env)
|
|
51760
|
+
oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env),
|
|
51761
|
+
deferMarket: true
|
|
50085
51762
|
});
|
|
50086
51763
|
return NA;
|
|
50087
51764
|
}
|
|
@@ -50090,13 +51767,10 @@ function evalCall(node, env) {
|
|
|
50090
51767
|
const mark = num2(env.ctx.close);
|
|
50091
51768
|
const qtyExpr = callArg(node.args, 1, ["qty"]);
|
|
50092
51769
|
const qtyRaw = qtyExpr == null ? undefined : unwrap2(evalExpr(qtyExpr, env));
|
|
50093
|
-
|
|
50094
|
-
env.
|
|
50095
|
-
|
|
50096
|
-
|
|
50097
|
-
});
|
|
50098
|
-
} else
|
|
50099
|
-
env.book.close(env.barIndex, id);
|
|
51770
|
+
env.book.placeClose(env.barIndex, id, mark ?? undefined, {
|
|
51771
|
+
time: num2(env.ctx.time) ?? undefined,
|
|
51772
|
+
qty: qtyRaw ?? undefined
|
|
51773
|
+
});
|
|
50100
51774
|
return NA;
|
|
50101
51775
|
}
|
|
50102
51776
|
if (fname === "strategy.exit") {
|
|
@@ -50116,17 +51790,12 @@ function evalCall(node, env) {
|
|
|
50116
51790
|
trail_offset: unwrap2(evalExpr(callArg(node.args, 10, ["trail_offset"]), env)),
|
|
50117
51791
|
price: num2(env.ctx.close) ?? undefined,
|
|
50118
51792
|
time: num2(env.ctx.time) ?? undefined,
|
|
50119
|
-
|
|
50120
|
-
open: num2(env.ctx.open) ?? undefined,
|
|
50121
|
-
high: num2(env.ctx.high) ?? undefined,
|
|
50122
|
-
low: num2(env.ctx.low) ?? undefined,
|
|
50123
|
-
close: num2(env.ctx.close) ?? undefined
|
|
50124
|
-
}
|
|
51793
|
+
deferMarket: true
|
|
50125
51794
|
});
|
|
50126
51795
|
return NA;
|
|
50127
51796
|
}
|
|
50128
51797
|
if (fname === "strategy.close_all") {
|
|
50129
|
-
env.book.
|
|
51798
|
+
env.book.placeCloseAll(env.barIndex, num2(env.ctx.close) ?? undefined);
|
|
50130
51799
|
return NA;
|
|
50131
51800
|
}
|
|
50132
51801
|
if (fname === "strategy.cancel") {
|
|
@@ -50148,7 +51817,8 @@ function evalCall(node, env) {
|
|
|
50148
51817
|
price: num2(env.ctx.close) ?? undefined,
|
|
50149
51818
|
time: num2(env.ctx.time) ?? undefined,
|
|
50150
51819
|
oca_name: evalAsString(callArg(node.args, -1, ["oca_name"]), env),
|
|
50151
|
-
oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env)
|
|
51820
|
+
oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env),
|
|
51821
|
+
deferMarket: true
|
|
50152
51822
|
});
|
|
50153
51823
|
return NA;
|
|
50154
51824
|
}
|
|
@@ -50498,15 +52168,57 @@ function packFills(book) {
|
|
|
50498
52168
|
function packDrawings(book) {
|
|
50499
52169
|
return book.items.length === 0 ? undefined : book.items;
|
|
50500
52170
|
}
|
|
50501
|
-
|
|
50502
|
-
|
|
52171
|
+
var FREQ_ONCE_PER_BAR = "once_per_bar";
|
|
52172
|
+
var FREQ_ONCE_PER_BAR_CLOSE = "once_per_bar_close";
|
|
52173
|
+
var FREQ_ALL = "all";
|
|
52174
|
+
var ALERT_FREQ_ALIASES = {
|
|
52175
|
+
once_per_bar: FREQ_ONCE_PER_BAR,
|
|
52176
|
+
freq_once_per_bar: FREQ_ONCE_PER_BAR,
|
|
52177
|
+
"alert.freq_once_per_bar": FREQ_ONCE_PER_BAR,
|
|
52178
|
+
once_per_bar_close: FREQ_ONCE_PER_BAR_CLOSE,
|
|
52179
|
+
freq_once_per_bar_close: FREQ_ONCE_PER_BAR_CLOSE,
|
|
52180
|
+
"alert.freq_once_per_bar_close": FREQ_ONCE_PER_BAR_CLOSE,
|
|
52181
|
+
all: FREQ_ALL,
|
|
52182
|
+
freq_all: FREQ_ALL,
|
|
52183
|
+
"alert.freq_all": FREQ_ALL
|
|
52184
|
+
};
|
|
52185
|
+
function normalizeAlertFreq(freq) {
|
|
52186
|
+
if (freq == null)
|
|
52187
|
+
return FREQ_ONCE_PER_BAR;
|
|
52188
|
+
if (typeof freq === "number" && !Number.isFinite(freq))
|
|
52189
|
+
return FREQ_ONCE_PER_BAR;
|
|
52190
|
+
const s = String(freq).trim().toLowerCase().replace(/ /g, "_");
|
|
52191
|
+
return ALERT_FREQ_ALIASES[s] ?? (s ? s : FREQ_ONCE_PER_BAR);
|
|
52192
|
+
}
|
|
52193
|
+
function barIsConfirmed(_env) {
|
|
52194
|
+
return true;
|
|
52195
|
+
}
|
|
52196
|
+
function shouldFireAlert(env, source, title, message, freq) {
|
|
52197
|
+
const freqN = normalizeAlertFreq(freq);
|
|
52198
|
+
if (freqN === FREQ_ALL)
|
|
52199
|
+
return true;
|
|
52200
|
+
if (freqN === FREQ_ONCE_PER_BAR_CLOSE && !barIsConfirmed(env))
|
|
52201
|
+
return false;
|
|
52202
|
+
const key = `${source}|${title}|${message}|${freqN}`;
|
|
50503
52203
|
if (env.alertFireBars.get(key) === env.barIndex)
|
|
50504
|
-
return;
|
|
52204
|
+
return false;
|
|
50505
52205
|
env.alertFireBars.set(key, env.barIndex);
|
|
52206
|
+
return true;
|
|
52207
|
+
}
|
|
52208
|
+
function emitAlert(env, message, freq, opts) {
|
|
52209
|
+
const source = opts?.source ?? "alert";
|
|
52210
|
+
const title = opts?.title ?? "";
|
|
52211
|
+
const freqN = normalizeAlertFreq(freq);
|
|
52212
|
+
if (!shouldFireAlert(env, source, title, message, freqN))
|
|
52213
|
+
return;
|
|
50506
52214
|
env.drawings.alert(env.barIndex, message);
|
|
50507
52215
|
const ev = env.drawings.items[env.drawings.items.length - 1];
|
|
50508
|
-
if (ev
|
|
50509
|
-
|
|
52216
|
+
if (ev == null)
|
|
52217
|
+
return;
|
|
52218
|
+
ev.extra = title ? { source, title, freq: freqN } : { source, freq: freqN };
|
|
52219
|
+
}
|
|
52220
|
+
function fireAlertCondition(env, title, message) {
|
|
52221
|
+
emitAlert(env, message, FREQ_ONCE_PER_BAR, { title, source: "alertcondition" });
|
|
50510
52222
|
}
|
|
50511
52223
|
function inputTitle(node) {
|
|
50512
52224
|
const named = namedStringArg(node.args, "title");
|
|
@@ -50828,9 +52540,75 @@ function evalRequestCall(fname, node, env) {
|
|
|
50828
52540
|
const v = resolveRequest(fname, host, { seed });
|
|
50829
52541
|
return typeof v === "number" || v === null ? v : NA;
|
|
50830
52542
|
}
|
|
52543
|
+
if (fname === "request.footprint") {
|
|
52544
|
+
const numTicks = unwrap2(evalExpr(callArg(node.args, 0, ["num_ticks"]), env));
|
|
52545
|
+
const va = unwrap2(evalExpr(callArg(node.args, 1, ["va_percentage"]), env));
|
|
52546
|
+
const v = resolveRequest(fname, host, {
|
|
52547
|
+
num_ticks: numTicks ?? 100,
|
|
52548
|
+
va_percentage: va ?? 70
|
|
52549
|
+
});
|
|
52550
|
+
return v instanceof Footprint ? v : NA;
|
|
52551
|
+
}
|
|
50831
52552
|
const v = resolveRequest(fname, host, {});
|
|
50832
52553
|
return typeof v === "number" || v === null ? v : NA;
|
|
50833
52554
|
}
|
|
52555
|
+
function evalFootprintCall(fname, node, env) {
|
|
52556
|
+
if (fname == null)
|
|
52557
|
+
return;
|
|
52558
|
+
if (fname.startsWith("footprint.")) {
|
|
52559
|
+
const fp = evalExpr(callArg(node.args, 0, ["id", "footprint"]), env);
|
|
52560
|
+
switch (fname) {
|
|
52561
|
+
case "footprint.buy_volume":
|
|
52562
|
+
return footprintBuyVolume(fp);
|
|
52563
|
+
case "footprint.sell_volume":
|
|
52564
|
+
return footprintSellVolume(fp);
|
|
52565
|
+
case "footprint.delta":
|
|
52566
|
+
return footprintDelta(fp);
|
|
52567
|
+
case "footprint.total_volume":
|
|
52568
|
+
return footprintTotalVolume(fp);
|
|
52569
|
+
case "footprint.vah":
|
|
52570
|
+
return footprintVah(fp);
|
|
52571
|
+
case "footprint.val":
|
|
52572
|
+
return footprintVal(fp);
|
|
52573
|
+
case "footprint.poc":
|
|
52574
|
+
return footprintPoc(fp);
|
|
52575
|
+
case "footprint.rows": {
|
|
52576
|
+
const arr = new PineArray;
|
|
52577
|
+
for (const row of footprintRows(fp))
|
|
52578
|
+
arr.push(row);
|
|
52579
|
+
return arr;
|
|
52580
|
+
}
|
|
52581
|
+
case "footprint.get_row_by_price":
|
|
52582
|
+
return footprintGetRowByPrice(fp, unwrap2(evalExpr(callArg(node.args, 1, ["price"]), env)));
|
|
52583
|
+
default:
|
|
52584
|
+
return;
|
|
52585
|
+
}
|
|
52586
|
+
}
|
|
52587
|
+
if (fname.startsWith("volume_row.")) {
|
|
52588
|
+
const vr = evalExpr(callArg(node.args, 0, ["id", "volume_row"]), env);
|
|
52589
|
+
switch (fname) {
|
|
52590
|
+
case "volume_row.up_price":
|
|
52591
|
+
return volumeRowUpPrice(vr);
|
|
52592
|
+
case "volume_row.down_price":
|
|
52593
|
+
return volumeRowDownPrice(vr);
|
|
52594
|
+
case "volume_row.buy_volume":
|
|
52595
|
+
return volumeRowBuyVolume(vr);
|
|
52596
|
+
case "volume_row.sell_volume":
|
|
52597
|
+
return volumeRowSellVolume(vr);
|
|
52598
|
+
case "volume_row.delta":
|
|
52599
|
+
return volumeRowDelta(vr);
|
|
52600
|
+
case "volume_row.total_volume":
|
|
52601
|
+
return volumeRowTotalVolume(vr);
|
|
52602
|
+
case "volume_row.has_buy_imbalance":
|
|
52603
|
+
return volumeRowHasBuyImbalance(vr);
|
|
52604
|
+
case "volume_row.has_sell_imbalance":
|
|
52605
|
+
return volumeRowHasSellImbalance(vr);
|
|
52606
|
+
default:
|
|
52607
|
+
return;
|
|
52608
|
+
}
|
|
52609
|
+
}
|
|
52610
|
+
return;
|
|
52611
|
+
}
|
|
50834
52612
|
function evalMathCall(fname, node, env) {
|
|
50835
52613
|
if (fname === "math.abs" || fname === "abs") {
|
|
50836
52614
|
return mathAbs(cellArg(node, env, 0, ["number", "x"]));
|
|
@@ -51445,11 +53223,11 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51445
53223
|
}
|
|
51446
53224
|
if (fname === "ta.engulfing" || fname === "engulfing") {
|
|
51447
53225
|
const msg = "ta.engulfing() requires 4 arguments: open, high, low, close";
|
|
51448
|
-
unwrap2(evalExpr(wave10aArg(0, ["open"], msg), env));
|
|
53226
|
+
const open = unwrap2(evalExpr(wave10aArg(0, ["open"], msg), env));
|
|
51449
53227
|
unwrap2(evalExpr(wave10aArg(1, ["high"], msg), env));
|
|
51450
53228
|
unwrap2(evalExpr(wave10aArg(2, ["low"], msg), env));
|
|
51451
|
-
unwrap2(evalExpr(wave10aArg(3, ["close"], msg), env));
|
|
51452
|
-
return env.ta.engulfing();
|
|
53229
|
+
const close = unwrap2(evalExpr(wave10aArg(3, ["close"], msg), env));
|
|
53230
|
+
return env.ta.engulfing(site, open, close);
|
|
51453
53231
|
}
|
|
51454
53232
|
if (fname === "ta.gap_detector" || fname === "gap_detector") {
|
|
51455
53233
|
const msg = "ta.gap_detector() requires 3 arguments: high, low, prev_close";
|
|
@@ -51457,15 +53235,15 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51457
53235
|
}
|
|
51458
53236
|
if (fname === "ta.double_top_bottom" || fname === "double_top_bottom") {
|
|
51459
53237
|
const msg = "ta.double_top_bottom() requires 3 arguments";
|
|
51460
|
-
unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
|
|
51461
|
-
unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
|
|
51462
|
-
return env.ta.doubleTopBottom(unwrap2(evalExpr(wave10aArg(2, ["period", "length"], msg), env)));
|
|
53238
|
+
const high = unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
|
|
53239
|
+
const low = unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
|
|
53240
|
+
return env.ta.doubleTopBottom(site, high, low, unwrap2(evalExpr(wave10aArg(2, ["period", "length"], msg), env)));
|
|
51463
53241
|
}
|
|
51464
53242
|
if (fname === "ta.inside_bar_pattern" || fname === "inside_bar_pattern") {
|
|
51465
53243
|
const msg = "ta.inside_bar_pattern() requires 2 arguments";
|
|
51466
|
-
unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
|
|
51467
|
-
unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
|
|
51468
|
-
return env.ta.insideBarPattern();
|
|
53244
|
+
const high = unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
|
|
53245
|
+
const low = unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
|
|
53246
|
+
return env.ta.insideBarPattern(site, high, low);
|
|
51469
53247
|
}
|
|
51470
53248
|
if (fname === "ta.macd_signal" || fname === "macd_signal") {
|
|
51471
53249
|
const msg = "ta.macd_signal() requires 2 arguments: macd_line, signal_line";
|
|
@@ -51477,7 +53255,7 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51477
53255
|
}
|
|
51478
53256
|
if (fname === "ta.stoch_smooth" || fname === "stoch_smooth") {
|
|
51479
53257
|
const msg = "ta.stoch_smooth() requires 6 arguments: high, low, close, period, smooth_k, smooth_d";
|
|
51480
|
-
return env.ta.stochSmooth(unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env)), unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env)), unwrap2(evalExpr(wave10aArg(2, ["close"], msg), env)), unwrap2(evalExpr(wave10aArg(3, ["period", "length"], msg), env)), unwrap2(evalExpr(wave10aArg(4, ["smooth_k", "k"], msg), env)), unwrap2(evalExpr(wave10aArg(5, ["smooth_d", "d"], msg), env)));
|
|
53258
|
+
return env.ta.stochSmooth(site, unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env)), unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env)), unwrap2(evalExpr(wave10aArg(2, ["close"], msg), env)), unwrap2(evalExpr(wave10aArg(3, ["period", "length"], msg), env)), unwrap2(evalExpr(wave10aArg(4, ["smooth_k", "k"], msg), env)), unwrap2(evalExpr(wave10aArg(5, ["smooth_d", "d"], msg), env)));
|
|
51481
53259
|
}
|
|
51482
53260
|
const wave10bList = (index, names) => {
|
|
51483
53261
|
const raw = evalExpr(callArg(node.args, index, names), env);
|
|
@@ -51502,7 +53280,7 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51502
53280
|
}
|
|
51503
53281
|
if (fname === "ta.rsi_divergence" || fname === "rsi_divergence") {
|
|
51504
53282
|
const period = unwrap2(evalExpr(callArg(node.args, 1, ["period", "length"]), env));
|
|
51505
|
-
return env.ta.rsiDivergence(
|
|
53283
|
+
return env.ta.rsiDivergence(site, seriesLastCell(evalExpr(callArg(node.args, 0, ["rsi_series", "series", "source"]), env)), period ?? 0);
|
|
51506
53284
|
}
|
|
51507
53285
|
if (fname === "ta.cumulative_delta" || fname === "cumulative_delta") {
|
|
51508
53286
|
const period = unwrap2(evalExpr(callArg(node.args, 2, ["period", "length"]), env));
|
|
@@ -51524,6 +53302,188 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51524
53302
|
const sens = unwrap2(evalExpr(callArg(node.args, 3, ["sensitivity"]), env));
|
|
51525
53303
|
return env.ta.volumeThrust(site, unwrap2(evalExpr(callArg(node.args, 0, ["close", "source"]), env)), unwrap2(evalExpr(callArg(node.args, 1, ["volume"]), env)), unwrap2(evalExpr(callArg(node.args, 2, ["volume_sma", "vol_sma", "sma"]), env)), sens ?? 0.3);
|
|
51526
53304
|
}
|
|
53305
|
+
const wave11 = (index, names, message) => unwrap2(evalExpr(wave10aArg(index, names, message), env));
|
|
53306
|
+
const wave11n = (index, names, message) => num2(wave11(index, names, message));
|
|
53307
|
+
if (fname === "ta.sma_weighted" || fname === "sma_weighted") {
|
|
53308
|
+
const msg = "ta.sma_weighted() requires at least 2 arguments: series, period";
|
|
53309
|
+
const weightArg = callArg(node.args, 2, ["weight_type", "weight"]);
|
|
53310
|
+
return env.ta.smaWeighted(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["period", "length"], msg), weightArg == null ? "linear" : evalExpr(weightArg, env));
|
|
53311
|
+
}
|
|
53312
|
+
if (fname === "ta.apo" || fname === "apo") {
|
|
53313
|
+
const msg = "ta.apo() requires 3 arguments: series, fast_period, slow_period";
|
|
53314
|
+
return env.ta.apo(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["fast_period", "fast"], msg), wave11n(2, ["slow_period", "slow"], msg));
|
|
53315
|
+
}
|
|
53316
|
+
if (fname === "ta.atr_normalized" || fname === "atr_normalized") {
|
|
53317
|
+
const msg = "ta.atr_normalized() requires 4 arguments: high, low, close, period";
|
|
53318
|
+
return env.ta.atrNormalized(site, wave11n(0, ["high"], msg), wave11n(1, ["low"], msg), wave11n(2, ["close"], msg), wave11n(3, ["period", "length"], msg));
|
|
53319
|
+
}
|
|
53320
|
+
if (fname === "ta.beta" || fname === "beta") {
|
|
53321
|
+
const msg = "ta.beta() requires 3 arguments: series1, series2, length";
|
|
53322
|
+
return env.ta.beta(site, wave11n(0, ["series1", "series", "source"], msg), wave11n(1, ["series2", "series_b", "other"], msg), wave11n(2, ["length", "period"], msg));
|
|
53323
|
+
}
|
|
53324
|
+
if (fname === "ta.r_squared" || fname === "r_squared") {
|
|
53325
|
+
const msg = "ta.r_squared() requires 3 arguments: series1, series2, length";
|
|
53326
|
+
return env.ta.rSquared(site, wave11n(0, ["series1", "series", "source"], msg), wave11n(1, ["series2", "series_b", "other"], msg), wave11n(2, ["length", "period"], msg));
|
|
53327
|
+
}
|
|
53328
|
+
if (fname === "ta.comovement" || fname === "comovement") {
|
|
53329
|
+
const msg = "ta.comovement() requires 3 arguments: series1, series2, length";
|
|
53330
|
+
return env.ta.comovement(site, wave11n(0, ["series1", "series", "source"], msg), wave11n(1, ["series2", "series_b", "other"], msg), wave11n(2, ["length", "period"], msg));
|
|
53331
|
+
}
|
|
53332
|
+
if (fname === "ta.skewness" || fname === "skewness") {
|
|
53333
|
+
const msg = "ta.skewness() requires 2 arguments: series, period";
|
|
53334
|
+
return env.ta.skewness(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["period", "length"], msg));
|
|
53335
|
+
}
|
|
53336
|
+
if (fname === "ta.kurtosis" || fname === "kurtosis") {
|
|
53337
|
+
const msg = "ta.kurtosis() requires 2 arguments: series, period";
|
|
53338
|
+
return env.ta.kurtosis(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["period", "length"], msg));
|
|
53339
|
+
}
|
|
53340
|
+
if (fname === "ta.volume_weighted_momentum" || fname === "volume_weighted_momentum") {
|
|
53341
|
+
const msg = "ta.volume_weighted_momentum() requires 3 arguments: series, volume, length";
|
|
53342
|
+
return env.ta.volumeWeightedMomentum(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["volume"], msg), wave11n(2, ["length", "period"], msg));
|
|
53343
|
+
}
|
|
53344
|
+
if (fname === "ta.parkinson" || fname === "parkinson") {
|
|
53345
|
+
const msg = "ta.parkinson() requires 2 arguments: high, low";
|
|
53346
|
+
const highArg = wave10aArg(0, ["high"], msg);
|
|
53347
|
+
const lowArg = wave10aArg(1, ["low"], msg);
|
|
53348
|
+
if (isSeriesExpr(highArg, env) || isSeriesExpr(lowArg, env))
|
|
53349
|
+
return NA;
|
|
53350
|
+
return env.ta.parkinson(num2(evalExpr(highArg, env)), num2(evalExpr(lowArg, env)));
|
|
53351
|
+
}
|
|
53352
|
+
if (fname === "ta.garman_klass" || fname === "garman_klass") {
|
|
53353
|
+
const msg = "ta.garman_klass() requires 4 arguments: high, low, close, open";
|
|
53354
|
+
const argsExpr = [
|
|
53355
|
+
wave10aArg(0, ["high"], msg),
|
|
53356
|
+
wave10aArg(1, ["low"], msg),
|
|
53357
|
+
wave10aArg(2, ["close"], msg),
|
|
53358
|
+
wave10aArg(3, ["open"], msg)
|
|
53359
|
+
];
|
|
53360
|
+
if (argsExpr.some((a) => isSeriesExpr(a, env)))
|
|
53361
|
+
return NA;
|
|
53362
|
+
return env.ta.garmanKlass(num2(evalExpr(argsExpr[0], env)), num2(evalExpr(argsExpr[1], env)), num2(evalExpr(argsExpr[2], env)), num2(evalExpr(argsExpr[3], env)));
|
|
53363
|
+
}
|
|
53364
|
+
if (fname === "ta.mean_reversion_score" || fname === "mean_reversion_score") {
|
|
53365
|
+
const msg = "ta.mean_reversion_score() requires 4 arguments";
|
|
53366
|
+
return env.ta.meanReversionScore(site, wave11n(0, ["close", "source"], msg), wave11n(1, ["sma"], msg), wave11n(2, ["stdev", "std_dev"], msg), wave11n(3, ["period", "length"], msg));
|
|
53367
|
+
}
|
|
53368
|
+
if (fname === "ta.market_condition" || fname === "market_condition") {
|
|
53369
|
+
const msg = "ta.market_condition() requires 4 arguments";
|
|
53370
|
+
return env.ta.marketCondition(site, wave11n(0, ["close", "source"], msg), wave11n(1, ["atr"], msg), wave11n(2, ["sma_period", "sma_length"], msg), wave11n(3, ["stdev_period", "stdev_length"], msg));
|
|
53371
|
+
}
|
|
53372
|
+
if (fname === "ta.order_flow_imbalance" || fname === "order_flow_imbalance") {
|
|
53373
|
+
const msg = "ta.order_flow_imbalance() requires 5 arguments";
|
|
53374
|
+
return env.ta.orderFlowImbalance(site, wave11n(0, ["high"], msg), wave11n(1, ["low"], msg), wave11n(2, ["close"], msg), wave11n(3, ["volume"], msg), wave11n(4, ["period", "length"], msg));
|
|
53375
|
+
}
|
|
53376
|
+
if (fname === "ta.liquidity_score" || fname === "liquidity_score") {
|
|
53377
|
+
const msg = "ta.liquidity_score() requires 4 arguments";
|
|
53378
|
+
return env.ta.liquidityScore(site, wave11n(0, ["volume"], msg), wave11n(1, ["volatility"], msg), wave11n(2, ["spread"], msg), wave11n(3, ["period", "length"], msg));
|
|
53379
|
+
}
|
|
53380
|
+
if (fname === "ta.fear_greed_index" || fname === "fear_greed_index") {
|
|
53381
|
+
const msg = "ta.fear_greed_index() requires 4 arguments";
|
|
53382
|
+
return env.ta.fearGreedIndex(wave11n(0, ["rsi"], msg), wave11n(1, ["vix"], msg), wave11n(2, ["put_call", "put_call_ratio"], msg), wave11n(3, ["breadth"], msg));
|
|
53383
|
+
}
|
|
53384
|
+
if (fname === "ta.crowd_sentiment" || fname === "crowd_sentiment") {
|
|
53385
|
+
const msg = "ta.crowd_sentiment() requires 3 arguments";
|
|
53386
|
+
return env.ta.crowdSentiment(wave11n(0, ["price_agreement", "price"], msg), wave11n(1, ["volume_agreement", "volume"], msg), wave11n(2, ["time_agreement", "time"], msg));
|
|
53387
|
+
}
|
|
53388
|
+
if (fname === "ta.smart_money_flow" || fname === "smart_money_flow") {
|
|
53389
|
+
const msg = "ta.smart_money_flow() requires 4 arguments";
|
|
53390
|
+
return env.ta.smartMoneyFlow(wave11n(0, ["price_change"], msg), wave11n(1, ["volume"], msg), wave11n(2, ["time_since_high", "time_high"], msg), wave11n(3, ["time_since_low", "time_low"], msg));
|
|
53391
|
+
}
|
|
53392
|
+
if (fname === "ta.trend_confirmation_score" || fname === "trend_confirmation_score") {
|
|
53393
|
+
const msg = "ta.trend_confirmation_score() requires 6 arguments";
|
|
53394
|
+
wave11n(5, ["support_distance"], msg);
|
|
53395
|
+
return env.ta.trendConfirmationScore(wave11n(0, ["momentum"], msg), wave11n(1, ["trend_alignment"], msg), wave11n(2, ["strength"], msg), wave11n(3, ["rsi"], msg), wave11n(4, ["rsi_alignment"], msg));
|
|
53396
|
+
}
|
|
53397
|
+
if (fname === "ta.max_loss_level" || fname === "max_loss_level") {
|
|
53398
|
+
const msg = "ta.max_loss_level() requires 3 arguments";
|
|
53399
|
+
return env.ta.maxLossLevel(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["account", "account_size"], msg), wave11n(2, ["max_loss_pct", "max_loss_percent"], msg));
|
|
53400
|
+
}
|
|
53401
|
+
if (fname === "ta.profit_lock_level" || fname === "profit_lock_level") {
|
|
53402
|
+
const msg = "ta.profit_lock_level() requires 4 arguments";
|
|
53403
|
+
return env.ta.profitLockLevel(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["current", "current_price"], msg), wave11n(2, ["trail_pct", "trail_percent"], msg), wave11n(3, ["direction"], msg));
|
|
53404
|
+
}
|
|
53405
|
+
const wave12s = (index, names, message) => evalExpr(wave10aArg(index, names, message), env);
|
|
53406
|
+
if (fname === "ta.position_sizing" || fname === "position_sizing") {
|
|
53407
|
+
const msg = "ta.position_sizing() requires 4 arguments";
|
|
53408
|
+
return env.ta.positionSizing(wave11n(0, ["account", "account_size"], msg), wave11n(1, ["risk_pct", "risk_percent"], msg), wave11n(2, ["entry", "entry_price"], msg), wave11n(3, ["stop", "stop_price"], msg));
|
|
53409
|
+
}
|
|
53410
|
+
if (fname === "ta.kelly_criterion" || fname === "kelly_criterion") {
|
|
53411
|
+
const msg = "ta.kelly_criterion() requires 3 arguments";
|
|
53412
|
+
return env.ta.kellyCriterion(wave11n(0, ["win_rate"], msg), wave11n(1, ["avg_win"], msg), wave11n(2, ["avg_loss"], msg));
|
|
53413
|
+
}
|
|
53414
|
+
if (fname === "ta.risk_reward_ratio" || fname === "risk_reward_ratio") {
|
|
53415
|
+
const msg = "ta.risk_reward_ratio() requires 3 arguments";
|
|
53416
|
+
return env.ta.riskRewardRatio(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["stop", "stop_price"], msg), wave11n(2, ["target", "target_price"], msg));
|
|
53417
|
+
}
|
|
53418
|
+
if (fname === "ta.risk_reward_asymmetry" || fname === "risk_reward_asymmetry") {
|
|
53419
|
+
const msg = "ta.risk_reward_asymmetry() requires 4 arguments";
|
|
53420
|
+
return env.ta.riskRewardAsymmetry(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["stop", "stop_price"], msg), wave11n(2, ["target", "target_price"], msg), wave11n(3, ["win_rate"], msg));
|
|
53421
|
+
}
|
|
53422
|
+
if (fname === "ta.probability_of_movement" || fname === "probability_of_movement") {
|
|
53423
|
+
const msg = "ta.probability_of_movement() requires 4 arguments";
|
|
53424
|
+
return env.ta.probabilityOfMovement(wave11n(0, ["current", "current_price"], msg), wave11n(1, ["target", "target_price"], msg), wave11n(2, ["atr"], msg), wave11n(3, ["period", "length"], msg));
|
|
53425
|
+
}
|
|
53426
|
+
if (fname === "ta.trend_strength" || fname === "trend_strength") {
|
|
53427
|
+
const msg = "ta.trend_strength() requires 3 arguments";
|
|
53428
|
+
return env.ta.trendStrength(wave11n(0, ["price", "source"], msg), wave11n(1, ["adx"], msg), wave11n(2, ["rsi"], msg));
|
|
53429
|
+
}
|
|
53430
|
+
if (fname === "ta.breakeven_level" || fname === "breakeven_level") {
|
|
53431
|
+
const msg = "ta.breakeven_level() requires 5 arguments";
|
|
53432
|
+
return env.ta.breakevenLevel(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["quantity", "qty"], msg), wave11n(2, ["commission"], msg), wave11n(3, ["slippage"], msg), wave11n(4, ["direction"], msg));
|
|
53433
|
+
}
|
|
53434
|
+
if (fname === "ta.market_structure_pivot" || fname === "market_structure_pivot") {
|
|
53435
|
+
const msg = "ta.market_structure_pivot() requires 5 arguments";
|
|
53436
|
+
wave11n(0, ["high"], msg);
|
|
53437
|
+
wave11n(1, ["low"], msg);
|
|
53438
|
+
const close = wave11n(2, ["close"], msg);
|
|
53439
|
+
wave11n(3, ["left", "left_bars"], msg);
|
|
53440
|
+
wave11n(4, ["right", "right_bars"], msg);
|
|
53441
|
+
return env.ta.marketStructurePivot(close);
|
|
53442
|
+
}
|
|
53443
|
+
if (fname === "ta.position_sizing_score" || fname === "position_sizing_score") {
|
|
53444
|
+
const msg = "ta.position_sizing_score() requires 4 arguments";
|
|
53445
|
+
return env.ta.positionSizingScore(wave11n(0, ["account_risk", "risk"], msg), wave11n(1, ["volatility"], msg), wave11n(2, ["conviction"], msg), wave11n(3, ["correlation"], msg));
|
|
53446
|
+
}
|
|
53447
|
+
if (fname === "ta.trailing_exit_level" || fname === "trailing_exit_level") {
|
|
53448
|
+
const msg = "ta.trailing_exit_level() requires 5 arguments";
|
|
53449
|
+
return env.ta.trailingExitLevel(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["current", "current_price"], msg), wave11n(2, ["atr"], msg), wave11n(3, ["multiplier", "mult"], msg), wave11n(4, ["step"], msg));
|
|
53450
|
+
}
|
|
53451
|
+
if (fname === "ta.optimal_entry_zone" || fname === "optimal_entry_zone") {
|
|
53452
|
+
const msg = "ta.optimal_entry_zone() requires 4 arguments";
|
|
53453
|
+
wave11n(0, ["high"], msg);
|
|
53454
|
+
wave11n(1, ["low"], msg);
|
|
53455
|
+
const close = wave11n(2, ["close"], msg);
|
|
53456
|
+
wave11n(3, ["period", "length"], msg);
|
|
53457
|
+
return env.ta.optimalEntryZone(close);
|
|
53458
|
+
}
|
|
53459
|
+
if (fname === "ta.mean_reversion_entry" || fname === "mean_reversion_entry") {
|
|
53460
|
+
const msg = "ta.mean_reversion_entry() requires 5 arguments";
|
|
53461
|
+
return env.ta.meanReversionEntry(wave11n(0, ["price", "source"], msg), wave11n(1, ["sma"], msg), wave11n(2, ["stdev", "std_dev"], msg), wave11n(4, ["threshold"], msg));
|
|
53462
|
+
}
|
|
53463
|
+
if (fname === "ta.multi_timeframe_signal" || fname === "multi_timeframe_signal") {
|
|
53464
|
+
const msg = "ta.multi_timeframe_signal() requires 6 arguments";
|
|
53465
|
+
return env.ta.multiTimeframeSignal(wave11n(0, ["s1", "signal1"], msg), wave11n(1, ["s2", "signal2"], msg), wave11n(2, ["s3", "signal3"], msg), wave11n(3, ["w1", "weight1"], msg), wave11n(4, ["w2", "weight2"], msg), wave11n(5, ["w3", "weight3"], msg));
|
|
53466
|
+
}
|
|
53467
|
+
if (fname === "ta.market_timing_index" || fname === "market_timing_index") {
|
|
53468
|
+
const msg = "ta.market_timing_index() requires 4 arguments";
|
|
53469
|
+
return env.ta.marketTimingIndex(wave11n(0, ["trend"], msg), wave11n(1, ["momentum"], msg), wave11n(2, ["volatility"], msg), wave11n(3, ["sentiment"], msg));
|
|
53470
|
+
}
|
|
53471
|
+
if (fname === "ta.regime_adaptive_signal" || fname === "regime_adaptive_signal") {
|
|
53472
|
+
const msg = "ta.regime_adaptive_signal() requires 4 arguments";
|
|
53473
|
+
const strength = wave11n(0, ["signal_strength", "strength"], msg);
|
|
53474
|
+
const volRegime = wave12s(1, ["volatility_regime", "vol_regime"], msg);
|
|
53475
|
+
const trendRegime = wave12s(2, ["trend_regime"], msg);
|
|
53476
|
+
wave11n(3, ["period", "length"], msg);
|
|
53477
|
+
return env.ta.regimeAdaptiveSignal(strength, volRegime, trendRegime);
|
|
53478
|
+
}
|
|
53479
|
+
if (fname === "ta.strategy_score" || fname === "strategy_score") {
|
|
53480
|
+
const msg = "ta.strategy_score() requires 4 arguments";
|
|
53481
|
+
return env.ta.strategyScore(wave11n(0, ["rsi"], msg), wave11n(1, ["macd"], msg), wave11n(2, ["ema_cross"], msg), wave11n(3, ["trend"], msg));
|
|
53482
|
+
}
|
|
53483
|
+
if (fname === "ta.breakout_detection" || fname === "breakout_detection") {
|
|
53484
|
+
const msg = "ta.breakout_detection() requires 3 arguments";
|
|
53485
|
+
return env.ta.breakoutDetection(wave11n(0, ["close", "source"], msg), wave11n(1, ["resistance"], msg), wave11n(2, ["support"], msg));
|
|
53486
|
+
}
|
|
51527
53487
|
return;
|
|
51528
53488
|
}
|
|
51529
53489
|
function hlc3(env) {
|
|
@@ -51534,6 +53494,14 @@ function hlc3(env) {
|
|
|
51534
53494
|
return c ?? h ?? l;
|
|
51535
53495
|
return (h + l + c) / 3;
|
|
51536
53496
|
}
|
|
53497
|
+
function seriesLastCell(value) {
|
|
53498
|
+
if (value instanceof PineArray) {
|
|
53499
|
+
const n = value.size();
|
|
53500
|
+
return n > 0 ? value.get(n - 1) : null;
|
|
53501
|
+
}
|
|
53502
|
+
const v = unwrap2(value);
|
|
53503
|
+
return typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
53504
|
+
}
|
|
51537
53505
|
function asArray2(value) {
|
|
51538
53506
|
if (value instanceof PineArray)
|
|
51539
53507
|
return value;
|
|
@@ -52415,8 +54383,16 @@ function evalDrawingCall(fname, node, env) {
|
|
|
52415
54383
|
return book.boxNew(env.barIndex, extra);
|
|
52416
54384
|
}
|
|
52417
54385
|
if (fname === "alert") {
|
|
54386
|
+
if (asArgs2(node.args).length === 0)
|
|
54387
|
+
return NA;
|
|
52418
54388
|
const msg = evalAlertMessage(callArg(node.args, 0, ["message"]), env);
|
|
52419
|
-
|
|
54389
|
+
const freqExpr = callArg(node.args, 1, ["freq"]);
|
|
54390
|
+
let freq = null;
|
|
54391
|
+
if (freqExpr != null) {
|
|
54392
|
+
const v = evalExpr(freqExpr, env);
|
|
54393
|
+
freq = typeof v === "string" ? v : unwrap2(v);
|
|
54394
|
+
}
|
|
54395
|
+
emitAlert(env, msg, freq, { source: "alert" });
|
|
52420
54396
|
return NA;
|
|
52421
54397
|
}
|
|
52422
54398
|
if (fname === "table.new") {
|
|
@@ -52424,8 +54400,22 @@ function evalDrawingCall(fname, node, env) {
|
|
|
52424
54400
|
const position = drawRaw(node, env, 0, ["position"]);
|
|
52425
54401
|
if (position !== undefined)
|
|
52426
54402
|
extra.position = position;
|
|
52427
|
-
putFinite(extra, "
|
|
52428
|
-
putFinite(extra, "
|
|
54403
|
+
putFinite(extra, "columns", drawNum(node, env, 1, ["columns"]));
|
|
54404
|
+
putFinite(extra, "rows", drawNum(node, env, 2, ["rows"]));
|
|
54405
|
+
const bgcolor = drawRaw(node, env, 3, ["bgcolor"]);
|
|
54406
|
+
if (bgcolor !== undefined)
|
|
54407
|
+
extra.bgcolor = bgcolor;
|
|
54408
|
+
const frameColor = drawRaw(node, env, 4, ["frame_color"]);
|
|
54409
|
+
if (frameColor !== undefined)
|
|
54410
|
+
extra.frame_color = frameColor;
|
|
54411
|
+
putFinite(extra, "frame_width", drawNum(node, env, 5, ["frame_width"]));
|
|
54412
|
+
const borderColor = drawRaw(node, env, 6, ["border_color"]);
|
|
54413
|
+
if (borderColor !== undefined)
|
|
54414
|
+
extra.border_color = borderColor;
|
|
54415
|
+
putFinite(extra, "border_width", drawNum(node, env, 7, ["border_width"]));
|
|
54416
|
+
const forceOverlay = drawRaw(node, env, 8, ["force_overlay"]);
|
|
54417
|
+
if (forceOverlay !== undefined)
|
|
54418
|
+
extra.force_overlay = forceOverlay;
|
|
52429
54419
|
return book.tableNew(env.barIndex, extra);
|
|
52430
54420
|
}
|
|
52431
54421
|
if (fname === "polyline.new") {
|
|
@@ -53472,8 +55462,8 @@ function syminfoPrefix2(node, env) {
|
|
|
53472
55462
|
function calendarMs(node, env) {
|
|
53473
55463
|
const arg = callArg(node.args, 0, ["time", "timestamp"]);
|
|
53474
55464
|
if (arg == null)
|
|
53475
|
-
return num2(env.ctx.time);
|
|
53476
|
-
return unwrap2(evalExpr(arg, env));
|
|
55465
|
+
return timestampToMs(num2(env.ctx.time));
|
|
55466
|
+
return timestampToMs(unwrap2(evalExpr(arg, env)));
|
|
53477
55467
|
}
|
|
53478
55468
|
function evalLibraryMemberCall(mod, attr, node, env) {
|
|
53479
55469
|
const exp = mod.get(attr);
|