@hoox-sh/pynets 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +6 -4
- package/dist/browser.js +68 -68
- package/dist/index.js +1719 -197
- 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 +324 -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 +447 -28
- package/src/runtime/str.ts +3 -2
- package/src/runtime/strategy.ts +164 -12
- package/src/runtime/ta.ts +1090 -149
- package/src/runtime/time.ts +12 -0
package/dist/index.js
CHANGED
|
@@ -6287,6 +6287,7 @@ class PinescriptLexerBase extends cn {
|
|
|
6287
6287
|
_lastPendingTokenType = 0;
|
|
6288
6288
|
_lastPendingTokenTypeFromDefaultChannel = 0;
|
|
6289
6289
|
_numOpens = 0;
|
|
6290
|
+
_numSqBrackets = 0;
|
|
6290
6291
|
_indentLengthStack = [];
|
|
6291
6292
|
_inputStarted = false;
|
|
6292
6293
|
constructor(input) {
|
|
@@ -6340,6 +6341,7 @@ class PinescriptLexerBase extends cn {
|
|
|
6340
6341
|
this._lastPendingTokenType = 0;
|
|
6341
6342
|
this._lastPendingTokenTypeFromDefaultChannel = 0;
|
|
6342
6343
|
this._numOpens = 0;
|
|
6344
|
+
this._numSqBrackets = 0;
|
|
6343
6345
|
this._indentLengthStack = [];
|
|
6344
6346
|
this._inputStarted = false;
|
|
6345
6347
|
}
|
|
@@ -6356,11 +6358,17 @@ class PinescriptLexerBase extends cn {
|
|
|
6356
6358
|
const tok = this._currentToken;
|
|
6357
6359
|
const tokType = tok.type;
|
|
6358
6360
|
const C = this.C;
|
|
6359
|
-
if (tokType === C.LPAR
|
|
6361
|
+
if (tokType === C.LPAR) {
|
|
6360
6362
|
this._numOpens += 1;
|
|
6361
6363
|
this._addPendingToken(tok);
|
|
6362
|
-
} else if (tokType === C.
|
|
6363
|
-
this.
|
|
6364
|
+
} else if (tokType === C.LSQB) {
|
|
6365
|
+
this._numSqBrackets += 1;
|
|
6366
|
+
this._addPendingToken(tok);
|
|
6367
|
+
} else if (tokType === C.RPAR) {
|
|
6368
|
+
this._numOpens = Math.max(0, this._numOpens - 1);
|
|
6369
|
+
this._addPendingToken(tok);
|
|
6370
|
+
} else if (tokType === C.RSQB) {
|
|
6371
|
+
this._numSqBrackets = Math.max(0, this._numSqBrackets - 1);
|
|
6364
6372
|
this._addPendingToken(tok);
|
|
6365
6373
|
} else if (tokType === C.NEWLINE) {
|
|
6366
6374
|
this._handleNEWLINEToken();
|
|
@@ -6452,7 +6460,7 @@ class PinescriptLexerBase extends cn {
|
|
|
6452
6460
|
return tok;
|
|
6453
6461
|
}
|
|
6454
6462
|
_handleNEWLINEToken() {
|
|
6455
|
-
if (this._numOpens > 0 || this._operators.has(this._lastPendingTokenTypeFromDefaultChannel)) {
|
|
6463
|
+
if (this._numOpens > 0 || this._numSqBrackets > 0 || this._operators.has(this._lastPendingTokenTypeFromDefaultChannel)) {
|
|
6456
6464
|
this._hideAndAddPendingToken(this._currentToken);
|
|
6457
6465
|
return;
|
|
6458
6466
|
}
|
|
@@ -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,22 @@ 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;
|
|
40356
40537
|
sma(site, source, period) {
|
|
40357
40538
|
const n = pinePeriod(period);
|
|
40358
40539
|
if (n === null)
|
|
@@ -40427,18 +40608,24 @@ class TaEngine {
|
|
|
40427
40608
|
st = {
|
|
40428
40609
|
period: n,
|
|
40429
40610
|
prevClose: null,
|
|
40611
|
+
started: false,
|
|
40430
40612
|
rma: { period: n, rma: null, seeded: false, started: false, seedBuf: [] }
|
|
40431
40613
|
};
|
|
40432
40614
|
this.atrSites.set(site, st);
|
|
40433
40615
|
}
|
|
40434
|
-
const prev = st.prevClose;
|
|
40435
|
-
st.prevClose = finiteCell2(close);
|
|
40436
|
-
if (prev === null)
|
|
40437
|
-
return null;
|
|
40438
40616
|
const h = finiteCell2(high);
|
|
40439
40617
|
const l = finiteCell2(low);
|
|
40440
40618
|
const c = finiteCell2(close);
|
|
40441
|
-
if (
|
|
40619
|
+
if (!st.started) {
|
|
40620
|
+
st.started = true;
|
|
40621
|
+
st.prevClose = c;
|
|
40622
|
+
if (h === null || l === null)
|
|
40623
|
+
return null;
|
|
40624
|
+
return rmaStep(st.rma, h - l, n);
|
|
40625
|
+
}
|
|
40626
|
+
const prev = st.prevClose;
|
|
40627
|
+
st.prevClose = c;
|
|
40628
|
+
if (prev === null || h === null || l === null || c === null)
|
|
40442
40629
|
return null;
|
|
40443
40630
|
const tr = Math.max(h - l, Math.abs(h - prev), Math.abs(l - prev));
|
|
40444
40631
|
return rmaStep(st.rma, tr, n);
|
|
@@ -40604,7 +40791,7 @@ class TaEngine {
|
|
|
40604
40791
|
}
|
|
40605
40792
|
if (st.window.length < n || st.count !== n)
|
|
40606
40793
|
return null;
|
|
40607
|
-
let v = (st.sumsq - st.sum * st.sum / n) /
|
|
40794
|
+
let v = (st.sumsq - st.sum * st.sum / n) / n;
|
|
40608
40795
|
if (v < 0)
|
|
40609
40796
|
v = 0;
|
|
40610
40797
|
return Math.sqrt(v);
|
|
@@ -41810,7 +41997,7 @@ class TaEngine {
|
|
|
41810
41997
|
}
|
|
41811
41998
|
if (st.window.length < n || st.count !== n)
|
|
41812
41999
|
return null;
|
|
41813
|
-
let v = (st.sumsq - st.sum * st.sum / n) /
|
|
42000
|
+
let v = (st.sumsq - st.sum * st.sum / n) / n;
|
|
41814
42001
|
if (v < 0)
|
|
41815
42002
|
v = 0;
|
|
41816
42003
|
return v;
|
|
@@ -42414,20 +42601,17 @@ class TaEngine {
|
|
|
42414
42601
|
st = { samples: [] };
|
|
42415
42602
|
this.zigzagSites.set(site, st);
|
|
42416
42603
|
}
|
|
42417
|
-
|
|
42418
|
-
|
|
42419
|
-
|
|
42420
|
-
|
|
42421
|
-
finite.push(v);
|
|
42422
|
-
}
|
|
42423
|
-
if (finite.length < 2)
|
|
42604
|
+
const x = finiteCell2(source);
|
|
42605
|
+
if (x !== null)
|
|
42606
|
+
pushCap(st.samples, x, 2);
|
|
42607
|
+
if (st.samples.length < 2)
|
|
42424
42608
|
return { high: null, low: null, dir: 0 };
|
|
42425
|
-
const oldest =
|
|
42426
|
-
const
|
|
42427
|
-
const recentHigh = Math.max(oldest,
|
|
42428
|
-
const recentLow = Math.min(oldest,
|
|
42609
|
+
const oldest = st.samples[0];
|
|
42610
|
+
const newest = st.samples[1];
|
|
42611
|
+
const recentHigh = Math.max(oldest, newest);
|
|
42612
|
+
const recentLow = Math.min(oldest, newest);
|
|
42429
42613
|
const pct = recentLow !== 0 ? (recentHigh - recentLow) / recentLow * 100 : 0;
|
|
42430
|
-
const direction = recentHigh ===
|
|
42614
|
+
const direction = recentHigh === newest ? 1 : -1;
|
|
42431
42615
|
return { high: recentHigh, low: recentLow, dir: pct > th ? 1 : direction };
|
|
42432
42616
|
}
|
|
42433
42617
|
accelSites = new Map;
|
|
@@ -42494,30 +42678,31 @@ class TaEngine {
|
|
|
42494
42678
|
}
|
|
42495
42679
|
accelerationFactor(site, source, period) {
|
|
42496
42680
|
const p = this.coerceTaInt(period, "ta.acceleration_factor() requires 2 arguments");
|
|
42497
|
-
|
|
42681
|
+
if (p <= 0)
|
|
42682
|
+
return 0;
|
|
42683
|
+
const key = `${site}:${p}`;
|
|
42684
|
+
let samples = this.accelSites.get(key);
|
|
42498
42685
|
if (samples === undefined) {
|
|
42499
42686
|
samples = [];
|
|
42500
|
-
this.accelSites.set(
|
|
42687
|
+
this.accelSites.set(key, samples);
|
|
42501
42688
|
}
|
|
42502
|
-
pushCap(samples, finiteCell2(source),
|
|
42503
|
-
if (samples.length < p + 1
|
|
42689
|
+
pushCap(samples, finiteCell2(source), p + 1);
|
|
42690
|
+
if (samples.length < p + 1)
|
|
42504
42691
|
return 0;
|
|
42505
|
-
const
|
|
42506
|
-
const
|
|
42507
|
-
for (let i = oldest.length - 1;i >= 0; i--) {
|
|
42508
|
-
const v = oldest[i];
|
|
42692
|
+
const clean = [];
|
|
42693
|
+
for (const v of samples) {
|
|
42509
42694
|
if (v !== null)
|
|
42510
|
-
|
|
42695
|
+
clean.push(v);
|
|
42511
42696
|
}
|
|
42512
|
-
if (
|
|
42697
|
+
if (clean.length < 2)
|
|
42513
42698
|
return 0;
|
|
42514
42699
|
let oldSum = 0;
|
|
42515
|
-
for (let i = 0;i <
|
|
42516
|
-
oldSum +=
|
|
42517
|
-
const oldMom = oldSum / (
|
|
42700
|
+
for (let i = 0;i < clean.length - 1; i++)
|
|
42701
|
+
oldSum += clean[i];
|
|
42702
|
+
const oldMom = oldSum / (clean.length - 1);
|
|
42703
|
+
const newMom = clean[clean.length - 1];
|
|
42518
42704
|
if (Math.abs(oldMom) < 0.0000000001)
|
|
42519
42705
|
return 0;
|
|
42520
|
-
const newMom = newestFirst[newestFirst.length - 1];
|
|
42521
42706
|
let acc = (newMom - oldMom) / oldMom;
|
|
42522
42707
|
if (acc < -2)
|
|
42523
42708
|
acc = -2;
|
|
@@ -42525,32 +42710,141 @@ class TaEngine {
|
|
|
42525
42710
|
acc = 2;
|
|
42526
42711
|
return finiteOut2(acc);
|
|
42527
42712
|
}
|
|
42528
|
-
stochSmooth(high, low, close, period, smoothK, smoothD) {
|
|
42713
|
+
stochSmooth(site, high, low, close, period, smoothK, smoothD) {
|
|
42529
42714
|
const p = this.coerceTaInt(period, "ta.stoch_smooth period must be integer");
|
|
42530
42715
|
const k = this.coerceTaInt(smoothK, "ta.stoch_smooth smooth_k must be integer");
|
|
42531
42716
|
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)
|
|
42717
|
+
if (p < 1 || k < 1 || d < 1)
|
|
42538
42718
|
return null;
|
|
42539
|
-
const
|
|
42540
|
-
|
|
42541
|
-
|
|
42542
|
-
|
|
42543
|
-
|
|
42544
|
-
|
|
42545
|
-
|
|
42546
|
-
|
|
42547
|
-
|
|
42719
|
+
const key = `${site}:${p}:${k}:${d}`;
|
|
42720
|
+
let st = this.stochSmoothSites.get(key);
|
|
42721
|
+
if (st === undefined) {
|
|
42722
|
+
st = { highs: [], lows: [] };
|
|
42723
|
+
this.stochSmoothSites.set(key, st);
|
|
42724
|
+
}
|
|
42725
|
+
pushCap(st.highs, finiteCell2(high), p);
|
|
42726
|
+
pushCap(st.lows, finiteCell2(low), p);
|
|
42727
|
+
const c = finiteCell2(close);
|
|
42728
|
+
let stoch = null;
|
|
42729
|
+
if (c !== null && !st.highs.includes(null) && !st.lows.includes(null)) {
|
|
42730
|
+
let hh = -Infinity;
|
|
42731
|
+
let ll = Infinity;
|
|
42732
|
+
for (const v of st.highs) {
|
|
42733
|
+
if (v > hh)
|
|
42734
|
+
hh = v;
|
|
42735
|
+
}
|
|
42736
|
+
for (const v of st.lows) {
|
|
42737
|
+
if (v < ll)
|
|
42738
|
+
ll = v;
|
|
42739
|
+
}
|
|
42740
|
+
stoch = hh === ll ? 50 : 100 * (c - ll) / (hh - ll);
|
|
42741
|
+
}
|
|
42742
|
+
const kVal = this.ema(`${site}:k`, stoch, k);
|
|
42743
|
+
return this.ema(`${site}:d`, kVal, d);
|
|
42744
|
+
}
|
|
42745
|
+
engulfing(site, open, close) {
|
|
42746
|
+
const off = taRec({ is_bullish: false, is_bearish: false, pattern_strength: 0 });
|
|
42747
|
+
let st = this.engulfingSites.get(site);
|
|
42748
|
+
if (st === undefined) {
|
|
42749
|
+
st = { prevOpen: null, prevClose: null, count: 0 };
|
|
42750
|
+
this.engulfingSites.set(site, st);
|
|
42751
|
+
}
|
|
42752
|
+
const o = finiteCell2(open);
|
|
42753
|
+
const c = finiteCell2(close);
|
|
42754
|
+
st.count += 1;
|
|
42755
|
+
const prevO = st.prevOpen;
|
|
42756
|
+
const prevC = st.prevClose;
|
|
42757
|
+
if (st.count < 2 || prevO === null || prevC === null || o === null || c === null) {
|
|
42758
|
+
st.prevOpen = o;
|
|
42759
|
+
st.prevClose = c;
|
|
42760
|
+
return off;
|
|
42761
|
+
}
|
|
42762
|
+
const isBullish = o < prevC && c > prevO && c > o;
|
|
42763
|
+
const isBearish = o > prevC && c < prevO && c < o;
|
|
42764
|
+
let engulf = 0;
|
|
42765
|
+
if (isBullish) {
|
|
42766
|
+
engulf = Math.max(0, Math.min(1, (c - prevO) / Math.abs(prevO - prevC + 0.0001)));
|
|
42767
|
+
} else if (isBearish) {
|
|
42768
|
+
engulf = Math.max(0, Math.min(1, (prevO - c) / Math.abs(prevC - prevO + 0.0001)));
|
|
42769
|
+
}
|
|
42770
|
+
st.prevOpen = o;
|
|
42771
|
+
st.prevClose = c;
|
|
42772
|
+
return taRec({
|
|
42773
|
+
is_bullish: isBullish,
|
|
42774
|
+
is_bearish: isBearish,
|
|
42775
|
+
pattern_strength: finiteOut2(engulf) ?? 0
|
|
42776
|
+
});
|
|
42548
42777
|
}
|
|
42549
|
-
|
|
42550
|
-
|
|
42551
|
-
|
|
42778
|
+
insideBarPattern(site, high, low) {
|
|
42779
|
+
let st = this.insideBarSites.get(site);
|
|
42780
|
+
if (st === undefined) {
|
|
42781
|
+
st = { prevHigh: null, prevLow: null, count: 0 };
|
|
42782
|
+
this.insideBarSites.set(site, st);
|
|
42783
|
+
}
|
|
42784
|
+
const currH = high !== null && Number.isFinite(high) ? high : 0;
|
|
42785
|
+
const currL = low !== null && Number.isFinite(low) ? low : 0;
|
|
42786
|
+
st.count += 1;
|
|
42787
|
+
const prevH = st.prevHigh;
|
|
42788
|
+
const prevL = st.prevLow;
|
|
42789
|
+
if (st.count < 2 || prevH === null || prevL === null) {
|
|
42790
|
+
st.prevHigh = currH;
|
|
42791
|
+
st.prevLow = currL;
|
|
42792
|
+
return false;
|
|
42552
42793
|
}
|
|
42553
|
-
|
|
42794
|
+
const val = currH < prevH && currL > prevL;
|
|
42795
|
+
st.prevHigh = currH;
|
|
42796
|
+
st.prevLow = currL;
|
|
42797
|
+
return val;
|
|
42798
|
+
}
|
|
42799
|
+
doubleTopBottom(site, high, low, period) {
|
|
42800
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
42801
|
+
const off = taRec({ pattern_type: "none", strength: 0, breakout_level: 0 });
|
|
42802
|
+
if (n < 1)
|
|
42803
|
+
return off;
|
|
42804
|
+
const key = `${site}:${n}`;
|
|
42805
|
+
let st = this.doubleTopBottomSites.get(key);
|
|
42806
|
+
if (st === undefined) {
|
|
42807
|
+
st = { highs: [], lows: [], count: 0 };
|
|
42808
|
+
this.doubleTopBottomSites.set(key, st);
|
|
42809
|
+
}
|
|
42810
|
+
pushCap(st.highs, finiteCell2(high), n);
|
|
42811
|
+
pushCap(st.lows, finiteCell2(low), n);
|
|
42812
|
+
st.count += 1;
|
|
42813
|
+
if (st.count < n)
|
|
42814
|
+
return off;
|
|
42815
|
+
const recentHigh = [];
|
|
42816
|
+
for (const v of st.highs) {
|
|
42817
|
+
if (v !== null)
|
|
42818
|
+
recentHigh.push(v);
|
|
42819
|
+
}
|
|
42820
|
+
const recentLow = [];
|
|
42821
|
+
for (const v of st.lows) {
|
|
42822
|
+
if (v !== null)
|
|
42823
|
+
recentLow.push(v);
|
|
42824
|
+
}
|
|
42825
|
+
if (recentHigh.length < 3 || recentLow.length === 0)
|
|
42826
|
+
return off;
|
|
42827
|
+
const peaks = [recentHigh[0]];
|
|
42828
|
+
for (let i = 1;i < recentHigh.length - 1; i++) {
|
|
42829
|
+
if (recentHigh[i] > recentHigh[i - 1] && recentHigh[i] > recentHigh[i + 1]) {
|
|
42830
|
+
peaks.push(recentHigh[i]);
|
|
42831
|
+
}
|
|
42832
|
+
}
|
|
42833
|
+
if (peaks.length < 2)
|
|
42834
|
+
return off;
|
|
42835
|
+
const peakDiff = Math.abs(peaks[peaks.length - 1] - peaks[peaks.length - 2]);
|
|
42836
|
+
const avgPeak = (peaks[peaks.length - 1] + peaks[peaks.length - 2]) / 2;
|
|
42837
|
+
const strength = avgPeak > 0 ? 1 - Math.min(1, peakDiff / avgPeak) : 0;
|
|
42838
|
+
let minLow = recentLow[0];
|
|
42839
|
+
for (const v of recentLow) {
|
|
42840
|
+
if (v < minLow)
|
|
42841
|
+
minLow = v;
|
|
42842
|
+
}
|
|
42843
|
+
return taRec({
|
|
42844
|
+
pattern_type: "double_top",
|
|
42845
|
+
strength: finiteOut2(strength) ?? 0,
|
|
42846
|
+
breakout_level: finiteOut2(minLow - avgPeak * 0.1) ?? 0
|
|
42847
|
+
});
|
|
42554
42848
|
}
|
|
42555
42849
|
cumDeltaSites = new Map;
|
|
42556
42850
|
volMomSites = new Map;
|
|
@@ -42603,96 +42897,91 @@ class TaEngine {
|
|
|
42603
42897
|
}
|
|
42604
42898
|
return taRec({ is_oversold: rsi < os, is_overbought: rsi > ob, rsi });
|
|
42605
42899
|
}
|
|
42606
|
-
rsiDivergence(
|
|
42900
|
+
rsiDivergence(site, value, period) {
|
|
42607
42901
|
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
|
-
|
|
42625
|
-
|
|
42626
|
-
|
|
42627
|
-
|
|
42628
|
-
|
|
42629
|
-
|
|
42630
|
-
|
|
42631
|
-
|
|
42632
|
-
|
|
42633
|
-
|
|
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;
|
|
42902
|
+
if (p === null || p < 1)
|
|
42903
|
+
return 0;
|
|
42904
|
+
let st = this.rsiDivergenceSites.get(`${site}:${p}`);
|
|
42905
|
+
if (st === undefined) {
|
|
42906
|
+
st = { window: [], count: 0 };
|
|
42907
|
+
this.rsiDivergenceSites.set(`${site}:${p}`, st);
|
|
42908
|
+
}
|
|
42909
|
+
const x = finiteCell2(value);
|
|
42910
|
+
pushCap(st.window, x, p + 1);
|
|
42911
|
+
st.count += 1;
|
|
42912
|
+
if (st.count <= p)
|
|
42913
|
+
return 0;
|
|
42914
|
+
const vals = [];
|
|
42915
|
+
for (const v of st.window) {
|
|
42916
|
+
if (v !== null)
|
|
42917
|
+
vals.push(v);
|
|
42918
|
+
}
|
|
42919
|
+
if (vals.length < 2 || x === null)
|
|
42920
|
+
return 0;
|
|
42921
|
+
let lo = vals[0];
|
|
42922
|
+
let hi = vals[0];
|
|
42923
|
+
for (const v of vals) {
|
|
42924
|
+
if (v < lo)
|
|
42925
|
+
lo = v;
|
|
42926
|
+
if (v > hi)
|
|
42927
|
+
hi = v;
|
|
42642
42928
|
}
|
|
42643
|
-
|
|
42929
|
+
const range = hi - lo;
|
|
42930
|
+
return range > 0 ? finiteOut2((x - lo) / range * 2 - 1) : 0;
|
|
42644
42931
|
}
|
|
42645
42932
|
cumulativeDelta(site, close, volume, period) {
|
|
42646
42933
|
const n = this.asCount(period);
|
|
42647
|
-
|
|
42934
|
+
if (n === null || n <= 0)
|
|
42935
|
+
return 0;
|
|
42936
|
+
let st = this.cumDeltaSites.get(`${site}:${n}`);
|
|
42648
42937
|
if (st === undefined) {
|
|
42649
|
-
st = {
|
|
42650
|
-
this.cumDeltaSites.set(site
|
|
42938
|
+
st = { closes: [], volumes: [], count: 0 };
|
|
42939
|
+
this.cumDeltaSites.set(`${site}:${n}`, st);
|
|
42651
42940
|
}
|
|
42652
|
-
|
|
42653
|
-
|
|
42654
|
-
|
|
42941
|
+
const c = finiteCell2(close);
|
|
42942
|
+
const v = volume !== null && Number.isFinite(volume) ? volume : 0;
|
|
42943
|
+
pushCap(st.closes, c, n + 1);
|
|
42944
|
+
pushCap(st.volumes, v, n);
|
|
42945
|
+
st.count += 1;
|
|
42946
|
+
if (st.count < n)
|
|
42655
42947
|
return 0;
|
|
42656
42948
|
let delta = 0;
|
|
42657
|
-
|
|
42658
|
-
|
|
42659
|
-
const
|
|
42660
|
-
const
|
|
42661
|
-
const
|
|
42662
|
-
|
|
42663
|
-
|
|
42664
|
-
|
|
42665
|
-
|
|
42666
|
-
|
|
42667
|
-
|
|
42668
|
-
|
|
42669
|
-
}
|
|
42949
|
+
const offset = st.closes.length - st.volumes.length;
|
|
42950
|
+
for (let j = 0;j < st.volumes.length; j++) {
|
|
42951
|
+
const idx = offset + j;
|
|
42952
|
+
const cRaw = st.closes[idx] ?? null;
|
|
42953
|
+
const cur = cRaw ?? 0;
|
|
42954
|
+
const prevRaw = idx === 0 ? null : st.closes[idx - 1] ?? null;
|
|
42955
|
+
const prev = prevRaw ?? cur;
|
|
42956
|
+
const vol = st.volumes[j];
|
|
42957
|
+
if (cur > prev)
|
|
42958
|
+
delta += vol;
|
|
42959
|
+
else if (cur < prev)
|
|
42960
|
+
delta -= vol;
|
|
42670
42961
|
}
|
|
42671
42962
|
return finiteOut2(delta);
|
|
42672
42963
|
}
|
|
42673
42964
|
volumeMomentum(site, volume, period) {
|
|
42674
42965
|
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)
|
|
42966
|
+
if (n === null || n <= 0)
|
|
42682
42967
|
return 0;
|
|
42683
|
-
|
|
42684
|
-
|
|
42685
|
-
|
|
42686
|
-
|
|
42687
|
-
clean.push(v);
|
|
42968
|
+
let st = this.volMomSites.get(`${site}:${n}`);
|
|
42969
|
+
if (st === undefined) {
|
|
42970
|
+
st = { window: [] };
|
|
42971
|
+
this.volMomSites.set(`${site}:${n}`, st);
|
|
42688
42972
|
}
|
|
42689
|
-
if (
|
|
42973
|
+
if (volume !== null && Number.isFinite(volume))
|
|
42974
|
+
pushCap(st.window, volume, n + 1);
|
|
42975
|
+
if (st.window.length < n + 1)
|
|
42690
42976
|
return 0;
|
|
42691
|
-
|
|
42692
|
-
let
|
|
42693
|
-
|
|
42694
|
-
|
|
42695
|
-
|
|
42977
|
+
let oldSum = 0;
|
|
42978
|
+
for (let i = 0;i < n; i++)
|
|
42979
|
+
oldSum += st.window[i];
|
|
42980
|
+
let newSum = 0;
|
|
42981
|
+
for (let i = 1;i <= n; i++)
|
|
42982
|
+
newSum += st.window[i];
|
|
42983
|
+
const oldVol = oldSum / n;
|
|
42984
|
+
const newVol = newSum / n;
|
|
42696
42985
|
if (oldVol === 0)
|
|
42697
42986
|
return 0;
|
|
42698
42987
|
let momentum = (newVol - oldVol) / oldVol * 100;
|
|
@@ -42702,6 +42991,667 @@ class TaEngine {
|
|
|
42702
42991
|
momentum = -100;
|
|
42703
42992
|
return finiteOut2(momentum);
|
|
42704
42993
|
}
|
|
42994
|
+
smaWeighted(site, source, period, weightType) {
|
|
42995
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
42996
|
+
const kind = typeof weightType === "string" ? weightType : "linear";
|
|
42997
|
+
if (n < 1)
|
|
42998
|
+
return null;
|
|
42999
|
+
const key = `${site}:${n}:${kind}`;
|
|
43000
|
+
let st = this.smaWeightedSites.get(key);
|
|
43001
|
+
if (st === undefined) {
|
|
43002
|
+
const weights = [];
|
|
43003
|
+
for (let i = 0;i < n; i++) {
|
|
43004
|
+
if (kind === "quadratic")
|
|
43005
|
+
weights.push((i + 1) ** 2);
|
|
43006
|
+
else if (kind === "sqrt")
|
|
43007
|
+
weights.push((i + 1) ** 0.5);
|
|
43008
|
+
else
|
|
43009
|
+
weights.push(i + 1);
|
|
43010
|
+
}
|
|
43011
|
+
st = { window: [], weights, wsum: weights.reduce((a, b) => a + b, 0) };
|
|
43012
|
+
this.smaWeightedSites.set(key, st);
|
|
43013
|
+
}
|
|
43014
|
+
pushCap(st.window, finiteCell2(source), n);
|
|
43015
|
+
if (st.window.length < n || st.window.includes(null) || st.wsum <= 0)
|
|
43016
|
+
return null;
|
|
43017
|
+
let total = 0;
|
|
43018
|
+
for (let i = 0;i < n; i++)
|
|
43019
|
+
total += st.window[i] * st.weights[i];
|
|
43020
|
+
return finiteOut2(total / st.wsum);
|
|
43021
|
+
}
|
|
43022
|
+
apo(site, source, fast, slow) {
|
|
43023
|
+
const f = this.coerceTaInt(fast, "ta.apo fast_period must be integer");
|
|
43024
|
+
const s = this.coerceTaInt(slow, "ta.apo slow_period must be integer");
|
|
43025
|
+
const fastV = this.ema(`${site}:fast`, source, f);
|
|
43026
|
+
const slowV = this.ema(`${site}:slow`, source, s);
|
|
43027
|
+
if (fastV === null || slowV === null)
|
|
43028
|
+
return null;
|
|
43029
|
+
return finiteOut2(fastV - slowV);
|
|
43030
|
+
}
|
|
43031
|
+
atrNormalized(site, high, low, close, period) {
|
|
43032
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43033
|
+
const atr = this.atr(`${site}:atr`, high, low, close, n);
|
|
43034
|
+
const c = finiteCell2(close);
|
|
43035
|
+
if (c === null || c === 0 || atr === null)
|
|
43036
|
+
return null;
|
|
43037
|
+
return finiteOut2(atr / c * 100);
|
|
43038
|
+
}
|
|
43039
|
+
pairWindow(sites, site, a, b, length) {
|
|
43040
|
+
const n = this.coerceTaInt(length, "length must be integer");
|
|
43041
|
+
if (n < 1)
|
|
43042
|
+
return null;
|
|
43043
|
+
const key = `${site}:${n}`;
|
|
43044
|
+
let st = sites.get(key);
|
|
43045
|
+
if (st === undefined) {
|
|
43046
|
+
st = { a: [], b: [] };
|
|
43047
|
+
sites.set(key, st);
|
|
43048
|
+
}
|
|
43049
|
+
pushCap(st.a, finiteCell2(a), n);
|
|
43050
|
+
pushCap(st.b, finiteCell2(b), n);
|
|
43051
|
+
if (st.a.length < n || st.b.length < n)
|
|
43052
|
+
return null;
|
|
43053
|
+
const left = [];
|
|
43054
|
+
const right = [];
|
|
43055
|
+
for (let i = 0;i < n; i++) {
|
|
43056
|
+
const av = st.a[i];
|
|
43057
|
+
const bv = st.b[i];
|
|
43058
|
+
if (av === null || bv === null)
|
|
43059
|
+
return null;
|
|
43060
|
+
left.push(av);
|
|
43061
|
+
right.push(bv);
|
|
43062
|
+
}
|
|
43063
|
+
return { a: left, b: right };
|
|
43064
|
+
}
|
|
43065
|
+
beta(site, a, b, length) {
|
|
43066
|
+
const pair = this.pairWindow(this.betaSites, site, a, b, length);
|
|
43067
|
+
if (pair === null)
|
|
43068
|
+
return null;
|
|
43069
|
+
const n = pair.a.length;
|
|
43070
|
+
let meanA = 0;
|
|
43071
|
+
let meanB = 0;
|
|
43072
|
+
for (let i = 0;i < n; i++) {
|
|
43073
|
+
meanA += pair.a[i];
|
|
43074
|
+
meanB += pair.b[i];
|
|
43075
|
+
}
|
|
43076
|
+
meanA /= n;
|
|
43077
|
+
meanB /= n;
|
|
43078
|
+
let covariance = 0;
|
|
43079
|
+
let varianceB = 0;
|
|
43080
|
+
for (let i = 0;i < n; i++) {
|
|
43081
|
+
covariance += (pair.a[i] - meanA) * (pair.b[i] - meanB);
|
|
43082
|
+
varianceB += (pair.b[i] - meanB) ** 2;
|
|
43083
|
+
}
|
|
43084
|
+
covariance /= n;
|
|
43085
|
+
varianceB /= n;
|
|
43086
|
+
if (varianceB === 0)
|
|
43087
|
+
return 0;
|
|
43088
|
+
return finiteOut2(covariance / varianceB);
|
|
43089
|
+
}
|
|
43090
|
+
rSquared(site, a, b, length) {
|
|
43091
|
+
const pair = this.pairWindow(this.rSquaredSites, site, a, b, length);
|
|
43092
|
+
if (pair === null)
|
|
43093
|
+
return null;
|
|
43094
|
+
const n = pair.a.length;
|
|
43095
|
+
let meanA = 0;
|
|
43096
|
+
let meanB = 0;
|
|
43097
|
+
for (let i = 0;i < n; i++) {
|
|
43098
|
+
meanA += pair.a[i];
|
|
43099
|
+
meanB += pair.b[i];
|
|
43100
|
+
}
|
|
43101
|
+
meanA /= n;
|
|
43102
|
+
meanB /= n;
|
|
43103
|
+
let covariance = 0;
|
|
43104
|
+
let varA = 0;
|
|
43105
|
+
let varB = 0;
|
|
43106
|
+
for (let i = 0;i < n; i++) {
|
|
43107
|
+
covariance += (pair.a[i] - meanA) * (pair.b[i] - meanB);
|
|
43108
|
+
varA += (pair.a[i] - meanA) ** 2;
|
|
43109
|
+
varB += (pair.b[i] - meanB) ** 2;
|
|
43110
|
+
}
|
|
43111
|
+
covariance /= n;
|
|
43112
|
+
varA /= n;
|
|
43113
|
+
varB /= n;
|
|
43114
|
+
if (varA === 0 || varB === 0)
|
|
43115
|
+
return 0;
|
|
43116
|
+
const corr = covariance / Math.sqrt(varA * varB);
|
|
43117
|
+
return finiteOut2(Math.max(0, Math.min(1, corr ** 2)));
|
|
43118
|
+
}
|
|
43119
|
+
comovement(site, a, b, length) {
|
|
43120
|
+
const pair = this.pairWindow(this.comovementSites, site, a, b, length);
|
|
43121
|
+
if (pair === null)
|
|
43122
|
+
return null;
|
|
43123
|
+
const n = pair.a.length;
|
|
43124
|
+
if (n <= 1)
|
|
43125
|
+
return 0;
|
|
43126
|
+
let same = 0;
|
|
43127
|
+
for (let i = 1;i < n; i++) {
|
|
43128
|
+
if ((pair.a[i] - pair.a[i - 1]) * (pair.b[i] - pair.b[i - 1]) > 0)
|
|
43129
|
+
same += 1;
|
|
43130
|
+
}
|
|
43131
|
+
return finiteOut2(same / (n - 1) * 100);
|
|
43132
|
+
}
|
|
43133
|
+
skewness(site, source, period) {
|
|
43134
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43135
|
+
if (n < 1)
|
|
43136
|
+
return null;
|
|
43137
|
+
const key = `${site}:${n}`;
|
|
43138
|
+
let st = this.skewnessSites.get(key);
|
|
43139
|
+
if (st === undefined) {
|
|
43140
|
+
st = { window: [] };
|
|
43141
|
+
this.skewnessSites.set(key, st);
|
|
43142
|
+
}
|
|
43143
|
+
pushCap(st.window, finiteCell2(source), n);
|
|
43144
|
+
if (st.window.length < n || st.window.includes(null))
|
|
43145
|
+
return null;
|
|
43146
|
+
const vals = st.window;
|
|
43147
|
+
let mean = 0;
|
|
43148
|
+
for (const v of vals)
|
|
43149
|
+
mean += v;
|
|
43150
|
+
mean /= n;
|
|
43151
|
+
let variance = 0;
|
|
43152
|
+
for (const v of vals)
|
|
43153
|
+
variance += (v - mean) ** 2;
|
|
43154
|
+
variance /= n;
|
|
43155
|
+
const std = Math.sqrt(variance);
|
|
43156
|
+
if (std === 0)
|
|
43157
|
+
return 0;
|
|
43158
|
+
let third = 0;
|
|
43159
|
+
for (const v of vals)
|
|
43160
|
+
third += (v - mean) ** 3;
|
|
43161
|
+
return finiteOut2(third / (n * std ** 3));
|
|
43162
|
+
}
|
|
43163
|
+
kurtosis(site, source, period) {
|
|
43164
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43165
|
+
if (n < 1)
|
|
43166
|
+
return null;
|
|
43167
|
+
const key = `${site}:${n}`;
|
|
43168
|
+
let st = this.kurtosisSites.get(key);
|
|
43169
|
+
if (st === undefined) {
|
|
43170
|
+
st = { window: [] };
|
|
43171
|
+
this.kurtosisSites.set(key, st);
|
|
43172
|
+
}
|
|
43173
|
+
pushCap(st.window, finiteCell2(source), n);
|
|
43174
|
+
if (st.window.length < n || st.window.includes(null))
|
|
43175
|
+
return null;
|
|
43176
|
+
const vals = st.window;
|
|
43177
|
+
let mean = 0;
|
|
43178
|
+
for (const v of vals)
|
|
43179
|
+
mean += v;
|
|
43180
|
+
mean /= n;
|
|
43181
|
+
let variance = 0;
|
|
43182
|
+
for (const v of vals)
|
|
43183
|
+
variance += (v - mean) ** 2;
|
|
43184
|
+
variance /= n;
|
|
43185
|
+
const std = Math.sqrt(variance);
|
|
43186
|
+
if (std === 0)
|
|
43187
|
+
return 0;
|
|
43188
|
+
let fourth = 0;
|
|
43189
|
+
for (const v of vals)
|
|
43190
|
+
fourth += (v - mean) ** 4;
|
|
43191
|
+
fourth /= n;
|
|
43192
|
+
return finiteOut2(fourth / std ** 4 - 3);
|
|
43193
|
+
}
|
|
43194
|
+
volumeWeightedMomentum(site, source, volume, length) {
|
|
43195
|
+
const n = this.coerceTaInt(length, "length must be integer");
|
|
43196
|
+
if (n < 1)
|
|
43197
|
+
return null;
|
|
43198
|
+
const key = `${site}:${n}`;
|
|
43199
|
+
let st = this.vwmSites.get(key);
|
|
43200
|
+
if (st === undefined) {
|
|
43201
|
+
st = { prices: [], volumes: [] };
|
|
43202
|
+
this.vwmSites.set(key, st);
|
|
43203
|
+
}
|
|
43204
|
+
pushCap(st.prices, finiteCell2(source), n + 1);
|
|
43205
|
+
pushCap(st.volumes, finiteCell2(volume), n);
|
|
43206
|
+
if (st.volumes.length < n)
|
|
43207
|
+
return null;
|
|
43208
|
+
const ps = st.prices;
|
|
43209
|
+
const vs = st.volumes;
|
|
43210
|
+
let momentumSum = 0;
|
|
43211
|
+
let volumeSum = 0;
|
|
43212
|
+
for (let i = 0;i < n; i++) {
|
|
43213
|
+
const pEnd = ps.length - 1 - i;
|
|
43214
|
+
const pPrev = pEnd - 1;
|
|
43215
|
+
if (pPrev < 0)
|
|
43216
|
+
break;
|
|
43217
|
+
const pv = ps[pEnd] ?? null;
|
|
43218
|
+
const pp = ps[pPrev] ?? null;
|
|
43219
|
+
if (pv === null || pp === null)
|
|
43220
|
+
return null;
|
|
43221
|
+
const vol = vs[vs.length - 1 - i] ?? 0;
|
|
43222
|
+
momentumSum += (pv - pp) * vol;
|
|
43223
|
+
volumeSum += vol;
|
|
43224
|
+
}
|
|
43225
|
+
return finiteOut2(volumeSum > 0 ? momentumSum / volumeSum : 0);
|
|
43226
|
+
}
|
|
43227
|
+
parkinson(high, low) {
|
|
43228
|
+
const h = finiteCell2(high);
|
|
43229
|
+
const l = finiteCell2(low);
|
|
43230
|
+
if (h === null || l === null || h <= l)
|
|
43231
|
+
return null;
|
|
43232
|
+
const ratio = h / l;
|
|
43233
|
+
if (ratio <= 0)
|
|
43234
|
+
return null;
|
|
43235
|
+
return finiteOut2(Math.sqrt(Math.log(ratio) ** 2 / (4 * Math.log(2))));
|
|
43236
|
+
}
|
|
43237
|
+
garmanKlass(high, low, close, open) {
|
|
43238
|
+
const h = finiteCell2(high);
|
|
43239
|
+
const l = finiteCell2(low);
|
|
43240
|
+
const c = finiteCell2(close);
|
|
43241
|
+
const o = finiteCell2(open);
|
|
43242
|
+
if (h === null || l === null || c === null || o === null)
|
|
43243
|
+
return null;
|
|
43244
|
+
if (h <= l || h <= 0 || c <= 0)
|
|
43245
|
+
return null;
|
|
43246
|
+
const term1 = 0.5 * Math.log(h / l) ** 2;
|
|
43247
|
+
const term2 = (2 * Math.log(2) - 1) * Math.log(c / o) ** 2;
|
|
43248
|
+
return finiteOut2(Math.sqrt(term1 - term2));
|
|
43249
|
+
}
|
|
43250
|
+
meanReversionScore(site, close, sma, stdev, period) {
|
|
43251
|
+
const n = this.coerceTaInt(period, "ta.mean_reversion_score() requires 4 arguments");
|
|
43252
|
+
if (n <= 0)
|
|
43253
|
+
return 50;
|
|
43254
|
+
let st = this.meanReversionSites.get(`${site}:${n}`);
|
|
43255
|
+
if (st === undefined) {
|
|
43256
|
+
st = { countClose: 0, countSma: 0 };
|
|
43257
|
+
this.meanReversionSites.set(`${site}:${n}`, st);
|
|
43258
|
+
}
|
|
43259
|
+
st.countClose += 1;
|
|
43260
|
+
st.countSma += 1;
|
|
43261
|
+
if (st.countClose < n || st.countSma < n)
|
|
43262
|
+
return 50;
|
|
43263
|
+
const c = finiteCell2(close) ?? 100;
|
|
43264
|
+
const s = finiteCell2(sma) ?? 100;
|
|
43265
|
+
const sd = finiteCell2(stdev) ?? 1;
|
|
43266
|
+
if (sd === 0)
|
|
43267
|
+
return 50;
|
|
43268
|
+
return Math.max(0, Math.min(100, Math.min(100, Math.abs(c - s) / sd * 20)));
|
|
43269
|
+
}
|
|
43270
|
+
marketCondition(site, close, atr, smaPeriod, stdevPeriod) {
|
|
43271
|
+
const smaN = this.coerceTaInt(smaPeriod, "sma period must be integer");
|
|
43272
|
+
const stdevN = this.coerceTaInt(stdevPeriod, "stdev period must be integer");
|
|
43273
|
+
if (smaN <= 0 || stdevN <= 0)
|
|
43274
|
+
return "ranging";
|
|
43275
|
+
const win = Math.max(smaN, stdevN);
|
|
43276
|
+
const key = `${site}:${smaN}:${stdevN}`;
|
|
43277
|
+
let st = this.marketConditionSites.get(key);
|
|
43278
|
+
if (st === undefined) {
|
|
43279
|
+
st = { window: [], atr: null };
|
|
43280
|
+
this.marketConditionSites.set(key, st);
|
|
43281
|
+
}
|
|
43282
|
+
pushCap(st.window, finiteCell2(close), win);
|
|
43283
|
+
st.atr = finiteCell2(atr);
|
|
43284
|
+
if (st.window.length < win)
|
|
43285
|
+
return "ranging";
|
|
43286
|
+
const cLast = st.window[st.window.length - 1] ?? null;
|
|
43287
|
+
const currentClose = cLast ?? 0;
|
|
43288
|
+
const currentAtr = st.atr ?? 1;
|
|
43289
|
+
const currentSma = smaOf(st.window, smaN) ?? currentClose;
|
|
43290
|
+
const stdevVal = stdevOf(st.window, stdevN);
|
|
43291
|
+
if (stdevVal !== null && stdevVal > currentAtr * 1.5)
|
|
43292
|
+
return "volatile";
|
|
43293
|
+
if (currentClose > currentSma && currentAtr > 0.5)
|
|
43294
|
+
return "trending_up";
|
|
43295
|
+
if (currentClose < currentSma && currentAtr > 0.5)
|
|
43296
|
+
return "trending_down";
|
|
43297
|
+
return "ranging";
|
|
43298
|
+
}
|
|
43299
|
+
orderFlowImbalance(site, high, low, close, volume, period) {
|
|
43300
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43301
|
+
if (n <= 0)
|
|
43302
|
+
return 0;
|
|
43303
|
+
const key = `${site}:${n}`;
|
|
43304
|
+
let st = this.orderFlowSites.get(key);
|
|
43305
|
+
if (st === undefined) {
|
|
43306
|
+
st = { highs: [], lows: [], closes: [], volumes: [] };
|
|
43307
|
+
this.orderFlowSites.set(key, st);
|
|
43308
|
+
}
|
|
43309
|
+
pushCap(st.highs, finiteCell2(high), n);
|
|
43310
|
+
pushCap(st.lows, finiteCell2(low), n);
|
|
43311
|
+
pushCap(st.closes, finiteCell2(close), n);
|
|
43312
|
+
pushCap(st.volumes, finiteCell2(volume), n);
|
|
43313
|
+
if (st.highs.length < n || st.lows.length < n)
|
|
43314
|
+
return 0;
|
|
43315
|
+
let buy = 0;
|
|
43316
|
+
let sell = 0;
|
|
43317
|
+
for (let i = 0;i < n; i++) {
|
|
43318
|
+
const h = st.highs[i] ?? 0;
|
|
43319
|
+
const l = st.lows[i] ?? 0;
|
|
43320
|
+
const c = st.closes[i] ?? 0;
|
|
43321
|
+
const v = st.volumes[i] ?? 0;
|
|
43322
|
+
if (h > l) {
|
|
43323
|
+
const mid = (h + l) / 2;
|
|
43324
|
+
if (c > mid)
|
|
43325
|
+
buy += v;
|
|
43326
|
+
else
|
|
43327
|
+
sell += v;
|
|
43328
|
+
}
|
|
43329
|
+
}
|
|
43330
|
+
const total = buy + sell;
|
|
43331
|
+
if (total === 0)
|
|
43332
|
+
return 0;
|
|
43333
|
+
return finiteOut2((buy - sell) / total) ?? 0;
|
|
43334
|
+
}
|
|
43335
|
+
liquidityScore(site, volume, volatility, spread, period) {
|
|
43336
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43337
|
+
if (n <= 0)
|
|
43338
|
+
return 50;
|
|
43339
|
+
const key = `${site}:${n}`;
|
|
43340
|
+
let st = this.liquiditySites.get(key);
|
|
43341
|
+
if (st === undefined) {
|
|
43342
|
+
st = { volume: [], volatility: [], spread: [] };
|
|
43343
|
+
this.liquiditySites.set(key, st);
|
|
43344
|
+
}
|
|
43345
|
+
pushCap(st.volume, finiteCell2(volume), n);
|
|
43346
|
+
pushCap(st.volatility, finiteCell2(volatility), n);
|
|
43347
|
+
pushCap(st.spread, finiteCell2(spread), n);
|
|
43348
|
+
if (st.volume.length < n || st.volatility.length < n || st.spread.length < n)
|
|
43349
|
+
return 50;
|
|
43350
|
+
let volSum = 0;
|
|
43351
|
+
for (const v of st.volume)
|
|
43352
|
+
if (v !== null)
|
|
43353
|
+
volSum += v;
|
|
43354
|
+
let volaSum = 0;
|
|
43355
|
+
for (const v of st.volatility)
|
|
43356
|
+
if (v !== null)
|
|
43357
|
+
volaSum += v;
|
|
43358
|
+
let spreadSum = 0;
|
|
43359
|
+
for (const v of st.spread)
|
|
43360
|
+
if (v !== null)
|
|
43361
|
+
spreadSum += v;
|
|
43362
|
+
const volScore = Math.min(100, volSum / n / 100);
|
|
43363
|
+
const volatilityScore = Math.max(0, 100 - volaSum / n * 50);
|
|
43364
|
+
const spreadScore = Math.max(0, 100 - spreadSum / n * 100);
|
|
43365
|
+
const liquidity = volScore * 0.4 + volatilityScore * 0.3 + spreadScore * 0.3;
|
|
43366
|
+
return Math.max(0, Math.min(100, liquidity));
|
|
43367
|
+
}
|
|
43368
|
+
fearGreedIndex(rsi, vix, putCall, breadth) {
|
|
43369
|
+
const r = finiteCell2(rsi) ?? 50;
|
|
43370
|
+
const v = finiteCell2(vix) ?? 2;
|
|
43371
|
+
const pc = finiteCell2(putCall) ?? 1;
|
|
43372
|
+
const b = finiteCell2(breadth) ?? 0.5;
|
|
43373
|
+
const index = ((r - 50) * 1 + (v - 2) * 10 + (1 - pc) * 50 + (b - 0.5) * 100) / 4;
|
|
43374
|
+
return Math.max(-100, Math.min(100, index));
|
|
43375
|
+
}
|
|
43376
|
+
crowdSentiment(priceAgreement, volumeAgreement, timeAgreement) {
|
|
43377
|
+
const p = finiteCell2(priceAgreement) ?? 0.5;
|
|
43378
|
+
const v = finiteCell2(volumeAgreement) ?? 0.5;
|
|
43379
|
+
const t = finiteCell2(timeAgreement) ?? 0.5;
|
|
43380
|
+
return Math.max(0, Math.min(100, (p + v + t) / 3 * 100));
|
|
43381
|
+
}
|
|
43382
|
+
smartMoneyFlow(priceChange, volume, timeHigh, timeLow) {
|
|
43383
|
+
const p = finiteCell2(priceChange) ?? 0;
|
|
43384
|
+
const v = finiteCell2(volume) ?? 1000;
|
|
43385
|
+
const th = finiteCell2(timeHigh) ?? 10;
|
|
43386
|
+
const tl = finiteCell2(timeLow) ?? 10;
|
|
43387
|
+
const volFactor = Math.min(1, v / 5000);
|
|
43388
|
+
let flow = 0;
|
|
43389
|
+
if (p > 0 && th < tl)
|
|
43390
|
+
flow = volFactor * 0.8;
|
|
43391
|
+
else if (p < 0 && tl < th)
|
|
43392
|
+
flow = -volFactor * 0.8;
|
|
43393
|
+
return Math.max(-1, Math.min(1, flow));
|
|
43394
|
+
}
|
|
43395
|
+
trendConfirmationScore(momentum, trendAlignment, strength, rsi, rsiAlignment) {
|
|
43396
|
+
const m = finiteCell2(momentum) ?? 0;
|
|
43397
|
+
const t = finiteCell2(trendAlignment) ?? 0;
|
|
43398
|
+
const s = finiteCell2(strength) ?? 1;
|
|
43399
|
+
const r = finiteCell2(rsi) ?? 50;
|
|
43400
|
+
const a = finiteCell2(rsiAlignment) ?? 0;
|
|
43401
|
+
const momentumScore = Math.min(100, Math.abs(m) * 20);
|
|
43402
|
+
const trendScore = Math.max(0, (t + 1) / 2 * 100);
|
|
43403
|
+
const strengthScore = Math.min(100, s * 50);
|
|
43404
|
+
const rsiScore = Math.abs(r - 50) > 10 ? Math.min(100, Math.abs(r - 50) * 2) : 40;
|
|
43405
|
+
const alignmentBonus = Math.abs(a) > 0.5 ? 20 : 0;
|
|
43406
|
+
const total = momentumScore * 0.25 + trendScore * 0.3 + strengthScore * 0.25 + rsiScore * 0.15 + alignmentBonus;
|
|
43407
|
+
return Math.max(0, Math.min(100, total));
|
|
43408
|
+
}
|
|
43409
|
+
maxLossLevel(entry, account, maxLossPct) {
|
|
43410
|
+
const e = finiteCell2(entry) ?? 100;
|
|
43411
|
+
const a = finiteCell2(account) ?? 1e4;
|
|
43412
|
+
const p = finiteCell2(maxLossPct) ?? 1;
|
|
43413
|
+
const maxLossAmount = a * (p / 100);
|
|
43414
|
+
if (e <= 0)
|
|
43415
|
+
return 0;
|
|
43416
|
+
const shares = a / e;
|
|
43417
|
+
const stop = shares > 0 ? e - maxLossAmount / shares : 0;
|
|
43418
|
+
return Math.max(0, stop);
|
|
43419
|
+
}
|
|
43420
|
+
profitLockLevel(entry, current, trailPct, direction) {
|
|
43421
|
+
const e = finiteCell2(entry) ?? 100;
|
|
43422
|
+
const c = finiteCell2(current) ?? 100;
|
|
43423
|
+
const t = Math.max(0, Math.min(1, finiteCell2(trailPct) ?? 0.05));
|
|
43424
|
+
const d = finiteCell2(direction) ?? 1;
|
|
43425
|
+
return d > 0 ? Math.max(e * 0.9, c - c * t) : Math.min(e * 1.1, c + c * t);
|
|
43426
|
+
}
|
|
43427
|
+
positionSizing(account, riskPct, entry, stop) {
|
|
43428
|
+
const a = finiteCell2(account) ?? 1e4;
|
|
43429
|
+
const r = finiteCell2(riskPct) ?? 0.01;
|
|
43430
|
+
const e = finiteCell2(entry) ?? 100;
|
|
43431
|
+
const s = finiteCell2(stop) ?? 95;
|
|
43432
|
+
const riskAmount = a * (r / 100);
|
|
43433
|
+
const distance = e - s;
|
|
43434
|
+
if (Math.abs(distance) < 0.0000000001)
|
|
43435
|
+
return 0;
|
|
43436
|
+
return Math.max(0, riskAmount / Math.abs(distance));
|
|
43437
|
+
}
|
|
43438
|
+
kellyCriterion(winRate, avgWin, avgLoss) {
|
|
43439
|
+
const wr = Math.max(0, Math.min(1, finiteCell2(winRate) ?? 0.5));
|
|
43440
|
+
const win = finiteCell2(avgWin) ?? 1;
|
|
43441
|
+
const loss = finiteCell2(avgLoss) ?? 1;
|
|
43442
|
+
if (Math.abs(win) < 0.0000000001)
|
|
43443
|
+
return 0;
|
|
43444
|
+
const kelly = (wr * win - (1 - wr) * loss) / win;
|
|
43445
|
+
return Math.max(0, kelly);
|
|
43446
|
+
}
|
|
43447
|
+
riskRewardRatio(entry, stop, target) {
|
|
43448
|
+
const e = finiteCell2(entry) ?? 0;
|
|
43449
|
+
const s = finiteCell2(stop) ?? 0;
|
|
43450
|
+
const t = finiteCell2(target) ?? 0;
|
|
43451
|
+
const risk = e - s;
|
|
43452
|
+
if (Math.abs(risk) < 0.0000000001)
|
|
43453
|
+
return null;
|
|
43454
|
+
return finiteOut2((t - e) / risk);
|
|
43455
|
+
}
|
|
43456
|
+
riskRewardAsymmetry(entry, stop, target, winRate) {
|
|
43457
|
+
const e = finiteCell2(entry) ?? 0;
|
|
43458
|
+
const s = finiteCell2(stop) ?? 0;
|
|
43459
|
+
const t = finiteCell2(target) ?? 0;
|
|
43460
|
+
const wr = finiteCell2(winRate) ?? 0.5;
|
|
43461
|
+
const risk = Math.abs(e - s);
|
|
43462
|
+
const reward = Math.abs(t - e);
|
|
43463
|
+
const ratio = risk > 0 ? reward / risk : 0;
|
|
43464
|
+
const ev = wr * reward - (1 - wr) * risk;
|
|
43465
|
+
const kelly = ratio > 0 ? wr - (1 - wr) / ratio : 0;
|
|
43466
|
+
return taRec({
|
|
43467
|
+
ratio: finiteOut2(ratio) ?? 0,
|
|
43468
|
+
expected_value: finiteOut2(ev) ?? 0,
|
|
43469
|
+
kelly_percent: finiteOut2(kelly * 100) ?? 0,
|
|
43470
|
+
is_favorable: ev > 0,
|
|
43471
|
+
risk_reward_ratio: finiteOut2(ratio) ?? 0,
|
|
43472
|
+
kelly_percentage: finiteOut2(kelly * 100) ?? 0
|
|
43473
|
+
});
|
|
43474
|
+
}
|
|
43475
|
+
probabilityOfMovement(current, target, atr, period) {
|
|
43476
|
+
const c = finiteCell2(current) ?? 100;
|
|
43477
|
+
const t = finiteCell2(target) ?? 100;
|
|
43478
|
+
const a = finiteCell2(atr) ?? 1;
|
|
43479
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
43480
|
+
if (Math.abs(c) < 0.0000000001 || Math.abs(a) < 0.0000000001)
|
|
43481
|
+
return 0.5;
|
|
43482
|
+
const distance = Math.abs(t - c);
|
|
43483
|
+
const expected = a * Math.sqrt(n);
|
|
43484
|
+
if (expected === 0)
|
|
43485
|
+
return 0.5;
|
|
43486
|
+
return Math.max(0, Math.min(1, Math.min(1, distance / expected) * 0.8 + 0.1));
|
|
43487
|
+
}
|
|
43488
|
+
trendStrength(price, adx, rsi) {
|
|
43489
|
+
const a = finiteCell2(adx) ?? 20;
|
|
43490
|
+
const r = finiteCell2(rsi) ?? 50;
|
|
43491
|
+
const adxNorm = Math.min(100, Math.max(0, a));
|
|
43492
|
+
const rsiExtremeness = Math.abs(r - 50) / 50;
|
|
43493
|
+
return Math.min(100, Math.max(0, adxNorm * 0.6 + rsiExtremeness * 40));
|
|
43494
|
+
}
|
|
43495
|
+
breakevenLevel(entry, qty, commission, slippage, direction) {
|
|
43496
|
+
const e = finiteCell2(entry) ?? 0;
|
|
43497
|
+
const q = finiteCell2(qty) ?? 0;
|
|
43498
|
+
const comm = finiteCell2(commission) ?? 0;
|
|
43499
|
+
const slip = finiteCell2(slippage) ?? 0;
|
|
43500
|
+
const d = finiteCell2(direction) ?? 1;
|
|
43501
|
+
const cost = comm + slip * q;
|
|
43502
|
+
const impact = q > 0 ? cost / q : 0;
|
|
43503
|
+
const breakeven = d >= 0 ? e + impact : e - impact;
|
|
43504
|
+
const move = e > 0 ? Math.abs(breakeven - e) / e * 100 : 0;
|
|
43505
|
+
return taRec({
|
|
43506
|
+
breakeven_price: finiteOut2(breakeven) ?? 0,
|
|
43507
|
+
total_cost: finiteOut2(cost) ?? 0,
|
|
43508
|
+
move_required_percent: finiteOut2(move) ?? 0
|
|
43509
|
+
});
|
|
43510
|
+
}
|
|
43511
|
+
marketStructurePivot(close) {
|
|
43512
|
+
const c = finiteCell2(close) ?? 0;
|
|
43513
|
+
return taRec({ pivot_price: c, structure: "fractal", type: "high" });
|
|
43514
|
+
}
|
|
43515
|
+
positionSizingScore(risk, volatility, conviction, correlation) {
|
|
43516
|
+
const r = finiteCell2(risk) ?? 0;
|
|
43517
|
+
const v = finiteCell2(volatility) ?? 0;
|
|
43518
|
+
const c = finiteCell2(conviction) ?? 0;
|
|
43519
|
+
const corr = finiteCell2(correlation) ?? 0;
|
|
43520
|
+
let score = r / (v + 0.1) * c * (1 - corr);
|
|
43521
|
+
score = Math.max(0, Math.min(1, score * 0.1));
|
|
43522
|
+
return taRec({
|
|
43523
|
+
score: finiteOut2(score * 100) ?? 0,
|
|
43524
|
+
position_size_ratio: finiteOut2(score) ?? 0,
|
|
43525
|
+
kelly_fraction: finiteOut2(score * 0.5) ?? 0,
|
|
43526
|
+
correlation_adjustment: finiteOut2(1 - corr) ?? 0
|
|
43527
|
+
});
|
|
43528
|
+
}
|
|
43529
|
+
trailingExitLevel(entry, current, atr, mult, step) {
|
|
43530
|
+
const e = finiteCell2(entry) ?? 0;
|
|
43531
|
+
const c = finiteCell2(current) ?? 0;
|
|
43532
|
+
const a = finiteCell2(atr) ?? 0;
|
|
43533
|
+
const m = finiteCell2(mult) ?? 0;
|
|
43534
|
+
finiteCell2(step);
|
|
43535
|
+
const trail = c > e ? Math.max(e * 1.001, c - a * m) : c + a * m;
|
|
43536
|
+
return taRec({
|
|
43537
|
+
trail_stop: finiteOut2(trail) ?? 0,
|
|
43538
|
+
protected_profit: c > e ? finiteOut2(Math.max(0, c - e)) ?? 0 : 0,
|
|
43539
|
+
risk_reward_current: a > 0 ? finiteOut2(Math.abs(c - e) / a) ?? 0 : 0
|
|
43540
|
+
});
|
|
43541
|
+
}
|
|
43542
|
+
optimalEntryZone(close) {
|
|
43543
|
+
const c = finiteCell2(close) ?? 0;
|
|
43544
|
+
return taRec({
|
|
43545
|
+
min: finiteOut2(c * 0.99) ?? 0,
|
|
43546
|
+
max: finiteOut2(c * 1.01) ?? 0,
|
|
43547
|
+
optimal: c,
|
|
43548
|
+
entry_zone_low: finiteOut2(c * 0.99) ?? 0,
|
|
43549
|
+
entry_zone_high: finiteOut2(c * 1.01) ?? 0,
|
|
43550
|
+
best_entry: c,
|
|
43551
|
+
zone_strength: 85
|
|
43552
|
+
});
|
|
43553
|
+
}
|
|
43554
|
+
meanReversionEntry(price, sma, stdev, threshold) {
|
|
43555
|
+
const p = finiteCell2(price) ?? 0;
|
|
43556
|
+
const s = finiteCell2(sma) ?? 0;
|
|
43557
|
+
const sd = finiteCell2(stdev) ?? 1;
|
|
43558
|
+
const th = finiteCell2(threshold) ?? 0;
|
|
43559
|
+
const z = sd !== 0 ? (p - s) / sd : 0;
|
|
43560
|
+
return taRec({
|
|
43561
|
+
entry_price: 100,
|
|
43562
|
+
stop_loss: 95,
|
|
43563
|
+
take_profit: 105,
|
|
43564
|
+
probability: 0.7,
|
|
43565
|
+
reversion_probability: 0.75,
|
|
43566
|
+
target_price: 105,
|
|
43567
|
+
z_score: finiteOut2(z) ?? 0,
|
|
43568
|
+
is_mean_reversion_setup: Math.abs(z) > th
|
|
43569
|
+
});
|
|
43570
|
+
}
|
|
43571
|
+
multiTimeframeSignal(s1, s2, s3, w1, w2, w3) {
|
|
43572
|
+
const score = (finiteCell2(s1) ?? 0) * (finiteCell2(w1) ?? 0) + (finiteCell2(s2) ?? 0) * (finiteCell2(w2) ?? 0) + (finiteCell2(s3) ?? 0) * (finiteCell2(w3) ?? 0);
|
|
43573
|
+
return taRec({ score: finiteOut2(score) ?? 0, signal: score > 0.5 ? "buy" : "sell", agreement: true });
|
|
43574
|
+
}
|
|
43575
|
+
marketTimingIndex(trend, momentum, volatility, sentiment) {
|
|
43576
|
+
const t = finiteCell2(trend) ?? 0;
|
|
43577
|
+
const m = finiteCell2(momentum) ?? 0;
|
|
43578
|
+
const v = finiteCell2(volatility) ?? 0;
|
|
43579
|
+
const s = finiteCell2(sentiment) ?? 0;
|
|
43580
|
+
const score = t * 0.3 + m * 0.3 + v * 0.2 + s * 0.2;
|
|
43581
|
+
let recommendation = "hold";
|
|
43582
|
+
if (score > 80)
|
|
43583
|
+
recommendation = "strong_buy";
|
|
43584
|
+
else if (score > 60)
|
|
43585
|
+
recommendation = "buy";
|
|
43586
|
+
else if (score < 20)
|
|
43587
|
+
recommendation = "strong_sell";
|
|
43588
|
+
else if (score < 40)
|
|
43589
|
+
recommendation = "sell";
|
|
43590
|
+
return taRec({
|
|
43591
|
+
score: finiteOut2(score) ?? 0,
|
|
43592
|
+
recommendation,
|
|
43593
|
+
regime: Math.abs(t) > 50 ? "trending" : "ranging",
|
|
43594
|
+
timing_index: finiteOut2(score) ?? 0,
|
|
43595
|
+
market_condition: score > 80 ? "optimal_long" : "neutral",
|
|
43596
|
+
confidence: 0.85
|
|
43597
|
+
});
|
|
43598
|
+
}
|
|
43599
|
+
regimeAdaptiveSignal(strength, volRegime, trendRegime) {
|
|
43600
|
+
const vol = typeof volRegime === "string" ? volRegime : "";
|
|
43601
|
+
const trend = typeof trendRegime === "string" ? trendRegime : "";
|
|
43602
|
+
let adapted = finiteCell2(strength) ?? 0;
|
|
43603
|
+
let fit = 1;
|
|
43604
|
+
if (vol === "high") {
|
|
43605
|
+
adapted *= 0.8;
|
|
43606
|
+
fit *= 0.8;
|
|
43607
|
+
}
|
|
43608
|
+
if (trend === "ranging") {
|
|
43609
|
+
adapted *= 0.5;
|
|
43610
|
+
fit *= 0.5;
|
|
43611
|
+
}
|
|
43612
|
+
return taRec({
|
|
43613
|
+
signal: adapted > 0.5 ? "buy" : "sell",
|
|
43614
|
+
strength: finiteOut2(adapted) ?? 0,
|
|
43615
|
+
confidence: finiteOut2(adapted * 100) ?? 0,
|
|
43616
|
+
adapted_signal: finiteOut2(adapted) ?? 0,
|
|
43617
|
+
regime_fit: finiteOut2(fit) ?? 0,
|
|
43618
|
+
strategy_recommendation: trend === "trending" ? "trend_following" : "mean_reversion",
|
|
43619
|
+
signal_confidence: finiteOut2(adapted) ?? 0
|
|
43620
|
+
});
|
|
43621
|
+
}
|
|
43622
|
+
strategyScore(rsi, macd, emaCross, trend) {
|
|
43623
|
+
const r = finiteCell2(rsi) ?? 50;
|
|
43624
|
+
const m = finiteCell2(macd) ?? 0;
|
|
43625
|
+
const cross = emaCross != null && emaCross !== 0;
|
|
43626
|
+
const t = finiteCell2(trend) ?? 50;
|
|
43627
|
+
const rsiNorm = (r - 50) / 50 * 25;
|
|
43628
|
+
const macdNorm = Math.max(-25, Math.min(25, m * 50));
|
|
43629
|
+
const emaBonus = cross ? 25 : -25;
|
|
43630
|
+
const trendNorm = (t - 50) / 50 * 25;
|
|
43631
|
+
return Math.max(-100, Math.min(100, rsiNorm + macdNorm + emaBonus + trendNorm));
|
|
43632
|
+
}
|
|
43633
|
+
breakoutDetection(close, resistance, support) {
|
|
43634
|
+
const c = finiteCell2(close) ?? 0;
|
|
43635
|
+
const r = finiteCell2(resistance) ?? 0;
|
|
43636
|
+
const s = finiteCell2(support) ?? 0;
|
|
43637
|
+
if (c > r) {
|
|
43638
|
+
const strength = r > 0 ? (c - r) / r * 100 : 0;
|
|
43639
|
+
return taRec({
|
|
43640
|
+
is_breakout: true,
|
|
43641
|
+
breakout_type: "resistance",
|
|
43642
|
+
breakout_strength: finiteOut2(strength) ?? 0
|
|
43643
|
+
});
|
|
43644
|
+
}
|
|
43645
|
+
if (c < s) {
|
|
43646
|
+
const strength = s > 0 ? (s - c) / s * 100 : 0;
|
|
43647
|
+
return taRec({
|
|
43648
|
+
is_breakout: true,
|
|
43649
|
+
breakout_type: "support",
|
|
43650
|
+
breakout_strength: finiteOut2(strength) ?? 0
|
|
43651
|
+
});
|
|
43652
|
+
}
|
|
43653
|
+
return taRec({ is_breakout: false, breakout_type: "none", breakout_strength: 0 });
|
|
43654
|
+
}
|
|
42705
43655
|
volumeProfileHigh(prices, volumes) {
|
|
42706
43656
|
if (prices.length === 0 || volumes.length === 0 || prices.length !== volumes.length)
|
|
42707
43657
|
return 0;
|
|
@@ -42774,19 +43724,27 @@ class TaEngine {
|
|
|
42774
43724
|
const sens = Number.isFinite(sensitivity) ? sensitivity : 0.3;
|
|
42775
43725
|
let st = this.volThrustSites.get(site);
|
|
42776
43726
|
if (st === undefined) {
|
|
42777
|
-
st = {
|
|
43727
|
+
st = { closes: [], volume: null, sma: null, nClose: 0, nVolume: 0, nSma: 0 };
|
|
42778
43728
|
this.volThrustSites.set(site, st);
|
|
42779
43729
|
}
|
|
42780
|
-
|
|
42781
|
-
|
|
42782
|
-
|
|
42783
|
-
|
|
43730
|
+
if (!(close === null && st.nClose === 0)) {
|
|
43731
|
+
pushCap(st.closes, finiteCell2(close), 2);
|
|
43732
|
+
st.nClose += 1;
|
|
43733
|
+
}
|
|
43734
|
+
if (!(volume === null && st.nVolume === 0)) {
|
|
43735
|
+
st.volume = finiteCell2(volume);
|
|
43736
|
+
st.nVolume += 1;
|
|
43737
|
+
}
|
|
43738
|
+
if (!(volSma === null && st.nSma === 0)) {
|
|
43739
|
+
st.sma = finiteCell2(volSma);
|
|
43740
|
+
st.nSma += 1;
|
|
43741
|
+
}
|
|
43742
|
+
if (st.nClose < 1 || st.nVolume < 1 || st.nSma < 1)
|
|
42784
43743
|
return 0;
|
|
42785
|
-
const
|
|
42786
|
-
const
|
|
42787
|
-
const
|
|
42788
|
-
const
|
|
42789
|
-
const vsVal = numOr(this.nf(st.sma, -1), 1000);
|
|
43744
|
+
const cVal = st.closes[st.closes.length - 1] ?? 100;
|
|
43745
|
+
const cPrev = st.closes.length > 1 ? st.closes[st.closes.length - 2] ?? 100 : 100;
|
|
43746
|
+
const vVal = st.volume ?? 1000;
|
|
43747
|
+
const vsVal = st.sma ?? 1000;
|
|
42790
43748
|
const spike = vVal > vsVal * (1 + sens);
|
|
42791
43749
|
const move = cPrev !== 0 ? Math.abs(cVal - cPrev) / cPrev > 0.01 : false;
|
|
42792
43750
|
return spike && move ? 1 : 0;
|
|
@@ -43279,7 +44237,45 @@ var TA_METHODS = new Set([
|
|
|
43279
44237
|
"volume_momentum",
|
|
43280
44238
|
"volume_profile_high",
|
|
43281
44239
|
"volume_profile_low",
|
|
43282
|
-
"volume_thrust"
|
|
44240
|
+
"volume_thrust",
|
|
44241
|
+
"sma_weighted",
|
|
44242
|
+
"apo",
|
|
44243
|
+
"atr_normalized",
|
|
44244
|
+
"beta",
|
|
44245
|
+
"r_squared",
|
|
44246
|
+
"comovement",
|
|
44247
|
+
"skewness",
|
|
44248
|
+
"kurtosis",
|
|
44249
|
+
"volume_weighted_momentum",
|
|
44250
|
+
"parkinson",
|
|
44251
|
+
"garman_klass",
|
|
44252
|
+
"mean_reversion_score",
|
|
44253
|
+
"market_condition",
|
|
44254
|
+
"order_flow_imbalance",
|
|
44255
|
+
"liquidity_score",
|
|
44256
|
+
"fear_greed_index",
|
|
44257
|
+
"crowd_sentiment",
|
|
44258
|
+
"smart_money_flow",
|
|
44259
|
+
"trend_confirmation_score",
|
|
44260
|
+
"max_loss_level",
|
|
44261
|
+
"profit_lock_level",
|
|
44262
|
+
"position_sizing",
|
|
44263
|
+
"kelly_criterion",
|
|
44264
|
+
"risk_reward_ratio",
|
|
44265
|
+
"risk_reward_asymmetry",
|
|
44266
|
+
"probability_of_movement",
|
|
44267
|
+
"trend_strength",
|
|
44268
|
+
"breakeven_level",
|
|
44269
|
+
"market_structure_pivot",
|
|
44270
|
+
"position_sizing_score",
|
|
44271
|
+
"trailing_exit_level",
|
|
44272
|
+
"optimal_entry_zone",
|
|
44273
|
+
"mean_reversion_entry",
|
|
44274
|
+
"multi_timeframe_signal",
|
|
44275
|
+
"market_timing_index",
|
|
44276
|
+
"regime_adaptive_signal",
|
|
44277
|
+
"strategy_score",
|
|
44278
|
+
"breakout_detection"
|
|
43283
44279
|
]);
|
|
43284
44280
|
var TA_BARE_ATTRS = new Set([
|
|
43285
44281
|
"accdist",
|
|
@@ -43624,6 +44620,23 @@ function hasArg(args, index, names) {
|
|
|
43624
44620
|
}
|
|
43625
44621
|
return index >= 0 && index < args.pos.length;
|
|
43626
44622
|
}
|
|
44623
|
+
var BARE_SERIES_NAMES = new Set([
|
|
44624
|
+
"open",
|
|
44625
|
+
"high",
|
|
44626
|
+
"low",
|
|
44627
|
+
"close",
|
|
44628
|
+
"volume",
|
|
44629
|
+
"hl2",
|
|
44630
|
+
"hlc3",
|
|
44631
|
+
"ohlc4",
|
|
44632
|
+
"hlcc4",
|
|
44633
|
+
"time",
|
|
44634
|
+
"time_close"
|
|
44635
|
+
]);
|
|
44636
|
+
function hasSeriesArg(args) {
|
|
44637
|
+
const isSeries = (n) => n.kind === "Name" && BARE_SERIES_NAMES.has(n.id);
|
|
44638
|
+
return args.posNodes.some(isSeries) || Object.values(args.kwNodes).some(isSeries);
|
|
44639
|
+
}
|
|
43627
44640
|
function hasAnyKw(args, names) {
|
|
43628
44641
|
return names.some((n) => Object.hasOwn(args.kw, n));
|
|
43629
44642
|
}
|
|
@@ -43639,6 +44652,9 @@ function cellOf(expr) {
|
|
|
43639
44652
|
function cellList(expr) {
|
|
43640
44653
|
return `(() => { const __v = ${expr}; const __cell = (e) => (e == null ? null : typeof e === "boolean" ? (e ? 1 : 0) : (typeof e === "number" && Number.isFinite(e) ? e : null)); if (__v != null && typeof __v.size === "function" && typeof __v.get === "function") { const __n = __v.size(); const __o = []; for (let __i = 0; __i < __n; __i++) __o.push(__cell(__v.get(__i))); return __o; } return [__cell(__v)]; })()`;
|
|
43641
44654
|
}
|
|
44655
|
+
function cellLast(expr) {
|
|
44656
|
+
return `(() => { const __v = ${expr}; const __cell = (e) => (e == null ? null : typeof e === "boolean" ? (e ? 1 : 0) : (typeof e === "number" && Number.isFinite(e) ? e : null)); if (__v != null && typeof __v.size === "function" && typeof __v.get === "function") { const __n = __v.size(); return __n === 0 ? null : __cell(__v.get(__n - 1)); } return __cell(__v); })()`;
|
|
44657
|
+
}
|
|
43642
44658
|
var DRAW_KINDS = new Set(["label", "line", "box", "table", "polyline", "linefill"]);
|
|
43643
44659
|
var ARRAY_SIGS = {
|
|
43644
44660
|
new: [["size"], ["initial_value", "initial"]],
|
|
@@ -44018,6 +45034,8 @@ function emitDraw(ctx, name, methodSrc, args) {
|
|
|
44018
45034
|
code = `__h.draw.box_new(__bar_idx, ${pick(args, 0, ["left"], "0")}, ${pick(args, 1, ["top"], "0")}, ${pick(args, 2, ["right"], "0")}, ${pick(args, 3, ["bottom"], "0")})`;
|
|
44019
45035
|
} else if (kind === "polyline") {
|
|
44020
45036
|
code = `__h.draw.polyline_new(__bar_idx, ${pick(args, 0, ["points"], "null")})`;
|
|
45037
|
+
} else if (kind === "table") {
|
|
45038
|
+
code = `__h.draw.table_new(__bar_idx, ${pick(args, 0, ["position"], "null")}, ${pick(args, 1, ["columns"], "null")}, ${pick(args, 2, ["rows"], "null")}, ${pick(args, 3, ["bgcolor"], "null")}, ${pick(args, 4, ["frame_color"], "null")}, ${pick(args, 5, ["frame_width"], "null")}, ${pick(args, 6, ["border_color"], "null")}, ${pick(args, 7, ["border_width"], "null")}, ${pick(args, 8, ["force_overlay"], "null")})`;
|
|
44021
45039
|
} else if (kind === "linefill") {
|
|
44022
45040
|
const color = hasArg(args, 2, ["color"]) ? pick(args, 2, ["color"], "null") : "null";
|
|
44023
45041
|
code = `__h.draw.linefill_new(__bar_idx, ${pick(args, 0, ["id1", "line1"], "null")}, ${pick(args, 1, ["id2", "line2"], "null")}, ${color})`;
|
|
@@ -44640,6 +45658,9 @@ function allocSite(ctx) {
|
|
|
44640
45658
|
function taCall(method, site, parts) {
|
|
44641
45659
|
return `__h.ta.${method}(${site}, ${parts.join(", ")})`;
|
|
44642
45660
|
}
|
|
45661
|
+
function taPure(method, parts) {
|
|
45662
|
+
return `__h.ta.${method}(${parts.join(", ")})`;
|
|
45663
|
+
}
|
|
44643
45664
|
function emitTa(ctx, method, args) {
|
|
44644
45665
|
if (!TA_METHODS.has(method))
|
|
44645
45666
|
return "null";
|
|
@@ -45063,16 +46084,30 @@ function emitTa(ctx, method, args) {
|
|
|
45063
46084
|
]);
|
|
45064
46085
|
}
|
|
45065
46086
|
if (method === "stoch_smooth") {
|
|
45066
|
-
return
|
|
46087
|
+
return taCall("stochSmooth", site, [
|
|
46088
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
46089
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
46090
|
+
cellOf(pick(args, 2, ["close"], "null")),
|
|
46091
|
+
cellOf(pick(args, 3, ["period", "length"], "null")),
|
|
46092
|
+
cellOf(pick(args, 4, ["smooth_k", "k"], "null")),
|
|
46093
|
+
cellOf(pick(args, 5, ["smooth_d", "d"], "null"))
|
|
46094
|
+
]);
|
|
45067
46095
|
}
|
|
45068
46096
|
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(); })()`;
|
|
46097
|
+
return `(() => { const __o = ${cellOf(pick(args, 0, ["open"], "null"))}; ${cellOf(pick(args, 1, ["high"], "null"))}; ${cellOf(pick(args, 2, ["low"], "null"))}; const __c = ${cellOf(pick(args, 3, ["close"], "null"))}; return __h.ta.engulfing(${site}, __o, __c); })()`;
|
|
45070
46098
|
}
|
|
45071
46099
|
if (method === "inside_bar_pattern") {
|
|
45072
|
-
return
|
|
46100
|
+
return taCall("insideBarPattern", site, [
|
|
46101
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
46102
|
+
cellOf(pick(args, 1, ["low"], "null"))
|
|
46103
|
+
]);
|
|
45073
46104
|
}
|
|
45074
46105
|
if (method === "double_top_bottom") {
|
|
45075
|
-
return
|
|
46106
|
+
return taCall("doubleTopBottom", site, [
|
|
46107
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
46108
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
46109
|
+
cellOf(pick(args, 2, ["period", "length"], "null"))
|
|
46110
|
+
]);
|
|
45076
46111
|
}
|
|
45077
46112
|
if (method === "voi") {
|
|
45078
46113
|
return `__h.ta.voi(${cellOf(pick(args, 0, ["buy_volume", "buy"], "null"))}, ${cellOf(pick(args, 1, ["sell_volume", "sell"], "null"))})`;
|
|
@@ -45085,7 +46120,10 @@ function emitTa(ctx, method, args) {
|
|
|
45085
46120
|
}
|
|
45086
46121
|
if (method === "rsi_divergence") {
|
|
45087
46122
|
const period = `((__n) => (__n == null ? 0 : __n))(${cellOf(pick(args, 1, ["period", "length"], "null"))})`;
|
|
45088
|
-
return
|
|
46123
|
+
return taCall("rsiDivergence", site, [
|
|
46124
|
+
cellLast(pick(args, 0, ["rsi_series", "series", "source"], "null")),
|
|
46125
|
+
period
|
|
46126
|
+
]);
|
|
45089
46127
|
}
|
|
45090
46128
|
if (method === "cumulative_delta") {
|
|
45091
46129
|
return taCall("cumulativeDelta", site, [
|
|
@@ -45120,6 +46158,237 @@ function emitTa(ctx, method, args) {
|
|
|
45120
46158
|
`((__n) => (__n == null ? 0.3 : __n))(${sens})`
|
|
45121
46159
|
]);
|
|
45122
46160
|
}
|
|
46161
|
+
if (method === "sma_weighted") {
|
|
46162
|
+
return taCall("smaWeighted", site, [
|
|
46163
|
+
cellOf(pick(args, 0, ["series", "source"], "null")),
|
|
46164
|
+
cellOf(pick(args, 1, ["period", "length"], "null")),
|
|
46165
|
+
pick(args, 2, ["weight_type", "weight"], '"linear"')
|
|
46166
|
+
]);
|
|
46167
|
+
}
|
|
46168
|
+
if (method === "apo") {
|
|
46169
|
+
return taCall("apo", site, [
|
|
46170
|
+
cellOf(pick(args, 0, ["series", "source"], "null")),
|
|
46171
|
+
cellOf(pick(args, 1, ["fast_period", "fast"], "null")),
|
|
46172
|
+
cellOf(pick(args, 2, ["slow_period", "slow"], "null"))
|
|
46173
|
+
]);
|
|
46174
|
+
}
|
|
46175
|
+
if (method === "atr_normalized") {
|
|
46176
|
+
return taCall("atrNormalized", site, [
|
|
46177
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
46178
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
46179
|
+
cellOf(pick(args, 2, ["close"], "null")),
|
|
46180
|
+
cellOf(pick(args, 3, ["period", "length"], "null"))
|
|
46181
|
+
]);
|
|
46182
|
+
}
|
|
46183
|
+
if (method === "beta" || method === "r_squared" || method === "comovement") {
|
|
46184
|
+
const fn = method === "beta" ? "beta" : method === "r_squared" ? "rSquared" : "comovement";
|
|
46185
|
+
return taCall(fn, site, [
|
|
46186
|
+
cellOf(pick(args, 0, ["series1", "series", "source"], "null")),
|
|
46187
|
+
cellOf(pick(args, 1, ["series2", "series_b", "other"], "null")),
|
|
46188
|
+
cellOf(pick(args, 2, ["length", "period"], "null"))
|
|
46189
|
+
]);
|
|
46190
|
+
}
|
|
46191
|
+
if (method === "skewness" || method === "kurtosis") {
|
|
46192
|
+
return taCall(method, site, [
|
|
46193
|
+
cellOf(pick(args, 0, ["series", "source"], "null")),
|
|
46194
|
+
cellOf(pick(args, 1, ["period", "length"], "null"))
|
|
46195
|
+
]);
|
|
46196
|
+
}
|
|
46197
|
+
if (method === "volume_weighted_momentum") {
|
|
46198
|
+
return taCall("volumeWeightedMomentum", site, [
|
|
46199
|
+
cellOf(pick(args, 0, ["series", "source"], "null")),
|
|
46200
|
+
cellOf(pick(args, 1, ["volume"], "null")),
|
|
46201
|
+
cellOf(pick(args, 2, ["length", "period"], "null"))
|
|
46202
|
+
]);
|
|
46203
|
+
}
|
|
46204
|
+
if (method === "parkinson") {
|
|
46205
|
+
if (hasSeriesArg(args))
|
|
46206
|
+
return "null";
|
|
46207
|
+
return `__h.ta.parkinson(${cellOf(pick(args, 0, ["high"], "null"))}, ${cellOf(pick(args, 1, ["low"], "null"))})`;
|
|
46208
|
+
}
|
|
46209
|
+
if (method === "garman_klass") {
|
|
46210
|
+
if (hasSeriesArg(args))
|
|
46211
|
+
return "null";
|
|
46212
|
+
return `__h.ta.garmanKlass(${cellOf(pick(args, 0, ["high"], "null"))}, ${cellOf(pick(args, 1, ["low"], "null"))}, ${cellOf(pick(args, 2, ["close"], "null"))}, ${cellOf(pick(args, 3, ["open"], "null"))})`;
|
|
46213
|
+
}
|
|
46214
|
+
if (method === "mean_reversion_score") {
|
|
46215
|
+
return taCall("meanReversionScore", site, [
|
|
46216
|
+
cellOf(pick(args, 0, ["close", "source"], "null")),
|
|
46217
|
+
cellOf(pick(args, 1, ["sma"], "null")),
|
|
46218
|
+
cellOf(pick(args, 2, ["stdev", "std_dev"], "null")),
|
|
46219
|
+
cellOf(pick(args, 3, ["period", "length"], "null"))
|
|
46220
|
+
]);
|
|
46221
|
+
}
|
|
46222
|
+
if (method === "market_condition") {
|
|
46223
|
+
return taCall("marketCondition", site, [
|
|
46224
|
+
cellOf(pick(args, 0, ["close", "source"], "null")),
|
|
46225
|
+
cellOf(pick(args, 1, ["atr"], "null")),
|
|
46226
|
+
cellOf(pick(args, 2, ["sma_period", "sma_length"], "null")),
|
|
46227
|
+
cellOf(pick(args, 3, ["stdev_period", "stdev_length"], "null"))
|
|
46228
|
+
]);
|
|
46229
|
+
}
|
|
46230
|
+
if (method === "order_flow_imbalance") {
|
|
46231
|
+
return taCall("orderFlowImbalance", site, [
|
|
46232
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
46233
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
46234
|
+
cellOf(pick(args, 2, ["close"], "null")),
|
|
46235
|
+
cellOf(pick(args, 3, ["volume"], "null")),
|
|
46236
|
+
cellOf(pick(args, 4, ["period", "length"], "null"))
|
|
46237
|
+
]);
|
|
46238
|
+
}
|
|
46239
|
+
if (method === "liquidity_score") {
|
|
46240
|
+
return taCall("liquidityScore", site, [
|
|
46241
|
+
cellOf(pick(args, 0, ["volume"], "null")),
|
|
46242
|
+
cellOf(pick(args, 1, ["volatility"], "null")),
|
|
46243
|
+
cellOf(pick(args, 2, ["spread"], "null")),
|
|
46244
|
+
cellOf(pick(args, 3, ["period", "length"], "null"))
|
|
46245
|
+
]);
|
|
46246
|
+
}
|
|
46247
|
+
if (method === "fear_greed_index") {
|
|
46248
|
+
return `__h.ta.fearGreedIndex(${cellOf(pick(args, 0, ["rsi"], "null"))}, ${cellOf(pick(args, 1, ["vix"], "null"))}, ${cellOf(pick(args, 2, ["put_call", "put_call_ratio"], "null"))}, ${cellOf(pick(args, 3, ["breadth"], "null"))})`;
|
|
46249
|
+
}
|
|
46250
|
+
if (method === "crowd_sentiment") {
|
|
46251
|
+
return `__h.ta.crowdSentiment(${cellOf(pick(args, 0, ["price_agreement", "price"], "null"))}, ${cellOf(pick(args, 1, ["volume_agreement", "volume"], "null"))}, ${cellOf(pick(args, 2, ["time_agreement", "time"], "null"))})`;
|
|
46252
|
+
}
|
|
46253
|
+
if (method === "smart_money_flow") {
|
|
46254
|
+
return `__h.ta.smartMoneyFlow(${cellOf(pick(args, 0, ["price_change"], "null"))}, ${cellOf(pick(args, 1, ["volume"], "null"))}, ${cellOf(pick(args, 2, ["time_since_high", "time_high"], "null"))}, ${cellOf(pick(args, 3, ["time_since_low", "time_low"], "null"))})`;
|
|
46255
|
+
}
|
|
46256
|
+
if (method === "trend_confirmation_score") {
|
|
46257
|
+
return `__h.ta.trendConfirmationScore(${cellOf(pick(args, 0, ["momentum"], "null"))}, ${cellOf(pick(args, 1, ["trend_alignment"], "null"))}, ${cellOf(pick(args, 2, ["strength"], "null"))}, ${cellOf(pick(args, 3, ["rsi"], "null"))}, ${cellOf(pick(args, 4, ["rsi_alignment"], "null"))})`;
|
|
46258
|
+
}
|
|
46259
|
+
if (method === "max_loss_level") {
|
|
46260
|
+
return `__h.ta.maxLossLevel(${cellOf(pick(args, 0, ["entry", "entry_price"], "null"))}, ${cellOf(pick(args, 1, ["account", "account_size"], "null"))}, ${cellOf(pick(args, 2, ["max_loss_pct", "max_loss_percent"], "null"))})`;
|
|
46261
|
+
}
|
|
46262
|
+
if (method === "profit_lock_level") {
|
|
46263
|
+
return `__h.ta.profitLockLevel(${cellOf(pick(args, 0, ["entry", "entry_price"], "null"))}, ${cellOf(pick(args, 1, ["current", "current_price"], "null"))}, ${cellOf(pick(args, 2, ["trail_pct", "trail_percent"], "null"))}, ${cellOf(pick(args, 3, ["direction"], "null"))})`;
|
|
46264
|
+
}
|
|
46265
|
+
if (method === "position_sizing") {
|
|
46266
|
+
return taPure("positionSizing", [
|
|
46267
|
+
cellOf(pick(args, 0, ["account", "account_size"], "null")),
|
|
46268
|
+
cellOf(pick(args, 1, ["risk_pct", "risk_percent"], "null")),
|
|
46269
|
+
cellOf(pick(args, 2, ["entry", "entry_price"], "null")),
|
|
46270
|
+
cellOf(pick(args, 3, ["stop", "stop_price"], "null"))
|
|
46271
|
+
]);
|
|
46272
|
+
}
|
|
46273
|
+
if (method === "kelly_criterion") {
|
|
46274
|
+
return taPure("kellyCriterion", [
|
|
46275
|
+
cellOf(pick(args, 0, ["win_rate"], "null")),
|
|
46276
|
+
cellOf(pick(args, 1, ["avg_win"], "null")),
|
|
46277
|
+
cellOf(pick(args, 2, ["avg_loss"], "null"))
|
|
46278
|
+
]);
|
|
46279
|
+
}
|
|
46280
|
+
if (method === "risk_reward_ratio") {
|
|
46281
|
+
return taPure("riskRewardRatio", [
|
|
46282
|
+
cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
|
|
46283
|
+
cellOf(pick(args, 1, ["stop", "stop_price"], "null")),
|
|
46284
|
+
cellOf(pick(args, 2, ["target", "target_price"], "null"))
|
|
46285
|
+
]);
|
|
46286
|
+
}
|
|
46287
|
+
if (method === "risk_reward_asymmetry") {
|
|
46288
|
+
return taPure("riskRewardAsymmetry", [
|
|
46289
|
+
cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
|
|
46290
|
+
cellOf(pick(args, 1, ["stop", "stop_price"], "null")),
|
|
46291
|
+
cellOf(pick(args, 2, ["target", "target_price"], "null")),
|
|
46292
|
+
cellOf(pick(args, 3, ["win_rate"], "null"))
|
|
46293
|
+
]);
|
|
46294
|
+
}
|
|
46295
|
+
if (method === "probability_of_movement") {
|
|
46296
|
+
return taPure("probabilityOfMovement", [
|
|
46297
|
+
cellOf(pick(args, 0, ["current", "current_price"], "null")),
|
|
46298
|
+
cellOf(pick(args, 1, ["target", "target_price"], "null")),
|
|
46299
|
+
cellOf(pick(args, 2, ["atr"], "null")),
|
|
46300
|
+
cellOf(pick(args, 3, ["period", "length"], "null"))
|
|
46301
|
+
]);
|
|
46302
|
+
}
|
|
46303
|
+
if (method === "trend_strength") {
|
|
46304
|
+
return taPure("trendStrength", [
|
|
46305
|
+
cellOf(pick(args, 0, ["price", "source"], "null")),
|
|
46306
|
+
cellOf(pick(args, 1, ["adx"], "null")),
|
|
46307
|
+
cellOf(pick(args, 2, ["rsi"], "null"))
|
|
46308
|
+
]);
|
|
46309
|
+
}
|
|
46310
|
+
if (method === "breakeven_level") {
|
|
46311
|
+
return taPure("breakevenLevel", [
|
|
46312
|
+
cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
|
|
46313
|
+
cellOf(pick(args, 1, ["quantity", "qty"], "null")),
|
|
46314
|
+
cellOf(pick(args, 2, ["commission"], "null")),
|
|
46315
|
+
cellOf(pick(args, 3, ["slippage"], "null")),
|
|
46316
|
+
cellOf(pick(args, 4, ["direction"], "null"))
|
|
46317
|
+
]);
|
|
46318
|
+
}
|
|
46319
|
+
if (method === "market_structure_pivot") {
|
|
46320
|
+
return taPure("marketStructurePivot", [
|
|
46321
|
+
cellOf(pick(args, 2, ["close"], "null"))
|
|
46322
|
+
]);
|
|
46323
|
+
}
|
|
46324
|
+
if (method === "position_sizing_score") {
|
|
46325
|
+
return taPure("positionSizingScore", [
|
|
46326
|
+
cellOf(pick(args, 0, ["account_risk", "risk"], "null")),
|
|
46327
|
+
cellOf(pick(args, 1, ["volatility"], "null")),
|
|
46328
|
+
cellOf(pick(args, 2, ["conviction"], "null")),
|
|
46329
|
+
cellOf(pick(args, 3, ["correlation"], "null"))
|
|
46330
|
+
]);
|
|
46331
|
+
}
|
|
46332
|
+
if (method === "trailing_exit_level") {
|
|
46333
|
+
return taPure("trailingExitLevel", [
|
|
46334
|
+
cellOf(pick(args, 0, ["entry", "entry_price"], "null")),
|
|
46335
|
+
cellOf(pick(args, 1, ["current", "current_price"], "null")),
|
|
46336
|
+
cellOf(pick(args, 2, ["atr"], "null")),
|
|
46337
|
+
cellOf(pick(args, 3, ["multiplier", "mult"], "null")),
|
|
46338
|
+
cellOf(pick(args, 4, ["step"], "null"))
|
|
46339
|
+
]);
|
|
46340
|
+
}
|
|
46341
|
+
if (method === "optimal_entry_zone") {
|
|
46342
|
+
return taPure("optimalEntryZone", [cellOf(pick(args, 2, ["close"], "null"))]);
|
|
46343
|
+
}
|
|
46344
|
+
if (method === "mean_reversion_entry") {
|
|
46345
|
+
return taPure("meanReversionEntry", [
|
|
46346
|
+
cellOf(pick(args, 0, ["price", "source"], "null")),
|
|
46347
|
+
cellOf(pick(args, 1, ["sma"], "null")),
|
|
46348
|
+
cellOf(pick(args, 2, ["stdev", "std_dev"], "null")),
|
|
46349
|
+
cellOf(pick(args, 4, ["threshold"], "null"))
|
|
46350
|
+
]);
|
|
46351
|
+
}
|
|
46352
|
+
if (method === "multi_timeframe_signal") {
|
|
46353
|
+
return taPure("multiTimeframeSignal", [
|
|
46354
|
+
cellOf(pick(args, 0, ["s1", "signal1"], "null")),
|
|
46355
|
+
cellOf(pick(args, 1, ["s2", "signal2"], "null")),
|
|
46356
|
+
cellOf(pick(args, 2, ["s3", "signal3"], "null")),
|
|
46357
|
+
cellOf(pick(args, 3, ["w1", "weight1"], "null")),
|
|
46358
|
+
cellOf(pick(args, 4, ["w2", "weight2"], "null")),
|
|
46359
|
+
cellOf(pick(args, 5, ["w3", "weight3"], "null"))
|
|
46360
|
+
]);
|
|
46361
|
+
}
|
|
46362
|
+
if (method === "market_timing_index") {
|
|
46363
|
+
return taPure("marketTimingIndex", [
|
|
46364
|
+
cellOf(pick(args, 0, ["trend"], "null")),
|
|
46365
|
+
cellOf(pick(args, 1, ["momentum"], "null")),
|
|
46366
|
+
cellOf(pick(args, 2, ["volatility"], "null")),
|
|
46367
|
+
cellOf(pick(args, 3, ["sentiment"], "null"))
|
|
46368
|
+
]);
|
|
46369
|
+
}
|
|
46370
|
+
if (method === "regime_adaptive_signal") {
|
|
46371
|
+
return taPure("regimeAdaptiveSignal", [
|
|
46372
|
+
cellOf(pick(args, 0, ["signal_strength", "strength"], "null")),
|
|
46373
|
+
pick(args, 1, ["volatility_regime", "vol_regime"], '""'),
|
|
46374
|
+
pick(args, 2, ["trend_regime"], '""')
|
|
46375
|
+
]);
|
|
46376
|
+
}
|
|
46377
|
+
if (method === "strategy_score") {
|
|
46378
|
+
return taPure("strategyScore", [
|
|
46379
|
+
cellOf(pick(args, 0, ["rsi"], "null")),
|
|
46380
|
+
cellOf(pick(args, 1, ["macd"], "null")),
|
|
46381
|
+
cellOf(pick(args, 2, ["ema_cross"], "null")),
|
|
46382
|
+
cellOf(pick(args, 3, ["trend"], "null"))
|
|
46383
|
+
]);
|
|
46384
|
+
}
|
|
46385
|
+
if (method === "breakout_detection") {
|
|
46386
|
+
return taPure("breakoutDetection", [
|
|
46387
|
+
cellOf(pick(args, 0, ["close", "source"], "null")),
|
|
46388
|
+
cellOf(pick(args, 1, ["resistance"], "null")),
|
|
46389
|
+
cellOf(pick(args, 2, ["support"], "null"))
|
|
46390
|
+
]);
|
|
46391
|
+
}
|
|
45123
46392
|
return "null";
|
|
45124
46393
|
}
|
|
45125
46394
|
|
|
@@ -46588,6 +47857,8 @@ function naNum(v) {
|
|
|
46588
47857
|
function hold(v) {
|
|
46589
47858
|
if (v != null && typeof v === "object")
|
|
46590
47859
|
return v;
|
|
47860
|
+
if (typeof v === "string")
|
|
47861
|
+
return v;
|
|
46591
47862
|
return naNum(v);
|
|
46592
47863
|
}
|
|
46593
47864
|
function pineEq(a, b) {
|
|
@@ -47280,8 +48551,23 @@ class CompileDraw {
|
|
|
47280
48551
|
putNum(extra, "bottom", bottom);
|
|
47281
48552
|
return this.book.boxNew(n3(bar, 0), Object.keys(extra).length ? extra : undefined);
|
|
47282
48553
|
}
|
|
47283
|
-
table_new(bar) {
|
|
47284
|
-
|
|
48554
|
+
table_new(bar, position, columns, rows, bgcolor, frameColor, frameWidth, borderColor, borderWidth, forceOverlay) {
|
|
48555
|
+
const extra = {};
|
|
48556
|
+
if (position != null)
|
|
48557
|
+
extra.position = position;
|
|
48558
|
+
putNum(extra, "columns", columns);
|
|
48559
|
+
putNum(extra, "rows", rows);
|
|
48560
|
+
if (bgcolor != null)
|
|
48561
|
+
extra.bgcolor = bgcolor;
|
|
48562
|
+
if (frameColor != null)
|
|
48563
|
+
extra.frame_color = frameColor;
|
|
48564
|
+
putNum(extra, "frame_width", frameWidth);
|
|
48565
|
+
if (borderColor != null)
|
|
48566
|
+
extra.border_color = borderColor;
|
|
48567
|
+
putNum(extra, "border_width", borderWidth);
|
|
48568
|
+
if (forceOverlay != null)
|
|
48569
|
+
extra.force_overlay = forceOverlay;
|
|
48570
|
+
return this.book.tableNew(n3(bar, 0), Object.keys(extra).length ? extra : undefined);
|
|
47285
48571
|
}
|
|
47286
48572
|
polyline_new(bar, points) {
|
|
47287
48573
|
const pts = pointsOf(points);
|
|
@@ -47915,7 +49201,8 @@ class CompileStrategy {
|
|
|
47915
49201
|
open: num(open, this.mark),
|
|
47916
49202
|
high: num(high, this.mark),
|
|
47917
49203
|
low: num(low, this.mark),
|
|
47918
|
-
close: this.mark
|
|
49204
|
+
close: this.mark,
|
|
49205
|
+
time: this.time
|
|
47919
49206
|
};
|
|
47920
49207
|
this.ohlc = ohlc;
|
|
47921
49208
|
this.book.processPending(this.bar, ohlc);
|
|
@@ -47931,17 +49218,18 @@ class CompileStrategy {
|
|
|
47931
49218
|
stop: opts?.stop,
|
|
47932
49219
|
comment: opts?.comment,
|
|
47933
49220
|
oca_name: opts?.oca_name,
|
|
47934
|
-
oca_type: opts?.oca_type
|
|
49221
|
+
oca_type: opts?.oca_type,
|
|
49222
|
+
deferMarket: true
|
|
47935
49223
|
});
|
|
47936
49224
|
}
|
|
47937
49225
|
close(id, qty) {
|
|
47938
|
-
this.book.
|
|
49226
|
+
this.book.placeClose(this.bar, str(id, ""), this.mark, {
|
|
47939
49227
|
time: this.time,
|
|
47940
49228
|
qty: optNum(qty)
|
|
47941
49229
|
});
|
|
47942
49230
|
}
|
|
47943
49231
|
close_all(_comment) {
|
|
47944
|
-
this.book.
|
|
49232
|
+
this.book.placeCloseAll(this.bar, this.mark);
|
|
47945
49233
|
}
|
|
47946
49234
|
order(id, direction, qty, opts) {
|
|
47947
49235
|
this.entry(id, direction, qty, opts);
|
|
@@ -47958,7 +49246,8 @@ class CompileStrategy {
|
|
|
47958
49246
|
...parsed,
|
|
47959
49247
|
price: this.mark,
|
|
47960
49248
|
time: this.time,
|
|
47961
|
-
ohlc: this.ohlc
|
|
49249
|
+
ohlc: this.ohlc,
|
|
49250
|
+
deferMarket: true
|
|
47962
49251
|
});
|
|
47963
49252
|
}
|
|
47964
49253
|
position_size() {
|
|
@@ -48326,8 +49615,8 @@ function createCompileHelpers(opts) {
|
|
|
48326
49615
|
second: calendarSecond,
|
|
48327
49616
|
dayofweek: calendarDayofweek,
|
|
48328
49617
|
timestamp,
|
|
48329
|
-
weekOfYear,
|
|
48330
|
-
timeTradingDay,
|
|
49618
|
+
weekOfYear: calendarWeekOfYear,
|
|
49619
|
+
timeTradingDay: calendarTimeTradingDay,
|
|
48331
49620
|
timeframeInSeconds: timeframeInSecondsOrDaily,
|
|
48332
49621
|
timeframeChange,
|
|
48333
49622
|
timeClose,
|
|
@@ -48451,7 +49740,20 @@ function NA_FN(v) {
|
|
|
48451
49740
|
function utcPart(t, key) {
|
|
48452
49741
|
if (typeof t !== "number" || !Number.isFinite(t))
|
|
48453
49742
|
return null;
|
|
48454
|
-
|
|
49743
|
+
const ms = timestampToMs(t);
|
|
49744
|
+
return ms == null ? null : utcPartsFromMs(ms)[key];
|
|
49745
|
+
}
|
|
49746
|
+
function calendarWeekOfYear(t) {
|
|
49747
|
+
if (typeof t !== "number" || !Number.isFinite(t))
|
|
49748
|
+
return null;
|
|
49749
|
+
const ms = timestampToMs(t);
|
|
49750
|
+
return ms == null ? null : weekOfYear(ms);
|
|
49751
|
+
}
|
|
49752
|
+
function calendarTimeTradingDay(t) {
|
|
49753
|
+
if (typeof t !== "number" || !Number.isFinite(t))
|
|
49754
|
+
return null;
|
|
49755
|
+
const ms = timestampToMs(t);
|
|
49756
|
+
return ms == null ? null : timeTradingDay(ms);
|
|
48455
49757
|
}
|
|
48456
49758
|
function calendarYear(t) {
|
|
48457
49759
|
return utcPart(t, "year");
|
|
@@ -48885,7 +50187,8 @@ function interpretTree(tree, ohlcv, host) {
|
|
|
48885
50187
|
open: num2(env.ctx.open) ?? undefined,
|
|
48886
50188
|
high: num2(env.ctx.high) ?? undefined,
|
|
48887
50189
|
low: num2(env.ctx.low) ?? undefined,
|
|
48888
|
-
close: num2(env.ctx.close) ?? undefined
|
|
50190
|
+
close: num2(env.ctx.close) ?? undefined,
|
|
50191
|
+
time: num2(env.ctx.time) ?? undefined
|
|
48889
50192
|
});
|
|
48890
50193
|
env.book.markOpenTrades(num2(env.ctx.high) ?? num2(env.ctx.close) ?? 0, num2(env.ctx.low) ?? num2(env.ctx.close) ?? 0, num2(env.ctx.close) ?? 0);
|
|
48891
50194
|
try {
|
|
@@ -49216,6 +50519,27 @@ function seriesGet(env, id) {
|
|
|
49216
50519
|
}
|
|
49217
50520
|
return env.series.get(id);
|
|
49218
50521
|
}
|
|
50522
|
+
var BARE_SERIES_NAMES2 = new Set([
|
|
50523
|
+
"open",
|
|
50524
|
+
"high",
|
|
50525
|
+
"low",
|
|
50526
|
+
"close",
|
|
50527
|
+
"volume",
|
|
50528
|
+
"hl2",
|
|
50529
|
+
"hlc3",
|
|
50530
|
+
"ohlc4",
|
|
50531
|
+
"hlcc4",
|
|
50532
|
+
"time",
|
|
50533
|
+
"time_close"
|
|
50534
|
+
]);
|
|
50535
|
+
function isSeriesExpr(value, env) {
|
|
50536
|
+
if (value.kind === "Name") {
|
|
50537
|
+
if (BARE_SERIES_NAMES2.has(value.id))
|
|
50538
|
+
return true;
|
|
50539
|
+
return seriesGet(env, value.id) != null;
|
|
50540
|
+
}
|
|
50541
|
+
return false;
|
|
50542
|
+
}
|
|
49219
50543
|
function bindName(env, id, value) {
|
|
49220
50544
|
const stored = typeof value === "number" && !Number.isFinite(value) ? NA : value;
|
|
49221
50545
|
const frame = activeFrame(env);
|
|
@@ -50433,7 +51757,8 @@ function evalCall(node, env) {
|
|
|
50433
51757
|
price: mark == null || !Number.isFinite(mark) ? undefined : mark,
|
|
50434
51758
|
time: num2(env.ctx.time) ?? undefined,
|
|
50435
51759
|
oca_name: evalAsString(callArg(node.args, -1, ["oca_name"]), env),
|
|
50436
|
-
oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env)
|
|
51760
|
+
oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env),
|
|
51761
|
+
deferMarket: true
|
|
50437
51762
|
});
|
|
50438
51763
|
return NA;
|
|
50439
51764
|
}
|
|
@@ -50442,13 +51767,10 @@ function evalCall(node, env) {
|
|
|
50442
51767
|
const mark = num2(env.ctx.close);
|
|
50443
51768
|
const qtyExpr = callArg(node.args, 1, ["qty"]);
|
|
50444
51769
|
const qtyRaw = qtyExpr == null ? undefined : unwrap2(evalExpr(qtyExpr, env));
|
|
50445
|
-
|
|
50446
|
-
env.
|
|
50447
|
-
|
|
50448
|
-
|
|
50449
|
-
});
|
|
50450
|
-
} else
|
|
50451
|
-
env.book.close(env.barIndex, id);
|
|
51770
|
+
env.book.placeClose(env.barIndex, id, mark ?? undefined, {
|
|
51771
|
+
time: num2(env.ctx.time) ?? undefined,
|
|
51772
|
+
qty: qtyRaw ?? undefined
|
|
51773
|
+
});
|
|
50452
51774
|
return NA;
|
|
50453
51775
|
}
|
|
50454
51776
|
if (fname === "strategy.exit") {
|
|
@@ -50468,17 +51790,12 @@ function evalCall(node, env) {
|
|
|
50468
51790
|
trail_offset: unwrap2(evalExpr(callArg(node.args, 10, ["trail_offset"]), env)),
|
|
50469
51791
|
price: num2(env.ctx.close) ?? undefined,
|
|
50470
51792
|
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
|
-
}
|
|
51793
|
+
deferMarket: true
|
|
50477
51794
|
});
|
|
50478
51795
|
return NA;
|
|
50479
51796
|
}
|
|
50480
51797
|
if (fname === "strategy.close_all") {
|
|
50481
|
-
env.book.
|
|
51798
|
+
env.book.placeCloseAll(env.barIndex, num2(env.ctx.close) ?? undefined);
|
|
50482
51799
|
return NA;
|
|
50483
51800
|
}
|
|
50484
51801
|
if (fname === "strategy.cancel") {
|
|
@@ -50500,7 +51817,8 @@ function evalCall(node, env) {
|
|
|
50500
51817
|
price: num2(env.ctx.close) ?? undefined,
|
|
50501
51818
|
time: num2(env.ctx.time) ?? undefined,
|
|
50502
51819
|
oca_name: evalAsString(callArg(node.args, -1, ["oca_name"]), env),
|
|
50503
|
-
oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env)
|
|
51820
|
+
oca_type: evalAsString(callArg(node.args, -1, ["oca_type"]), env),
|
|
51821
|
+
deferMarket: true
|
|
50504
51822
|
});
|
|
50505
51823
|
return NA;
|
|
50506
51824
|
}
|
|
@@ -51905,11 +53223,11 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51905
53223
|
}
|
|
51906
53224
|
if (fname === "ta.engulfing" || fname === "engulfing") {
|
|
51907
53225
|
const msg = "ta.engulfing() requires 4 arguments: open, high, low, close";
|
|
51908
|
-
unwrap2(evalExpr(wave10aArg(0, ["open"], msg), env));
|
|
53226
|
+
const open = unwrap2(evalExpr(wave10aArg(0, ["open"], msg), env));
|
|
51909
53227
|
unwrap2(evalExpr(wave10aArg(1, ["high"], msg), env));
|
|
51910
53228
|
unwrap2(evalExpr(wave10aArg(2, ["low"], msg), env));
|
|
51911
|
-
unwrap2(evalExpr(wave10aArg(3, ["close"], msg), env));
|
|
51912
|
-
return env.ta.engulfing();
|
|
53229
|
+
const close = unwrap2(evalExpr(wave10aArg(3, ["close"], msg), env));
|
|
53230
|
+
return env.ta.engulfing(site, open, close);
|
|
51913
53231
|
}
|
|
51914
53232
|
if (fname === "ta.gap_detector" || fname === "gap_detector") {
|
|
51915
53233
|
const msg = "ta.gap_detector() requires 3 arguments: high, low, prev_close";
|
|
@@ -51917,15 +53235,15 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51917
53235
|
}
|
|
51918
53236
|
if (fname === "ta.double_top_bottom" || fname === "double_top_bottom") {
|
|
51919
53237
|
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)));
|
|
53238
|
+
const high = unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
|
|
53239
|
+
const low = unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
|
|
53240
|
+
return env.ta.doubleTopBottom(site, high, low, unwrap2(evalExpr(wave10aArg(2, ["period", "length"], msg), env)));
|
|
51923
53241
|
}
|
|
51924
53242
|
if (fname === "ta.inside_bar_pattern" || fname === "inside_bar_pattern") {
|
|
51925
53243
|
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();
|
|
53244
|
+
const high = unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
|
|
53245
|
+
const low = unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
|
|
53246
|
+
return env.ta.insideBarPattern(site, high, low);
|
|
51929
53247
|
}
|
|
51930
53248
|
if (fname === "ta.macd_signal" || fname === "macd_signal") {
|
|
51931
53249
|
const msg = "ta.macd_signal() requires 2 arguments: macd_line, signal_line";
|
|
@@ -51937,7 +53255,7 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51937
53255
|
}
|
|
51938
53256
|
if (fname === "ta.stoch_smooth" || fname === "stoch_smooth") {
|
|
51939
53257
|
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)));
|
|
53258
|
+
return env.ta.stochSmooth(site, unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env)), unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env)), unwrap2(evalExpr(wave10aArg(2, ["close"], msg), env)), unwrap2(evalExpr(wave10aArg(3, ["period", "length"], msg), env)), unwrap2(evalExpr(wave10aArg(4, ["smooth_k", "k"], msg), env)), unwrap2(evalExpr(wave10aArg(5, ["smooth_d", "d"], msg), env)));
|
|
51941
53259
|
}
|
|
51942
53260
|
const wave10bList = (index, names) => {
|
|
51943
53261
|
const raw = evalExpr(callArg(node.args, index, names), env);
|
|
@@ -51962,7 +53280,7 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51962
53280
|
}
|
|
51963
53281
|
if (fname === "ta.rsi_divergence" || fname === "rsi_divergence") {
|
|
51964
53282
|
const period = unwrap2(evalExpr(callArg(node.args, 1, ["period", "length"]), env));
|
|
51965
|
-
return env.ta.rsiDivergence(
|
|
53283
|
+
return env.ta.rsiDivergence(site, seriesLastCell(evalExpr(callArg(node.args, 0, ["rsi_series", "series", "source"]), env)), period ?? 0);
|
|
51966
53284
|
}
|
|
51967
53285
|
if (fname === "ta.cumulative_delta" || fname === "cumulative_delta") {
|
|
51968
53286
|
const period = unwrap2(evalExpr(callArg(node.args, 2, ["period", "length"]), env));
|
|
@@ -51984,6 +53302,188 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
51984
53302
|
const sens = unwrap2(evalExpr(callArg(node.args, 3, ["sensitivity"]), env));
|
|
51985
53303
|
return env.ta.volumeThrust(site, unwrap2(evalExpr(callArg(node.args, 0, ["close", "source"]), env)), unwrap2(evalExpr(callArg(node.args, 1, ["volume"]), env)), unwrap2(evalExpr(callArg(node.args, 2, ["volume_sma", "vol_sma", "sma"]), env)), sens ?? 0.3);
|
|
51986
53304
|
}
|
|
53305
|
+
const wave11 = (index, names, message) => unwrap2(evalExpr(wave10aArg(index, names, message), env));
|
|
53306
|
+
const wave11n = (index, names, message) => num2(wave11(index, names, message));
|
|
53307
|
+
if (fname === "ta.sma_weighted" || fname === "sma_weighted") {
|
|
53308
|
+
const msg = "ta.sma_weighted() requires at least 2 arguments: series, period";
|
|
53309
|
+
const weightArg = callArg(node.args, 2, ["weight_type", "weight"]);
|
|
53310
|
+
return env.ta.smaWeighted(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["period", "length"], msg), weightArg == null ? "linear" : evalExpr(weightArg, env));
|
|
53311
|
+
}
|
|
53312
|
+
if (fname === "ta.apo" || fname === "apo") {
|
|
53313
|
+
const msg = "ta.apo() requires 3 arguments: series, fast_period, slow_period";
|
|
53314
|
+
return env.ta.apo(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["fast_period", "fast"], msg), wave11n(2, ["slow_period", "slow"], msg));
|
|
53315
|
+
}
|
|
53316
|
+
if (fname === "ta.atr_normalized" || fname === "atr_normalized") {
|
|
53317
|
+
const msg = "ta.atr_normalized() requires 4 arguments: high, low, close, period";
|
|
53318
|
+
return env.ta.atrNormalized(site, wave11n(0, ["high"], msg), wave11n(1, ["low"], msg), wave11n(2, ["close"], msg), wave11n(3, ["period", "length"], msg));
|
|
53319
|
+
}
|
|
53320
|
+
if (fname === "ta.beta" || fname === "beta") {
|
|
53321
|
+
const msg = "ta.beta() requires 3 arguments: series1, series2, length";
|
|
53322
|
+
return env.ta.beta(site, wave11n(0, ["series1", "series", "source"], msg), wave11n(1, ["series2", "series_b", "other"], msg), wave11n(2, ["length", "period"], msg));
|
|
53323
|
+
}
|
|
53324
|
+
if (fname === "ta.r_squared" || fname === "r_squared") {
|
|
53325
|
+
const msg = "ta.r_squared() requires 3 arguments: series1, series2, length";
|
|
53326
|
+
return env.ta.rSquared(site, wave11n(0, ["series1", "series", "source"], msg), wave11n(1, ["series2", "series_b", "other"], msg), wave11n(2, ["length", "period"], msg));
|
|
53327
|
+
}
|
|
53328
|
+
if (fname === "ta.comovement" || fname === "comovement") {
|
|
53329
|
+
const msg = "ta.comovement() requires 3 arguments: series1, series2, length";
|
|
53330
|
+
return env.ta.comovement(site, wave11n(0, ["series1", "series", "source"], msg), wave11n(1, ["series2", "series_b", "other"], msg), wave11n(2, ["length", "period"], msg));
|
|
53331
|
+
}
|
|
53332
|
+
if (fname === "ta.skewness" || fname === "skewness") {
|
|
53333
|
+
const msg = "ta.skewness() requires 2 arguments: series, period";
|
|
53334
|
+
return env.ta.skewness(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["period", "length"], msg));
|
|
53335
|
+
}
|
|
53336
|
+
if (fname === "ta.kurtosis" || fname === "kurtosis") {
|
|
53337
|
+
const msg = "ta.kurtosis() requires 2 arguments: series, period";
|
|
53338
|
+
return env.ta.kurtosis(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["period", "length"], msg));
|
|
53339
|
+
}
|
|
53340
|
+
if (fname === "ta.volume_weighted_momentum" || fname === "volume_weighted_momentum") {
|
|
53341
|
+
const msg = "ta.volume_weighted_momentum() requires 3 arguments: series, volume, length";
|
|
53342
|
+
return env.ta.volumeWeightedMomentum(site, wave11n(0, ["series", "source"], msg), wave11n(1, ["volume"], msg), wave11n(2, ["length", "period"], msg));
|
|
53343
|
+
}
|
|
53344
|
+
if (fname === "ta.parkinson" || fname === "parkinson") {
|
|
53345
|
+
const msg = "ta.parkinson() requires 2 arguments: high, low";
|
|
53346
|
+
const highArg = wave10aArg(0, ["high"], msg);
|
|
53347
|
+
const lowArg = wave10aArg(1, ["low"], msg);
|
|
53348
|
+
if (isSeriesExpr(highArg, env) || isSeriesExpr(lowArg, env))
|
|
53349
|
+
return NA;
|
|
53350
|
+
return env.ta.parkinson(num2(evalExpr(highArg, env)), num2(evalExpr(lowArg, env)));
|
|
53351
|
+
}
|
|
53352
|
+
if (fname === "ta.garman_klass" || fname === "garman_klass") {
|
|
53353
|
+
const msg = "ta.garman_klass() requires 4 arguments: high, low, close, open";
|
|
53354
|
+
const argsExpr = [
|
|
53355
|
+
wave10aArg(0, ["high"], msg),
|
|
53356
|
+
wave10aArg(1, ["low"], msg),
|
|
53357
|
+
wave10aArg(2, ["close"], msg),
|
|
53358
|
+
wave10aArg(3, ["open"], msg)
|
|
53359
|
+
];
|
|
53360
|
+
if (argsExpr.some((a) => isSeriesExpr(a, env)))
|
|
53361
|
+
return NA;
|
|
53362
|
+
return env.ta.garmanKlass(num2(evalExpr(argsExpr[0], env)), num2(evalExpr(argsExpr[1], env)), num2(evalExpr(argsExpr[2], env)), num2(evalExpr(argsExpr[3], env)));
|
|
53363
|
+
}
|
|
53364
|
+
if (fname === "ta.mean_reversion_score" || fname === "mean_reversion_score") {
|
|
53365
|
+
const msg = "ta.mean_reversion_score() requires 4 arguments";
|
|
53366
|
+
return env.ta.meanReversionScore(site, wave11n(0, ["close", "source"], msg), wave11n(1, ["sma"], msg), wave11n(2, ["stdev", "std_dev"], msg), wave11n(3, ["period", "length"], msg));
|
|
53367
|
+
}
|
|
53368
|
+
if (fname === "ta.market_condition" || fname === "market_condition") {
|
|
53369
|
+
const msg = "ta.market_condition() requires 4 arguments";
|
|
53370
|
+
return env.ta.marketCondition(site, wave11n(0, ["close", "source"], msg), wave11n(1, ["atr"], msg), wave11n(2, ["sma_period", "sma_length"], msg), wave11n(3, ["stdev_period", "stdev_length"], msg));
|
|
53371
|
+
}
|
|
53372
|
+
if (fname === "ta.order_flow_imbalance" || fname === "order_flow_imbalance") {
|
|
53373
|
+
const msg = "ta.order_flow_imbalance() requires 5 arguments";
|
|
53374
|
+
return env.ta.orderFlowImbalance(site, wave11n(0, ["high"], msg), wave11n(1, ["low"], msg), wave11n(2, ["close"], msg), wave11n(3, ["volume"], msg), wave11n(4, ["period", "length"], msg));
|
|
53375
|
+
}
|
|
53376
|
+
if (fname === "ta.liquidity_score" || fname === "liquidity_score") {
|
|
53377
|
+
const msg = "ta.liquidity_score() requires 4 arguments";
|
|
53378
|
+
return env.ta.liquidityScore(site, wave11n(0, ["volume"], msg), wave11n(1, ["volatility"], msg), wave11n(2, ["spread"], msg), wave11n(3, ["period", "length"], msg));
|
|
53379
|
+
}
|
|
53380
|
+
if (fname === "ta.fear_greed_index" || fname === "fear_greed_index") {
|
|
53381
|
+
const msg = "ta.fear_greed_index() requires 4 arguments";
|
|
53382
|
+
return env.ta.fearGreedIndex(wave11n(0, ["rsi"], msg), wave11n(1, ["vix"], msg), wave11n(2, ["put_call", "put_call_ratio"], msg), wave11n(3, ["breadth"], msg));
|
|
53383
|
+
}
|
|
53384
|
+
if (fname === "ta.crowd_sentiment" || fname === "crowd_sentiment") {
|
|
53385
|
+
const msg = "ta.crowd_sentiment() requires 3 arguments";
|
|
53386
|
+
return env.ta.crowdSentiment(wave11n(0, ["price_agreement", "price"], msg), wave11n(1, ["volume_agreement", "volume"], msg), wave11n(2, ["time_agreement", "time"], msg));
|
|
53387
|
+
}
|
|
53388
|
+
if (fname === "ta.smart_money_flow" || fname === "smart_money_flow") {
|
|
53389
|
+
const msg = "ta.smart_money_flow() requires 4 arguments";
|
|
53390
|
+
return env.ta.smartMoneyFlow(wave11n(0, ["price_change"], msg), wave11n(1, ["volume"], msg), wave11n(2, ["time_since_high", "time_high"], msg), wave11n(3, ["time_since_low", "time_low"], msg));
|
|
53391
|
+
}
|
|
53392
|
+
if (fname === "ta.trend_confirmation_score" || fname === "trend_confirmation_score") {
|
|
53393
|
+
const msg = "ta.trend_confirmation_score() requires 6 arguments";
|
|
53394
|
+
wave11n(5, ["support_distance"], msg);
|
|
53395
|
+
return env.ta.trendConfirmationScore(wave11n(0, ["momentum"], msg), wave11n(1, ["trend_alignment"], msg), wave11n(2, ["strength"], msg), wave11n(3, ["rsi"], msg), wave11n(4, ["rsi_alignment"], msg));
|
|
53396
|
+
}
|
|
53397
|
+
if (fname === "ta.max_loss_level" || fname === "max_loss_level") {
|
|
53398
|
+
const msg = "ta.max_loss_level() requires 3 arguments";
|
|
53399
|
+
return env.ta.maxLossLevel(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["account", "account_size"], msg), wave11n(2, ["max_loss_pct", "max_loss_percent"], msg));
|
|
53400
|
+
}
|
|
53401
|
+
if (fname === "ta.profit_lock_level" || fname === "profit_lock_level") {
|
|
53402
|
+
const msg = "ta.profit_lock_level() requires 4 arguments";
|
|
53403
|
+
return env.ta.profitLockLevel(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["current", "current_price"], msg), wave11n(2, ["trail_pct", "trail_percent"], msg), wave11n(3, ["direction"], msg));
|
|
53404
|
+
}
|
|
53405
|
+
const wave12s = (index, names, message) => evalExpr(wave10aArg(index, names, message), env);
|
|
53406
|
+
if (fname === "ta.position_sizing" || fname === "position_sizing") {
|
|
53407
|
+
const msg = "ta.position_sizing() requires 4 arguments";
|
|
53408
|
+
return env.ta.positionSizing(wave11n(0, ["account", "account_size"], msg), wave11n(1, ["risk_pct", "risk_percent"], msg), wave11n(2, ["entry", "entry_price"], msg), wave11n(3, ["stop", "stop_price"], msg));
|
|
53409
|
+
}
|
|
53410
|
+
if (fname === "ta.kelly_criterion" || fname === "kelly_criterion") {
|
|
53411
|
+
const msg = "ta.kelly_criterion() requires 3 arguments";
|
|
53412
|
+
return env.ta.kellyCriterion(wave11n(0, ["win_rate"], msg), wave11n(1, ["avg_win"], msg), wave11n(2, ["avg_loss"], msg));
|
|
53413
|
+
}
|
|
53414
|
+
if (fname === "ta.risk_reward_ratio" || fname === "risk_reward_ratio") {
|
|
53415
|
+
const msg = "ta.risk_reward_ratio() requires 3 arguments";
|
|
53416
|
+
return env.ta.riskRewardRatio(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["stop", "stop_price"], msg), wave11n(2, ["target", "target_price"], msg));
|
|
53417
|
+
}
|
|
53418
|
+
if (fname === "ta.risk_reward_asymmetry" || fname === "risk_reward_asymmetry") {
|
|
53419
|
+
const msg = "ta.risk_reward_asymmetry() requires 4 arguments";
|
|
53420
|
+
return env.ta.riskRewardAsymmetry(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["stop", "stop_price"], msg), wave11n(2, ["target", "target_price"], msg), wave11n(3, ["win_rate"], msg));
|
|
53421
|
+
}
|
|
53422
|
+
if (fname === "ta.probability_of_movement" || fname === "probability_of_movement") {
|
|
53423
|
+
const msg = "ta.probability_of_movement() requires 4 arguments";
|
|
53424
|
+
return env.ta.probabilityOfMovement(wave11n(0, ["current", "current_price"], msg), wave11n(1, ["target", "target_price"], msg), wave11n(2, ["atr"], msg), wave11n(3, ["period", "length"], msg));
|
|
53425
|
+
}
|
|
53426
|
+
if (fname === "ta.trend_strength" || fname === "trend_strength") {
|
|
53427
|
+
const msg = "ta.trend_strength() requires 3 arguments";
|
|
53428
|
+
return env.ta.trendStrength(wave11n(0, ["price", "source"], msg), wave11n(1, ["adx"], msg), wave11n(2, ["rsi"], msg));
|
|
53429
|
+
}
|
|
53430
|
+
if (fname === "ta.breakeven_level" || fname === "breakeven_level") {
|
|
53431
|
+
const msg = "ta.breakeven_level() requires 5 arguments";
|
|
53432
|
+
return env.ta.breakevenLevel(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["quantity", "qty"], msg), wave11n(2, ["commission"], msg), wave11n(3, ["slippage"], msg), wave11n(4, ["direction"], msg));
|
|
53433
|
+
}
|
|
53434
|
+
if (fname === "ta.market_structure_pivot" || fname === "market_structure_pivot") {
|
|
53435
|
+
const msg = "ta.market_structure_pivot() requires 5 arguments";
|
|
53436
|
+
wave11n(0, ["high"], msg);
|
|
53437
|
+
wave11n(1, ["low"], msg);
|
|
53438
|
+
const close = wave11n(2, ["close"], msg);
|
|
53439
|
+
wave11n(3, ["left", "left_bars"], msg);
|
|
53440
|
+
wave11n(4, ["right", "right_bars"], msg);
|
|
53441
|
+
return env.ta.marketStructurePivot(close);
|
|
53442
|
+
}
|
|
53443
|
+
if (fname === "ta.position_sizing_score" || fname === "position_sizing_score") {
|
|
53444
|
+
const msg = "ta.position_sizing_score() requires 4 arguments";
|
|
53445
|
+
return env.ta.positionSizingScore(wave11n(0, ["account_risk", "risk"], msg), wave11n(1, ["volatility"], msg), wave11n(2, ["conviction"], msg), wave11n(3, ["correlation"], msg));
|
|
53446
|
+
}
|
|
53447
|
+
if (fname === "ta.trailing_exit_level" || fname === "trailing_exit_level") {
|
|
53448
|
+
const msg = "ta.trailing_exit_level() requires 5 arguments";
|
|
53449
|
+
return env.ta.trailingExitLevel(wave11n(0, ["entry", "entry_price"], msg), wave11n(1, ["current", "current_price"], msg), wave11n(2, ["atr"], msg), wave11n(3, ["multiplier", "mult"], msg), wave11n(4, ["step"], msg));
|
|
53450
|
+
}
|
|
53451
|
+
if (fname === "ta.optimal_entry_zone" || fname === "optimal_entry_zone") {
|
|
53452
|
+
const msg = "ta.optimal_entry_zone() requires 4 arguments";
|
|
53453
|
+
wave11n(0, ["high"], msg);
|
|
53454
|
+
wave11n(1, ["low"], msg);
|
|
53455
|
+
const close = wave11n(2, ["close"], msg);
|
|
53456
|
+
wave11n(3, ["period", "length"], msg);
|
|
53457
|
+
return env.ta.optimalEntryZone(close);
|
|
53458
|
+
}
|
|
53459
|
+
if (fname === "ta.mean_reversion_entry" || fname === "mean_reversion_entry") {
|
|
53460
|
+
const msg = "ta.mean_reversion_entry() requires 5 arguments";
|
|
53461
|
+
return env.ta.meanReversionEntry(wave11n(0, ["price", "source"], msg), wave11n(1, ["sma"], msg), wave11n(2, ["stdev", "std_dev"], msg), wave11n(4, ["threshold"], msg));
|
|
53462
|
+
}
|
|
53463
|
+
if (fname === "ta.multi_timeframe_signal" || fname === "multi_timeframe_signal") {
|
|
53464
|
+
const msg = "ta.multi_timeframe_signal() requires 6 arguments";
|
|
53465
|
+
return env.ta.multiTimeframeSignal(wave11n(0, ["s1", "signal1"], msg), wave11n(1, ["s2", "signal2"], msg), wave11n(2, ["s3", "signal3"], msg), wave11n(3, ["w1", "weight1"], msg), wave11n(4, ["w2", "weight2"], msg), wave11n(5, ["w3", "weight3"], msg));
|
|
53466
|
+
}
|
|
53467
|
+
if (fname === "ta.market_timing_index" || fname === "market_timing_index") {
|
|
53468
|
+
const msg = "ta.market_timing_index() requires 4 arguments";
|
|
53469
|
+
return env.ta.marketTimingIndex(wave11n(0, ["trend"], msg), wave11n(1, ["momentum"], msg), wave11n(2, ["volatility"], msg), wave11n(3, ["sentiment"], msg));
|
|
53470
|
+
}
|
|
53471
|
+
if (fname === "ta.regime_adaptive_signal" || fname === "regime_adaptive_signal") {
|
|
53472
|
+
const msg = "ta.regime_adaptive_signal() requires 4 arguments";
|
|
53473
|
+
const strength = wave11n(0, ["signal_strength", "strength"], msg);
|
|
53474
|
+
const volRegime = wave12s(1, ["volatility_regime", "vol_regime"], msg);
|
|
53475
|
+
const trendRegime = wave12s(2, ["trend_regime"], msg);
|
|
53476
|
+
wave11n(3, ["period", "length"], msg);
|
|
53477
|
+
return env.ta.regimeAdaptiveSignal(strength, volRegime, trendRegime);
|
|
53478
|
+
}
|
|
53479
|
+
if (fname === "ta.strategy_score" || fname === "strategy_score") {
|
|
53480
|
+
const msg = "ta.strategy_score() requires 4 arguments";
|
|
53481
|
+
return env.ta.strategyScore(wave11n(0, ["rsi"], msg), wave11n(1, ["macd"], msg), wave11n(2, ["ema_cross"], msg), wave11n(3, ["trend"], msg));
|
|
53482
|
+
}
|
|
53483
|
+
if (fname === "ta.breakout_detection" || fname === "breakout_detection") {
|
|
53484
|
+
const msg = "ta.breakout_detection() requires 3 arguments";
|
|
53485
|
+
return env.ta.breakoutDetection(wave11n(0, ["close", "source"], msg), wave11n(1, ["resistance"], msg), wave11n(2, ["support"], msg));
|
|
53486
|
+
}
|
|
51987
53487
|
return;
|
|
51988
53488
|
}
|
|
51989
53489
|
function hlc3(env) {
|
|
@@ -51994,6 +53494,14 @@ function hlc3(env) {
|
|
|
51994
53494
|
return c ?? h ?? l;
|
|
51995
53495
|
return (h + l + c) / 3;
|
|
51996
53496
|
}
|
|
53497
|
+
function seriesLastCell(value) {
|
|
53498
|
+
if (value instanceof PineArray) {
|
|
53499
|
+
const n = value.size();
|
|
53500
|
+
return n > 0 ? value.get(n - 1) : null;
|
|
53501
|
+
}
|
|
53502
|
+
const v = unwrap2(value);
|
|
53503
|
+
return typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
53504
|
+
}
|
|
51997
53505
|
function asArray2(value) {
|
|
51998
53506
|
if (value instanceof PineArray)
|
|
51999
53507
|
return value;
|
|
@@ -52892,8 +54400,22 @@ function evalDrawingCall(fname, node, env) {
|
|
|
52892
54400
|
const position = drawRaw(node, env, 0, ["position"]);
|
|
52893
54401
|
if (position !== undefined)
|
|
52894
54402
|
extra.position = position;
|
|
52895
|
-
putFinite(extra, "
|
|
52896
|
-
putFinite(extra, "
|
|
54403
|
+
putFinite(extra, "columns", drawNum(node, env, 1, ["columns"]));
|
|
54404
|
+
putFinite(extra, "rows", drawNum(node, env, 2, ["rows"]));
|
|
54405
|
+
const bgcolor = drawRaw(node, env, 3, ["bgcolor"]);
|
|
54406
|
+
if (bgcolor !== undefined)
|
|
54407
|
+
extra.bgcolor = bgcolor;
|
|
54408
|
+
const frameColor = drawRaw(node, env, 4, ["frame_color"]);
|
|
54409
|
+
if (frameColor !== undefined)
|
|
54410
|
+
extra.frame_color = frameColor;
|
|
54411
|
+
putFinite(extra, "frame_width", drawNum(node, env, 5, ["frame_width"]));
|
|
54412
|
+
const borderColor = drawRaw(node, env, 6, ["border_color"]);
|
|
54413
|
+
if (borderColor !== undefined)
|
|
54414
|
+
extra.border_color = borderColor;
|
|
54415
|
+
putFinite(extra, "border_width", drawNum(node, env, 7, ["border_width"]));
|
|
54416
|
+
const forceOverlay = drawRaw(node, env, 8, ["force_overlay"]);
|
|
54417
|
+
if (forceOverlay !== undefined)
|
|
54418
|
+
extra.force_overlay = forceOverlay;
|
|
52897
54419
|
return book.tableNew(env.barIndex, extra);
|
|
52898
54420
|
}
|
|
52899
54421
|
if (fname === "polyline.new") {
|
|
@@ -53940,8 +55462,8 @@ function syminfoPrefix2(node, env) {
|
|
|
53940
55462
|
function calendarMs(node, env) {
|
|
53941
55463
|
const arg = callArg(node.args, 0, ["time", "timestamp"]);
|
|
53942
55464
|
if (arg == null)
|
|
53943
|
-
return num2(env.ctx.time);
|
|
53944
|
-
return unwrap2(evalExpr(arg, env));
|
|
55465
|
+
return timestampToMs(num2(env.ctx.time));
|
|
55466
|
+
return timestampToMs(unwrap2(evalExpr(arg, env)));
|
|
53945
55467
|
}
|
|
53946
55468
|
function evalLibraryMemberCall(mod, attr, node, env) {
|
|
53947
55469
|
const exp = mod.get(attr);
|