@hoox-sh/pynets 0.5.0 → 0.7.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 +35 -0
- package/README.md +6 -4
- package/dist/browser.js +68 -68
- package/dist/index.js +2551 -205
- 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_call.ts +485 -6
- package/src/runtime/compile/helpers.ts +2 -1
- package/src/runtime/compile/runtime.ts +20 -5
- package/src/runtime/compile/strategy.ts +5 -2
- package/src/runtime/interpret.ts +680 -41
- package/src/runtime/str.ts +3 -2
- package/src/runtime/strategy.ts +164 -12
- package/src/runtime/ta.ts +1667 -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
|
}
|
|
@@ -36320,6 +36328,13 @@ function mathRandom(a, b, rng = Math.random) {
|
|
|
36320
36328
|
// src/runtime/time.ts
|
|
36321
36329
|
var MIN_T = -62167219200;
|
|
36322
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
|
+
}
|
|
36323
36338
|
function utcPartsFromMs(ms) {
|
|
36324
36339
|
let t = Number.isFinite(ms) ? Math.trunc(ms / 1000) : 0;
|
|
36325
36340
|
if (t < MIN_T)
|
|
@@ -37176,8 +37191,7 @@ function coerceFormatTimeMs(time) {
|
|
|
37176
37191
|
if (typeof raw !== "number" || !Number.isFinite(raw))
|
|
37177
37192
|
return null;
|
|
37178
37193
|
let ts = Math.trunc(raw);
|
|
37179
|
-
|
|
37180
|
-
ts *= 1000;
|
|
37194
|
+
ts = timestampToMs(ts) ?? ts;
|
|
37181
37195
|
return ts;
|
|
37182
37196
|
}
|
|
37183
37197
|
function formatOffsetHours(offsetHours) {
|
|
@@ -37930,6 +37944,48 @@ class StrategyBook {
|
|
|
37930
37944
|
bar: isFiniteNumber2(bar) ? bar : 0
|
|
37931
37945
|
});
|
|
37932
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
|
+
}
|
|
37933
37989
|
exit(bar, id, qty) {
|
|
37934
37990
|
const event = {
|
|
37935
37991
|
type: "exit",
|
|
@@ -37967,10 +38023,46 @@ class StrategyBook {
|
|
|
37967
38023
|
placeEntry(bar, id, direction, qty, opts) {
|
|
37968
38024
|
const limit = optLevel(opts?.limit);
|
|
37969
38025
|
const stop = optLevel(opts?.stop);
|
|
38026
|
+
const b = isFiniteNumber2(bar) ? bar : 0;
|
|
38027
|
+
const oid = String(id ?? "");
|
|
37970
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
|
+
}
|
|
37971
38063
|
if (isFiniteNumber2(opts?.price)) {
|
|
37972
38064
|
const dir = mapDirection(direction);
|
|
37973
|
-
const t = isFiniteNumber2(opts?.time) ? opts.time :
|
|
38065
|
+
const t = isFiniteNumber2(opts?.time) ? opts.time : b;
|
|
37974
38066
|
this.updateEquityExtremes(opts.price);
|
|
37975
38067
|
if (!this.riskAllowsEntry(dir, t))
|
|
37976
38068
|
return;
|
|
@@ -37981,8 +38073,6 @@ class StrategyBook {
|
|
|
37981
38073
|
}
|
|
37982
38074
|
const dir = mapDirection(direction);
|
|
37983
38075
|
const absQty = isFiniteNumber2(qty) ? Math.abs(qty) : Number.NaN;
|
|
37984
|
-
const b = isFiniteNumber2(bar) ? bar : 0;
|
|
37985
|
-
const oid = String(id ?? "");
|
|
37986
38076
|
this.entry(b, oid, dir, isFiniteNumber2(absQty) ? absQty : qty);
|
|
37987
38077
|
if (!isFiniteNumber2(absQty) || absQty === 0)
|
|
37988
38078
|
return;
|
|
@@ -38032,6 +38122,23 @@ class StrategyBook {
|
|
|
38032
38122
|
return;
|
|
38033
38123
|
const t = isFiniteNumber2(opts?.time) ? opts.time : b;
|
|
38034
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
|
+
}
|
|
38035
38142
|
if (!isFiniteNumber2(opts?.price))
|
|
38036
38143
|
return;
|
|
38037
38144
|
this.reducePosition(b, oid, opts.price, qty, fromEntry, t, opts?.comment);
|
|
@@ -38102,13 +38209,24 @@ class StrategyBook {
|
|
|
38102
38209
|
for (const order of this.pending.slice()) {
|
|
38103
38210
|
if (!this.pending.some((p) => p.id === order.id))
|
|
38104
38211
|
continue;
|
|
38212
|
+
if (order.bar === b)
|
|
38213
|
+
continue;
|
|
38105
38214
|
if (order.kind === "exit" && isTrailOrder(order))
|
|
38106
38215
|
updateTrailStop(order, high, low);
|
|
38107
|
-
|
|
38216
|
+
let px;
|
|
38217
|
+
if (order.limit == null && order.stop == null)
|
|
38218
|
+
px = open;
|
|
38219
|
+
else
|
|
38220
|
+
px = triggerPrice(order, open, high, low);
|
|
38108
38221
|
if (px == null)
|
|
38109
38222
|
continue;
|
|
38110
38223
|
this.dropPending(order.id);
|
|
38111
|
-
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
|
+
});
|
|
38112
38230
|
if (applied) {
|
|
38113
38231
|
const q = Math.abs(this.fills.at(-1)?.qty ?? order.qty);
|
|
38114
38232
|
this.ocaAfterFill(order, q, b);
|
|
@@ -38124,6 +38242,22 @@ class StrategyBook {
|
|
|
38124
38242
|
}
|
|
38125
38243
|
return filled;
|
|
38126
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
|
+
}
|
|
38127
38261
|
fillEntry(bar, id, direction, qty, price, opts) {
|
|
38128
38262
|
this.applyEntryFill(bar, id, direction, qty, price, true, opts);
|
|
38129
38263
|
}
|
|
@@ -38246,9 +38380,9 @@ class StrategyBook {
|
|
|
38246
38380
|
return { status: "invalid", qty: 0 };
|
|
38247
38381
|
return { status: "ok", qty: Math.min(rawQty, target) };
|
|
38248
38382
|
}
|
|
38249
|
-
applyExitFill(bar, order, price) {
|
|
38383
|
+
applyExitFill(bar, order, price, time) {
|
|
38250
38384
|
const t = isFiniteNumber2(bar) ? bar : 0;
|
|
38251
|
-
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);
|
|
38252
38386
|
}
|
|
38253
38387
|
closeLeg(ot, bar, exitPrice, qty, profit, commission, exitTime, exitComment) {
|
|
38254
38388
|
const closed = {
|
|
@@ -40255,6 +40389,37 @@ function pushCap(window2, value, cap) {
|
|
|
40255
40389
|
function finiteOut2(value) {
|
|
40256
40390
|
return Number.isFinite(value) ? value : null;
|
|
40257
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
|
+
}
|
|
40258
40423
|
var PERIOD_INT_EPS = 0.000000001;
|
|
40259
40424
|
function pinePeriod(period) {
|
|
40260
40425
|
if (!Number.isFinite(period) || period <= 0)
|
|
@@ -40353,6 +40518,26 @@ class TaEngine {
|
|
|
40353
40518
|
emvSites = new Map;
|
|
40354
40519
|
fractalSites = new Map;
|
|
40355
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;
|
|
40537
|
+
emaCrossSites = new Map;
|
|
40538
|
+
historySites = new Map;
|
|
40539
|
+
momentumFilterSites = new Map;
|
|
40540
|
+
volatilityRegimeSites = new Map;
|
|
40356
40541
|
sma(site, source, period) {
|
|
40357
40542
|
const n = pinePeriod(period);
|
|
40358
40543
|
if (n === null)
|
|
@@ -40427,18 +40612,24 @@ class TaEngine {
|
|
|
40427
40612
|
st = {
|
|
40428
40613
|
period: n,
|
|
40429
40614
|
prevClose: null,
|
|
40615
|
+
started: false,
|
|
40430
40616
|
rma: { period: n, rma: null, seeded: false, started: false, seedBuf: [] }
|
|
40431
40617
|
};
|
|
40432
40618
|
this.atrSites.set(site, st);
|
|
40433
40619
|
}
|
|
40434
|
-
const prev = st.prevClose;
|
|
40435
|
-
st.prevClose = finiteCell2(close);
|
|
40436
|
-
if (prev === null)
|
|
40437
|
-
return null;
|
|
40438
40620
|
const h = finiteCell2(high);
|
|
40439
40621
|
const l = finiteCell2(low);
|
|
40440
40622
|
const c = finiteCell2(close);
|
|
40441
|
-
if (
|
|
40623
|
+
if (!st.started) {
|
|
40624
|
+
st.started = true;
|
|
40625
|
+
st.prevClose = c;
|
|
40626
|
+
if (h === null || l === null)
|
|
40627
|
+
return null;
|
|
40628
|
+
return rmaStep(st.rma, h - l, n);
|
|
40629
|
+
}
|
|
40630
|
+
const prev = st.prevClose;
|
|
40631
|
+
st.prevClose = c;
|
|
40632
|
+
if (prev === null || h === null || l === null || c === null)
|
|
40442
40633
|
return null;
|
|
40443
40634
|
const tr = Math.max(h - l, Math.abs(h - prev), Math.abs(l - prev));
|
|
40444
40635
|
return rmaStep(st.rma, tr, n);
|
|
@@ -40604,7 +40795,7 @@ class TaEngine {
|
|
|
40604
40795
|
}
|
|
40605
40796
|
if (st.window.length < n || st.count !== n)
|
|
40606
40797
|
return null;
|
|
40607
|
-
let v = (st.sumsq - st.sum * st.sum / n) /
|
|
40798
|
+
let v = (st.sumsq - st.sum * st.sum / n) / n;
|
|
40608
40799
|
if (v < 0)
|
|
40609
40800
|
v = 0;
|
|
40610
40801
|
return Math.sqrt(v);
|
|
@@ -41810,7 +42001,7 @@ class TaEngine {
|
|
|
41810
42001
|
}
|
|
41811
42002
|
if (st.window.length < n || st.count !== n)
|
|
41812
42003
|
return null;
|
|
41813
|
-
let v = (st.sumsq - st.sum * st.sum / n) /
|
|
42004
|
+
let v = (st.sumsq - st.sum * st.sum / n) / n;
|
|
41814
42005
|
if (v < 0)
|
|
41815
42006
|
v = 0;
|
|
41816
42007
|
return v;
|
|
@@ -42414,20 +42605,17 @@ class TaEngine {
|
|
|
42414
42605
|
st = { samples: [] };
|
|
42415
42606
|
this.zigzagSites.set(site, st);
|
|
42416
42607
|
}
|
|
42417
|
-
|
|
42418
|
-
|
|
42419
|
-
|
|
42420
|
-
|
|
42421
|
-
finite.push(v);
|
|
42422
|
-
}
|
|
42423
|
-
if (finite.length < 2)
|
|
42608
|
+
const x = finiteCell2(source);
|
|
42609
|
+
if (x !== null)
|
|
42610
|
+
pushCap(st.samples, x, 2);
|
|
42611
|
+
if (st.samples.length < 2)
|
|
42424
42612
|
return { high: null, low: null, dir: 0 };
|
|
42425
|
-
const oldest =
|
|
42426
|
-
const
|
|
42427
|
-
const recentHigh = Math.max(oldest,
|
|
42428
|
-
const recentLow = Math.min(oldest,
|
|
42613
|
+
const oldest = st.samples[0];
|
|
42614
|
+
const newest = st.samples[1];
|
|
42615
|
+
const recentHigh = Math.max(oldest, newest);
|
|
42616
|
+
const recentLow = Math.min(oldest, newest);
|
|
42429
42617
|
const pct = recentLow !== 0 ? (recentHigh - recentLow) / recentLow * 100 : 0;
|
|
42430
|
-
const direction = recentHigh ===
|
|
42618
|
+
const direction = recentHigh === newest ? 1 : -1;
|
|
42431
42619
|
return { high: recentHigh, low: recentLow, dir: pct > th ? 1 : direction };
|
|
42432
42620
|
}
|
|
42433
42621
|
accelSites = new Map;
|
|
@@ -42494,30 +42682,31 @@ class TaEngine {
|
|
|
42494
42682
|
}
|
|
42495
42683
|
accelerationFactor(site, source, period) {
|
|
42496
42684
|
const p = this.coerceTaInt(period, "ta.acceleration_factor() requires 2 arguments");
|
|
42497
|
-
|
|
42685
|
+
if (p <= 0)
|
|
42686
|
+
return 0;
|
|
42687
|
+
const key = `${site}:${p}`;
|
|
42688
|
+
let samples = this.accelSites.get(key);
|
|
42498
42689
|
if (samples === undefined) {
|
|
42499
42690
|
samples = [];
|
|
42500
|
-
this.accelSites.set(
|
|
42691
|
+
this.accelSites.set(key, samples);
|
|
42501
42692
|
}
|
|
42502
|
-
pushCap(samples, finiteCell2(source),
|
|
42503
|
-
if (samples.length < p + 1
|
|
42693
|
+
pushCap(samples, finiteCell2(source), p + 1);
|
|
42694
|
+
if (samples.length < p + 1)
|
|
42504
42695
|
return 0;
|
|
42505
|
-
const
|
|
42506
|
-
const
|
|
42507
|
-
for (let i = oldest.length - 1;i >= 0; i--) {
|
|
42508
|
-
const v = oldest[i];
|
|
42696
|
+
const clean = [];
|
|
42697
|
+
for (const v of samples) {
|
|
42509
42698
|
if (v !== null)
|
|
42510
|
-
|
|
42699
|
+
clean.push(v);
|
|
42511
42700
|
}
|
|
42512
|
-
if (
|
|
42701
|
+
if (clean.length < 2)
|
|
42513
42702
|
return 0;
|
|
42514
42703
|
let oldSum = 0;
|
|
42515
|
-
for (let i = 0;i <
|
|
42516
|
-
oldSum +=
|
|
42517
|
-
const oldMom = oldSum / (
|
|
42704
|
+
for (let i = 0;i < clean.length - 1; i++)
|
|
42705
|
+
oldSum += clean[i];
|
|
42706
|
+
const oldMom = oldSum / (clean.length - 1);
|
|
42707
|
+
const newMom = clean[clean.length - 1];
|
|
42518
42708
|
if (Math.abs(oldMom) < 0.0000000001)
|
|
42519
42709
|
return 0;
|
|
42520
|
-
const newMom = newestFirst[newestFirst.length - 1];
|
|
42521
42710
|
let acc = (newMom - oldMom) / oldMom;
|
|
42522
42711
|
if (acc < -2)
|
|
42523
42712
|
acc = -2;
|
|
@@ -42525,32 +42714,141 @@ class TaEngine {
|
|
|
42525
42714
|
acc = 2;
|
|
42526
42715
|
return finiteOut2(acc);
|
|
42527
42716
|
}
|
|
42528
|
-
stochSmooth(high, low, close, period, smoothK, smoothD) {
|
|
42717
|
+
stochSmooth(site, high, low, close, period, smoothK, smoothD) {
|
|
42529
42718
|
const p = this.coerceTaInt(period, "ta.stoch_smooth period must be integer");
|
|
42530
42719
|
const k = this.coerceTaInt(smoothK, "ta.stoch_smooth smooth_k must be integer");
|
|
42531
42720
|
const d = this.coerceTaInt(smoothD, "ta.stoch_smooth smooth_d must be integer");
|
|
42532
|
-
if (p
|
|
42533
|
-
throw new Error("max() iterable argument is empty");
|
|
42534
|
-
if (high === null || low === null || close === null) {
|
|
42535
|
-
throw new Error("unsupported operand type(s) for /: 'float' and 'NoneType'");
|
|
42536
|
-
}
|
|
42537
|
-
if (k !== 1 || d !== 1)
|
|
42721
|
+
if (p < 1 || k < 1 || d < 1)
|
|
42538
42722
|
return null;
|
|
42539
|
-
const
|
|
42540
|
-
|
|
42541
|
-
|
|
42542
|
-
|
|
42543
|
-
|
|
42544
|
-
|
|
42545
|
-
|
|
42546
|
-
|
|
42547
|
-
|
|
42723
|
+
const key = `${site}:${p}:${k}:${d}`;
|
|
42724
|
+
let st = this.stochSmoothSites.get(key);
|
|
42725
|
+
if (st === undefined) {
|
|
42726
|
+
st = { highs: [], lows: [] };
|
|
42727
|
+
this.stochSmoothSites.set(key, st);
|
|
42728
|
+
}
|
|
42729
|
+
pushCap(st.highs, finiteCell2(high), p);
|
|
42730
|
+
pushCap(st.lows, finiteCell2(low), p);
|
|
42731
|
+
const c = finiteCell2(close);
|
|
42732
|
+
let stoch = null;
|
|
42733
|
+
if (c !== null && !st.highs.includes(null) && !st.lows.includes(null)) {
|
|
42734
|
+
let hh = -Infinity;
|
|
42735
|
+
let ll = Infinity;
|
|
42736
|
+
for (const v of st.highs) {
|
|
42737
|
+
if (v > hh)
|
|
42738
|
+
hh = v;
|
|
42739
|
+
}
|
|
42740
|
+
for (const v of st.lows) {
|
|
42741
|
+
if (v < ll)
|
|
42742
|
+
ll = v;
|
|
42743
|
+
}
|
|
42744
|
+
stoch = hh === ll ? 50 : 100 * (c - ll) / (hh - ll);
|
|
42745
|
+
}
|
|
42746
|
+
const kVal = this.ema(`${site}:k`, stoch, k);
|
|
42747
|
+
return this.ema(`${site}:d`, kVal, d);
|
|
42748
|
+
}
|
|
42749
|
+
engulfing(site, open, close) {
|
|
42750
|
+
const off = taRec({ is_bullish: false, is_bearish: false, pattern_strength: 0 });
|
|
42751
|
+
let st = this.engulfingSites.get(site);
|
|
42752
|
+
if (st === undefined) {
|
|
42753
|
+
st = { prevOpen: null, prevClose: null, count: 0 };
|
|
42754
|
+
this.engulfingSites.set(site, st);
|
|
42755
|
+
}
|
|
42756
|
+
const o = finiteCell2(open);
|
|
42757
|
+
const c = finiteCell2(close);
|
|
42758
|
+
st.count += 1;
|
|
42759
|
+
const prevO = st.prevOpen;
|
|
42760
|
+
const prevC = st.prevClose;
|
|
42761
|
+
if (st.count < 2 || prevO === null || prevC === null || o === null || c === null) {
|
|
42762
|
+
st.prevOpen = o;
|
|
42763
|
+
st.prevClose = c;
|
|
42764
|
+
return off;
|
|
42765
|
+
}
|
|
42766
|
+
const isBullish = o < prevC && c > prevO && c > o;
|
|
42767
|
+
const isBearish = o > prevC && c < prevO && c < o;
|
|
42768
|
+
let engulf = 0;
|
|
42769
|
+
if (isBullish) {
|
|
42770
|
+
engulf = Math.max(0, Math.min(1, (c - prevO) / Math.abs(prevO - prevC + 0.0001)));
|
|
42771
|
+
} else if (isBearish) {
|
|
42772
|
+
engulf = Math.max(0, Math.min(1, (prevO - c) / Math.abs(prevC - prevO + 0.0001)));
|
|
42773
|
+
}
|
|
42774
|
+
st.prevOpen = o;
|
|
42775
|
+
st.prevClose = c;
|
|
42776
|
+
return taRec({
|
|
42777
|
+
is_bullish: isBullish,
|
|
42778
|
+
is_bearish: isBearish,
|
|
42779
|
+
pattern_strength: finiteOut2(engulf) ?? 0
|
|
42780
|
+
});
|
|
42548
42781
|
}
|
|
42549
|
-
|
|
42550
|
-
|
|
42551
|
-
|
|
42782
|
+
insideBarPattern(site, high, low) {
|
|
42783
|
+
let st = this.insideBarSites.get(site);
|
|
42784
|
+
if (st === undefined) {
|
|
42785
|
+
st = { prevHigh: null, prevLow: null, count: 0 };
|
|
42786
|
+
this.insideBarSites.set(site, st);
|
|
42787
|
+
}
|
|
42788
|
+
const currH = high !== null && Number.isFinite(high) ? high : 0;
|
|
42789
|
+
const currL = low !== null && Number.isFinite(low) ? low : 0;
|
|
42790
|
+
st.count += 1;
|
|
42791
|
+
const prevH = st.prevHigh;
|
|
42792
|
+
const prevL = st.prevLow;
|
|
42793
|
+
if (st.count < 2 || prevH === null || prevL === null) {
|
|
42794
|
+
st.prevHigh = currH;
|
|
42795
|
+
st.prevLow = currL;
|
|
42796
|
+
return false;
|
|
42797
|
+
}
|
|
42798
|
+
const val = currH < prevH && currL > prevL;
|
|
42799
|
+
st.prevHigh = currH;
|
|
42800
|
+
st.prevLow = currL;
|
|
42801
|
+
return val;
|
|
42802
|
+
}
|
|
42803
|
+
doubleTopBottom(site, high, low, period) {
|
|
42804
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
42805
|
+
const off = taRec({ pattern_type: "none", strength: 0, breakout_level: 0 });
|
|
42806
|
+
if (n < 1)
|
|
42807
|
+
return off;
|
|
42808
|
+
const key = `${site}:${n}`;
|
|
42809
|
+
let st = this.doubleTopBottomSites.get(key);
|
|
42810
|
+
if (st === undefined) {
|
|
42811
|
+
st = { highs: [], lows: [], count: 0 };
|
|
42812
|
+
this.doubleTopBottomSites.set(key, st);
|
|
42813
|
+
}
|
|
42814
|
+
pushCap(st.highs, finiteCell2(high), n);
|
|
42815
|
+
pushCap(st.lows, finiteCell2(low), n);
|
|
42816
|
+
st.count += 1;
|
|
42817
|
+
if (st.count < n)
|
|
42818
|
+
return off;
|
|
42819
|
+
const recentHigh = [];
|
|
42820
|
+
for (const v of st.highs) {
|
|
42821
|
+
if (v !== null)
|
|
42822
|
+
recentHigh.push(v);
|
|
42823
|
+
}
|
|
42824
|
+
const recentLow = [];
|
|
42825
|
+
for (const v of st.lows) {
|
|
42826
|
+
if (v !== null)
|
|
42827
|
+
recentLow.push(v);
|
|
42828
|
+
}
|
|
42829
|
+
if (recentHigh.length < 3 || recentLow.length === 0)
|
|
42830
|
+
return off;
|
|
42831
|
+
const peaks = [recentHigh[0]];
|
|
42832
|
+
for (let i = 1;i < recentHigh.length - 1; i++) {
|
|
42833
|
+
if (recentHigh[i] > recentHigh[i - 1] && recentHigh[i] > recentHigh[i + 1]) {
|
|
42834
|
+
peaks.push(recentHigh[i]);
|
|
42835
|
+
}
|
|
42836
|
+
}
|
|
42837
|
+
if (peaks.length < 2)
|
|
42838
|
+
return off;
|
|
42839
|
+
const peakDiff = Math.abs(peaks[peaks.length - 1] - peaks[peaks.length - 2]);
|
|
42840
|
+
const avgPeak = (peaks[peaks.length - 1] + peaks[peaks.length - 2]) / 2;
|
|
42841
|
+
const strength = avgPeak > 0 ? 1 - Math.min(1, peakDiff / avgPeak) : 0;
|
|
42842
|
+
let minLow = recentLow[0];
|
|
42843
|
+
for (const v of recentLow) {
|
|
42844
|
+
if (v < minLow)
|
|
42845
|
+
minLow = v;
|
|
42552
42846
|
}
|
|
42553
|
-
return taRec({
|
|
42847
|
+
return taRec({
|
|
42848
|
+
pattern_type: "double_top",
|
|
42849
|
+
strength: finiteOut2(strength) ?? 0,
|
|
42850
|
+
breakout_level: finiteOut2(minLow - avgPeak * 0.1) ?? 0
|
|
42851
|
+
});
|
|
42554
42852
|
}
|
|
42555
42853
|
cumDeltaSites = new Map;
|
|
42556
42854
|
volMomSites = new Map;
|
|
@@ -42571,6 +42869,39 @@ class TaEngine {
|
|
|
42571
42869
|
const v = buf[-i - 1];
|
|
42572
42870
|
return v === undefined ? null : v;
|
|
42573
42871
|
}
|
|
42872
|
+
hist(site, value) {
|
|
42873
|
+
let h = this.historySites.get(site);
|
|
42874
|
+
if (h === undefined) {
|
|
42875
|
+
h = [];
|
|
42876
|
+
this.historySites.set(site, h);
|
|
42877
|
+
}
|
|
42878
|
+
h.unshift(finiteCell2(value));
|
|
42879
|
+
if (h.length > 1000)
|
|
42880
|
+
h.pop();
|
|
42881
|
+
return h;
|
|
42882
|
+
}
|
|
42883
|
+
windowFor(site, value) {
|
|
42884
|
+
if (Array.isArray(value)) {
|
|
42885
|
+
return value.map((v) => typeof v === "number" ? finiteCell2(v) : null);
|
|
42886
|
+
}
|
|
42887
|
+
if (value != null && typeof value === "object" && typeof value.size === "function" && typeof value.get === "function") {
|
|
42888
|
+
const arr = value;
|
|
42889
|
+
const out = [];
|
|
42890
|
+
const n = arr.size();
|
|
42891
|
+
for (let i = 0;i < n; i++) {
|
|
42892
|
+
const v = arr.get(i);
|
|
42893
|
+
out.push(typeof v === "number" ? finiteCell2(v) : null);
|
|
42894
|
+
}
|
|
42895
|
+
return out;
|
|
42896
|
+
}
|
|
42897
|
+
return this.hist(site, typeof value === "number" ? value : null);
|
|
42898
|
+
}
|
|
42899
|
+
static oldest(h) {
|
|
42900
|
+
return h.length === 0 ? null : h[h.length - 1];
|
|
42901
|
+
}
|
|
42902
|
+
static secondOldest(h) {
|
|
42903
|
+
return h.length < 2 ? null : h[h.length - 2];
|
|
42904
|
+
}
|
|
42574
42905
|
voi(buy, sell) {
|
|
42575
42906
|
const b = buy !== null && Number.isFinite(buy) ? buy : 0;
|
|
42576
42907
|
const s = sell !== null && Number.isFinite(sell) ? sell : 0;
|
|
@@ -42603,96 +42934,91 @@ class TaEngine {
|
|
|
42603
42934
|
}
|
|
42604
42935
|
return taRec({ is_oversold: rsi < os, is_overbought: rsi > ob, rsi });
|
|
42605
42936
|
}
|
|
42606
|
-
rsiDivergence(
|
|
42937
|
+
rsiDivergence(site, value, period) {
|
|
42607
42938
|
const p = this.asCount(period);
|
|
42608
|
-
if (p === null ||
|
|
42609
|
-
return
|
|
42610
|
-
let
|
|
42611
|
-
|
|
42612
|
-
|
|
42613
|
-
|
|
42614
|
-
|
|
42615
|
-
|
|
42616
|
-
|
|
42617
|
-
|
|
42618
|
-
|
|
42619
|
-
|
|
42620
|
-
|
|
42621
|
-
|
|
42622
|
-
|
|
42623
|
-
|
|
42624
|
-
last = 0;
|
|
42625
|
-
continue;
|
|
42626
|
-
}
|
|
42627
|
-
let rsiMin = vals[0];
|
|
42628
|
-
let rsiMax = vals[0];
|
|
42629
|
-
for (const v of vals) {
|
|
42630
|
-
if (v < rsiMin)
|
|
42631
|
-
rsiMin = v;
|
|
42632
|
-
if (v > rsiMax)
|
|
42633
|
-
rsiMax = v;
|
|
42634
|
-
}
|
|
42635
|
-
const cur = series[i];
|
|
42636
|
-
const range = rsiMax - rsiMin;
|
|
42637
|
-
if (cur === null || !Number.isFinite(cur) || range <= 0) {
|
|
42638
|
-
last = 0;
|
|
42639
|
-
continue;
|
|
42640
|
-
}
|
|
42641
|
-
last = (cur - rsiMin) / range * 2 - 1;
|
|
42939
|
+
if (p === null || p < 1)
|
|
42940
|
+
return 0;
|
|
42941
|
+
let st = this.rsiDivergenceSites.get(`${site}:${p}`);
|
|
42942
|
+
if (st === undefined) {
|
|
42943
|
+
st = { window: [], count: 0 };
|
|
42944
|
+
this.rsiDivergenceSites.set(`${site}:${p}`, st);
|
|
42945
|
+
}
|
|
42946
|
+
const x = finiteCell2(value);
|
|
42947
|
+
pushCap(st.window, x, p + 1);
|
|
42948
|
+
st.count += 1;
|
|
42949
|
+
if (st.count <= p)
|
|
42950
|
+
return 0;
|
|
42951
|
+
const vals = [];
|
|
42952
|
+
for (const v of st.window) {
|
|
42953
|
+
if (v !== null)
|
|
42954
|
+
vals.push(v);
|
|
42642
42955
|
}
|
|
42643
|
-
|
|
42956
|
+
if (vals.length < 2 || x === null)
|
|
42957
|
+
return 0;
|
|
42958
|
+
let lo = vals[0];
|
|
42959
|
+
let hi = vals[0];
|
|
42960
|
+
for (const v of vals) {
|
|
42961
|
+
if (v < lo)
|
|
42962
|
+
lo = v;
|
|
42963
|
+
if (v > hi)
|
|
42964
|
+
hi = v;
|
|
42965
|
+
}
|
|
42966
|
+
const range = hi - lo;
|
|
42967
|
+
return range > 0 ? finiteOut2((x - lo) / range * 2 - 1) : 0;
|
|
42644
42968
|
}
|
|
42645
42969
|
cumulativeDelta(site, close, volume, period) {
|
|
42646
42970
|
const n = this.asCount(period);
|
|
42647
|
-
|
|
42971
|
+
if (n === null || n <= 0)
|
|
42972
|
+
return 0;
|
|
42973
|
+
let st = this.cumDeltaSites.get(`${site}:${n}`);
|
|
42648
42974
|
if (st === undefined) {
|
|
42649
|
-
st = {
|
|
42650
|
-
this.cumDeltaSites.set(site
|
|
42975
|
+
st = { closes: [], volumes: [], count: 0 };
|
|
42976
|
+
this.cumDeltaSites.set(`${site}:${n}`, st);
|
|
42651
42977
|
}
|
|
42652
|
-
|
|
42653
|
-
|
|
42654
|
-
|
|
42978
|
+
const c = finiteCell2(close);
|
|
42979
|
+
const v = volume !== null && Number.isFinite(volume) ? volume : 0;
|
|
42980
|
+
pushCap(st.closes, c, n + 1);
|
|
42981
|
+
pushCap(st.volumes, v, n);
|
|
42982
|
+
st.count += 1;
|
|
42983
|
+
if (st.count < n)
|
|
42655
42984
|
return 0;
|
|
42656
42985
|
let delta = 0;
|
|
42657
|
-
|
|
42658
|
-
|
|
42659
|
-
const
|
|
42660
|
-
const
|
|
42661
|
-
const
|
|
42662
|
-
|
|
42663
|
-
|
|
42664
|
-
|
|
42665
|
-
|
|
42666
|
-
|
|
42667
|
-
|
|
42668
|
-
|
|
42669
|
-
}
|
|
42986
|
+
const offset = st.closes.length - st.volumes.length;
|
|
42987
|
+
for (let j = 0;j < st.volumes.length; j++) {
|
|
42988
|
+
const idx = offset + j;
|
|
42989
|
+
const cRaw = st.closes[idx] ?? null;
|
|
42990
|
+
const cur = cRaw ?? 0;
|
|
42991
|
+
const prevRaw = idx === 0 ? null : st.closes[idx - 1] ?? null;
|
|
42992
|
+
const prev = prevRaw ?? cur;
|
|
42993
|
+
const vol = st.volumes[j];
|
|
42994
|
+
if (cur > prev)
|
|
42995
|
+
delta += vol;
|
|
42996
|
+
else if (cur < prev)
|
|
42997
|
+
delta -= vol;
|
|
42670
42998
|
}
|
|
42671
42999
|
return finiteOut2(delta);
|
|
42672
43000
|
}
|
|
42673
43001
|
volumeMomentum(site, volume, period) {
|
|
42674
43002
|
const n = this.asCount(period);
|
|
42675
|
-
|
|
42676
|
-
if (st === undefined) {
|
|
42677
|
-
st = { volume: [] };
|
|
42678
|
-
this.volMomSites.set(site, st);
|
|
42679
|
-
}
|
|
42680
|
-
this.pushChrono(st.volume, volume);
|
|
42681
|
-
if (n === null || n <= 0 || st.volume.length < n + 1)
|
|
43003
|
+
if (n === null || n <= 0)
|
|
42682
43004
|
return 0;
|
|
42683
|
-
|
|
42684
|
-
|
|
42685
|
-
|
|
42686
|
-
|
|
42687
|
-
clean.push(v);
|
|
43005
|
+
let st = this.volMomSites.get(`${site}:${n}`);
|
|
43006
|
+
if (st === undefined) {
|
|
43007
|
+
st = { window: [] };
|
|
43008
|
+
this.volMomSites.set(`${site}:${n}`, st);
|
|
42688
43009
|
}
|
|
42689
|
-
if (
|
|
43010
|
+
if (volume !== null && Number.isFinite(volume))
|
|
43011
|
+
pushCap(st.window, volume, n + 1);
|
|
43012
|
+
if (st.window.length < n + 1)
|
|
42690
43013
|
return 0;
|
|
42691
|
-
|
|
42692
|
-
let
|
|
42693
|
-
|
|
42694
|
-
|
|
42695
|
-
|
|
43014
|
+
let oldSum = 0;
|
|
43015
|
+
for (let i = 0;i < n; i++)
|
|
43016
|
+
oldSum += st.window[i];
|
|
43017
|
+
let newSum = 0;
|
|
43018
|
+
for (let i = 1;i <= n; i++)
|
|
43019
|
+
newSum += st.window[i];
|
|
43020
|
+
const oldVol = oldSum / n;
|
|
43021
|
+
const newVol = newSum / n;
|
|
42696
43022
|
if (oldVol === 0)
|
|
42697
43023
|
return 0;
|
|
42698
43024
|
let momentum = (newVol - oldVol) / oldVol * 100;
|
|
@@ -42702,6 +43028,1167 @@ class TaEngine {
|
|
|
42702
43028
|
momentum = -100;
|
|
42703
43029
|
return finiteOut2(momentum);
|
|
42704
43030
|
}
|
|
43031
|
+
smaWeighted(site, source, period, weightType) {
|
|
43032
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43033
|
+
const kind = typeof weightType === "string" ? weightType : "linear";
|
|
43034
|
+
if (n < 1)
|
|
43035
|
+
return null;
|
|
43036
|
+
const key = `${site}:${n}:${kind}`;
|
|
43037
|
+
let st = this.smaWeightedSites.get(key);
|
|
43038
|
+
if (st === undefined) {
|
|
43039
|
+
const weights = [];
|
|
43040
|
+
for (let i = 0;i < n; i++) {
|
|
43041
|
+
if (kind === "quadratic")
|
|
43042
|
+
weights.push((i + 1) ** 2);
|
|
43043
|
+
else if (kind === "sqrt")
|
|
43044
|
+
weights.push((i + 1) ** 0.5);
|
|
43045
|
+
else
|
|
43046
|
+
weights.push(i + 1);
|
|
43047
|
+
}
|
|
43048
|
+
st = { window: [], weights, wsum: weights.reduce((a, b) => a + b, 0) };
|
|
43049
|
+
this.smaWeightedSites.set(key, st);
|
|
43050
|
+
}
|
|
43051
|
+
pushCap(st.window, finiteCell2(source), n);
|
|
43052
|
+
if (st.window.length < n || st.window.includes(null) || st.wsum <= 0)
|
|
43053
|
+
return null;
|
|
43054
|
+
let total = 0;
|
|
43055
|
+
for (let i = 0;i < n; i++)
|
|
43056
|
+
total += st.window[i] * st.weights[i];
|
|
43057
|
+
return finiteOut2(total / st.wsum);
|
|
43058
|
+
}
|
|
43059
|
+
apo(site, source, fast, slow) {
|
|
43060
|
+
const f = this.coerceTaInt(fast, "ta.apo fast_period must be integer");
|
|
43061
|
+
const s = this.coerceTaInt(slow, "ta.apo slow_period must be integer");
|
|
43062
|
+
const fastV = this.ema(`${site}:fast`, source, f);
|
|
43063
|
+
const slowV = this.ema(`${site}:slow`, source, s);
|
|
43064
|
+
if (fastV === null || slowV === null)
|
|
43065
|
+
return null;
|
|
43066
|
+
return finiteOut2(fastV - slowV);
|
|
43067
|
+
}
|
|
43068
|
+
atrNormalized(site, high, low, close, period) {
|
|
43069
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43070
|
+
const atr = this.atr(`${site}:atr`, high, low, close, n);
|
|
43071
|
+
const c = finiteCell2(close);
|
|
43072
|
+
if (c === null || c === 0 || atr === null)
|
|
43073
|
+
return null;
|
|
43074
|
+
return finiteOut2(atr / c * 100);
|
|
43075
|
+
}
|
|
43076
|
+
pairWindow(sites, site, a, b, length) {
|
|
43077
|
+
const n = this.coerceTaInt(length, "length must be integer");
|
|
43078
|
+
if (n < 1)
|
|
43079
|
+
return null;
|
|
43080
|
+
const key = `${site}:${n}`;
|
|
43081
|
+
let st = sites.get(key);
|
|
43082
|
+
if (st === undefined) {
|
|
43083
|
+
st = { a: [], b: [] };
|
|
43084
|
+
sites.set(key, st);
|
|
43085
|
+
}
|
|
43086
|
+
pushCap(st.a, finiteCell2(a), n);
|
|
43087
|
+
pushCap(st.b, finiteCell2(b), n);
|
|
43088
|
+
if (st.a.length < n || st.b.length < n)
|
|
43089
|
+
return null;
|
|
43090
|
+
const left = [];
|
|
43091
|
+
const right = [];
|
|
43092
|
+
for (let i = 0;i < n; i++) {
|
|
43093
|
+
const av = st.a[i];
|
|
43094
|
+
const bv = st.b[i];
|
|
43095
|
+
if (av === null || bv === null)
|
|
43096
|
+
return null;
|
|
43097
|
+
left.push(av);
|
|
43098
|
+
right.push(bv);
|
|
43099
|
+
}
|
|
43100
|
+
return { a: left, b: right };
|
|
43101
|
+
}
|
|
43102
|
+
beta(site, a, b, length) {
|
|
43103
|
+
const pair = this.pairWindow(this.betaSites, site, a, b, length);
|
|
43104
|
+
if (pair === null)
|
|
43105
|
+
return null;
|
|
43106
|
+
const n = pair.a.length;
|
|
43107
|
+
let meanA = 0;
|
|
43108
|
+
let meanB = 0;
|
|
43109
|
+
for (let i = 0;i < n; i++) {
|
|
43110
|
+
meanA += pair.a[i];
|
|
43111
|
+
meanB += pair.b[i];
|
|
43112
|
+
}
|
|
43113
|
+
meanA /= n;
|
|
43114
|
+
meanB /= n;
|
|
43115
|
+
let covariance = 0;
|
|
43116
|
+
let varianceB = 0;
|
|
43117
|
+
for (let i = 0;i < n; i++) {
|
|
43118
|
+
covariance += (pair.a[i] - meanA) * (pair.b[i] - meanB);
|
|
43119
|
+
varianceB += (pair.b[i] - meanB) ** 2;
|
|
43120
|
+
}
|
|
43121
|
+
covariance /= n;
|
|
43122
|
+
varianceB /= n;
|
|
43123
|
+
if (varianceB === 0)
|
|
43124
|
+
return 0;
|
|
43125
|
+
return finiteOut2(covariance / varianceB);
|
|
43126
|
+
}
|
|
43127
|
+
rSquared(site, a, b, length) {
|
|
43128
|
+
const pair = this.pairWindow(this.rSquaredSites, site, a, b, length);
|
|
43129
|
+
if (pair === null)
|
|
43130
|
+
return null;
|
|
43131
|
+
const n = pair.a.length;
|
|
43132
|
+
let meanA = 0;
|
|
43133
|
+
let meanB = 0;
|
|
43134
|
+
for (let i = 0;i < n; i++) {
|
|
43135
|
+
meanA += pair.a[i];
|
|
43136
|
+
meanB += pair.b[i];
|
|
43137
|
+
}
|
|
43138
|
+
meanA /= n;
|
|
43139
|
+
meanB /= n;
|
|
43140
|
+
let covariance = 0;
|
|
43141
|
+
let varA = 0;
|
|
43142
|
+
let varB = 0;
|
|
43143
|
+
for (let i = 0;i < n; i++) {
|
|
43144
|
+
covariance += (pair.a[i] - meanA) * (pair.b[i] - meanB);
|
|
43145
|
+
varA += (pair.a[i] - meanA) ** 2;
|
|
43146
|
+
varB += (pair.b[i] - meanB) ** 2;
|
|
43147
|
+
}
|
|
43148
|
+
covariance /= n;
|
|
43149
|
+
varA /= n;
|
|
43150
|
+
varB /= n;
|
|
43151
|
+
if (varA === 0 || varB === 0)
|
|
43152
|
+
return 0;
|
|
43153
|
+
const corr = covariance / Math.sqrt(varA * varB);
|
|
43154
|
+
return finiteOut2(Math.max(0, Math.min(1, corr ** 2)));
|
|
43155
|
+
}
|
|
43156
|
+
comovement(site, a, b, length) {
|
|
43157
|
+
const pair = this.pairWindow(this.comovementSites, site, a, b, length);
|
|
43158
|
+
if (pair === null)
|
|
43159
|
+
return null;
|
|
43160
|
+
const n = pair.a.length;
|
|
43161
|
+
if (n <= 1)
|
|
43162
|
+
return 0;
|
|
43163
|
+
let same = 0;
|
|
43164
|
+
for (let i = 1;i < n; i++) {
|
|
43165
|
+
if ((pair.a[i] - pair.a[i - 1]) * (pair.b[i] - pair.b[i - 1]) > 0)
|
|
43166
|
+
same += 1;
|
|
43167
|
+
}
|
|
43168
|
+
return finiteOut2(same / (n - 1) * 100);
|
|
43169
|
+
}
|
|
43170
|
+
skewness(site, source, period) {
|
|
43171
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43172
|
+
if (n < 1)
|
|
43173
|
+
return null;
|
|
43174
|
+
const key = `${site}:${n}`;
|
|
43175
|
+
let st = this.skewnessSites.get(key);
|
|
43176
|
+
if (st === undefined) {
|
|
43177
|
+
st = { window: [] };
|
|
43178
|
+
this.skewnessSites.set(key, st);
|
|
43179
|
+
}
|
|
43180
|
+
pushCap(st.window, finiteCell2(source), n);
|
|
43181
|
+
if (st.window.length < n || st.window.includes(null))
|
|
43182
|
+
return null;
|
|
43183
|
+
const vals = st.window;
|
|
43184
|
+
let mean = 0;
|
|
43185
|
+
for (const v of vals)
|
|
43186
|
+
mean += v;
|
|
43187
|
+
mean /= n;
|
|
43188
|
+
let variance = 0;
|
|
43189
|
+
for (const v of vals)
|
|
43190
|
+
variance += (v - mean) ** 2;
|
|
43191
|
+
variance /= n;
|
|
43192
|
+
const std = Math.sqrt(variance);
|
|
43193
|
+
if (std === 0)
|
|
43194
|
+
return 0;
|
|
43195
|
+
let third = 0;
|
|
43196
|
+
for (const v of vals)
|
|
43197
|
+
third += (v - mean) ** 3;
|
|
43198
|
+
return finiteOut2(third / (n * std ** 3));
|
|
43199
|
+
}
|
|
43200
|
+
kurtosis(site, source, period) {
|
|
43201
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43202
|
+
if (n < 1)
|
|
43203
|
+
return null;
|
|
43204
|
+
const key = `${site}:${n}`;
|
|
43205
|
+
let st = this.kurtosisSites.get(key);
|
|
43206
|
+
if (st === undefined) {
|
|
43207
|
+
st = { window: [] };
|
|
43208
|
+
this.kurtosisSites.set(key, st);
|
|
43209
|
+
}
|
|
43210
|
+
pushCap(st.window, finiteCell2(source), n);
|
|
43211
|
+
if (st.window.length < n || st.window.includes(null))
|
|
43212
|
+
return null;
|
|
43213
|
+
const vals = st.window;
|
|
43214
|
+
let mean = 0;
|
|
43215
|
+
for (const v of vals)
|
|
43216
|
+
mean += v;
|
|
43217
|
+
mean /= n;
|
|
43218
|
+
let variance = 0;
|
|
43219
|
+
for (const v of vals)
|
|
43220
|
+
variance += (v - mean) ** 2;
|
|
43221
|
+
variance /= n;
|
|
43222
|
+
const std = Math.sqrt(variance);
|
|
43223
|
+
if (std === 0)
|
|
43224
|
+
return 0;
|
|
43225
|
+
let fourth = 0;
|
|
43226
|
+
for (const v of vals)
|
|
43227
|
+
fourth += (v - mean) ** 4;
|
|
43228
|
+
fourth /= n;
|
|
43229
|
+
return finiteOut2(fourth / std ** 4 - 3);
|
|
43230
|
+
}
|
|
43231
|
+
volumeWeightedMomentum(site, source, volume, length) {
|
|
43232
|
+
const n = this.coerceTaInt(length, "length must be integer");
|
|
43233
|
+
if (n < 1)
|
|
43234
|
+
return null;
|
|
43235
|
+
const key = `${site}:${n}`;
|
|
43236
|
+
let st = this.vwmSites.get(key);
|
|
43237
|
+
if (st === undefined) {
|
|
43238
|
+
st = { prices: [], volumes: [] };
|
|
43239
|
+
this.vwmSites.set(key, st);
|
|
43240
|
+
}
|
|
43241
|
+
pushCap(st.prices, finiteCell2(source), n + 1);
|
|
43242
|
+
pushCap(st.volumes, finiteCell2(volume), n);
|
|
43243
|
+
if (st.volumes.length < n)
|
|
43244
|
+
return null;
|
|
43245
|
+
const ps = st.prices;
|
|
43246
|
+
const vs = st.volumes;
|
|
43247
|
+
let momentumSum = 0;
|
|
43248
|
+
let volumeSum = 0;
|
|
43249
|
+
for (let i = 0;i < n; i++) {
|
|
43250
|
+
const pEnd = ps.length - 1 - i;
|
|
43251
|
+
const pPrev = pEnd - 1;
|
|
43252
|
+
if (pPrev < 0)
|
|
43253
|
+
break;
|
|
43254
|
+
const pv = ps[pEnd] ?? null;
|
|
43255
|
+
const pp = ps[pPrev] ?? null;
|
|
43256
|
+
if (pv === null || pp === null)
|
|
43257
|
+
return null;
|
|
43258
|
+
const vol = vs[vs.length - 1 - i] ?? 0;
|
|
43259
|
+
momentumSum += (pv - pp) * vol;
|
|
43260
|
+
volumeSum += vol;
|
|
43261
|
+
}
|
|
43262
|
+
return finiteOut2(volumeSum > 0 ? momentumSum / volumeSum : 0);
|
|
43263
|
+
}
|
|
43264
|
+
parkinson(high, low) {
|
|
43265
|
+
const h = finiteCell2(high);
|
|
43266
|
+
const l = finiteCell2(low);
|
|
43267
|
+
if (h === null || l === null || h <= l)
|
|
43268
|
+
return null;
|
|
43269
|
+
const ratio = h / l;
|
|
43270
|
+
if (ratio <= 0)
|
|
43271
|
+
return null;
|
|
43272
|
+
return finiteOut2(Math.sqrt(Math.log(ratio) ** 2 / (4 * Math.log(2))));
|
|
43273
|
+
}
|
|
43274
|
+
garmanKlass(high, low, close, open) {
|
|
43275
|
+
const h = finiteCell2(high);
|
|
43276
|
+
const l = finiteCell2(low);
|
|
43277
|
+
const c = finiteCell2(close);
|
|
43278
|
+
const o = finiteCell2(open);
|
|
43279
|
+
if (h === null || l === null || c === null || o === null)
|
|
43280
|
+
return null;
|
|
43281
|
+
if (h <= l || h <= 0 || c <= 0)
|
|
43282
|
+
return null;
|
|
43283
|
+
const term1 = 0.5 * Math.log(h / l) ** 2;
|
|
43284
|
+
const term2 = (2 * Math.log(2) - 1) * Math.log(c / o) ** 2;
|
|
43285
|
+
return finiteOut2(Math.sqrt(term1 - term2));
|
|
43286
|
+
}
|
|
43287
|
+
meanReversionScore(site, close, sma, stdev, period) {
|
|
43288
|
+
const n = this.coerceTaInt(period, "ta.mean_reversion_score() requires 4 arguments");
|
|
43289
|
+
if (n <= 0)
|
|
43290
|
+
return 50;
|
|
43291
|
+
let st = this.meanReversionSites.get(`${site}:${n}`);
|
|
43292
|
+
if (st === undefined) {
|
|
43293
|
+
st = { countClose: 0, countSma: 0 };
|
|
43294
|
+
this.meanReversionSites.set(`${site}:${n}`, st);
|
|
43295
|
+
}
|
|
43296
|
+
st.countClose += 1;
|
|
43297
|
+
st.countSma += 1;
|
|
43298
|
+
if (st.countClose < n || st.countSma < n)
|
|
43299
|
+
return 50;
|
|
43300
|
+
const c = finiteCell2(close) ?? 100;
|
|
43301
|
+
const s = finiteCell2(sma) ?? 100;
|
|
43302
|
+
const sd = finiteCell2(stdev) ?? 1;
|
|
43303
|
+
if (sd === 0)
|
|
43304
|
+
return 50;
|
|
43305
|
+
return Math.max(0, Math.min(100, Math.min(100, Math.abs(c - s) / sd * 20)));
|
|
43306
|
+
}
|
|
43307
|
+
marketCondition(site, close, atr, smaPeriod, stdevPeriod) {
|
|
43308
|
+
const smaN = this.coerceTaInt(smaPeriod, "sma period must be integer");
|
|
43309
|
+
const stdevN = this.coerceTaInt(stdevPeriod, "stdev period must be integer");
|
|
43310
|
+
if (smaN <= 0 || stdevN <= 0)
|
|
43311
|
+
return "ranging";
|
|
43312
|
+
const win = Math.max(smaN, stdevN);
|
|
43313
|
+
const key = `${site}:${smaN}:${stdevN}`;
|
|
43314
|
+
let st = this.marketConditionSites.get(key);
|
|
43315
|
+
if (st === undefined) {
|
|
43316
|
+
st = { window: [], atr: null };
|
|
43317
|
+
this.marketConditionSites.set(key, st);
|
|
43318
|
+
}
|
|
43319
|
+
pushCap(st.window, finiteCell2(close), win);
|
|
43320
|
+
st.atr = finiteCell2(atr);
|
|
43321
|
+
if (st.window.length < win)
|
|
43322
|
+
return "ranging";
|
|
43323
|
+
const cLast = st.window[st.window.length - 1] ?? null;
|
|
43324
|
+
const currentClose = cLast ?? 0;
|
|
43325
|
+
const currentAtr = st.atr ?? 1;
|
|
43326
|
+
const currentSma = smaOf(st.window, smaN) ?? currentClose;
|
|
43327
|
+
const stdevVal = stdevOf(st.window, stdevN);
|
|
43328
|
+
if (stdevVal !== null && stdevVal > currentAtr * 1.5)
|
|
43329
|
+
return "volatile";
|
|
43330
|
+
if (currentClose > currentSma && currentAtr > 0.5)
|
|
43331
|
+
return "trending_up";
|
|
43332
|
+
if (currentClose < currentSma && currentAtr > 0.5)
|
|
43333
|
+
return "trending_down";
|
|
43334
|
+
return "ranging";
|
|
43335
|
+
}
|
|
43336
|
+
orderFlowImbalance(site, high, low, close, volume, period) {
|
|
43337
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43338
|
+
if (n <= 0)
|
|
43339
|
+
return 0;
|
|
43340
|
+
const key = `${site}:${n}`;
|
|
43341
|
+
let st = this.orderFlowSites.get(key);
|
|
43342
|
+
if (st === undefined) {
|
|
43343
|
+
st = { highs: [], lows: [], closes: [], volumes: [] };
|
|
43344
|
+
this.orderFlowSites.set(key, st);
|
|
43345
|
+
}
|
|
43346
|
+
pushCap(st.highs, finiteCell2(high), n);
|
|
43347
|
+
pushCap(st.lows, finiteCell2(low), n);
|
|
43348
|
+
pushCap(st.closes, finiteCell2(close), n);
|
|
43349
|
+
pushCap(st.volumes, finiteCell2(volume), n);
|
|
43350
|
+
if (st.highs.length < n || st.lows.length < n)
|
|
43351
|
+
return 0;
|
|
43352
|
+
let buy = 0;
|
|
43353
|
+
let sell = 0;
|
|
43354
|
+
for (let i = 0;i < n; i++) {
|
|
43355
|
+
const h = st.highs[i] ?? 0;
|
|
43356
|
+
const l = st.lows[i] ?? 0;
|
|
43357
|
+
const c = st.closes[i] ?? 0;
|
|
43358
|
+
const v = st.volumes[i] ?? 0;
|
|
43359
|
+
if (h > l) {
|
|
43360
|
+
const mid = (h + l) / 2;
|
|
43361
|
+
if (c > mid)
|
|
43362
|
+
buy += v;
|
|
43363
|
+
else
|
|
43364
|
+
sell += v;
|
|
43365
|
+
}
|
|
43366
|
+
}
|
|
43367
|
+
const total = buy + sell;
|
|
43368
|
+
if (total === 0)
|
|
43369
|
+
return 0;
|
|
43370
|
+
return finiteOut2((buy - sell) / total) ?? 0;
|
|
43371
|
+
}
|
|
43372
|
+
liquidityScore(site, volume, volatility, spread, period) {
|
|
43373
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43374
|
+
if (n <= 0)
|
|
43375
|
+
return 50;
|
|
43376
|
+
const key = `${site}:${n}`;
|
|
43377
|
+
let st = this.liquiditySites.get(key);
|
|
43378
|
+
if (st === undefined) {
|
|
43379
|
+
st = { volume: [], volatility: [], spread: [] };
|
|
43380
|
+
this.liquiditySites.set(key, st);
|
|
43381
|
+
}
|
|
43382
|
+
pushCap(st.volume, finiteCell2(volume), n);
|
|
43383
|
+
pushCap(st.volatility, finiteCell2(volatility), n);
|
|
43384
|
+
pushCap(st.spread, finiteCell2(spread), n);
|
|
43385
|
+
if (st.volume.length < n || st.volatility.length < n || st.spread.length < n)
|
|
43386
|
+
return 50;
|
|
43387
|
+
let volSum = 0;
|
|
43388
|
+
for (const v of st.volume)
|
|
43389
|
+
if (v !== null)
|
|
43390
|
+
volSum += v;
|
|
43391
|
+
let volaSum = 0;
|
|
43392
|
+
for (const v of st.volatility)
|
|
43393
|
+
if (v !== null)
|
|
43394
|
+
volaSum += v;
|
|
43395
|
+
let spreadSum = 0;
|
|
43396
|
+
for (const v of st.spread)
|
|
43397
|
+
if (v !== null)
|
|
43398
|
+
spreadSum += v;
|
|
43399
|
+
const volScore = Math.min(100, volSum / n / 100);
|
|
43400
|
+
const volatilityScore = Math.max(0, 100 - volaSum / n * 50);
|
|
43401
|
+
const spreadScore = Math.max(0, 100 - spreadSum / n * 100);
|
|
43402
|
+
const liquidity = volScore * 0.4 + volatilityScore * 0.3 + spreadScore * 0.3;
|
|
43403
|
+
return Math.max(0, Math.min(100, liquidity));
|
|
43404
|
+
}
|
|
43405
|
+
fearGreedIndex(rsi, vix, putCall, breadth) {
|
|
43406
|
+
const r = finiteCell2(rsi) ?? 50;
|
|
43407
|
+
const v = finiteCell2(vix) ?? 2;
|
|
43408
|
+
const pc = finiteCell2(putCall) ?? 1;
|
|
43409
|
+
const b = finiteCell2(breadth) ?? 0.5;
|
|
43410
|
+
const index = ((r - 50) * 1 + (v - 2) * 10 + (1 - pc) * 50 + (b - 0.5) * 100) / 4;
|
|
43411
|
+
return Math.max(-100, Math.min(100, index));
|
|
43412
|
+
}
|
|
43413
|
+
crowdSentiment(priceAgreement, volumeAgreement, timeAgreement) {
|
|
43414
|
+
const p = finiteCell2(priceAgreement) ?? 0.5;
|
|
43415
|
+
const v = finiteCell2(volumeAgreement) ?? 0.5;
|
|
43416
|
+
const t = finiteCell2(timeAgreement) ?? 0.5;
|
|
43417
|
+
return Math.max(0, Math.min(100, (p + v + t) / 3 * 100));
|
|
43418
|
+
}
|
|
43419
|
+
smartMoneyFlow(priceChange, volume, timeHigh, timeLow) {
|
|
43420
|
+
const p = finiteCell2(priceChange) ?? 0;
|
|
43421
|
+
const v = finiteCell2(volume) ?? 1000;
|
|
43422
|
+
const th = finiteCell2(timeHigh) ?? 10;
|
|
43423
|
+
const tl = finiteCell2(timeLow) ?? 10;
|
|
43424
|
+
const volFactor = Math.min(1, v / 5000);
|
|
43425
|
+
let flow = 0;
|
|
43426
|
+
if (p > 0 && th < tl)
|
|
43427
|
+
flow = volFactor * 0.8;
|
|
43428
|
+
else if (p < 0 && tl < th)
|
|
43429
|
+
flow = -volFactor * 0.8;
|
|
43430
|
+
return Math.max(-1, Math.min(1, flow));
|
|
43431
|
+
}
|
|
43432
|
+
trendConfirmationScore(momentum, trendAlignment, strength, rsi, rsiAlignment) {
|
|
43433
|
+
const m = finiteCell2(momentum) ?? 0;
|
|
43434
|
+
const t = finiteCell2(trendAlignment) ?? 0;
|
|
43435
|
+
const s = finiteCell2(strength) ?? 1;
|
|
43436
|
+
const r = finiteCell2(rsi) ?? 50;
|
|
43437
|
+
const a = finiteCell2(rsiAlignment) ?? 0;
|
|
43438
|
+
const momentumScore = Math.min(100, Math.abs(m) * 20);
|
|
43439
|
+
const trendScore = Math.max(0, (t + 1) / 2 * 100);
|
|
43440
|
+
const strengthScore = Math.min(100, s * 50);
|
|
43441
|
+
const rsiScore = Math.abs(r - 50) > 10 ? Math.min(100, Math.abs(r - 50) * 2) : 40;
|
|
43442
|
+
const alignmentBonus = Math.abs(a) > 0.5 ? 20 : 0;
|
|
43443
|
+
const total = momentumScore * 0.25 + trendScore * 0.3 + strengthScore * 0.25 + rsiScore * 0.15 + alignmentBonus;
|
|
43444
|
+
return Math.max(0, Math.min(100, total));
|
|
43445
|
+
}
|
|
43446
|
+
maxLossLevel(entry, account, maxLossPct) {
|
|
43447
|
+
const e = finiteCell2(entry) ?? 100;
|
|
43448
|
+
const a = finiteCell2(account) ?? 1e4;
|
|
43449
|
+
const p = finiteCell2(maxLossPct) ?? 1;
|
|
43450
|
+
const maxLossAmount = a * (p / 100);
|
|
43451
|
+
if (e <= 0)
|
|
43452
|
+
return 0;
|
|
43453
|
+
const shares = a / e;
|
|
43454
|
+
const stop = shares > 0 ? e - maxLossAmount / shares : 0;
|
|
43455
|
+
return Math.max(0, stop);
|
|
43456
|
+
}
|
|
43457
|
+
profitLockLevel(entry, current, trailPct, direction) {
|
|
43458
|
+
const e = finiteCell2(entry) ?? 100;
|
|
43459
|
+
const c = finiteCell2(current) ?? 100;
|
|
43460
|
+
const t = Math.max(0, Math.min(1, finiteCell2(trailPct) ?? 0.05));
|
|
43461
|
+
const d = finiteCell2(direction) ?? 1;
|
|
43462
|
+
return d > 0 ? Math.max(e * 0.9, c - c * t) : Math.min(e * 1.1, c + c * t);
|
|
43463
|
+
}
|
|
43464
|
+
positionSizing(account, riskPct, entry, stop) {
|
|
43465
|
+
const a = finiteCell2(account) ?? 1e4;
|
|
43466
|
+
const r = finiteCell2(riskPct) ?? 0.01;
|
|
43467
|
+
const e = finiteCell2(entry) ?? 100;
|
|
43468
|
+
const s = finiteCell2(stop) ?? 95;
|
|
43469
|
+
const riskAmount = a * (r / 100);
|
|
43470
|
+
const distance = e - s;
|
|
43471
|
+
if (Math.abs(distance) < 0.0000000001)
|
|
43472
|
+
return 0;
|
|
43473
|
+
return Math.max(0, riskAmount / Math.abs(distance));
|
|
43474
|
+
}
|
|
43475
|
+
kellyCriterion(winRate, avgWin, avgLoss) {
|
|
43476
|
+
const wr = Math.max(0, Math.min(1, finiteCell2(winRate) ?? 0.5));
|
|
43477
|
+
const win = finiteCell2(avgWin) ?? 1;
|
|
43478
|
+
const loss = finiteCell2(avgLoss) ?? 1;
|
|
43479
|
+
if (Math.abs(win) < 0.0000000001)
|
|
43480
|
+
return 0;
|
|
43481
|
+
const kelly = (wr * win - (1 - wr) * loss) / win;
|
|
43482
|
+
return Math.max(0, kelly);
|
|
43483
|
+
}
|
|
43484
|
+
riskRewardRatio(entry, stop, target) {
|
|
43485
|
+
const e = finiteCell2(entry) ?? 0;
|
|
43486
|
+
const s = finiteCell2(stop) ?? 0;
|
|
43487
|
+
const t = finiteCell2(target) ?? 0;
|
|
43488
|
+
const risk = e - s;
|
|
43489
|
+
if (Math.abs(risk) < 0.0000000001)
|
|
43490
|
+
return null;
|
|
43491
|
+
return finiteOut2((t - e) / risk);
|
|
43492
|
+
}
|
|
43493
|
+
riskRewardAsymmetry(entry, stop, target, winRate) {
|
|
43494
|
+
const e = finiteCell2(entry) ?? 0;
|
|
43495
|
+
const s = finiteCell2(stop) ?? 0;
|
|
43496
|
+
const t = finiteCell2(target) ?? 0;
|
|
43497
|
+
const wr = finiteCell2(winRate) ?? 0.5;
|
|
43498
|
+
const risk = Math.abs(e - s);
|
|
43499
|
+
const reward = Math.abs(t - e);
|
|
43500
|
+
const ratio = risk > 0 ? reward / risk : 0;
|
|
43501
|
+
const ev = wr * reward - (1 - wr) * risk;
|
|
43502
|
+
const kelly = ratio > 0 ? wr - (1 - wr) / ratio : 0;
|
|
43503
|
+
return taRec({
|
|
43504
|
+
ratio: finiteOut2(ratio) ?? 0,
|
|
43505
|
+
expected_value: finiteOut2(ev) ?? 0,
|
|
43506
|
+
kelly_percent: finiteOut2(kelly * 100) ?? 0,
|
|
43507
|
+
is_favorable: ev > 0,
|
|
43508
|
+
risk_reward_ratio: finiteOut2(ratio) ?? 0,
|
|
43509
|
+
kelly_percentage: finiteOut2(kelly * 100) ?? 0
|
|
43510
|
+
});
|
|
43511
|
+
}
|
|
43512
|
+
probabilityOfMovement(current, target, atr, period) {
|
|
43513
|
+
const c = finiteCell2(current) ?? 100;
|
|
43514
|
+
const t = finiteCell2(target) ?? 100;
|
|
43515
|
+
const a = finiteCell2(atr) ?? 1;
|
|
43516
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43517
|
+
if (Math.abs(c) < 0.0000000001 || Math.abs(a) < 0.0000000001)
|
|
43518
|
+
return 0.5;
|
|
43519
|
+
const distance = Math.abs(t - c);
|
|
43520
|
+
const expected = a * Math.sqrt(n);
|
|
43521
|
+
if (expected === 0)
|
|
43522
|
+
return 0.5;
|
|
43523
|
+
return Math.max(0, Math.min(1, Math.min(1, distance / expected) * 0.8 + 0.1));
|
|
43524
|
+
}
|
|
43525
|
+
trendStrength(price, adx, rsi) {
|
|
43526
|
+
const a = finiteCell2(adx) ?? 20;
|
|
43527
|
+
const r = finiteCell2(rsi) ?? 50;
|
|
43528
|
+
const adxNorm = Math.min(100, Math.max(0, a));
|
|
43529
|
+
const rsiExtremeness = Math.abs(r - 50) / 50;
|
|
43530
|
+
return Math.min(100, Math.max(0, adxNorm * 0.6 + rsiExtremeness * 40));
|
|
43531
|
+
}
|
|
43532
|
+
breakevenLevel(entry, qty, commission, slippage, direction) {
|
|
43533
|
+
const e = finiteCell2(entry) ?? 0;
|
|
43534
|
+
const q = finiteCell2(qty) ?? 0;
|
|
43535
|
+
const comm = finiteCell2(commission) ?? 0;
|
|
43536
|
+
const slip = finiteCell2(slippage) ?? 0;
|
|
43537
|
+
const d = finiteCell2(direction) ?? 1;
|
|
43538
|
+
const cost = comm + slip * q;
|
|
43539
|
+
const impact = q > 0 ? cost / q : 0;
|
|
43540
|
+
const breakeven = d >= 0 ? e + impact : e - impact;
|
|
43541
|
+
const move = e > 0 ? Math.abs(breakeven - e) / e * 100 : 0;
|
|
43542
|
+
return taRec({
|
|
43543
|
+
breakeven_price: finiteOut2(breakeven) ?? 0,
|
|
43544
|
+
total_cost: finiteOut2(cost) ?? 0,
|
|
43545
|
+
move_required_percent: finiteOut2(move) ?? 0
|
|
43546
|
+
});
|
|
43547
|
+
}
|
|
43548
|
+
marketStructurePivot(site, high, low, period, mode) {
|
|
43549
|
+
const hh = this.windowFor(`${site}:high`, high);
|
|
43550
|
+
const ll = this.windowFor(`${site}:low`, low);
|
|
43551
|
+
const n = this.coerceTaInt(period, "ta.market_structure_pivot() requires 5 arguments");
|
|
43552
|
+
const m = this.coerceTaInt(mode, "ta.market_structure_pivot() requires 5 arguments");
|
|
43553
|
+
const off = taRec({ pivot_price: 100, strength: 50, structure: "neutral" });
|
|
43554
|
+
if (hh.length === 0 || ll.length === 0 || hh.length < n || n <= 0)
|
|
43555
|
+
return off;
|
|
43556
|
+
const hVals = hh.slice(-n).filter((v) => v !== null);
|
|
43557
|
+
const lVals = ll.slice(-n).filter((v) => v !== null);
|
|
43558
|
+
if (hVals.length === 0 || lVals.length === 0)
|
|
43559
|
+
return off;
|
|
43560
|
+
let pivotHigh = hVals[0];
|
|
43561
|
+
let pivotLow = lVals[0];
|
|
43562
|
+
for (const v of hVals)
|
|
43563
|
+
if (v > pivotHigh)
|
|
43564
|
+
pivotHigh = v;
|
|
43565
|
+
for (const v of lVals)
|
|
43566
|
+
if (v < pivotLow)
|
|
43567
|
+
pivotLow = v;
|
|
43568
|
+
const price = (pivotHigh + pivotLow) / 2;
|
|
43569
|
+
const range = pivotHigh - pivotLow;
|
|
43570
|
+
let structure = "block";
|
|
43571
|
+
let strength = Math.min(100, range * 0.5);
|
|
43572
|
+
if (m === 0) {
|
|
43573
|
+
structure = "fractal";
|
|
43574
|
+
strength = Math.min(100, range * 2);
|
|
43575
|
+
} else if (m === 1) {
|
|
43576
|
+
structure = "swing";
|
|
43577
|
+
strength = Math.min(100, range * 1.5);
|
|
43578
|
+
}
|
|
43579
|
+
return taRec({
|
|
43580
|
+
pivot_price: finiteOut2(price) ?? 0,
|
|
43581
|
+
strength: finiteOut2(strength) ?? 0,
|
|
43582
|
+
structure
|
|
43583
|
+
});
|
|
43584
|
+
}
|
|
43585
|
+
positionSizingScore(risk, volatility, conviction, correlation) {
|
|
43586
|
+
const r = finiteCell2(risk) ?? 0;
|
|
43587
|
+
const v = finiteCell2(volatility) ?? 0;
|
|
43588
|
+
const c = finiteCell2(conviction) ?? 0;
|
|
43589
|
+
const corr = finiteCell2(correlation) ?? 0;
|
|
43590
|
+
let score = r / (v + 0.1) * c * (1 - corr);
|
|
43591
|
+
score = Math.max(0, Math.min(1, score * 0.1));
|
|
43592
|
+
return taRec({
|
|
43593
|
+
score: finiteOut2(score * 100) ?? 0,
|
|
43594
|
+
position_size_ratio: finiteOut2(score) ?? 0,
|
|
43595
|
+
kelly_fraction: finiteOut2(score * 0.5) ?? 0,
|
|
43596
|
+
correlation_adjustment: finiteOut2(1 - corr) ?? 0
|
|
43597
|
+
});
|
|
43598
|
+
}
|
|
43599
|
+
trailingExitLevel(entry, current, atr, mult, step) {
|
|
43600
|
+
const e = finiteCell2(entry) ?? 0;
|
|
43601
|
+
const c = finiteCell2(current) ?? 0;
|
|
43602
|
+
const a = finiteCell2(atr) ?? 0;
|
|
43603
|
+
const m = finiteCell2(mult) ?? 0;
|
|
43604
|
+
finiteCell2(step);
|
|
43605
|
+
const trail = c > e ? Math.max(e * 1.001, c - a * m) : c + a * m;
|
|
43606
|
+
return taRec({
|
|
43607
|
+
trail_stop: finiteOut2(trail) ?? 0,
|
|
43608
|
+
protected_profit: c > e ? finiteOut2(Math.max(0, c - e)) ?? 0 : 0,
|
|
43609
|
+
risk_reward_current: a > 0 ? finiteOut2(Math.abs(c - e) / a) ?? 0 : 0
|
|
43610
|
+
});
|
|
43611
|
+
}
|
|
43612
|
+
optimalEntryZone(site, close) {
|
|
43613
|
+
const h = this.windowFor(`${site}:close`, close);
|
|
43614
|
+
const c = TaEngine.oldest(h) ?? 0;
|
|
43615
|
+
return taRec({
|
|
43616
|
+
min: finiteOut2(c * 0.99) ?? 0,
|
|
43617
|
+
max: finiteOut2(c * 1.01) ?? 0,
|
|
43618
|
+
optimal: c,
|
|
43619
|
+
entry_zone_low: finiteOut2(c * 0.99) ?? 0,
|
|
43620
|
+
entry_zone_high: finiteOut2(c * 1.01) ?? 0,
|
|
43621
|
+
best_entry: c,
|
|
43622
|
+
zone_strength: 85
|
|
43623
|
+
});
|
|
43624
|
+
}
|
|
43625
|
+
meanReversionEntry(site, price, sma, stdev, threshold) {
|
|
43626
|
+
const ph = this.windowFor(`${site}:price`, price);
|
|
43627
|
+
const sh = this.windowFor(`${site}:sma`, sma);
|
|
43628
|
+
const dh = this.windowFor(`${site}:stdev`, stdev);
|
|
43629
|
+
const p = TaEngine.oldest(ph) ?? 0;
|
|
43630
|
+
const s = TaEngine.oldest(sh) ?? 0;
|
|
43631
|
+
const sd = TaEngine.oldest(dh) ?? 1;
|
|
43632
|
+
const th = finiteCell2(threshold) ?? 0;
|
|
43633
|
+
const z = sd !== 0 ? (p - s) / sd : 0;
|
|
43634
|
+
return taRec({
|
|
43635
|
+
entry_price: 100,
|
|
43636
|
+
stop_loss: 95,
|
|
43637
|
+
take_profit: 105,
|
|
43638
|
+
probability: 0.7,
|
|
43639
|
+
reversion_probability: 0.75,
|
|
43640
|
+
target_price: 105,
|
|
43641
|
+
z_score: finiteOut2(z) ?? 0,
|
|
43642
|
+
is_mean_reversion_setup: Math.abs(z) > th
|
|
43643
|
+
});
|
|
43644
|
+
}
|
|
43645
|
+
multiTimeframeSignal(s1, s2, s3, w1, w2, w3) {
|
|
43646
|
+
const score = (finiteCell2(s1) ?? 0) * (finiteCell2(w1) ?? 0) + (finiteCell2(s2) ?? 0) * (finiteCell2(w2) ?? 0) + (finiteCell2(s3) ?? 0) * (finiteCell2(w3) ?? 0);
|
|
43647
|
+
return taRec({ score: finiteOut2(score) ?? 0, signal: score > 0.5 ? "buy" : "sell", agreement: true });
|
|
43648
|
+
}
|
|
43649
|
+
marketTimingIndex(trend, momentum, volatility, sentiment) {
|
|
43650
|
+
const t = finiteCell2(trend) ?? 0;
|
|
43651
|
+
const m = finiteCell2(momentum) ?? 0;
|
|
43652
|
+
const v = finiteCell2(volatility) ?? 0;
|
|
43653
|
+
const s = finiteCell2(sentiment) ?? 0;
|
|
43654
|
+
const score = t * 0.3 + m * 0.3 + v * 0.2 + s * 0.2;
|
|
43655
|
+
let recommendation = "hold";
|
|
43656
|
+
if (score > 80)
|
|
43657
|
+
recommendation = "strong_buy";
|
|
43658
|
+
else if (score > 60)
|
|
43659
|
+
recommendation = "buy";
|
|
43660
|
+
else if (score < 20)
|
|
43661
|
+
recommendation = "strong_sell";
|
|
43662
|
+
else if (score < 40)
|
|
43663
|
+
recommendation = "sell";
|
|
43664
|
+
return taRec({
|
|
43665
|
+
score: finiteOut2(score) ?? 0,
|
|
43666
|
+
recommendation,
|
|
43667
|
+
regime: Math.abs(t) > 50 ? "trending" : "ranging",
|
|
43668
|
+
timing_index: finiteOut2(score) ?? 0,
|
|
43669
|
+
market_condition: score > 80 ? "optimal_long" : "neutral",
|
|
43670
|
+
confidence: 0.85
|
|
43671
|
+
});
|
|
43672
|
+
}
|
|
43673
|
+
regimeAdaptiveSignal(strength, volRegime, trendRegime) {
|
|
43674
|
+
const vol = typeof volRegime === "string" ? volRegime : "";
|
|
43675
|
+
const trend = typeof trendRegime === "string" ? trendRegime : "";
|
|
43676
|
+
let adapted = finiteCell2(strength) ?? 0;
|
|
43677
|
+
let fit = 1;
|
|
43678
|
+
if (vol === "high") {
|
|
43679
|
+
adapted *= 0.8;
|
|
43680
|
+
fit *= 0.8;
|
|
43681
|
+
}
|
|
43682
|
+
if (trend === "ranging") {
|
|
43683
|
+
adapted *= 0.5;
|
|
43684
|
+
fit *= 0.5;
|
|
43685
|
+
}
|
|
43686
|
+
return taRec({
|
|
43687
|
+
signal: adapted > 0.5 ? "buy" : "sell",
|
|
43688
|
+
strength: finiteOut2(adapted) ?? 0,
|
|
43689
|
+
confidence: finiteOut2(adapted * 100) ?? 0,
|
|
43690
|
+
adapted_signal: finiteOut2(adapted) ?? 0,
|
|
43691
|
+
regime_fit: finiteOut2(fit) ?? 0,
|
|
43692
|
+
strategy_recommendation: trend === "trending" ? "trend_following" : "mean_reversion",
|
|
43693
|
+
signal_confidence: finiteOut2(adapted) ?? 0
|
|
43694
|
+
});
|
|
43695
|
+
}
|
|
43696
|
+
strategyScore(rsi, macd, emaCross, trend) {
|
|
43697
|
+
const r = finiteCell2(rsi) ?? 50;
|
|
43698
|
+
const m = finiteCell2(macd) ?? 0;
|
|
43699
|
+
const cross = emaCross != null && emaCross !== 0;
|
|
43700
|
+
const t = finiteCell2(trend) ?? 50;
|
|
43701
|
+
const rsiNorm = (r - 50) / 50 * 25;
|
|
43702
|
+
const macdNorm = Math.max(-25, Math.min(25, m * 50));
|
|
43703
|
+
const emaBonus = cross ? 25 : -25;
|
|
43704
|
+
const trendNorm = (t - 50) / 50 * 25;
|
|
43705
|
+
return Math.max(-100, Math.min(100, rsiNorm + macdNorm + emaBonus + trendNorm));
|
|
43706
|
+
}
|
|
43707
|
+
breakoutDetection(close, resistance, support) {
|
|
43708
|
+
const c = finiteCell2(close) ?? 0;
|
|
43709
|
+
const r = finiteCell2(resistance) ?? 0;
|
|
43710
|
+
const s = finiteCell2(support) ?? 0;
|
|
43711
|
+
if (c > r) {
|
|
43712
|
+
const strength = r > 0 ? (c - r) / r * 100 : 0;
|
|
43713
|
+
return taRec({
|
|
43714
|
+
is_breakout: true,
|
|
43715
|
+
breakout_type: "resistance",
|
|
43716
|
+
breakout_strength: finiteOut2(strength) ?? 0
|
|
43717
|
+
});
|
|
43718
|
+
}
|
|
43719
|
+
if (c < s) {
|
|
43720
|
+
const strength = s > 0 ? (s - c) / s * 100 : 0;
|
|
43721
|
+
return taRec({
|
|
43722
|
+
is_breakout: true,
|
|
43723
|
+
breakout_type: "support",
|
|
43724
|
+
breakout_strength: finiteOut2(strength) ?? 0
|
|
43725
|
+
});
|
|
43726
|
+
}
|
|
43727
|
+
return taRec({ is_breakout: false, breakout_type: "none", breakout_strength: 0 });
|
|
43728
|
+
}
|
|
43729
|
+
emaCrossSignal(site, fast, slow, threshold) {
|
|
43730
|
+
const off = taRec({ signal: "neutral", strength: 0, trend_direction: 0 });
|
|
43731
|
+
let st = this.emaCrossSites.get(site);
|
|
43732
|
+
if (st === undefined) {
|
|
43733
|
+
st = { prevFast: null, prevSlow: null, count: 0 };
|
|
43734
|
+
this.emaCrossSites.set(site, st);
|
|
43735
|
+
}
|
|
43736
|
+
const f = finiteCell2(fast) ?? 0;
|
|
43737
|
+
const s = finiteCell2(slow) ?? 0;
|
|
43738
|
+
const th = finiteCell2(threshold) ?? 0;
|
|
43739
|
+
st.count += 1;
|
|
43740
|
+
const prevFast = st.prevFast;
|
|
43741
|
+
const prevSlow = st.prevSlow;
|
|
43742
|
+
if (st.count < 2 || prevFast === null || prevSlow === null) {
|
|
43743
|
+
st.prevFast = f;
|
|
43744
|
+
st.prevSlow = s;
|
|
43745
|
+
return off;
|
|
43746
|
+
}
|
|
43747
|
+
const diff = f - s;
|
|
43748
|
+
const prevDiff = prevFast - prevSlow;
|
|
43749
|
+
const crossover = prevDiff <= 0 && diff > 0;
|
|
43750
|
+
const crossunder = prevDiff >= 0 && diff < 0;
|
|
43751
|
+
const strength = Math.abs(diff);
|
|
43752
|
+
const trend = diff > 0 ? 1 : -1;
|
|
43753
|
+
let signal = "neutral";
|
|
43754
|
+
if (crossover && strength > th)
|
|
43755
|
+
signal = "buy";
|
|
43756
|
+
else if (crossunder && strength > th)
|
|
43757
|
+
signal = "sell";
|
|
43758
|
+
st.prevFast = f;
|
|
43759
|
+
st.prevSlow = s;
|
|
43760
|
+
return taRec({ signal, strength: finiteOut2(strength) ?? 0, trend_direction: trend });
|
|
43761
|
+
}
|
|
43762
|
+
momentumFilter(site, momentum, volume, period) {
|
|
43763
|
+
const n = this.coerceTaInt(period, "ta.momentum_filter() requires 3 arguments");
|
|
43764
|
+
if (n <= 0)
|
|
43765
|
+
return 0;
|
|
43766
|
+
let st = this.momentumFilterSites.get(`${site}:${n}`);
|
|
43767
|
+
if (st === undefined) {
|
|
43768
|
+
st = { momentum: [], volume: [] };
|
|
43769
|
+
this.momentumFilterSites.set(`${site}:${n}`, st);
|
|
43770
|
+
}
|
|
43771
|
+
pushCap(st.momentum, finiteCell2(momentum), n);
|
|
43772
|
+
pushCap(st.volume, finiteCell2(volume), n);
|
|
43773
|
+
if (st.momentum.length < n || st.volume.length < n)
|
|
43774
|
+
return 0;
|
|
43775
|
+
let volSum = 0;
|
|
43776
|
+
for (const v of st.volume)
|
|
43777
|
+
if (v !== null)
|
|
43778
|
+
volSum += v;
|
|
43779
|
+
if (volSum === 0)
|
|
43780
|
+
return 0;
|
|
43781
|
+
let numerator = 0;
|
|
43782
|
+
let paired = false;
|
|
43783
|
+
for (let i = 0;i < n; i++) {
|
|
43784
|
+
const m = st.momentum[i];
|
|
43785
|
+
const v = st.volume[i];
|
|
43786
|
+
if (m !== null && v !== null) {
|
|
43787
|
+
numerator += m * v;
|
|
43788
|
+
paired = true;
|
|
43789
|
+
}
|
|
43790
|
+
}
|
|
43791
|
+
if (!paired)
|
|
43792
|
+
return 0;
|
|
43793
|
+
return finiteOut2(numerator / volSum) ?? 0;
|
|
43794
|
+
}
|
|
43795
|
+
volatilityRegime(site, atr, period) {
|
|
43796
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43797
|
+
if (n < 1)
|
|
43798
|
+
return "medium";
|
|
43799
|
+
let w = this.volatilityRegimeSites.get(`${site}:${n}`);
|
|
43800
|
+
if (w === undefined) {
|
|
43801
|
+
w = [];
|
|
43802
|
+
this.volatilityRegimeSites.set(`${site}:${n}`, w);
|
|
43803
|
+
}
|
|
43804
|
+
pushCap(w, finiteCell2(atr), n);
|
|
43805
|
+
if (w.length < n)
|
|
43806
|
+
return "medium";
|
|
43807
|
+
const recent = [];
|
|
43808
|
+
for (const v of w)
|
|
43809
|
+
if (v !== null)
|
|
43810
|
+
recent.push(v);
|
|
43811
|
+
if (recent.length === 0)
|
|
43812
|
+
return "medium";
|
|
43813
|
+
const current = recent[recent.length - 1];
|
|
43814
|
+
let sum = 0;
|
|
43815
|
+
for (const v of recent)
|
|
43816
|
+
sum += v;
|
|
43817
|
+
const avg = sum / recent.length;
|
|
43818
|
+
if (current < avg * 0.5)
|
|
43819
|
+
return "low";
|
|
43820
|
+
if (current > avg * 2)
|
|
43821
|
+
return "extreme";
|
|
43822
|
+
if (current > avg * 1.3)
|
|
43823
|
+
return "high";
|
|
43824
|
+
return "medium";
|
|
43825
|
+
}
|
|
43826
|
+
economicImpactScore(priceChange, volatility, volumeChange) {
|
|
43827
|
+
const pc = finiteCell2(priceChange) ?? 0;
|
|
43828
|
+
const vol = finiteCell2(volatility) ?? 0;
|
|
43829
|
+
const vc = finiteCell2(volumeChange) ?? 0;
|
|
43830
|
+
const pcScore = Math.min(100, Math.abs(pc) * 20);
|
|
43831
|
+
const volScore = Math.min(100, vol * 30);
|
|
43832
|
+
const vcScore = Math.min(100, vc * 25);
|
|
43833
|
+
return Math.max(0, Math.min(100, (pcScore + volScore + vcScore) / 3));
|
|
43834
|
+
}
|
|
43835
|
+
contrarianSignal(sentiment, volatility, timeSinceExtreme) {
|
|
43836
|
+
const sent = finiteCell2(sentiment) ?? 50;
|
|
43837
|
+
const vol = finiteCell2(volatility) ?? 1;
|
|
43838
|
+
const time = finiteCell2(timeSinceExtreme) ?? 10;
|
|
43839
|
+
let signal = "neutral";
|
|
43840
|
+
let strength = 0.5;
|
|
43841
|
+
let confidence = 0.5;
|
|
43842
|
+
if ((sent > 80 || sent < 20) && vol > 2 && time < 5) {
|
|
43843
|
+
signal = "strong_contrarian";
|
|
43844
|
+
strength = 0.9;
|
|
43845
|
+
confidence = 0.8;
|
|
43846
|
+
} else if (sent > 65 || sent < 35) {
|
|
43847
|
+
signal = "mild_contrarian";
|
|
43848
|
+
strength = 0.6;
|
|
43849
|
+
confidence = 0.6;
|
|
43850
|
+
} else if (sent > 45 && sent < 55) {
|
|
43851
|
+
signal = "follow_crowd";
|
|
43852
|
+
strength = 0.3;
|
|
43853
|
+
confidence = 0.4;
|
|
43854
|
+
}
|
|
43855
|
+
return taRec({ signal, strength, confidence });
|
|
43856
|
+
}
|
|
43857
|
+
drawdownRecoveryLevel(peak, current, factor, period) {
|
|
43858
|
+
const p = finiteCell2(peak) ?? 0;
|
|
43859
|
+
const c = finiteCell2(current) ?? 0;
|
|
43860
|
+
const f = finiteCell2(factor) ?? 0;
|
|
43861
|
+
const n = this.coerceTaInt(period, "ta.drawdown_recovery_level() requires 4 arguments");
|
|
43862
|
+
const drawdown = p > 0 ? (p - c) / p : 0;
|
|
43863
|
+
const recovery = drawdown < 1 ? drawdown / (1 - drawdown) : 0;
|
|
43864
|
+
return taRec({
|
|
43865
|
+
recovery_level: p,
|
|
43866
|
+
percent_needed: finiteOut2(recovery * 100) ?? 0,
|
|
43867
|
+
estimated_time: finiteOut2(n * f) ?? 0,
|
|
43868
|
+
confidence: 80,
|
|
43869
|
+
drawdown_percent: finiteOut2(drawdown * 100) ?? 0,
|
|
43870
|
+
recovery_timeframe: finiteOut2(n * f) ?? 0,
|
|
43871
|
+
recovery_confidence: 0.8
|
|
43872
|
+
});
|
|
43873
|
+
}
|
|
43874
|
+
pivotPointLevels(high, low, close, traditional) {
|
|
43875
|
+
const h = finiteCell2(high) ?? 0;
|
|
43876
|
+
const l = finiteCell2(low) ?? 0;
|
|
43877
|
+
const c = finiteCell2(close) ?? 0;
|
|
43878
|
+
const pivot = (h + l + c) / 3;
|
|
43879
|
+
let r1;
|
|
43880
|
+
let s1;
|
|
43881
|
+
let r2;
|
|
43882
|
+
let s2;
|
|
43883
|
+
let r3;
|
|
43884
|
+
let s3;
|
|
43885
|
+
if (traditional) {
|
|
43886
|
+
r1 = 2 * pivot - l;
|
|
43887
|
+
s1 = 2 * pivot - h;
|
|
43888
|
+
r2 = pivot + (h - l);
|
|
43889
|
+
s2 = pivot - (h - l);
|
|
43890
|
+
r3 = h + 2 * (pivot - l);
|
|
43891
|
+
s3 = l - 2 * (h - pivot);
|
|
43892
|
+
} else {
|
|
43893
|
+
const diff = h - l;
|
|
43894
|
+
r1 = pivot + 0.382 * diff;
|
|
43895
|
+
s1 = pivot - 0.382 * diff;
|
|
43896
|
+
r2 = pivot + 0.618 * diff;
|
|
43897
|
+
s2 = pivot - 0.618 * diff;
|
|
43898
|
+
r3 = pivot + diff;
|
|
43899
|
+
s3 = pivot - diff;
|
|
43900
|
+
}
|
|
43901
|
+
return taRec({
|
|
43902
|
+
pivot: finiteOut2(pivot) ?? 0,
|
|
43903
|
+
r1: finiteOut2(r1) ?? 0,
|
|
43904
|
+
s1: finiteOut2(s1) ?? 0,
|
|
43905
|
+
r2: finiteOut2(r2) ?? 0,
|
|
43906
|
+
s2: finiteOut2(s2) ?? 0,
|
|
43907
|
+
r3: finiteOut2(r3) ?? 0,
|
|
43908
|
+
s3: finiteOut2(s3) ?? 0
|
|
43909
|
+
});
|
|
43910
|
+
}
|
|
43911
|
+
volatilityRegimeScore(site, atr, volatility, vix, threshold) {
|
|
43912
|
+
const a = this.windowFor(`${site}:atr`, atr);
|
|
43913
|
+
const v = this.windowFor(`${site}:vol`, volatility);
|
|
43914
|
+
const x = this.windowFor(`${site}:vix`, vix);
|
|
43915
|
+
const th = finiteCell2(threshold) ?? 50;
|
|
43916
|
+
if (a.length === 0 || v.length === 0 || x.length === 0) {
|
|
43917
|
+
return taRec({ regime: "normal", volatility_score: 50, momentum: "stable" });
|
|
43918
|
+
}
|
|
43919
|
+
const atrVal = TaEngine.oldest(a) ?? 2;
|
|
43920
|
+
const volVal = TaEngine.oldest(v) ?? 0.02;
|
|
43921
|
+
const vixVal = TaEngine.oldest(x) ?? 15;
|
|
43922
|
+
const atrScore = Math.min(100, atrVal * 20);
|
|
43923
|
+
const volScore = Math.min(100, volVal * 100);
|
|
43924
|
+
const vixScore = Math.min(100, vixVal * 2);
|
|
43925
|
+
const score = atrScore * 0.4 + volScore * 0.3 + vixScore * 0.3;
|
|
43926
|
+
let regime;
|
|
43927
|
+
if (score < th * 0.5)
|
|
43928
|
+
regime = "low";
|
|
43929
|
+
else if (score < th)
|
|
43930
|
+
regime = "normal";
|
|
43931
|
+
else if (score < th * 1.5)
|
|
43932
|
+
regime = "high";
|
|
43933
|
+
else
|
|
43934
|
+
regime = "extreme";
|
|
43935
|
+
let momentum = "stable";
|
|
43936
|
+
const prevAtr = TaEngine.secondOldest(a);
|
|
43937
|
+
if (a.length > 1 && prevAtr !== null) {
|
|
43938
|
+
if (atrVal > prevAtr * 1.05)
|
|
43939
|
+
momentum = "accelerating";
|
|
43940
|
+
else if (atrVal < prevAtr * 0.95)
|
|
43941
|
+
momentum = "decelerating";
|
|
43942
|
+
}
|
|
43943
|
+
return taRec({ regime, volatility_score: finiteOut2(score) ?? 0, momentum });
|
|
43944
|
+
}
|
|
43945
|
+
correlationFilter(site, s1, s2, s3, threshold) {
|
|
43946
|
+
const h1 = this.windowFor(`${site}:s1`, s1);
|
|
43947
|
+
const h2 = this.windowFor(`${site}:s2`, s2);
|
|
43948
|
+
const h3 = this.windowFor(`${site}:s3`, s3);
|
|
43949
|
+
const histories = [h1, h2, h3].filter((h) => h.length > 0);
|
|
43950
|
+
const off = taRec({ is_correlated: false, signal_agreement: 0, divergence_count: 0 });
|
|
43951
|
+
if (histories.length < 2)
|
|
43952
|
+
return off;
|
|
43953
|
+
const lastVals = [];
|
|
43954
|
+
for (const h of histories) {
|
|
43955
|
+
const v = TaEngine.oldest(h);
|
|
43956
|
+
if (v !== null)
|
|
43957
|
+
lastVals.push(v);
|
|
43958
|
+
}
|
|
43959
|
+
if (lastVals.length === 0)
|
|
43960
|
+
return off;
|
|
43961
|
+
let agreement = 0;
|
|
43962
|
+
let divergence = 0;
|
|
43963
|
+
for (let i = 0;i < lastVals.length - 1; i++) {
|
|
43964
|
+
for (let j = i + 1;j < lastVals.length; j++) {
|
|
43965
|
+
if (lastVals[i] * lastVals[j] > 0)
|
|
43966
|
+
agreement += 1;
|
|
43967
|
+
else
|
|
43968
|
+
divergence += 1;
|
|
43969
|
+
}
|
|
43970
|
+
}
|
|
43971
|
+
const pairs = lastVals.length * (lastVals.length - 1) / 2;
|
|
43972
|
+
const pct = pairs > 0 ? agreement / pairs * 100 : 0;
|
|
43973
|
+
const th = finiteCell2(threshold) ?? 0.7;
|
|
43974
|
+
return taRec({
|
|
43975
|
+
is_correlated: pct / 100 >= th,
|
|
43976
|
+
signal_agreement: finiteOut2(pct) ?? 0,
|
|
43977
|
+
divergence_count: divergence
|
|
43978
|
+
});
|
|
43979
|
+
}
|
|
43980
|
+
advancedBreakoutDetector(site, price, volume, level, lookback, volumeMultiplier) {
|
|
43981
|
+
const ph = this.windowFor(`${site}:price`, price);
|
|
43982
|
+
const vh = this.windowFor(`${site}:vol`, volume);
|
|
43983
|
+
const lvl = finiteCell2(level) ?? 100;
|
|
43984
|
+
const n = this.coerceTaInt(lookback, "ta.advanced_breakout_detector() requires 5 arguments");
|
|
43985
|
+
const mult = finiteCell2(volumeMultiplier) ?? 0.5;
|
|
43986
|
+
const off = taRec({ breakout_detected: false, breakout_type: "none", pullback_probability: 0.5 });
|
|
43987
|
+
if (ph.length === 0 || vh.length === 0 || ph.length < 2 || n <= 0)
|
|
43988
|
+
return off;
|
|
43989
|
+
const currentPrice = TaEngine.oldest(ph) ?? 100;
|
|
43990
|
+
const prevPrice = TaEngine.secondOldest(ph) ?? 100;
|
|
43991
|
+
const currentVol = TaEngine.oldest(vh) ?? 1000;
|
|
43992
|
+
const recentVol = vh.slice(-n).filter((v) => v !== null);
|
|
43993
|
+
const avgVol = recentVol.length > 0 ? recentVol.reduce((a, b) => a + b, 0) / recentVol.length : 1000;
|
|
43994
|
+
const gap = currentPrice > lvl && prevPrice <= lvl;
|
|
43995
|
+
const closeBreak = currentPrice > lvl && Math.abs(currentPrice - lvl) < 0.5;
|
|
43996
|
+
const volumeBreak = currentVol > avgVol * (1 + mult);
|
|
43997
|
+
const detected = gap || closeBreak || volumeBreak;
|
|
43998
|
+
let type = "none";
|
|
43999
|
+
if (gap)
|
|
44000
|
+
type = "gap";
|
|
44001
|
+
else if (closeBreak && volumeBreak)
|
|
44002
|
+
type = "volume_break";
|
|
44003
|
+
else if (closeBreak)
|
|
44004
|
+
type = "close_above";
|
|
44005
|
+
const pullback = avgVol !== 0 ? Math.max(0.1, 0.8 - (currentVol / avgVol - 1) * 0.3) : 0.8;
|
|
44006
|
+
return taRec({
|
|
44007
|
+
breakout_detected: detected,
|
|
44008
|
+
breakout_type: type,
|
|
44009
|
+
pullback_probability: finiteOut2(pullback) ?? 0.5
|
|
44010
|
+
});
|
|
44011
|
+
}
|
|
44012
|
+
pullbackBounceLevel(site, high, low, trendDirection, lookback) {
|
|
44013
|
+
const hh = this.windowFor(`${site}:high`, high);
|
|
44014
|
+
const ll = this.windowFor(`${site}:low`, low);
|
|
44015
|
+
const trend = this.coerceTaInt(trendDirection, "trend direction must be integer");
|
|
44016
|
+
const n = this.coerceTaInt(lookback, "ta.pullback_bounce_level() requires 5 arguments");
|
|
44017
|
+
const off = taRec({ primary_level: 100, bounce_probability: 0.5, support_strength: 50 });
|
|
44018
|
+
if (hh.length === 0 || ll.length === 0 || n <= 0)
|
|
44019
|
+
return off;
|
|
44020
|
+
const hVals = hh.slice(-n).filter((v) => v !== null);
|
|
44021
|
+
const lVals = ll.slice(-n).filter((v) => v !== null);
|
|
44022
|
+
if (hVals.length === 0 || lVals.length === 0)
|
|
44023
|
+
return off;
|
|
44024
|
+
let swingHigh = hVals[0];
|
|
44025
|
+
let swingLow = lVals[0];
|
|
44026
|
+
for (const v of hVals)
|
|
44027
|
+
if (v > swingHigh)
|
|
44028
|
+
swingHigh = v;
|
|
44029
|
+
for (const v of lVals)
|
|
44030
|
+
if (v < swingLow)
|
|
44031
|
+
swingLow = v;
|
|
44032
|
+
const range = swingHigh - swingLow;
|
|
44033
|
+
const fib = trend > 0 ? swingLow + range * 0.382 : swingHigh - range * 0.382;
|
|
44034
|
+
const bounce = swingHigh !== 0 ? Math.min(0.95, 0.5 + range / swingHigh * 1) : 0.5;
|
|
44035
|
+
const strength = swingHigh !== 0 ? Math.min(100, range / swingHigh * 100) : 0;
|
|
44036
|
+
return taRec({
|
|
44037
|
+
primary_level: finiteOut2(fib) ?? 0,
|
|
44038
|
+
bounce_probability: finiteOut2(bounce) ?? 0.5,
|
|
44039
|
+
support_strength: finiteOut2(strength) ?? 0
|
|
44040
|
+
});
|
|
44041
|
+
}
|
|
44042
|
+
divergenceDetector(site, price, indicator, lookback) {
|
|
44043
|
+
const ph = this.windowFor(`${site}:price`, price);
|
|
44044
|
+
const ih = this.windowFor(`${site}:ind`, indicator);
|
|
44045
|
+
const n = this.coerceTaInt(lookback, "lookback must be integer");
|
|
44046
|
+
const off = taRec({ is_bullish: false, is_bearish: false, strength: 0 });
|
|
44047
|
+
if (ph.length < n || ih.length < n)
|
|
44048
|
+
return off;
|
|
44049
|
+
const pv = ph.slice(-n).filter((v) => v !== null);
|
|
44050
|
+
const iv = ih.slice(-n).filter((v) => v !== null);
|
|
44051
|
+
if (pv.length < 2 || iv.length < 2)
|
|
44052
|
+
return off;
|
|
44053
|
+
const priceLower = pv[pv.length - 1] < pv[0];
|
|
44054
|
+
const indHigher = iv[iv.length - 1] > iv[0];
|
|
44055
|
+
const bullish = priceLower && indHigher;
|
|
44056
|
+
const priceHigher = pv[pv.length - 1] > pv[0];
|
|
44057
|
+
const indLower = iv[iv.length - 1] < iv[0];
|
|
44058
|
+
const bearish = priceHigher && indLower;
|
|
44059
|
+
const strength = Math.min(1, Math.abs(iv[iv.length - 1] - iv[0]) / 100);
|
|
44060
|
+
return taRec({
|
|
44061
|
+
is_bullish: bullish,
|
|
44062
|
+
is_bearish: bearish,
|
|
44063
|
+
strength: finiteOut2(strength) ?? 0
|
|
44064
|
+
});
|
|
44065
|
+
}
|
|
44066
|
+
momentumDivergence(site, price, momentumFast, momentumSlow) {
|
|
44067
|
+
const ph = this.windowFor(`${site}:price`, price);
|
|
44068
|
+
const fh = this.windowFor(`${site}:fast`, momentumFast);
|
|
44069
|
+
const sh = this.windowFor(`${site}:slow`, momentumSlow);
|
|
44070
|
+
const off = taRec({ divergence_type: "none", strength: 0, bars_since: 0 });
|
|
44071
|
+
if (ph.length < 2 || fh.length < 2 || sh.length < 2)
|
|
44072
|
+
return off;
|
|
44073
|
+
const pv = ph.slice(-2).filter((v) => v !== null);
|
|
44074
|
+
const fv = fh.slice(-2).filter((v) => v !== null);
|
|
44075
|
+
const sv = sh.slice(-2).filter((v) => v !== null);
|
|
44076
|
+
if (pv.length < 2 || fv.length < 2 || sv.length < 2)
|
|
44077
|
+
return off;
|
|
44078
|
+
const priceLower = pv[1] < pv[0];
|
|
44079
|
+
const fastHigher = fv[1] > fv[0];
|
|
44080
|
+
const slowHigher = sv[1] > sv[0];
|
|
44081
|
+
const bullish = priceLower && fastHigher && slowHigher;
|
|
44082
|
+
const bearish = !priceLower && !fastHigher && !slowHigher;
|
|
44083
|
+
const type = bullish ? "bullish" : bearish ? "bearish" : "none";
|
|
44084
|
+
const strength = Math.min(1, Math.abs(fv[1] - fv[0]) / 100);
|
|
44085
|
+
return taRec({ divergence_type: type, strength: finiteOut2(strength) ?? 0, bars_since: 1 });
|
|
44086
|
+
}
|
|
44087
|
+
spreadAnalysis(site, bid, ask, period) {
|
|
44088
|
+
const bh = this.windowFor(`${site}:bid`, bid);
|
|
44089
|
+
const ah = this.windowFor(`${site}:ask`, ask);
|
|
44090
|
+
const n = this.coerceTaInt(period, "ta.spread_analysis() requires 3 arguments");
|
|
44091
|
+
const off = taRec({ avg_spread: 0, spread_percent: 0, spread_trend: "stable" });
|
|
44092
|
+
if (bh.length < n || ah.length < n || n <= 0)
|
|
44093
|
+
return off;
|
|
44094
|
+
const bSlice = bh.slice(-n);
|
|
44095
|
+
const aSlice = ah.slice(-n);
|
|
44096
|
+
const spreads = [];
|
|
44097
|
+
for (let i = 0;i < n; i++) {
|
|
44098
|
+
const b = bSlice[i] ?? 0;
|
|
44099
|
+
const a = aSlice[i] ?? 0;
|
|
44100
|
+
if (a > b && b > 0)
|
|
44101
|
+
spreads.push(a - b);
|
|
44102
|
+
}
|
|
44103
|
+
if (spreads.length === 0)
|
|
44104
|
+
return off;
|
|
44105
|
+
const avg = spreads.reduce((a, b) => a + b, 0) / spreads.length;
|
|
44106
|
+
const askOld = TaEngine.oldest(ah);
|
|
44107
|
+
const bidOld = TaEngine.oldest(bh);
|
|
44108
|
+
const mid = askOld !== null && bidOld !== null ? (askOld + bidOld) / 2 : 100;
|
|
44109
|
+
const pct = mid > 0 ? avg / mid * 100 : 0;
|
|
44110
|
+
let trend = "stable";
|
|
44111
|
+
if (spreads.length >= 2) {
|
|
44112
|
+
const first = spreads[0];
|
|
44113
|
+
const last = spreads[spreads.length - 1];
|
|
44114
|
+
if (last > first * 1.1)
|
|
44115
|
+
trend = "increasing";
|
|
44116
|
+
else if (last < first * 0.9)
|
|
44117
|
+
trend = "decreasing";
|
|
44118
|
+
}
|
|
44119
|
+
return taRec({
|
|
44120
|
+
avg_spread: finiteOut2(avg) ?? 0,
|
|
44121
|
+
spread_percent: finiteOut2(pct) ?? 0,
|
|
44122
|
+
spread_trend: trend
|
|
44123
|
+
});
|
|
44124
|
+
}
|
|
44125
|
+
employmentCycleIndicator(site, cyclical, defensive, unemployment) {
|
|
44126
|
+
const ch = this.windowFor(`${site}:cyc`, cyclical);
|
|
44127
|
+
const dh = this.windowFor(`${site}:def`, defensive);
|
|
44128
|
+
const uh = this.windowFor(`${site}:unemp`, unemployment);
|
|
44129
|
+
if (ch.length === 0 || dh.length === 0 || uh.length === 0)
|
|
44130
|
+
return "mid_cycle";
|
|
44131
|
+
const cNew = ch[0];
|
|
44132
|
+
const cOld = TaEngine.oldest(ch);
|
|
44133
|
+
const dNew = dh[0];
|
|
44134
|
+
const dOld = TaEngine.oldest(dh);
|
|
44135
|
+
const cycPerf = cNew !== null && cOld !== null && cNew !== 0 ? (cOld - cNew) / cNew : 0;
|
|
44136
|
+
const defPerf = dNew !== null && dOld !== null && dNew !== 0 ? (dOld - dNew) / dNew : 0;
|
|
44137
|
+
const unemp = TaEngine.oldest(uh) ?? 0.05;
|
|
44138
|
+
if (cycPerf > defPerf && unemp < 0.04)
|
|
44139
|
+
return "early_cycle";
|
|
44140
|
+
if (cycPerf > defPerf && unemp < 0.06)
|
|
44141
|
+
return "mid_cycle";
|
|
44142
|
+
if (cycPerf < defPerf && unemp > 0.05)
|
|
44143
|
+
return "late_cycle";
|
|
44144
|
+
return "recession";
|
|
44145
|
+
}
|
|
44146
|
+
gdpGrowthProxy(site, breadth, volume, momentum) {
|
|
44147
|
+
const bh = this.windowFor(`${site}:breadth`, breadth);
|
|
44148
|
+
const vh = this.windowFor(`${site}:volume`, volume);
|
|
44149
|
+
const mh = this.windowFor(`${site}:momentum`, momentum);
|
|
44150
|
+
if (bh.length === 0 || vh.length === 0 || mh.length === 0)
|
|
44151
|
+
return 0;
|
|
44152
|
+
const b = TaEngine.oldest(bh) ?? 0.5;
|
|
44153
|
+
const bScore = b * 2 - 1;
|
|
44154
|
+
const vNew = vh[0];
|
|
44155
|
+
const vOld = TaEngine.oldest(vh);
|
|
44156
|
+
const vChange = vNew !== null && vOld !== null && vNew !== 0 ? (vOld - vNew) / vNew * 100 : 0;
|
|
44157
|
+
const m = TaEngine.oldest(mh) ?? 0;
|
|
44158
|
+
const gdp = bScore * 1.5 + vChange / 100 + m / 100;
|
|
44159
|
+
return Math.max(-2, Math.min(4, gdp));
|
|
44160
|
+
}
|
|
44161
|
+
inflationProxyIndicator(site, usdIndex, commodities, bondYields) {
|
|
44162
|
+
const uh = this.windowFor(`${site}:usd`, usdIndex);
|
|
44163
|
+
const ch = this.windowFor(`${site}:comm`, commodities);
|
|
44164
|
+
const yh = this.windowFor(`${site}:yield`, bondYields);
|
|
44165
|
+
if (uh.length === 0 || ch.length === 0 || yh.length === 0)
|
|
44166
|
+
return 0;
|
|
44167
|
+
const uNew = uh[0];
|
|
44168
|
+
const uOld = TaEngine.oldest(uh);
|
|
44169
|
+
const usdChange = uNew !== null && uOld !== null && uNew !== 0 ? -((uOld - uNew) / uNew) * 100 : 0;
|
|
44170
|
+
const cNew = ch[0];
|
|
44171
|
+
const cOld = TaEngine.oldest(ch);
|
|
44172
|
+
const commChange = cNew !== null && cOld !== null && cNew !== 0 ? (cOld - cNew) / cNew * 100 : 0;
|
|
44173
|
+
const yNew = yh[0];
|
|
44174
|
+
const yOld = TaEngine.oldest(yh);
|
|
44175
|
+
const yieldsChange = yNew !== null && yOld !== null ? yOld - yNew : 0;
|
|
44176
|
+
const pressure = usdChange * 0.3 + commChange * 0.4 + yieldsChange * 0.3;
|
|
44177
|
+
return Math.max(-100, Math.min(100, pressure * 10));
|
|
44178
|
+
}
|
|
44179
|
+
expectedValue(returns, probabilities) {
|
|
44180
|
+
if (returns.length !== probabilities.length)
|
|
44181
|
+
return 0;
|
|
44182
|
+
let totalProb = 0;
|
|
44183
|
+
for (const p of probabilities)
|
|
44184
|
+
totalProb += p;
|
|
44185
|
+
if (totalProb === 0)
|
|
44186
|
+
return 0;
|
|
44187
|
+
let ev = 0;
|
|
44188
|
+
for (let i = 0;i < returns.length; i++)
|
|
44189
|
+
ev += returns[i] * probabilities[i];
|
|
44190
|
+
return finiteOut2(ev / totalProb) ?? 0;
|
|
44191
|
+
}
|
|
42705
44192
|
volumeProfileHigh(prices, volumes) {
|
|
42706
44193
|
if (prices.length === 0 || volumes.length === 0 || prices.length !== volumes.length)
|
|
42707
44194
|
return 0;
|
|
@@ -42774,19 +44261,27 @@ class TaEngine {
|
|
|
42774
44261
|
const sens = Number.isFinite(sensitivity) ? sensitivity : 0.3;
|
|
42775
44262
|
let st = this.volThrustSites.get(site);
|
|
42776
44263
|
if (st === undefined) {
|
|
42777
|
-
st = {
|
|
44264
|
+
st = { closes: [], volume: null, sma: null, nClose: 0, nVolume: 0, nSma: 0 };
|
|
42778
44265
|
this.volThrustSites.set(site, st);
|
|
42779
44266
|
}
|
|
42780
|
-
|
|
42781
|
-
|
|
42782
|
-
|
|
42783
|
-
|
|
44267
|
+
if (!(close === null && st.nClose === 0)) {
|
|
44268
|
+
pushCap(st.closes, finiteCell2(close), 2);
|
|
44269
|
+
st.nClose += 1;
|
|
44270
|
+
}
|
|
44271
|
+
if (!(volume === null && st.nVolume === 0)) {
|
|
44272
|
+
st.volume = finiteCell2(volume);
|
|
44273
|
+
st.nVolume += 1;
|
|
44274
|
+
}
|
|
44275
|
+
if (!(volSma === null && st.nSma === 0)) {
|
|
44276
|
+
st.sma = finiteCell2(volSma);
|
|
44277
|
+
st.nSma += 1;
|
|
44278
|
+
}
|
|
44279
|
+
if (st.nClose < 1 || st.nVolume < 1 || st.nSma < 1)
|
|
42784
44280
|
return 0;
|
|
42785
|
-
const
|
|
42786
|
-
const
|
|
42787
|
-
const
|
|
42788
|
-
const
|
|
42789
|
-
const vsVal = numOr(this.nf(st.sma, -1), 1000);
|
|
44281
|
+
const cVal = st.closes[st.closes.length - 1] ?? 100;
|
|
44282
|
+
const cPrev = st.closes.length > 1 ? st.closes[st.closes.length - 2] ?? 100 : 100;
|
|
44283
|
+
const vVal = st.volume ?? 1000;
|
|
44284
|
+
const vsVal = st.sma ?? 1000;
|
|
42790
44285
|
const spike = vVal > vsVal * (1 + sens);
|
|
42791
44286
|
const move = cPrev !== 0 ? Math.abs(cVal - cPrev) / cPrev > 0.01 : false;
|
|
42792
44287
|
return spike && move ? 1 : 0;
|
|
@@ -43279,7 +44774,63 @@ var TA_METHODS = new Set([
|
|
|
43279
44774
|
"volume_momentum",
|
|
43280
44775
|
"volume_profile_high",
|
|
43281
44776
|
"volume_profile_low",
|
|
43282
|
-
"volume_thrust"
|
|
44777
|
+
"volume_thrust",
|
|
44778
|
+
"sma_weighted",
|
|
44779
|
+
"apo",
|
|
44780
|
+
"atr_normalized",
|
|
44781
|
+
"beta",
|
|
44782
|
+
"r_squared",
|
|
44783
|
+
"comovement",
|
|
44784
|
+
"skewness",
|
|
44785
|
+
"kurtosis",
|
|
44786
|
+
"volume_weighted_momentum",
|
|
44787
|
+
"parkinson",
|
|
44788
|
+
"garman_klass",
|
|
44789
|
+
"mean_reversion_score",
|
|
44790
|
+
"market_condition",
|
|
44791
|
+
"order_flow_imbalance",
|
|
44792
|
+
"liquidity_score",
|
|
44793
|
+
"fear_greed_index",
|
|
44794
|
+
"crowd_sentiment",
|
|
44795
|
+
"smart_money_flow",
|
|
44796
|
+
"trend_confirmation_score",
|
|
44797
|
+
"max_loss_level",
|
|
44798
|
+
"profit_lock_level",
|
|
44799
|
+
"position_sizing",
|
|
44800
|
+
"kelly_criterion",
|
|
44801
|
+
"risk_reward_ratio",
|
|
44802
|
+
"risk_reward_asymmetry",
|
|
44803
|
+
"probability_of_movement",
|
|
44804
|
+
"trend_strength",
|
|
44805
|
+
"breakeven_level",
|
|
44806
|
+
"market_structure_pivot",
|
|
44807
|
+
"position_sizing_score",
|
|
44808
|
+
"trailing_exit_level",
|
|
44809
|
+
"optimal_entry_zone",
|
|
44810
|
+
"mean_reversion_entry",
|
|
44811
|
+
"multi_timeframe_signal",
|
|
44812
|
+
"market_timing_index",
|
|
44813
|
+
"regime_adaptive_signal",
|
|
44814
|
+
"strategy_score",
|
|
44815
|
+
"breakout_detection",
|
|
44816
|
+
"ema_cross_signal",
|
|
44817
|
+
"momentum_filter",
|
|
44818
|
+
"volatility_regime",
|
|
44819
|
+
"economic_impact_score",
|
|
44820
|
+
"contrarian_signal",
|
|
44821
|
+
"drawdown_recovery_level",
|
|
44822
|
+
"pivot_point_levels",
|
|
44823
|
+
"volatility_regime_score",
|
|
44824
|
+
"correlation_filter",
|
|
44825
|
+
"advanced_breakout_detector",
|
|
44826
|
+
"pullback_bounce_level",
|
|
44827
|
+
"divergence_detector",
|
|
44828
|
+
"momentum_divergence",
|
|
44829
|
+
"spread_analysis",
|
|
44830
|
+
"employment_cycle_indicator",
|
|
44831
|
+
"gdp_growth_proxy",
|
|
44832
|
+
"inflation_proxy_indicator",
|
|
44833
|
+
"expected_value"
|
|
43283
44834
|
]);
|
|
43284
44835
|
var TA_BARE_ATTRS = new Set([
|
|
43285
44836
|
"accdist",
|
|
@@ -43467,6 +45018,13 @@ function emitCall2(ctx, node, visit) {
|
|
|
43467
45018
|
ctx.needsHeikinashi = true;
|
|
43468
45019
|
return `"__HEIKINASHI__"`;
|
|
43469
45020
|
}
|
|
45021
|
+
if (name === "ticker_inherit") {
|
|
45022
|
+
const fallback = pick(args, 0, ["ticker", "tickerid", "from", "source"], `"SYMBOL"`);
|
|
45023
|
+
return pick(args, 1, ["symbol", "ticker"], fallback);
|
|
45024
|
+
}
|
|
45025
|
+
if (name === "renko" || name === "kagi" || name === "linebreak" || name === "pointfigure") {
|
|
45026
|
+
return pick(args, 0, ["ticker", "tickerid", "symbol"], `"SYMBOL"`);
|
|
45027
|
+
}
|
|
43470
45028
|
if (name.startsWith("ticker_")) {
|
|
43471
45029
|
return pick(args, 0, ["symbol", "ticker", "tickerid"], `"SYMBOL"`);
|
|
43472
45030
|
}
|
|
@@ -43624,6 +45182,23 @@ function hasArg(args, index, names) {
|
|
|
43624
45182
|
}
|
|
43625
45183
|
return index >= 0 && index < args.pos.length;
|
|
43626
45184
|
}
|
|
45185
|
+
var BARE_SERIES_NAMES = new Set([
|
|
45186
|
+
"open",
|
|
45187
|
+
"high",
|
|
45188
|
+
"low",
|
|
45189
|
+
"close",
|
|
45190
|
+
"volume",
|
|
45191
|
+
"hl2",
|
|
45192
|
+
"hlc3",
|
|
45193
|
+
"ohlc4",
|
|
45194
|
+
"hlcc4",
|
|
45195
|
+
"time",
|
|
45196
|
+
"time_close"
|
|
45197
|
+
]);
|
|
45198
|
+
function hasSeriesArg(args) {
|
|
45199
|
+
const isSeries = (n) => n.kind === "Name" && BARE_SERIES_NAMES.has(n.id);
|
|
45200
|
+
return args.posNodes.some(isSeries) || Object.values(args.kwNodes).some(isSeries);
|
|
45201
|
+
}
|
|
43627
45202
|
function hasAnyKw(args, names) {
|
|
43628
45203
|
return names.some((n) => Object.hasOwn(args.kw, n));
|
|
43629
45204
|
}
|
|
@@ -43636,9 +45211,15 @@ function finiteOr2(expr, fb) {
|
|
|
43636
45211
|
function cellOf(expr) {
|
|
43637
45212
|
return `((__c) => (__c == null ? null : typeof __c === "boolean" ? (__c ? 1 : 0) : (typeof __c === "number" && Number.isFinite(__c) ? __c : null)))(${expr})`;
|
|
43638
45213
|
}
|
|
45214
|
+
function arrOrCell(expr) {
|
|
45215
|
+
return `((__v) => (__v != null && typeof __v === "object" ? __v : (__v == null ? null : typeof __v === "boolean" ? (__v ? 1 : 0) : (typeof __v === "number" && Number.isFinite(__v) ? __v : null))))(${expr})`;
|
|
45216
|
+
}
|
|
43639
45217
|
function cellList(expr) {
|
|
43640
45218
|
return `(() => { const __v = ${expr}; const __cell = (e) => (e == null ? null : typeof e === "boolean" ? (e ? 1 : 0) : (typeof e === "number" && Number.isFinite(e) ? e : null)); if (__v != null && typeof __v.size === "function" && typeof __v.get === "function") { const __n = __v.size(); const __o = []; for (let __i = 0; __i < __n; __i++) __o.push(__cell(__v.get(__i))); return __o; } return [__cell(__v)]; })()`;
|
|
43641
45219
|
}
|
|
45220
|
+
function cellLast(expr) {
|
|
45221
|
+
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); })()`;
|
|
45222
|
+
}
|
|
43642
45223
|
var DRAW_KINDS = new Set(["label", "line", "box", "table", "polyline", "linefill"]);
|
|
43643
45224
|
var ARRAY_SIGS = {
|
|
43644
45225
|
new: [["size"], ["initial_value", "initial"]],
|
|
@@ -44018,6 +45599,8 @@ function emitDraw(ctx, name, methodSrc, args) {
|
|
|
44018
45599
|
code = `__h.draw.box_new(__bar_idx, ${pick(args, 0, ["left"], "0")}, ${pick(args, 1, ["top"], "0")}, ${pick(args, 2, ["right"], "0")}, ${pick(args, 3, ["bottom"], "0")})`;
|
|
44019
45600
|
} else if (kind === "polyline") {
|
|
44020
45601
|
code = `__h.draw.polyline_new(__bar_idx, ${pick(args, 0, ["points"], "null")})`;
|
|
45602
|
+
} else if (kind === "table") {
|
|
45603
|
+
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")})`;
|
|
44021
45604
|
} else if (kind === "linefill") {
|
|
44022
45605
|
const color = hasArg(args, 2, ["color"]) ? pick(args, 2, ["color"], "null") : "null";
|
|
44023
45606
|
code = `__h.draw.linefill_new(__bar_idx, ${pick(args, 0, ["id1", "line1"], "null")}, ${pick(args, 1, ["id2", "line2"], "null")}, ${color})`;
|
|
@@ -44640,6 +46223,9 @@ function allocSite(ctx) {
|
|
|
44640
46223
|
function taCall(method, site, parts) {
|
|
44641
46224
|
return `__h.ta.${method}(${site}, ${parts.join(", ")})`;
|
|
44642
46225
|
}
|
|
46226
|
+
function taPure(method, parts) {
|
|
46227
|
+
return `__h.ta.${method}(${parts.join(", ")})`;
|
|
46228
|
+
}
|
|
44643
46229
|
function emitTa(ctx, method, args) {
|
|
44644
46230
|
if (!TA_METHODS.has(method))
|
|
44645
46231
|
return "null";
|
|
@@ -45063,16 +46649,30 @@ function emitTa(ctx, method, args) {
|
|
|
45063
46649
|
]);
|
|
45064
46650
|
}
|
|
45065
46651
|
if (method === "stoch_smooth") {
|
|
45066
|
-
return
|
|
46652
|
+
return taCall("stochSmooth", site, [
|
|
46653
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
46654
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
46655
|
+
cellOf(pick(args, 2, ["close"], "null")),
|
|
46656
|
+
cellOf(pick(args, 3, ["period", "length"], "null")),
|
|
46657
|
+
cellOf(pick(args, 4, ["smooth_k", "k"], "null")),
|
|
46658
|
+
cellOf(pick(args, 5, ["smooth_d", "d"], "null"))
|
|
46659
|
+
]);
|
|
45067
46660
|
}
|
|
45068
46661
|
if (method === "engulfing") {
|
|
45069
|
-
return `(() => { ${cellOf(pick(args, 0, ["open"], "null"))}; ${cellOf(pick(args, 1, ["high"], "null"))}; ${cellOf(pick(args, 2, ["low"], "null"))}; ${cellOf(pick(args, 3, ["close"], "null"))}; return __h.ta.engulfing(); })()`;
|
|
46662
|
+
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); })()`;
|
|
45070
46663
|
}
|
|
45071
46664
|
if (method === "inside_bar_pattern") {
|
|
45072
|
-
return
|
|
46665
|
+
return taCall("insideBarPattern", site, [
|
|
46666
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
46667
|
+
cellOf(pick(args, 1, ["low"], "null"))
|
|
46668
|
+
]);
|
|
45073
46669
|
}
|
|
45074
46670
|
if (method === "double_top_bottom") {
|
|
45075
|
-
return
|
|
46671
|
+
return taCall("doubleTopBottom", site, [
|
|
46672
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
46673
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
46674
|
+
cellOf(pick(args, 2, ["period", "length"], "null"))
|
|
46675
|
+
]);
|
|
45076
46676
|
}
|
|
45077
46677
|
if (method === "voi") {
|
|
45078
46678
|
return `__h.ta.voi(${cellOf(pick(args, 0, ["buy_volume", "buy"], "null"))}, ${cellOf(pick(args, 1, ["sell_volume", "sell"], "null"))})`;
|
|
@@ -45085,7 +46685,10 @@ function emitTa(ctx, method, args) {
|
|
|
45085
46685
|
}
|
|
45086
46686
|
if (method === "rsi_divergence") {
|
|
45087
46687
|
const period = `((__n) => (__n == null ? 0 : __n))(${cellOf(pick(args, 1, ["period", "length"], "null"))})`;
|
|
45088
|
-
return
|
|
46688
|
+
return taCall("rsiDivergence", site, [
|
|
46689
|
+
cellLast(pick(args, 0, ["rsi_series", "series", "source"], "null")),
|
|
46690
|
+
period
|
|
46691
|
+
]);
|
|
45089
46692
|
}
|
|
45090
46693
|
if (method === "cumulative_delta") {
|
|
45091
46694
|
return taCall("cumulativeDelta", site, [
|
|
@@ -45120,6 +46723,368 @@ function emitTa(ctx, method, args) {
|
|
|
45120
46723
|
`((__n) => (__n == null ? 0.3 : __n))(${sens})`
|
|
45121
46724
|
]);
|
|
45122
46725
|
}
|
|
46726
|
+
if (method === "sma_weighted") {
|
|
46727
|
+
return taCall("smaWeighted", site, [
|
|
46728
|
+
cellOf(pick(args, 0, ["series", "source"], "null")),
|
|
46729
|
+
cellOf(pick(args, 1, ["period", "length"], "null")),
|
|
46730
|
+
pick(args, 2, ["weight_type", "weight"], '"linear"')
|
|
46731
|
+
]);
|
|
46732
|
+
}
|
|
46733
|
+
if (method === "apo") {
|
|
46734
|
+
return taCall("apo", site, [
|
|
46735
|
+
cellOf(pick(args, 0, ["series", "source"], "null")),
|
|
46736
|
+
cellOf(pick(args, 1, ["fast_period", "fast"], "null")),
|
|
46737
|
+
cellOf(pick(args, 2, ["slow_period", "slow"], "null"))
|
|
46738
|
+
]);
|
|
46739
|
+
}
|
|
46740
|
+
if (method === "atr_normalized") {
|
|
46741
|
+
return taCall("atrNormalized", site, [
|
|
46742
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
46743
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
46744
|
+
cellOf(pick(args, 2, ["close"], "null")),
|
|
46745
|
+
cellOf(pick(args, 3, ["period", "length"], "null"))
|
|
46746
|
+
]);
|
|
46747
|
+
}
|
|
46748
|
+
if (method === "beta" || method === "r_squared" || method === "comovement") {
|
|
46749
|
+
const fn = method === "beta" ? "beta" : method === "r_squared" ? "rSquared" : "comovement";
|
|
46750
|
+
return taCall(fn, site, [
|
|
46751
|
+
cellOf(pick(args, 0, ["series1", "series", "source"], "null")),
|
|
46752
|
+
cellOf(pick(args, 1, ["series2", "series_b", "other"], "null")),
|
|
46753
|
+
cellOf(pick(args, 2, ["length", "period"], "null"))
|
|
46754
|
+
]);
|
|
46755
|
+
}
|
|
46756
|
+
if (method === "skewness" || method === "kurtosis") {
|
|
46757
|
+
return taCall(method, site, [
|
|
46758
|
+
cellOf(pick(args, 0, ["series", "source"], "null")),
|
|
46759
|
+
cellOf(pick(args, 1, ["period", "length"], "null"))
|
|
46760
|
+
]);
|
|
46761
|
+
}
|
|
46762
|
+
if (method === "volume_weighted_momentum") {
|
|
46763
|
+
return taCall("volumeWeightedMomentum", site, [
|
|
46764
|
+
cellOf(pick(args, 0, ["series", "source"], "null")),
|
|
46765
|
+
cellOf(pick(args, 1, ["volume"], "null")),
|
|
46766
|
+
cellOf(pick(args, 2, ["length", "period"], "null"))
|
|
46767
|
+
]);
|
|
46768
|
+
}
|
|
46769
|
+
if (method === "parkinson") {
|
|
46770
|
+
if (hasSeriesArg(args))
|
|
46771
|
+
return "null";
|
|
46772
|
+
return `__h.ta.parkinson(${cellOf(pick(args, 0, ["high"], "null"))}, ${cellOf(pick(args, 1, ["low"], "null"))})`;
|
|
46773
|
+
}
|
|
46774
|
+
if (method === "garman_klass") {
|
|
46775
|
+
if (hasSeriesArg(args))
|
|
46776
|
+
return "null";
|
|
46777
|
+
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"))})`;
|
|
46778
|
+
}
|
|
46779
|
+
if (method === "mean_reversion_score") {
|
|
46780
|
+
return taCall("meanReversionScore", site, [
|
|
46781
|
+
cellOf(pick(args, 0, ["close", "source"], "null")),
|
|
46782
|
+
cellOf(pick(args, 1, ["sma"], "null")),
|
|
46783
|
+
cellOf(pick(args, 2, ["stdev", "std_dev"], "null")),
|
|
46784
|
+
cellOf(pick(args, 3, ["period", "length"], "null"))
|
|
46785
|
+
]);
|
|
46786
|
+
}
|
|
46787
|
+
if (method === "market_condition") {
|
|
46788
|
+
return taCall("marketCondition", site, [
|
|
46789
|
+
cellOf(pick(args, 0, ["close", "source"], "null")),
|
|
46790
|
+
cellOf(pick(args, 1, ["atr"], "null")),
|
|
46791
|
+
cellOf(pick(args, 2, ["sma_period", "sma_length"], "null")),
|
|
46792
|
+
cellOf(pick(args, 3, ["stdev_period", "stdev_length"], "null"))
|
|
46793
|
+
]);
|
|
46794
|
+
}
|
|
46795
|
+
if (method === "order_flow_imbalance") {
|
|
46796
|
+
return taCall("orderFlowImbalance", site, [
|
|
46797
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
46798
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
46799
|
+
cellOf(pick(args, 2, ["close"], "null")),
|
|
46800
|
+
cellOf(pick(args, 3, ["volume"], "null")),
|
|
46801
|
+
cellOf(pick(args, 4, ["period", "length"], "null"))
|
|
46802
|
+
]);
|
|
46803
|
+
}
|
|
46804
|
+
if (method === "liquidity_score") {
|
|
46805
|
+
return taCall("liquidityScore", site, [
|
|
46806
|
+
cellOf(pick(args, 0, ["volume"], "null")),
|
|
46807
|
+
cellOf(pick(args, 1, ["volatility"], "null")),
|
|
46808
|
+
cellOf(pick(args, 2, ["spread"], "null")),
|
|
46809
|
+
cellOf(pick(args, 3, ["period", "length"], "null"))
|
|
46810
|
+
]);
|
|
46811
|
+
}
|
|
46812
|
+
if (method === "fear_greed_index") {
|
|
46813
|
+
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"))})`;
|
|
46814
|
+
}
|
|
46815
|
+
if (method === "crowd_sentiment") {
|
|
46816
|
+
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"))})`;
|
|
46817
|
+
}
|
|
46818
|
+
if (method === "smart_money_flow") {
|
|
46819
|
+
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"))})`;
|
|
46820
|
+
}
|
|
46821
|
+
if (method === "trend_confirmation_score") {
|
|
46822
|
+
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"))})`;
|
|
46823
|
+
}
|
|
46824
|
+
if (method === "max_loss_level") {
|
|
46825
|
+
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"))})`;
|
|
46826
|
+
}
|
|
46827
|
+
if (method === "profit_lock_level") {
|
|
46828
|
+
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"))})`;
|
|
46829
|
+
}
|
|
46830
|
+
if (method === "position_sizing") {
|
|
46831
|
+
return taPure("positionSizing", [
|
|
46832
|
+
cellOf(pick(args, 0, ["account", "account_size"], "null")),
|
|
46833
|
+
cellOf(pick(args, 1, ["risk_pct", "risk_percent"], "null")),
|
|
46834
|
+
cellOf(pick(args, 2, ["entry", "entry_price"], "null")),
|
|
46835
|
+
cellOf(pick(args, 3, ["stop", "stop_price"], "null"))
|
|
46836
|
+
]);
|
|
46837
|
+
}
|
|
46838
|
+
if (method === "kelly_criterion") {
|
|
46839
|
+
return taPure("kellyCriterion", [
|
|
46840
|
+
cellOf(pick(args, 0, ["win_rate"], "null")),
|
|
46841
|
+
cellOf(pick(args, 1, ["avg_win"], "null")),
|
|
46842
|
+
cellOf(pick(args, 2, ["avg_loss"], "null"))
|
|
46843
|
+
]);
|
|
46844
|
+
}
|
|
46845
|
+
if (method === "risk_reward_ratio") {
|
|
46846
|
+
return taPure("riskRewardRatio", [
|
|
46847
|
+
cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
|
|
46848
|
+
cellOf(pick(args, 1, ["stop", "stop_price"], "null")),
|
|
46849
|
+
cellOf(pick(args, 2, ["target", "target_price"], "null"))
|
|
46850
|
+
]);
|
|
46851
|
+
}
|
|
46852
|
+
if (method === "risk_reward_asymmetry") {
|
|
46853
|
+
return taPure("riskRewardAsymmetry", [
|
|
46854
|
+
cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
|
|
46855
|
+
cellOf(pick(args, 1, ["stop", "stop_price"], "null")),
|
|
46856
|
+
cellOf(pick(args, 2, ["target", "target_price"], "null")),
|
|
46857
|
+
cellOf(pick(args, 3, ["win_rate"], "null"))
|
|
46858
|
+
]);
|
|
46859
|
+
}
|
|
46860
|
+
if (method === "probability_of_movement") {
|
|
46861
|
+
return taPure("probabilityOfMovement", [
|
|
46862
|
+
cellOf(pick(args, 0, ["current", "current_price"], "null")),
|
|
46863
|
+
cellOf(pick(args, 1, ["target", "target_price"], "null")),
|
|
46864
|
+
cellOf(pick(args, 2, ["atr"], "null")),
|
|
46865
|
+
cellOf(pick(args, 3, ["period", "length"], "null"))
|
|
46866
|
+
]);
|
|
46867
|
+
}
|
|
46868
|
+
if (method === "trend_strength") {
|
|
46869
|
+
return taPure("trendStrength", [
|
|
46870
|
+
cellOf(pick(args, 0, ["price", "source"], "null")),
|
|
46871
|
+
cellOf(pick(args, 1, ["adx"], "null")),
|
|
46872
|
+
cellOf(pick(args, 2, ["rsi"], "null"))
|
|
46873
|
+
]);
|
|
46874
|
+
}
|
|
46875
|
+
if (method === "breakeven_level") {
|
|
46876
|
+
return taPure("breakevenLevel", [
|
|
46877
|
+
cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
|
|
46878
|
+
cellOf(pick(args, 1, ["quantity", "qty"], "null")),
|
|
46879
|
+
cellOf(pick(args, 2, ["commission"], "null")),
|
|
46880
|
+
cellOf(pick(args, 3, ["slippage"], "null")),
|
|
46881
|
+
cellOf(pick(args, 4, ["direction"], "null"))
|
|
46882
|
+
]);
|
|
46883
|
+
}
|
|
46884
|
+
if (method === "market_structure_pivot") {
|
|
46885
|
+
return taCall("marketStructurePivot", site, [
|
|
46886
|
+
arrOrCell(pick(args, 0, ["high_list", "high"], "null")),
|
|
46887
|
+
arrOrCell(pick(args, 1, ["low_list", "low"], "null")),
|
|
46888
|
+
cellOf(pick(args, 3, ["period", "left", "left_bars"], "null")),
|
|
46889
|
+
cellOf(pick(args, 4, ["mode", "right", "right_bars"], "null"))
|
|
46890
|
+
]);
|
|
46891
|
+
}
|
|
46892
|
+
if (method === "position_sizing_score") {
|
|
46893
|
+
return taPure("positionSizingScore", [
|
|
46894
|
+
cellOf(pick(args, 0, ["account_risk", "risk"], "null")),
|
|
46895
|
+
cellOf(pick(args, 1, ["volatility"], "null")),
|
|
46896
|
+
cellOf(pick(args, 2, ["conviction"], "null")),
|
|
46897
|
+
cellOf(pick(args, 3, ["correlation"], "null"))
|
|
46898
|
+
]);
|
|
46899
|
+
}
|
|
46900
|
+
if (method === "trailing_exit_level") {
|
|
46901
|
+
return taPure("trailingExitLevel", [
|
|
46902
|
+
cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
|
|
46903
|
+
cellOf(pick(args, 1, ["current", "current_price"], "null")),
|
|
46904
|
+
cellOf(pick(args, 2, ["atr"], "null")),
|
|
46905
|
+
cellOf(pick(args, 3, ["multiplier", "mult"], "null")),
|
|
46906
|
+
cellOf(pick(args, 4, ["step"], "null"))
|
|
46907
|
+
]);
|
|
46908
|
+
}
|
|
46909
|
+
if (method === "optimal_entry_zone") {
|
|
46910
|
+
return taCall("optimalEntryZone", site, [arrOrCell(pick(args, 2, ["close"], "null"))]);
|
|
46911
|
+
}
|
|
46912
|
+
if (method === "mean_reversion_entry") {
|
|
46913
|
+
return taCall("meanReversionEntry", site, [
|
|
46914
|
+
arrOrCell(pick(args, 0, ["price", "source"], "null")),
|
|
46915
|
+
arrOrCell(pick(args, 1, ["sma"], "null")),
|
|
46916
|
+
arrOrCell(pick(args, 2, ["stdev", "std_dev"], "null")),
|
|
46917
|
+
cellOf(pick(args, 4, ["threshold"], "null"))
|
|
46918
|
+
]);
|
|
46919
|
+
}
|
|
46920
|
+
if (method === "multi_timeframe_signal") {
|
|
46921
|
+
return taPure("multiTimeframeSignal", [
|
|
46922
|
+
cellOf(pick(args, 0, ["s1", "signal1"], "null")),
|
|
46923
|
+
cellOf(pick(args, 1, ["s2", "signal2"], "null")),
|
|
46924
|
+
cellOf(pick(args, 2, ["s3", "signal3"], "null")),
|
|
46925
|
+
cellOf(pick(args, 3, ["w1", "weight1"], "null")),
|
|
46926
|
+
cellOf(pick(args, 4, ["w2", "weight2"], "null")),
|
|
46927
|
+
cellOf(pick(args, 5, ["w3", "weight3"], "null"))
|
|
46928
|
+
]);
|
|
46929
|
+
}
|
|
46930
|
+
if (method === "market_timing_index") {
|
|
46931
|
+
return taPure("marketTimingIndex", [
|
|
46932
|
+
cellOf(pick(args, 0, ["trend"], "null")),
|
|
46933
|
+
cellOf(pick(args, 1, ["momentum"], "null")),
|
|
46934
|
+
cellOf(pick(args, 2, ["volatility"], "null")),
|
|
46935
|
+
cellOf(pick(args, 3, ["sentiment"], "null"))
|
|
46936
|
+
]);
|
|
46937
|
+
}
|
|
46938
|
+
if (method === "regime_adaptive_signal") {
|
|
46939
|
+
return taPure("regimeAdaptiveSignal", [
|
|
46940
|
+
cellOf(pick(args, 0, ["signal_strength", "strength"], "null")),
|
|
46941
|
+
pick(args, 1, ["volatility_regime", "vol_regime"], '""'),
|
|
46942
|
+
pick(args, 2, ["trend_regime"], '""')
|
|
46943
|
+
]);
|
|
46944
|
+
}
|
|
46945
|
+
if (method === "strategy_score") {
|
|
46946
|
+
return taPure("strategyScore", [
|
|
46947
|
+
cellOf(pick(args, 0, ["rsi"], "null")),
|
|
46948
|
+
cellOf(pick(args, 1, ["macd"], "null")),
|
|
46949
|
+
cellOf(pick(args, 2, ["ema_cross"], "null")),
|
|
46950
|
+
cellOf(pick(args, 3, ["trend"], "null"))
|
|
46951
|
+
]);
|
|
46952
|
+
}
|
|
46953
|
+
if (method === "breakout_detection") {
|
|
46954
|
+
return taPure("breakoutDetection", [
|
|
46955
|
+
cellOf(pick(args, 0, ["close", "source"], "null")),
|
|
46956
|
+
cellOf(pick(args, 1, ["resistance"], "null")),
|
|
46957
|
+
cellOf(pick(args, 2, ["support"], "null"))
|
|
46958
|
+
]);
|
|
46959
|
+
}
|
|
46960
|
+
if (method === "ema_cross_signal") {
|
|
46961
|
+
return taCall("emaCrossSignal", site, [
|
|
46962
|
+
cellOf(pick(args, 0, ["fast_ema", "fast"], "null")),
|
|
46963
|
+
cellOf(pick(args, 1, ["slow_ema", "slow"], "null")),
|
|
46964
|
+
cellOf(pick(args, 2, ["threshold"], "null"))
|
|
46965
|
+
]);
|
|
46966
|
+
}
|
|
46967
|
+
if (method === "momentum_filter") {
|
|
46968
|
+
return taCall("momentumFilter", site, [
|
|
46969
|
+
cellOf(pick(args, 0, ["momentum_raw", "momentum"], "null")),
|
|
46970
|
+
cellOf(pick(args, 1, ["volume"], "null")),
|
|
46971
|
+
cellOf(pick(args, 2, ["period", "length"], "null"))
|
|
46972
|
+
]);
|
|
46973
|
+
}
|
|
46974
|
+
if (method === "volatility_regime") {
|
|
46975
|
+
return taCall("volatilityRegime", site, [
|
|
46976
|
+
cellOf(pick(args, 0, ["atr_series", "atr", "source"], "null")),
|
|
46977
|
+
cellOf(pick(args, 1, ["period", "length"], "null"))
|
|
46978
|
+
]);
|
|
46979
|
+
}
|
|
46980
|
+
if (method === "economic_impact_score") {
|
|
46981
|
+
return taPure("economicImpactScore", [
|
|
46982
|
+
cellOf(pick(args, 0, ["price_change"], "null")),
|
|
46983
|
+
cellOf(pick(args, 1, ["volatility"], "null")),
|
|
46984
|
+
cellOf(pick(args, 2, ["volume_change"], "null"))
|
|
46985
|
+
]);
|
|
46986
|
+
}
|
|
46987
|
+
if (method === "contrarian_signal") {
|
|
46988
|
+
return taPure("contrarianSignal", [
|
|
46989
|
+
cellOf(pick(args, 0, ["sentiment"], "null")),
|
|
46990
|
+
cellOf(pick(args, 1, ["volatility"], "null")),
|
|
46991
|
+
cellOf(pick(args, 2, ["time_since_extreme", "time_extreme"], "null"))
|
|
46992
|
+
]);
|
|
46993
|
+
}
|
|
46994
|
+
if (method === "drawdown_recovery_level") {
|
|
46995
|
+
return taPure("drawdownRecoveryLevel", [
|
|
46996
|
+
cellOf(pick(args, 0, ["peak"], "null")),
|
|
46997
|
+
cellOf(pick(args, 1, ["current", "current_price"], "null")),
|
|
46998
|
+
cellOf(pick(args, 2, ["recovery_factor", "factor"], "null")),
|
|
46999
|
+
cellOf(pick(args, 3, ["period", "length"], "null"))
|
|
47000
|
+
]);
|
|
47001
|
+
}
|
|
47002
|
+
if (method === "pivot_point_levels") {
|
|
47003
|
+
return taPure("pivotPointLevels", [
|
|
47004
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
47005
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
47006
|
+
cellOf(pick(args, 2, ["close"], "null")),
|
|
47007
|
+
pick(args, 3, ["traditional"], "true")
|
|
47008
|
+
]);
|
|
47009
|
+
}
|
|
47010
|
+
if (method === "volatility_regime_score") {
|
|
47011
|
+
return taCall("volatilityRegimeScore", site, [
|
|
47012
|
+
arrOrCell(pick(args, 0, ["atr_list", "atr"], "null")),
|
|
47013
|
+
arrOrCell(pick(args, 1, ["volatility_list", "volatility"], "null")),
|
|
47014
|
+
arrOrCell(pick(args, 2, ["vix_list", "vix"], "null")),
|
|
47015
|
+
cellOf(pick(args, 3, ["threshold"], "null"))
|
|
47016
|
+
]);
|
|
47017
|
+
}
|
|
47018
|
+
if (method === "correlation_filter") {
|
|
47019
|
+
return taCall("correlationFilter", site, [
|
|
47020
|
+
arrOrCell(pick(args, 0, ["signal1_list", "signal1", "s1"], "null")),
|
|
47021
|
+
arrOrCell(pick(args, 1, ["signal2_list", "signal2", "s2"], "null")),
|
|
47022
|
+
arrOrCell(pick(args, 2, ["signal3_list", "signal3", "s3"], "null")),
|
|
47023
|
+
cellOf(pick(args, 4, ["threshold"], "null"))
|
|
47024
|
+
]);
|
|
47025
|
+
}
|
|
47026
|
+
if (method === "advanced_breakout_detector") {
|
|
47027
|
+
return taCall("advancedBreakoutDetector", site, [
|
|
47028
|
+
arrOrCell(pick(args, 0, ["price_list", "price"], "null")),
|
|
47029
|
+
arrOrCell(pick(args, 1, ["volume_list", "volume"], "null")),
|
|
47030
|
+
cellOf(pick(args, 2, ["level"], "null")),
|
|
47031
|
+
cellOf(pick(args, 3, ["lookback"], "null")),
|
|
47032
|
+
cellOf(pick(args, 4, ["volume_multiplier", "vol_mult"], "null"))
|
|
47033
|
+
]);
|
|
47034
|
+
}
|
|
47035
|
+
if (method === "pullback_bounce_level") {
|
|
47036
|
+
return taCall("pullbackBounceLevel", site, [
|
|
47037
|
+
arrOrCell(pick(args, 0, ["high_list", "high"], "null")),
|
|
47038
|
+
arrOrCell(pick(args, 1, ["low_list", "low"], "null")),
|
|
47039
|
+
cellOf(pick(args, 3, ["trend_direction", "trend_dir"], "null")),
|
|
47040
|
+
cellOf(pick(args, 4, ["lookback"], "null"))
|
|
47041
|
+
]);
|
|
47042
|
+
}
|
|
47043
|
+
if (method === "divergence_detector") {
|
|
47044
|
+
return taCall("divergenceDetector", site, [
|
|
47045
|
+
arrOrCell(pick(args, 0, ["price_list", "price"], "null")),
|
|
47046
|
+
arrOrCell(pick(args, 1, ["indicator_list", "indicator"], "null")),
|
|
47047
|
+
cellOf(pick(args, 2, ["lookback"], "null"))
|
|
47048
|
+
]);
|
|
47049
|
+
}
|
|
47050
|
+
if (method === "momentum_divergence") {
|
|
47051
|
+
return taCall("momentumDivergence", site, [
|
|
47052
|
+
arrOrCell(pick(args, 0, ["price"], "null")),
|
|
47053
|
+
arrOrCell(pick(args, 1, ["momentum_fast", "mom_fast"], "null")),
|
|
47054
|
+
arrOrCell(pick(args, 2, ["momentum_slow", "mom_slow"], "null"))
|
|
47055
|
+
]);
|
|
47056
|
+
}
|
|
47057
|
+
if (method === "spread_analysis") {
|
|
47058
|
+
return taCall("spreadAnalysis", site, [
|
|
47059
|
+
arrOrCell(pick(args, 0, ["bid"], "null")),
|
|
47060
|
+
arrOrCell(pick(args, 1, ["ask"], "null")),
|
|
47061
|
+
cellOf(pick(args, 2, ["period", "length"], "null"))
|
|
47062
|
+
]);
|
|
47063
|
+
}
|
|
47064
|
+
if (method === "employment_cycle_indicator") {
|
|
47065
|
+
return taCall("employmentCycleIndicator", site, [
|
|
47066
|
+
arrOrCell(pick(args, 0, ["cyclical_stocks", "cyclical"], "null")),
|
|
47067
|
+
arrOrCell(pick(args, 1, ["defensive_stocks", "defensive"], "null")),
|
|
47068
|
+
arrOrCell(pick(args, 2, ["unemployment_proxy", "unemployment"], "null"))
|
|
47069
|
+
]);
|
|
47070
|
+
}
|
|
47071
|
+
if (method === "gdp_growth_proxy") {
|
|
47072
|
+
return taCall("gdpGrowthProxy", site, [
|
|
47073
|
+
arrOrCell(pick(args, 0, ["market_breadth", "breadth"], "null")),
|
|
47074
|
+
arrOrCell(pick(args, 1, ["market_volume", "volume"], "null")),
|
|
47075
|
+
arrOrCell(pick(args, 2, ["price_momentum", "momentum"], "null"))
|
|
47076
|
+
]);
|
|
47077
|
+
}
|
|
47078
|
+
if (method === "inflation_proxy_indicator") {
|
|
47079
|
+
return taCall("inflationProxyIndicator", site, [
|
|
47080
|
+
arrOrCell(pick(args, 0, ["usd_index", "usd"], "null")),
|
|
47081
|
+
arrOrCell(pick(args, 1, ["commodity_prices", "commodities"], "null")),
|
|
47082
|
+
arrOrCell(pick(args, 2, ["bond_yields", "yields"], "null"))
|
|
47083
|
+
]);
|
|
47084
|
+
}
|
|
47085
|
+
if (method === "expected_value") {
|
|
47086
|
+
return `__h.ta.expectedValue(${cellList(pick(args, 0, ["returns"], "null"))}, ${cellList(pick(args, 1, ["probabilities", "probs"], "null"))})`;
|
|
47087
|
+
}
|
|
45123
47088
|
return "null";
|
|
45124
47089
|
}
|
|
45125
47090
|
|
|
@@ -46588,6 +48553,8 @@ function naNum(v) {
|
|
|
46588
48553
|
function hold(v) {
|
|
46589
48554
|
if (v != null && typeof v === "object")
|
|
46590
48555
|
return v;
|
|
48556
|
+
if (typeof v === "string")
|
|
48557
|
+
return v;
|
|
46591
48558
|
return naNum(v);
|
|
46592
48559
|
}
|
|
46593
48560
|
function pineEq(a, b) {
|
|
@@ -47280,8 +49247,23 @@ class CompileDraw {
|
|
|
47280
49247
|
putNum(extra, "bottom", bottom);
|
|
47281
49248
|
return this.book.boxNew(n3(bar, 0), Object.keys(extra).length ? extra : undefined);
|
|
47282
49249
|
}
|
|
47283
|
-
table_new(bar) {
|
|
47284
|
-
|
|
49250
|
+
table_new(bar, position, columns, rows, bgcolor, frameColor, frameWidth, borderColor, borderWidth, forceOverlay) {
|
|
49251
|
+
const extra = {};
|
|
49252
|
+
if (position != null)
|
|
49253
|
+
extra.position = position;
|
|
49254
|
+
putNum(extra, "columns", columns);
|
|
49255
|
+
putNum(extra, "rows", rows);
|
|
49256
|
+
if (bgcolor != null)
|
|
49257
|
+
extra.bgcolor = bgcolor;
|
|
49258
|
+
if (frameColor != null)
|
|
49259
|
+
extra.frame_color = frameColor;
|
|
49260
|
+
putNum(extra, "frame_width", frameWidth);
|
|
49261
|
+
if (borderColor != null)
|
|
49262
|
+
extra.border_color = borderColor;
|
|
49263
|
+
putNum(extra, "border_width", borderWidth);
|
|
49264
|
+
if (forceOverlay != null)
|
|
49265
|
+
extra.force_overlay = forceOverlay;
|
|
49266
|
+
return this.book.tableNew(n3(bar, 0), Object.keys(extra).length ? extra : undefined);
|
|
47285
49267
|
}
|
|
47286
49268
|
polyline_new(bar, points) {
|
|
47287
49269
|
const pts = pointsOf(points);
|
|
@@ -47915,7 +49897,8 @@ class CompileStrategy {
|
|
|
47915
49897
|
open: num(open, this.mark),
|
|
47916
49898
|
high: num(high, this.mark),
|
|
47917
49899
|
low: num(low, this.mark),
|
|
47918
|
-
close: this.mark
|
|
49900
|
+
close: this.mark,
|
|
49901
|
+
time: this.time
|
|
47919
49902
|
};
|
|
47920
49903
|
this.ohlc = ohlc;
|
|
47921
49904
|
this.book.processPending(this.bar, ohlc);
|
|
@@ -47931,17 +49914,18 @@ class CompileStrategy {
|
|
|
47931
49914
|
stop: opts?.stop,
|
|
47932
49915
|
comment: opts?.comment,
|
|
47933
49916
|
oca_name: opts?.oca_name,
|
|
47934
|
-
oca_type: opts?.oca_type
|
|
49917
|
+
oca_type: opts?.oca_type,
|
|
49918
|
+
deferMarket: true
|
|
47935
49919
|
});
|
|
47936
49920
|
}
|
|
47937
49921
|
close(id, qty) {
|
|
47938
|
-
this.book.
|
|
49922
|
+
this.book.placeClose(this.bar, str(id, ""), this.mark, {
|
|
47939
49923
|
time: this.time,
|
|
47940
49924
|
qty: optNum(qty)
|
|
47941
49925
|
});
|
|
47942
49926
|
}
|
|
47943
49927
|
close_all(_comment) {
|
|
47944
|
-
this.book.
|
|
49928
|
+
this.book.placeCloseAll(this.bar, this.mark);
|
|
47945
49929
|
}
|
|
47946
49930
|
order(id, direction, qty, opts) {
|
|
47947
49931
|
this.entry(id, direction, qty, opts);
|
|
@@ -47958,7 +49942,8 @@ class CompileStrategy {
|
|
|
47958
49942
|
...parsed,
|
|
47959
49943
|
price: this.mark,
|
|
47960
49944
|
time: this.time,
|
|
47961
|
-
ohlc: this.ohlc
|
|
49945
|
+
ohlc: this.ohlc,
|
|
49946
|
+
deferMarket: true
|
|
47962
49947
|
});
|
|
47963
49948
|
}
|
|
47964
49949
|
position_size() {
|
|
@@ -48326,8 +50311,8 @@ function createCompileHelpers(opts) {
|
|
|
48326
50311
|
second: calendarSecond,
|
|
48327
50312
|
dayofweek: calendarDayofweek,
|
|
48328
50313
|
timestamp,
|
|
48329
|
-
weekOfYear,
|
|
48330
|
-
timeTradingDay,
|
|
50314
|
+
weekOfYear: calendarWeekOfYear,
|
|
50315
|
+
timeTradingDay: calendarTimeTradingDay,
|
|
48331
50316
|
timeframeInSeconds: timeframeInSecondsOrDaily,
|
|
48332
50317
|
timeframeChange,
|
|
48333
50318
|
timeClose,
|
|
@@ -48451,7 +50436,20 @@ function NA_FN(v) {
|
|
|
48451
50436
|
function utcPart(t, key) {
|
|
48452
50437
|
if (typeof t !== "number" || !Number.isFinite(t))
|
|
48453
50438
|
return null;
|
|
48454
|
-
|
|
50439
|
+
const ms = timestampToMs(t);
|
|
50440
|
+
return ms == null ? null : utcPartsFromMs(ms)[key];
|
|
50441
|
+
}
|
|
50442
|
+
function calendarWeekOfYear(t) {
|
|
50443
|
+
if (typeof t !== "number" || !Number.isFinite(t))
|
|
50444
|
+
return null;
|
|
50445
|
+
const ms = timestampToMs(t);
|
|
50446
|
+
return ms == null ? null : weekOfYear(ms);
|
|
50447
|
+
}
|
|
50448
|
+
function calendarTimeTradingDay(t) {
|
|
50449
|
+
if (typeof t !== "number" || !Number.isFinite(t))
|
|
50450
|
+
return null;
|
|
50451
|
+
const ms = timestampToMs(t);
|
|
50452
|
+
return ms == null ? null : timeTradingDay(ms);
|
|
48455
50453
|
}
|
|
48456
50454
|
function calendarYear(t) {
|
|
48457
50455
|
return utcPart(t, "year");
|
|
@@ -48885,7 +50883,8 @@ function interpretTree(tree, ohlcv, host) {
|
|
|
48885
50883
|
open: num2(env.ctx.open) ?? undefined,
|
|
48886
50884
|
high: num2(env.ctx.high) ?? undefined,
|
|
48887
50885
|
low: num2(env.ctx.low) ?? undefined,
|
|
48888
|
-
close: num2(env.ctx.close) ?? undefined
|
|
50886
|
+
close: num2(env.ctx.close) ?? undefined,
|
|
50887
|
+
time: num2(env.ctx.time) ?? undefined
|
|
48889
50888
|
});
|
|
48890
50889
|
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);
|
|
48891
50890
|
try {
|
|
@@ -49216,6 +51215,27 @@ function seriesGet(env, id) {
|
|
|
49216
51215
|
}
|
|
49217
51216
|
return env.series.get(id);
|
|
49218
51217
|
}
|
|
51218
|
+
var BARE_SERIES_NAMES2 = new Set([
|
|
51219
|
+
"open",
|
|
51220
|
+
"high",
|
|
51221
|
+
"low",
|
|
51222
|
+
"close",
|
|
51223
|
+
"volume",
|
|
51224
|
+
"hl2",
|
|
51225
|
+
"hlc3",
|
|
51226
|
+
"ohlc4",
|
|
51227
|
+
"hlcc4",
|
|
51228
|
+
"time",
|
|
51229
|
+
"time_close"
|
|
51230
|
+
]);
|
|
51231
|
+
function isSeriesExpr(value, env) {
|
|
51232
|
+
if (value.kind === "Name") {
|
|
51233
|
+
if (BARE_SERIES_NAMES2.has(value.id))
|
|
51234
|
+
return true;
|
|
51235
|
+
return seriesGet(env, value.id) != null;
|
|
51236
|
+
}
|
|
51237
|
+
return false;
|
|
51238
|
+
}
|
|
49219
51239
|
function bindName(env, id, value) {
|
|
49220
51240
|
const stored = typeof value === "number" && !Number.isFinite(value) ? NA : value;
|
|
49221
51241
|
const frame = activeFrame(env);
|
|
@@ -50399,6 +52419,33 @@ function evalCall(node, env) {
|
|
|
50399
52419
|
adjust: evalAsString(callArg(node.args, 3, ["adjust", "adjustment"]), env) ?? undefined
|
|
50400
52420
|
});
|
|
50401
52421
|
}
|
|
52422
|
+
if (fname === "ticker.inherit") {
|
|
52423
|
+
const first = evalExpr(callArg(node.args, 0, ["ticker", "tickerid", "from", "source"]), env);
|
|
52424
|
+
const secondArg = callArg(node.args, 1, ["symbol", "ticker"]);
|
|
52425
|
+
if (secondArg != null) {
|
|
52426
|
+
const target = evalExpr(secondArg, env);
|
|
52427
|
+
const sym = target instanceof TickerId ? target.symbol : typeof target === "string" ? target : env.symbol;
|
|
52428
|
+
if (first instanceof TickerId)
|
|
52429
|
+
return tickerNew(sym, first.session, first.adjust);
|
|
52430
|
+
return tickerNew(sym);
|
|
52431
|
+
}
|
|
52432
|
+
if (first instanceof TickerId) {
|
|
52433
|
+
return tickerNew(first.symbol, first.session, first.adjust);
|
|
52434
|
+
}
|
|
52435
|
+
const sym = typeof first === "string" ? first : env.symbol;
|
|
52436
|
+
return tickerNew(sym);
|
|
52437
|
+
}
|
|
52438
|
+
if (fname === "renko" || fname === "kagi" || fname === "linebreak" || fname === "pointfigure") {
|
|
52439
|
+
const raw = evalExpr(callArg(node.args, 0, ["ticker", "tickerid", "symbol"]), env);
|
|
52440
|
+
const sym = raw instanceof TickerId ? raw.symbol : typeof raw === "string" ? raw : env.symbol;
|
|
52441
|
+
if (fname === "renko")
|
|
52442
|
+
return tickerRenko(sym);
|
|
52443
|
+
if (fname === "kagi")
|
|
52444
|
+
return tickerKagi(sym);
|
|
52445
|
+
if (fname === "linebreak")
|
|
52446
|
+
return tickerLinebreak(sym);
|
|
52447
|
+
return tickerPointfigure(sym);
|
|
52448
|
+
}
|
|
50402
52449
|
const mapVal = evalMapCall(fname, node, env);
|
|
50403
52450
|
if (mapVal !== undefined)
|
|
50404
52451
|
return mapVal;
|
|
@@ -50433,7 +52480,8 @@ function evalCall(node, env) {
|
|
|
50433
52480
|
price: mark == null || !Number.isFinite(mark) ? undefined : mark,
|
|
50434
52481
|
time: num2(env.ctx.time) ?? undefined,
|
|
50435
52482
|
oca_name: evalAsString(callArg(node.args, -1, ["oca_name"]), env),
|
|
50436
|
-
oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env)
|
|
52483
|
+
oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env),
|
|
52484
|
+
deferMarket: true
|
|
50437
52485
|
});
|
|
50438
52486
|
return NA;
|
|
50439
52487
|
}
|
|
@@ -50442,13 +52490,10 @@ function evalCall(node, env) {
|
|
|
50442
52490
|
const mark = num2(env.ctx.close);
|
|
50443
52491
|
const qtyExpr = callArg(node.args, 1, ["qty"]);
|
|
50444
52492
|
const qtyRaw = qtyExpr == null ? undefined : unwrap2(evalExpr(qtyExpr, env));
|
|
50445
|
-
|
|
50446
|
-
env.
|
|
50447
|
-
|
|
50448
|
-
|
|
50449
|
-
});
|
|
50450
|
-
} else
|
|
50451
|
-
env.book.close(env.barIndex, id);
|
|
52493
|
+
env.book.placeClose(env.barIndex, id, mark ?? undefined, {
|
|
52494
|
+
time: num2(env.ctx.time) ?? undefined,
|
|
52495
|
+
qty: qtyRaw ?? undefined
|
|
52496
|
+
});
|
|
50452
52497
|
return NA;
|
|
50453
52498
|
}
|
|
50454
52499
|
if (fname === "strategy.exit") {
|
|
@@ -50468,17 +52513,12 @@ function evalCall(node, env) {
|
|
|
50468
52513
|
trail_offset: unwrap2(evalExpr(callArg(node.args, 10, ["trail_offset"]), env)),
|
|
50469
52514
|
price: num2(env.ctx.close) ?? undefined,
|
|
50470
52515
|
time: num2(env.ctx.time) ?? undefined,
|
|
50471
|
-
|
|
50472
|
-
open: num2(env.ctx.open) ?? undefined,
|
|
50473
|
-
high: num2(env.ctx.high) ?? undefined,
|
|
50474
|
-
low: num2(env.ctx.low) ?? undefined,
|
|
50475
|
-
close: num2(env.ctx.close) ?? undefined
|
|
50476
|
-
}
|
|
52516
|
+
deferMarket: true
|
|
50477
52517
|
});
|
|
50478
52518
|
return NA;
|
|
50479
52519
|
}
|
|
50480
52520
|
if (fname === "strategy.close_all") {
|
|
50481
|
-
env.book.
|
|
52521
|
+
env.book.placeCloseAll(env.barIndex, num2(env.ctx.close) ?? undefined);
|
|
50482
52522
|
return NA;
|
|
50483
52523
|
}
|
|
50484
52524
|
if (fname === "strategy.cancel") {
|
|
@@ -50500,7 +52540,8 @@ function evalCall(node, env) {
|
|
|
50500
52540
|
price: num2(env.ctx.close) ?? undefined,
|
|
50501
52541
|
time: num2(env.ctx.time) ?? undefined,
|
|
50502
52542
|
oca_name: evalAsString(callArg(node.args, -1, ["oca_name"]), env),
|
|
50503
|
-
oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env)
|
|
52543
|
+
oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env),
|
|
52544
|
+
deferMarket: true
|
|
50504
52545
|
});
|
|
50505
52546
|
return NA;
|
|
50506
52547
|
}
|
|
@@ -51725,12 +53766,12 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51725
53766
|
return NA;
|
|
51726
53767
|
return ta.percentrank.call(env.ta, site, srcArg(node, env), lenArg(node, env, 1));
|
|
51727
53768
|
}
|
|
51728
|
-
if (fname === "ta.percentile_nearest_rank") {
|
|
53769
|
+
if (fname === "ta.percentile_nearest_rank" || fname === "percentile_nearest_rank") {
|
|
51729
53770
|
if (typeof ta.percentileNearest !== "function")
|
|
51730
53771
|
return NA;
|
|
51731
53772
|
return ta.percentileNearest.call(env.ta, site, srcArg(node, env), lenArg(node, env, 1), lenOrDefault(node, env, 2, ["percentage", "percent"], 50));
|
|
51732
53773
|
}
|
|
51733
|
-
if (fname === "ta.percentile_linear_interpolation") {
|
|
53774
|
+
if (fname === "ta.percentile_linear_interpolation" || fname === "percentile_linear_interpolation") {
|
|
51734
53775
|
if (typeof ta.percentileLinear !== "function")
|
|
51735
53776
|
return NA;
|
|
51736
53777
|
return ta.percentileLinear.call(env.ta, site, srcArg(node, env), lenArg(node, env, 1), lenOrDefault(node, env, 2, ["percentage", "percent"], 50));
|
|
@@ -51845,12 +53886,6 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51845
53886
|
const r = env.ta.aroon(site, num2(env.ctx.high), num2(env.ctx.low), length ?? 14);
|
|
51846
53887
|
return tupleOf([r.down, r.up]);
|
|
51847
53888
|
}
|
|
51848
|
-
if (fname === "ta.pivot_point_levels") {
|
|
51849
|
-
if (typeof ta.pivotPoints !== "function")
|
|
51850
|
-
return NA;
|
|
51851
|
-
const r = ta.pivotPoints.call(env.ta, site, num2(env.ctx.high), num2(env.ctx.low), num2(env.ctx.close));
|
|
51852
|
-
return tupleOf([r.pp, r.r1, r.s1, r.r2, r.s2]);
|
|
51853
|
-
}
|
|
51854
53889
|
if (fname === "ta.uo" || fname === "uo") {
|
|
51855
53890
|
return env.ta.uo(site, num2(env.ctx.high), num2(env.ctx.low), num2(env.ctx.close), lenArg(node, env, 0), lenArg(node, env, 1), lenArg(node, env, 2));
|
|
51856
53891
|
}
|
|
@@ -51905,11 +53940,11 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51905
53940
|
}
|
|
51906
53941
|
if (fname === "ta.engulfing" || fname === "engulfing") {
|
|
51907
53942
|
const msg = "ta.engulfing() requires 4 arguments: open, high, low, close";
|
|
51908
|
-
unwrap2(evalExpr(wave10aArg(0, ["open"], msg), env));
|
|
53943
|
+
const open = unwrap2(evalExpr(wave10aArg(0, ["open"], msg), env));
|
|
51909
53944
|
unwrap2(evalExpr(wave10aArg(1, ["high"], msg), env));
|
|
51910
53945
|
unwrap2(evalExpr(wave10aArg(2, ["low"], msg), env));
|
|
51911
|
-
unwrap2(evalExpr(wave10aArg(3, ["close"], msg), env));
|
|
51912
|
-
return env.ta.engulfing();
|
|
53946
|
+
const close = unwrap2(evalExpr(wave10aArg(3, ["close"], msg), env));
|
|
53947
|
+
return env.ta.engulfing(site, open, close);
|
|
51913
53948
|
}
|
|
51914
53949
|
if (fname === "ta.gap_detector" || fname === "gap_detector") {
|
|
51915
53950
|
const msg = "ta.gap_detector() requires 3 arguments: high, low, prev_close";
|
|
@@ -51917,15 +53952,15 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51917
53952
|
}
|
|
51918
53953
|
if (fname === "ta.double_top_bottom" || fname === "double_top_bottom") {
|
|
51919
53954
|
const msg = "ta.double_top_bottom() requires 3 arguments";
|
|
51920
|
-
unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
|
|
51921
|
-
unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
|
|
51922
|
-
return env.ta.doubleTopBottom(unwrap2(evalExpr(wave10aArg(2, ["period", "length"], msg), env)));
|
|
53955
|
+
const high = unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
|
|
53956
|
+
const low = unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
|
|
53957
|
+
return env.ta.doubleTopBottom(site, high, low, unwrap2(evalExpr(wave10aArg(2, ["period", "length"], msg), env)));
|
|
51923
53958
|
}
|
|
51924
53959
|
if (fname === "ta.inside_bar_pattern" || fname === "inside_bar_pattern") {
|
|
51925
53960
|
const msg = "ta.inside_bar_pattern() requires 2 arguments";
|
|
51926
|
-
unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
|
|
51927
|
-
unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
|
|
51928
|
-
return env.ta.insideBarPattern();
|
|
53961
|
+
const high = unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
|
|
53962
|
+
const low = unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
|
|
53963
|
+
return env.ta.insideBarPattern(site, high, low);
|
|
51929
53964
|
}
|
|
51930
53965
|
if (fname === "ta.macd_signal" || fname === "macd_signal") {
|
|
51931
53966
|
const msg = "ta.macd_signal() requires 2 arguments: macd_line, signal_line";
|
|
@@ -51937,7 +53972,7 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51937
53972
|
}
|
|
51938
53973
|
if (fname === "ta.stoch_smooth" || fname === "stoch_smooth") {
|
|
51939
53974
|
const msg = "ta.stoch_smooth() requires 6 arguments: high, low, close, period, smooth_k, smooth_d";
|
|
51940
|
-
return env.ta.stochSmooth(unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env)), unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env)), unwrap2(evalExpr(wave10aArg(2, ["close"], msg), env)), unwrap2(evalExpr(wave10aArg(3, ["period", "length"], msg), env)), unwrap2(evalExpr(wave10aArg(4, ["smooth_k", "k"], msg), env)), unwrap2(evalExpr(wave10aArg(5, ["smooth_d", "d"], msg), env)));
|
|
53975
|
+
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)));
|
|
51941
53976
|
}
|
|
51942
53977
|
const wave10bList = (index, names) => {
|
|
51943
53978
|
const raw = evalExpr(callArg(node.args, index, names), env);
|
|
@@ -51962,7 +53997,7 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51962
53997
|
}
|
|
51963
53998
|
if (fname === "ta.rsi_divergence" || fname === "rsi_divergence") {
|
|
51964
53999
|
const period = unwrap2(evalExpr(callArg(node.args, 1, ["period", "length"]), env));
|
|
51965
|
-
return env.ta.rsiDivergence(
|
|
54000
|
+
return env.ta.rsiDivergence(site, seriesLastCell(evalExpr(callArg(node.args, 0, ["rsi_series", "series", "source"]), env)), period ?? 0);
|
|
51966
54001
|
}
|
|
51967
54002
|
if (fname === "ta.cumulative_delta" || fname === "cumulative_delta") {
|
|
51968
54003
|
const period = unwrap2(evalExpr(callArg(node.args, 2, ["period", "length"]), env));
|
|
@@ -51984,6 +54019,281 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51984
54019
|
const sens = unwrap2(evalExpr(callArg(node.args, 3, ["sensitivity"]), env));
|
|
51985
54020
|
return env.ta.volumeThrust(site, unwrap2(evalExpr(callArg(node.args, 0, ["close", "source"]), env)), unwrap2(evalExpr(callArg(node.args, 1, ["volume"]), env)), unwrap2(evalExpr(callArg(node.args, 2, ["volume_sma", "vol_sma", "sma"]), env)), sens ?? 0.3);
|
|
51986
54021
|
}
|
|
54022
|
+
const wave11 = (index, names, message) => unwrap2(evalExpr(wave10aArg(index, names, message), env));
|
|
54023
|
+
const wave11n = (index, names, message) => num2(wave11(index, names, message));
|
|
54024
|
+
const wave13v = (index, names, message) => evalExpr(wave10aArg(index, names, message), env);
|
|
54025
|
+
if (fname === "ta.sma_weighted" || fname === "sma_weighted") {
|
|
54026
|
+
const msg = "ta.sma_weighted() requires at least 2 arguments: series, period";
|
|
54027
|
+
const weightArg = callArg(node.args, 2, ["weight_type", "weight"]);
|
|
54028
|
+
return env.ta.smaWeighted(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["period", "length"], msg), weightArg == null ? "linear" : evalExpr(weightArg, env));
|
|
54029
|
+
}
|
|
54030
|
+
if (fname === "ta.apo" || fname === "apo") {
|
|
54031
|
+
const msg = "ta.apo() requires 3 arguments: series, fast_period, slow_period";
|
|
54032
|
+
return env.ta.apo(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["fast_period", "fast"], msg), wave11n(2, ["slow_period", "slow"], msg));
|
|
54033
|
+
}
|
|
54034
|
+
if (fname === "ta.atr_normalized" || fname === "atr_normalized") {
|
|
54035
|
+
const msg = "ta.atr_normalized() requires 4 arguments: high, low, close, period";
|
|
54036
|
+
return env.ta.atrNormalized(site, wave11n(0, ["high"], msg), wave11n(1, ["low"], msg), wave11n(2, ["close"], msg), wave11n(3, ["period", "length"], msg));
|
|
54037
|
+
}
|
|
54038
|
+
if (fname === "ta.beta" || fname === "beta") {
|
|
54039
|
+
const msg = "ta.beta() requires 3 arguments: series1, series2, length";
|
|
54040
|
+
return env.ta.beta(site, wave11n(0, ["series1", "series", "source"], msg), wave11n(1, ["series2", "series_b", "other"], msg), wave11n(2, ["length", "period"], msg));
|
|
54041
|
+
}
|
|
54042
|
+
if (fname === "ta.r_squared" || fname === "r_squared") {
|
|
54043
|
+
const msg = "ta.r_squared() requires 3 arguments: series1, series2, length";
|
|
54044
|
+
return env.ta.rSquared(site, wave11n(0, ["series1", "series", "source"], msg), wave11n(1, ["series2", "series_b", "other"], msg), wave11n(2, ["length", "period"], msg));
|
|
54045
|
+
}
|
|
54046
|
+
if (fname === "ta.comovement" || fname === "comovement") {
|
|
54047
|
+
const msg = "ta.comovement() requires 3 arguments: series1, series2, length";
|
|
54048
|
+
return env.ta.comovement(site, wave11n(0, ["series1", "series", "source"], msg), wave11n(1, ["series2", "series_b", "other"], msg), wave11n(2, ["length", "period"], msg));
|
|
54049
|
+
}
|
|
54050
|
+
if (fname === "ta.skewness" || fname === "skewness") {
|
|
54051
|
+
const msg = "ta.skewness() requires 2 arguments: series, period";
|
|
54052
|
+
return env.ta.skewness(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["period", "length"], msg));
|
|
54053
|
+
}
|
|
54054
|
+
if (fname === "ta.kurtosis" || fname === "kurtosis") {
|
|
54055
|
+
const msg = "ta.kurtosis() requires 2 arguments: series, period";
|
|
54056
|
+
return env.ta.kurtosis(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["period", "length"], msg));
|
|
54057
|
+
}
|
|
54058
|
+
if (fname === "ta.volume_weighted_momentum" || fname === "volume_weighted_momentum") {
|
|
54059
|
+
const msg = "ta.volume_weighted_momentum() requires 3 arguments: series, volume, length";
|
|
54060
|
+
return env.ta.volumeWeightedMomentum(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["volume"], msg), wave11n(2, ["length", "period"], msg));
|
|
54061
|
+
}
|
|
54062
|
+
if (fname === "ta.parkinson" || fname === "parkinson") {
|
|
54063
|
+
const msg = "ta.parkinson() requires 2 arguments: high, low";
|
|
54064
|
+
const highArg = wave10aArg(0, ["high"], msg);
|
|
54065
|
+
const lowArg = wave10aArg(1, ["low"], msg);
|
|
54066
|
+
if (isSeriesExpr(highArg, env) || isSeriesExpr(lowArg, env))
|
|
54067
|
+
return NA;
|
|
54068
|
+
return env.ta.parkinson(num2(evalExpr(highArg, env)), num2(evalExpr(lowArg, env)));
|
|
54069
|
+
}
|
|
54070
|
+
if (fname === "ta.garman_klass" || fname === "garman_klass") {
|
|
54071
|
+
const msg = "ta.garman_klass() requires 4 arguments: high, low, close, open";
|
|
54072
|
+
const argsExpr = [
|
|
54073
|
+
wave10aArg(0, ["high"], msg),
|
|
54074
|
+
wave10aArg(1, ["low"], msg),
|
|
54075
|
+
wave10aArg(2, ["close"], msg),
|
|
54076
|
+
wave10aArg(3, ["open"], msg)
|
|
54077
|
+
];
|
|
54078
|
+
if (argsExpr.some((a) => isSeriesExpr(a, env)))
|
|
54079
|
+
return NA;
|
|
54080
|
+
return env.ta.garmanKlass(num2(evalExpr(argsExpr[0], env)), num2(evalExpr(argsExpr[1], env)), num2(evalExpr(argsExpr[2], env)), num2(evalExpr(argsExpr[3], env)));
|
|
54081
|
+
}
|
|
54082
|
+
if (fname === "ta.mean_reversion_score" || fname === "mean_reversion_score") {
|
|
54083
|
+
const msg = "ta.mean_reversion_score() requires 4 arguments";
|
|
54084
|
+
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));
|
|
54085
|
+
}
|
|
54086
|
+
if (fname === "ta.market_condition" || fname === "market_condition") {
|
|
54087
|
+
const msg = "ta.market_condition() requires 4 arguments";
|
|
54088
|
+
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));
|
|
54089
|
+
}
|
|
54090
|
+
if (fname === "ta.order_flow_imbalance" || fname === "order_flow_imbalance") {
|
|
54091
|
+
const msg = "ta.order_flow_imbalance() requires 5 arguments";
|
|
54092
|
+
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));
|
|
54093
|
+
}
|
|
54094
|
+
if (fname === "ta.liquidity_score" || fname === "liquidity_score") {
|
|
54095
|
+
const msg = "ta.liquidity_score() requires 4 arguments";
|
|
54096
|
+
return env.ta.liquidityScore(site, wave11n(0, ["volume"], msg), wave11n(1, ["volatility"], msg), wave11n(2, ["spread"], msg), wave11n(3, ["period", "length"], msg));
|
|
54097
|
+
}
|
|
54098
|
+
if (fname === "ta.fear_greed_index" || fname === "fear_greed_index") {
|
|
54099
|
+
const msg = "ta.fear_greed_index() requires 4 arguments";
|
|
54100
|
+
return env.ta.fearGreedIndex(wave11n(0, ["rsi"], msg), wave11n(1, ["vix"], msg), wave11n(2, ["put_call", "put_call_ratio"], msg), wave11n(3, ["breadth"], msg));
|
|
54101
|
+
}
|
|
54102
|
+
if (fname === "ta.crowd_sentiment" || fname === "crowd_sentiment") {
|
|
54103
|
+
const msg = "ta.crowd_sentiment() requires 3 arguments";
|
|
54104
|
+
return env.ta.crowdSentiment(wave11n(0, ["price_agreement", "price"], msg), wave11n(1, ["volume_agreement", "volume"], msg), wave11n(2, ["time_agreement", "time"], msg));
|
|
54105
|
+
}
|
|
54106
|
+
if (fname === "ta.smart_money_flow" || fname === "smart_money_flow") {
|
|
54107
|
+
const msg = "ta.smart_money_flow() requires 4 arguments";
|
|
54108
|
+
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));
|
|
54109
|
+
}
|
|
54110
|
+
if (fname === "ta.trend_confirmation_score" || fname === "trend_confirmation_score") {
|
|
54111
|
+
const msg = "ta.trend_confirmation_score() requires 6 arguments";
|
|
54112
|
+
wave11n(5, ["support_distance"], msg);
|
|
54113
|
+
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));
|
|
54114
|
+
}
|
|
54115
|
+
if (fname === "ta.max_loss_level" || fname === "max_loss_level") {
|
|
54116
|
+
const msg = "ta.max_loss_level() requires 3 arguments";
|
|
54117
|
+
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));
|
|
54118
|
+
}
|
|
54119
|
+
if (fname === "ta.profit_lock_level" || fname === "profit_lock_level") {
|
|
54120
|
+
const msg = "ta.profit_lock_level() requires 4 arguments";
|
|
54121
|
+
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));
|
|
54122
|
+
}
|
|
54123
|
+
const wave12s = (index, names, message) => evalExpr(wave10aArg(index, names, message), env);
|
|
54124
|
+
if (fname === "ta.position_sizing" || fname === "position_sizing") {
|
|
54125
|
+
const msg = "ta.position_sizing() requires 4 arguments";
|
|
54126
|
+
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));
|
|
54127
|
+
}
|
|
54128
|
+
if (fname === "ta.kelly_criterion" || fname === "kelly_criterion") {
|
|
54129
|
+
const msg = "ta.kelly_criterion() requires 3 arguments";
|
|
54130
|
+
return env.ta.kellyCriterion(wave11n(0, ["win_rate"], msg), wave11n(1, ["avg_win"], msg), wave11n(2, ["avg_loss"], msg));
|
|
54131
|
+
}
|
|
54132
|
+
if (fname === "ta.risk_reward_ratio" || fname === "risk_reward_ratio") {
|
|
54133
|
+
const msg = "ta.risk_reward_ratio() requires 3 arguments";
|
|
54134
|
+
return env.ta.riskRewardRatio(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["stop", "stop_price"], msg), wave11n(2, ["target", "target_price"], msg));
|
|
54135
|
+
}
|
|
54136
|
+
if (fname === "ta.risk_reward_asymmetry" || fname === "risk_reward_asymmetry") {
|
|
54137
|
+
const msg = "ta.risk_reward_asymmetry() requires 4 arguments";
|
|
54138
|
+
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));
|
|
54139
|
+
}
|
|
54140
|
+
if (fname === "ta.probability_of_movement" || fname === "probability_of_movement") {
|
|
54141
|
+
const msg = "ta.probability_of_movement() requires 4 arguments";
|
|
54142
|
+
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));
|
|
54143
|
+
}
|
|
54144
|
+
if (fname === "ta.trend_strength" || fname === "trend_strength") {
|
|
54145
|
+
const msg = "ta.trend_strength() requires 3 arguments";
|
|
54146
|
+
return env.ta.trendStrength(wave11n(0, ["price", "source"], msg), wave11n(1, ["adx"], msg), wave11n(2, ["rsi"], msg));
|
|
54147
|
+
}
|
|
54148
|
+
if (fname === "ta.breakeven_level" || fname === "breakeven_level") {
|
|
54149
|
+
const msg = "ta.breakeven_level() requires 5 arguments";
|
|
54150
|
+
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));
|
|
54151
|
+
}
|
|
54152
|
+
if (fname === "ta.market_structure_pivot" || fname === "market_structure_pivot") {
|
|
54153
|
+
const msg = "ta.market_structure_pivot() requires 5 arguments";
|
|
54154
|
+
const high = wave13v(0, ["high_list", "high"], msg);
|
|
54155
|
+
const low = wave13v(1, ["low_list", "low"], msg);
|
|
54156
|
+
wave13v(2, ["close_list", "close"], msg);
|
|
54157
|
+
const period = wave11n(3, ["period", "left", "left_bars"], msg);
|
|
54158
|
+
const mode = wave11n(4, ["mode", "right", "right_bars"], msg);
|
|
54159
|
+
return env.ta.marketStructurePivot(site, high, low, period, mode);
|
|
54160
|
+
}
|
|
54161
|
+
if (fname === "ta.position_sizing_score" || fname === "position_sizing_score") {
|
|
54162
|
+
const msg = "ta.position_sizing_score() requires 4 arguments";
|
|
54163
|
+
return env.ta.positionSizingScore(wave11n(0, ["account_risk", "risk"], msg), wave11n(1, ["volatility"], msg), wave11n(2, ["conviction"], msg), wave11n(3, ["correlation"], msg));
|
|
54164
|
+
}
|
|
54165
|
+
if (fname === "ta.trailing_exit_level" || fname === "trailing_exit_level") {
|
|
54166
|
+
const msg = "ta.trailing_exit_level() requires 5 arguments";
|
|
54167
|
+
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));
|
|
54168
|
+
}
|
|
54169
|
+
if (fname === "ta.optimal_entry_zone" || fname === "optimal_entry_zone") {
|
|
54170
|
+
const msg = "ta.optimal_entry_zone() requires 4 arguments";
|
|
54171
|
+
wave11n(0, ["high"], msg);
|
|
54172
|
+
wave11n(1, ["low"], msg);
|
|
54173
|
+
const close = wave13v(2, ["close"], msg);
|
|
54174
|
+
wave11n(3, ["period", "length"], msg);
|
|
54175
|
+
return env.ta.optimalEntryZone(site, close);
|
|
54176
|
+
}
|
|
54177
|
+
if (fname === "ta.mean_reversion_entry" || fname === "mean_reversion_entry") {
|
|
54178
|
+
const msg = "ta.mean_reversion_entry() requires 5 arguments";
|
|
54179
|
+
return env.ta.meanReversionEntry(site, wave13v(0, ["price", "source"], msg), wave13v(1, ["sma"], msg), wave13v(2, ["stdev", "std_dev"], msg), wave11n(4, ["threshold"], msg));
|
|
54180
|
+
}
|
|
54181
|
+
if (fname === "ta.multi_timeframe_signal" || fname === "multi_timeframe_signal") {
|
|
54182
|
+
const msg = "ta.multi_timeframe_signal() requires 6 arguments";
|
|
54183
|
+
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));
|
|
54184
|
+
}
|
|
54185
|
+
if (fname === "ta.market_timing_index" || fname === "market_timing_index") {
|
|
54186
|
+
const msg = "ta.market_timing_index() requires 4 arguments";
|
|
54187
|
+
return env.ta.marketTimingIndex(wave11n(0, ["trend"], msg), wave11n(1, ["momentum"], msg), wave11n(2, ["volatility"], msg), wave11n(3, ["sentiment"], msg));
|
|
54188
|
+
}
|
|
54189
|
+
if (fname === "ta.regime_adaptive_signal" || fname === "regime_adaptive_signal") {
|
|
54190
|
+
const msg = "ta.regime_adaptive_signal() requires 4 arguments";
|
|
54191
|
+
const strength = wave11n(0, ["signal_strength", "strength"], msg);
|
|
54192
|
+
const volRegime = wave12s(1, ["volatility_regime", "vol_regime"], msg);
|
|
54193
|
+
const trendRegime = wave12s(2, ["trend_regime"], msg);
|
|
54194
|
+
wave11n(3, ["period", "length"], msg);
|
|
54195
|
+
return env.ta.regimeAdaptiveSignal(strength, volRegime, trendRegime);
|
|
54196
|
+
}
|
|
54197
|
+
if (fname === "ta.strategy_score" || fname === "strategy_score") {
|
|
54198
|
+
const msg = "ta.strategy_score() requires 4 arguments";
|
|
54199
|
+
return env.ta.strategyScore(wave11n(0, ["rsi"], msg), wave11n(1, ["macd"], msg), wave11n(2, ["ema_cross"], msg), wave11n(3, ["trend"], msg));
|
|
54200
|
+
}
|
|
54201
|
+
if (fname === "ta.breakout_detection" || fname === "breakout_detection") {
|
|
54202
|
+
const msg = "ta.breakout_detection() requires 3 arguments";
|
|
54203
|
+
return env.ta.breakoutDetection(wave11n(0, ["close", "source"], msg), wave11n(1, ["resistance"], msg), wave11n(2, ["support"], msg));
|
|
54204
|
+
}
|
|
54205
|
+
if (fname === "ta.ema_cross_signal" || fname === "ema_cross_signal") {
|
|
54206
|
+
const msg = "ta.ema_cross_signal() requires 3 arguments";
|
|
54207
|
+
return env.ta.emaCrossSignal(site, wave11n(0, ["fast_ema", "fast"], msg), wave11n(1, ["slow_ema", "slow"], msg), wave11n(2, ["threshold"], msg));
|
|
54208
|
+
}
|
|
54209
|
+
if (fname === "ta.momentum_filter" || fname === "momentum_filter") {
|
|
54210
|
+
const msg = "ta.momentum_filter() requires 3 arguments";
|
|
54211
|
+
return env.ta.momentumFilter(site, wave11n(0, ["momentum_raw", "momentum"], msg), wave11n(1, ["volume"], msg), wave11n(2, ["period", "length"], msg));
|
|
54212
|
+
}
|
|
54213
|
+
if (fname === "ta.volatility_regime" || fname === "volatility_regime") {
|
|
54214
|
+
const msg = "ta.volatility_regime() requires 2 arguments";
|
|
54215
|
+
return env.ta.volatilityRegime(site, wave11n(0, ["atr_series", "atr", "source"], msg), wave11n(1, ["period", "length"], msg));
|
|
54216
|
+
}
|
|
54217
|
+
if (fname === "ta.economic_impact_score" || fname === "economic_impact_score") {
|
|
54218
|
+
const msg = "ta.economic_impact_score() requires 3 arguments";
|
|
54219
|
+
return env.ta.economicImpactScore(wave11n(0, ["price_change"], msg), wave11n(1, ["volatility"], msg), wave11n(2, ["volume_change"], msg));
|
|
54220
|
+
}
|
|
54221
|
+
if (fname === "ta.contrarian_signal" || fname === "contrarian_signal") {
|
|
54222
|
+
const msg = "ta.contrarian_signal() requires 3 arguments";
|
|
54223
|
+
return env.ta.contrarianSignal(wave11n(0, ["sentiment"], msg), wave11n(1, ["volatility"], msg), wave11n(2, ["time_since_extreme", "time_extreme"], msg));
|
|
54224
|
+
}
|
|
54225
|
+
if (fname === "ta.drawdown_recovery_level" || fname === "drawdown_recovery_level") {
|
|
54226
|
+
const msg = "ta.drawdown_recovery_level() requires 4 arguments";
|
|
54227
|
+
return env.ta.drawdownRecoveryLevel(wave11n(0, ["peak"], msg), wave11n(1, ["current", "current_price"], msg), wave11n(2, ["recovery_factor", "factor"], msg), wave11n(3, ["period", "length"], msg));
|
|
54228
|
+
}
|
|
54229
|
+
if (fname === "ta.pivot_point_levels" || fname === "pivot_point_levels") {
|
|
54230
|
+
const msg = "ta.pivot_point_levels() requires type+anchor or high, low, close";
|
|
54231
|
+
const first = wave11(0, ["type", "high"], msg);
|
|
54232
|
+
if (typeof first === "string") {
|
|
54233
|
+
if (typeof env.ta.pivotPoints !== "function")
|
|
54234
|
+
return NA;
|
|
54235
|
+
const r = env.ta.pivotPoints.call(env.ta, site, num2(env.ctx.high), num2(env.ctx.low), num2(env.ctx.close));
|
|
54236
|
+
return tupleOf([r.pp, r.r1, r.s1, r.r2, r.s2]);
|
|
54237
|
+
}
|
|
54238
|
+
const tradArg = callArg(node.args, 3, ["traditional"]);
|
|
54239
|
+
const traditional = tradArg == null ? true : unwrap2(evalExpr(tradArg, env)) !== 0;
|
|
54240
|
+
return env.ta.pivotPointLevels(num2(first), wave11n(1, ["low"], msg), wave11n(2, ["close"], msg), traditional);
|
|
54241
|
+
}
|
|
54242
|
+
if (fname === "ta.volatility_regime_score" || fname === "volatility_regime_score") {
|
|
54243
|
+
const msg = "ta.volatility_regime_score() requires 4 arguments";
|
|
54244
|
+
return env.ta.volatilityRegimeScore(site, wave13v(0, ["atr_list", "atr"], msg), wave13v(1, ["volatility_list", "volatility"], msg), wave13v(2, ["vix_list", "vix"], msg), wave11n(3, ["threshold"], msg));
|
|
54245
|
+
}
|
|
54246
|
+
if (fname === "ta.correlation_filter" || fname === "correlation_filter") {
|
|
54247
|
+
const msg = "ta.correlation_filter() requires 5 arguments";
|
|
54248
|
+
const s1 = wave13v(0, ["signal1_list", "signal1", "s1"], msg);
|
|
54249
|
+
const s2 = wave13v(1, ["signal2_list", "signal2", "s2"], msg);
|
|
54250
|
+
const s3 = wave13v(2, ["signal3_list", "signal3", "s3"], msg);
|
|
54251
|
+
wave11n(3, ["num_signals"], msg);
|
|
54252
|
+
return env.ta.correlationFilter(site, s1, s2, s3, wave11n(4, ["threshold"], msg));
|
|
54253
|
+
}
|
|
54254
|
+
if (fname === "ta.advanced_breakout_detector" || fname === "advanced_breakout_detector") {
|
|
54255
|
+
const msg = "ta.advanced_breakout_detector() requires 5 arguments";
|
|
54256
|
+
return env.ta.advancedBreakoutDetector(site, wave13v(0, ["price_list", "price"], msg), wave13v(1, ["volume_list", "volume"], msg), wave11n(2, ["level"], msg), wave11n(3, ["lookback"], msg), wave11n(4, ["volume_multiplier", "vol_mult"], msg));
|
|
54257
|
+
}
|
|
54258
|
+
if (fname === "ta.pullback_bounce_level" || fname === "pullback_bounce_level") {
|
|
54259
|
+
const msg = "ta.pullback_bounce_level() requires 5 arguments";
|
|
54260
|
+
const high = wave13v(0, ["high_list", "high"], msg);
|
|
54261
|
+
const low = wave13v(1, ["low_list", "low"], msg);
|
|
54262
|
+
wave13v(2, ["close_list", "close"], msg);
|
|
54263
|
+
return env.ta.pullbackBounceLevel(site, high, low, wave11n(3, ["trend_direction", "trend_dir"], msg), wave11n(4, ["lookback"], msg));
|
|
54264
|
+
}
|
|
54265
|
+
if (fname === "ta.divergence_detector" || fname === "divergence_detector") {
|
|
54266
|
+
const msg = "ta.divergence_detector() requires 3 arguments";
|
|
54267
|
+
return env.ta.divergenceDetector(site, wave13v(0, ["price_list", "price"], msg), wave13v(1, ["indicator_list", "indicator"], msg), wave11n(2, ["lookback"], msg));
|
|
54268
|
+
}
|
|
54269
|
+
if (fname === "ta.momentum_divergence" || fname === "momentum_divergence") {
|
|
54270
|
+
const msg = "ta.momentum_divergence() requires 3 arguments";
|
|
54271
|
+
return env.ta.momentumDivergence(site, wave13v(0, ["price"], msg), wave13v(1, ["momentum_fast", "mom_fast"], msg), wave13v(2, ["momentum_slow", "mom_slow"], msg));
|
|
54272
|
+
}
|
|
54273
|
+
if (fname === "ta.spread_analysis" || fname === "spread_analysis") {
|
|
54274
|
+
const msg = "ta.spread_analysis() requires 3 arguments";
|
|
54275
|
+
return env.ta.spreadAnalysis(site, wave13v(0, ["bid"], msg), wave13v(1, ["ask"], msg), wave11n(2, ["period", "length"], msg));
|
|
54276
|
+
}
|
|
54277
|
+
if (fname === "ta.employment_cycle_indicator" || fname === "employment_cycle_indicator") {
|
|
54278
|
+
const msg = "ta.employment_cycle_indicator() requires 3 arguments";
|
|
54279
|
+
return env.ta.employmentCycleIndicator(site, wave13v(0, ["cyclical_stocks", "cyclical"], msg), wave13v(1, ["defensive_stocks", "defensive"], msg), wave13v(2, ["unemployment_proxy", "unemployment"], msg));
|
|
54280
|
+
}
|
|
54281
|
+
if (fname === "ta.gdp_growth_proxy" || fname === "gdp_growth_proxy") {
|
|
54282
|
+
const msg = "ta.gdp_growth_proxy() requires 3 arguments";
|
|
54283
|
+
return env.ta.gdpGrowthProxy(site, wave13v(0, ["market_breadth", "breadth"], msg), wave13v(1, ["market_volume", "volume"], msg), wave13v(2, ["price_momentum", "momentum"], msg));
|
|
54284
|
+
}
|
|
54285
|
+
if (fname === "ta.inflation_proxy_indicator" || fname === "inflation_proxy_indicator") {
|
|
54286
|
+
const msg = "ta.inflation_proxy_indicator() requires 3 arguments";
|
|
54287
|
+
return env.ta.inflationProxyIndicator(site, wave13v(0, ["usd_index", "usd"], msg), wave13v(1, ["commodity_prices", "commodities"], msg), wave13v(2, ["bond_yields", "yields"], msg));
|
|
54288
|
+
}
|
|
54289
|
+
if (fname === "ta.expected_value" || fname === "expected_value") {
|
|
54290
|
+
const msg = "ta.expected_value() requires 2 arguments: returns, probabilities";
|
|
54291
|
+
const returns = numericList(evalExpr(wave10aArg(0, ["returns"], msg), env));
|
|
54292
|
+
const probs = numericList(evalExpr(wave10aArg(1, ["probabilities", "probs"], msg), env));
|
|
54293
|
+
if (returns.length !== probs.length)
|
|
54294
|
+
runtimeError("Returns and probabilities must have same length");
|
|
54295
|
+
return env.ta.expectedValue(returns, probs);
|
|
54296
|
+
}
|
|
51987
54297
|
return;
|
|
51988
54298
|
}
|
|
51989
54299
|
function hlc3(env) {
|
|
@@ -51994,6 +54304,28 @@ function hlc3(env) {
|
|
|
51994
54304
|
return c ?? h ?? l;
|
|
51995
54305
|
return (h + l + c) / 3;
|
|
51996
54306
|
}
|
|
54307
|
+
function seriesLastCell(value) {
|
|
54308
|
+
if (value instanceof PineArray) {
|
|
54309
|
+
const n = value.size();
|
|
54310
|
+
return n > 0 ? value.get(n - 1) : null;
|
|
54311
|
+
}
|
|
54312
|
+
const v = unwrap2(value);
|
|
54313
|
+
return typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
54314
|
+
}
|
|
54315
|
+
function numericList(value) {
|
|
54316
|
+
const arr = asArray2(value);
|
|
54317
|
+
if (arr == null) {
|
|
54318
|
+
const v = unwrap2(value);
|
|
54319
|
+
return typeof v === "number" && Number.isFinite(v) ? [v] : [];
|
|
54320
|
+
}
|
|
54321
|
+
const out = [];
|
|
54322
|
+
for (let i = 0;i < arr.size(); i++) {
|
|
54323
|
+
const v = arr.get(i);
|
|
54324
|
+
if (typeof v === "number" && Number.isFinite(v))
|
|
54325
|
+
out.push(v);
|
|
54326
|
+
}
|
|
54327
|
+
return out;
|
|
54328
|
+
}
|
|
51997
54329
|
function asArray2(value) {
|
|
51998
54330
|
if (value instanceof PineArray)
|
|
51999
54331
|
return value;
|
|
@@ -52892,8 +55224,22 @@ function evalDrawingCall(fname, node, env) {
|
|
|
52892
55224
|
const position = drawRaw(node, env, 0, ["position"]);
|
|
52893
55225
|
if (position !== undefined)
|
|
52894
55226
|
extra.position = position;
|
|
52895
|
-
putFinite(extra, "
|
|
52896
|
-
putFinite(extra, "
|
|
55227
|
+
putFinite(extra, "columns", drawNum(node, env, 1, ["columns"]));
|
|
55228
|
+
putFinite(extra, "rows", drawNum(node, env, 2, ["rows"]));
|
|
55229
|
+
const bgcolor = drawRaw(node, env, 3, ["bgcolor"]);
|
|
55230
|
+
if (bgcolor !== undefined)
|
|
55231
|
+
extra.bgcolor = bgcolor;
|
|
55232
|
+
const frameColor = drawRaw(node, env, 4, ["frame_color"]);
|
|
55233
|
+
if (frameColor !== undefined)
|
|
55234
|
+
extra.frame_color = frameColor;
|
|
55235
|
+
putFinite(extra, "frame_width", drawNum(node, env, 5, ["frame_width"]));
|
|
55236
|
+
const borderColor = drawRaw(node, env, 6, ["border_color"]);
|
|
55237
|
+
if (borderColor !== undefined)
|
|
55238
|
+
extra.border_color = borderColor;
|
|
55239
|
+
putFinite(extra, "border_width", drawNum(node, env, 7, ["border_width"]));
|
|
55240
|
+
const forceOverlay = drawRaw(node, env, 8, ["force_overlay"]);
|
|
55241
|
+
if (forceOverlay !== undefined)
|
|
55242
|
+
extra.force_overlay = forceOverlay;
|
|
52897
55243
|
return book.tableNew(env.barIndex, extra);
|
|
52898
55244
|
}
|
|
52899
55245
|
if (fname === "polyline.new") {
|
|
@@ -53940,8 +56286,8 @@ function syminfoPrefix2(node, env) {
|
|
|
53940
56286
|
function calendarMs(node, env) {
|
|
53941
56287
|
const arg = callArg(node.args, 0, ["time", "timestamp"]);
|
|
53942
56288
|
if (arg == null)
|
|
53943
|
-
return num2(env.ctx.time);
|
|
53944
|
-
return unwrap2(evalExpr(arg, env));
|
|
56289
|
+
return timestampToMs(num2(env.ctx.time));
|
|
56290
|
+
return timestampToMs(unwrap2(evalExpr(arg, env)));
|
|
53945
56291
|
}
|
|
53946
56292
|
function evalLibraryMemberCall(mod, attr, node, env) {
|
|
53947
56293
|
const exp = mod.get(attr);
|