@hoox-sh/pynets 0.3.0 → 0.4.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/dist/index.js CHANGED
@@ -42191,6 +42191,367 @@ class TaEngine {
42191
42191
  const direction = recentHigh === oldest ? 1 : -1;
42192
42192
  return { high: recentHigh, low: recentLow, dir: pct > th ? 1 : direction };
42193
42193
  }
42194
+ accelSites = new Map;
42195
+ coerceTaInt(value, message) {
42196
+ if (value === null || !Number.isFinite(value))
42197
+ throw new Error(`${message}. Got: na`);
42198
+ const nearest = Math.round(value);
42199
+ if (Math.abs(value - nearest) <= PERIOD_INT_EPS)
42200
+ return nearest;
42201
+ return Math.floor(value);
42202
+ }
42203
+ hammer(open, high, low, close) {
42204
+ if (open === null || high === null || low === null || close === null) {
42205
+ throw new Error("bad operand type for abs(): 'NoneType'");
42206
+ }
42207
+ const body = Math.abs(close - open);
42208
+ const range = high - low;
42209
+ const lower = Math.min(open, close) - low;
42210
+ const upper = high - Math.max(open, close);
42211
+ const isDoji = body < range * 0.1;
42212
+ const isHammer = body > 0 && lower > body * 2 && upper < body;
42213
+ let strength = 0;
42214
+ if (isDoji)
42215
+ strength = 1 - body / (range + 0.0001);
42216
+ else if (isHammer)
42217
+ strength = Math.min(1, lower / (range + 0.0001));
42218
+ return taRec({
42219
+ is_hammer: isHammer,
42220
+ is_doji: isDoji,
42221
+ pattern_strength: Number.isFinite(strength) ? strength : null
42222
+ });
42223
+ }
42224
+ gapDetector(high, low, prevClose) {
42225
+ const none = taRec({ gap_size: 0, gap_type: 0, gap_percent: 0 });
42226
+ if (prevClose === null)
42227
+ return none;
42228
+ if (high === null || low === null) {
42229
+ throw new Error("unsupported operand type(s) for -: 'float' and 'NoneType'");
42230
+ }
42231
+ const upside = Math.max(0, low - prevClose);
42232
+ const downside = Math.max(0, prevClose - high);
42233
+ if (upside > downside) {
42234
+ const pct = prevClose !== 0 ? upside / prevClose * 100 : 0;
42235
+ return taRec({
42236
+ gap_size: upside,
42237
+ gap_type: 1,
42238
+ gap_percent: Number.isFinite(pct) ? pct : null
42239
+ });
42240
+ }
42241
+ if (downside > 0) {
42242
+ const pct = prevClose !== 0 ? downside / prevClose * 100 : 0;
42243
+ return taRec({
42244
+ gap_size: downside,
42245
+ gap_type: -1,
42246
+ gap_percent: Number.isFinite(pct) ? pct : null
42247
+ });
42248
+ }
42249
+ return none;
42250
+ }
42251
+ macdSignal(macdLine, signalLine) {
42252
+ if (macdLine === null || signalLine === null)
42253
+ return null;
42254
+ return finiteOut2(macdLine - signalLine);
42255
+ }
42256
+ accelerationFactor(site, source, period) {
42257
+ const p = this.coerceTaInt(period, "ta.acceleration_factor() requires 2 arguments");
42258
+ let samples = this.accelSites.get(site);
42259
+ if (samples === undefined) {
42260
+ samples = [];
42261
+ this.accelSites.set(site, samples);
42262
+ }
42263
+ pushCap(samples, finiteCell2(source), 1000);
42264
+ if (samples.length < p + 1 || p <= 0)
42265
+ return 0;
42266
+ const oldest = samples.slice(0, p + 1);
42267
+ const newestFirst = [];
42268
+ for (let i = oldest.length - 1;i >= 0; i--) {
42269
+ const v = oldest[i];
42270
+ if (v !== null)
42271
+ newestFirst.push(v);
42272
+ }
42273
+ if (newestFirst.length < 2)
42274
+ return 0;
42275
+ let oldSum = 0;
42276
+ for (let i = 0;i < newestFirst.length - 1; i++)
42277
+ oldSum += newestFirst[i];
42278
+ const oldMom = oldSum / (newestFirst.length - 1);
42279
+ if (Math.abs(oldMom) < 0.0000000001)
42280
+ return 0;
42281
+ const newMom = newestFirst[newestFirst.length - 1];
42282
+ let acc = (newMom - oldMom) / oldMom;
42283
+ if (acc < -2)
42284
+ acc = -2;
42285
+ if (acc > 2)
42286
+ acc = 2;
42287
+ return finiteOut2(acc);
42288
+ }
42289
+ stochSmooth(high, low, close, period, smoothK, smoothD) {
42290
+ const p = this.coerceTaInt(period, "ta.stoch_smooth period must be integer");
42291
+ const k = this.coerceTaInt(smoothK, "ta.stoch_smooth smooth_k must be integer");
42292
+ const d = this.coerceTaInt(smoothD, "ta.stoch_smooth smooth_d must be integer");
42293
+ if (p <= 0)
42294
+ throw new Error("max() iterable argument is empty");
42295
+ if (high === null || low === null || close === null) {
42296
+ throw new Error("unsupported operand type(s) for /: 'float' and 'NoneType'");
42297
+ }
42298
+ if (k !== 1 || d !== 1)
42299
+ return null;
42300
+ const span = high - low;
42301
+ const stoch = span !== 0 ? 100 * (close - low) / span : 50;
42302
+ return finiteOut2(stoch);
42303
+ }
42304
+ engulfing() {
42305
+ return taRec({ is_bullish: false, is_bearish: false, pattern_strength: 0 });
42306
+ }
42307
+ insideBarPattern() {
42308
+ return false;
42309
+ }
42310
+ doubleTopBottom(period) {
42311
+ if (period === null || !Number.isFinite(period)) {
42312
+ throw new Error("period must be integer. Got: na");
42313
+ }
42314
+ return taRec({ pattern_type: "none", strength: 0, breakout_level: 0 });
42315
+ }
42316
+ cumDeltaSites = new Map;
42317
+ volMomSites = new Map;
42318
+ volProfileLowSites = new Map;
42319
+ volThrustSites = new Map;
42320
+ asCount(value) {
42321
+ if (!Number.isFinite(value))
42322
+ return null;
42323
+ const nearest = Math.round(value);
42324
+ return Math.abs(value - nearest) <= PERIOD_INT_EPS ? nearest : Math.floor(value);
42325
+ }
42326
+ pushChrono(buf, value) {
42327
+ buf.push(value !== null && Number.isFinite(value) ? value : null);
42328
+ if (buf.length > 1000)
42329
+ buf.shift();
42330
+ }
42331
+ nf(buf, i) {
42332
+ const v = buf[-i - 1];
42333
+ return v === undefined ? null : v;
42334
+ }
42335
+ voi(buy, sell) {
42336
+ const b = buy !== null && Number.isFinite(buy) ? buy : 0;
42337
+ const s = sell !== null && Number.isFinite(sell) ? sell : 0;
42338
+ const total = b + s;
42339
+ if (total === 0)
42340
+ return 0;
42341
+ return finiteOut2((b - s) / total);
42342
+ }
42343
+ bidAskImbalance(bidSize, askSize, bidPrice, askPrice) {
42344
+ const bid = bidSize !== null && Number.isFinite(bidSize) ? bidSize : 0;
42345
+ const ask = askSize !== null && Number.isFinite(askSize) ? askSize : 0;
42346
+ const bidPx = bidPrice !== null && Number.isFinite(bidPrice) ? bidPrice : 0;
42347
+ const askPx = askPrice !== null && Number.isFinite(askPrice) ? askPrice : 0;
42348
+ const total = bid + ask;
42349
+ if (total === 0)
42350
+ return taRec({ imbalance_ratio: 0, spread: 0 });
42351
+ return taRec({
42352
+ imbalance_ratio: finiteOut2((bid - ask) / total),
42353
+ spread: finiteOut2(bidPx > 0 ? askPx - bidPx : 0)
42354
+ });
42355
+ }
42356
+ rsiOversoldOverbought(rsi, oversold, overbought) {
42357
+ if (rsi === null || !Number.isFinite(rsi)) {
42358
+ return taRec({ is_oversold: false, is_overbought: false, rsi: null });
42359
+ }
42360
+ const os = this.asCount(oversold);
42361
+ const ob = this.asCount(overbought);
42362
+ if (os === null || ob === null) {
42363
+ return taRec({ is_oversold: false, is_overbought: false, rsi });
42364
+ }
42365
+ return taRec({ is_oversold: rsi < os, is_overbought: rsi > ob, rsi });
42366
+ }
42367
+ rsiDivergence(series, period) {
42368
+ const p = this.asCount(period);
42369
+ if (p === null || series.length === 0)
42370
+ return null;
42371
+ let last = 0;
42372
+ for (let i = 0;i < series.length; i++) {
42373
+ if (i < p) {
42374
+ last = 0;
42375
+ continue;
42376
+ }
42377
+ const start = Math.max(0, i - p);
42378
+ const vals = [];
42379
+ for (let j = start;j <= i; j++) {
42380
+ const v = series[j];
42381
+ if (v !== null && Number.isFinite(v))
42382
+ vals.push(v);
42383
+ }
42384
+ if (vals.length < 2) {
42385
+ last = 0;
42386
+ continue;
42387
+ }
42388
+ let rsiMin = vals[0];
42389
+ let rsiMax = vals[0];
42390
+ for (const v of vals) {
42391
+ if (v < rsiMin)
42392
+ rsiMin = v;
42393
+ if (v > rsiMax)
42394
+ rsiMax = v;
42395
+ }
42396
+ const cur = series[i];
42397
+ const range = rsiMax - rsiMin;
42398
+ if (cur === null || !Number.isFinite(cur) || range <= 0) {
42399
+ last = 0;
42400
+ continue;
42401
+ }
42402
+ last = (cur - rsiMin) / range * 2 - 1;
42403
+ }
42404
+ return finiteOut2(last);
42405
+ }
42406
+ cumulativeDelta(site, close, volume, period) {
42407
+ const n = this.asCount(period);
42408
+ let st = this.cumDeltaSites.get(site);
42409
+ if (st === undefined) {
42410
+ st = { close: [], volume: [] };
42411
+ this.cumDeltaSites.set(site, st);
42412
+ }
42413
+ this.pushChrono(st.close, close);
42414
+ this.pushChrono(st.volume, volume);
42415
+ if (n === null || n <= 0 || st.close.length < n || st.volume.length < n)
42416
+ return 0;
42417
+ let delta = 0;
42418
+ for (let i = -n;i < 0; i++) {
42419
+ const cRaw = this.nf(st.close, i);
42420
+ const vRaw = this.nf(st.volume, i);
42421
+ const c = cRaw !== null && Number.isFinite(cRaw) ? cRaw : 0;
42422
+ const v = vRaw !== null && Number.isFinite(vRaw) ? vRaw : 0;
42423
+ if (i > -n) {
42424
+ const prevRaw = this.nf(st.close, i - 1);
42425
+ const prev = prevRaw !== null && Number.isFinite(prevRaw) ? prevRaw : c;
42426
+ if (c > prev)
42427
+ delta += v;
42428
+ else if (c < prev)
42429
+ delta -= v;
42430
+ }
42431
+ }
42432
+ return finiteOut2(delta);
42433
+ }
42434
+ volumeMomentum(site, volume, period) {
42435
+ const n = this.asCount(period);
42436
+ let st = this.volMomSites.get(site);
42437
+ if (st === undefined) {
42438
+ st = { volume: [] };
42439
+ this.volMomSites.set(site, st);
42440
+ }
42441
+ this.pushChrono(st.volume, volume);
42442
+ if (n === null || n <= 0 || st.volume.length < n + 1)
42443
+ return 0;
42444
+ const clean = [];
42445
+ for (let i = 0;i < n + 1; i++) {
42446
+ const v = st.volume[i];
42447
+ if (v !== null && Number.isFinite(v))
42448
+ clean.push(v);
42449
+ }
42450
+ if (clean.length < 2)
42451
+ return 0;
42452
+ const newVol = clean[0];
42453
+ let sum = 0;
42454
+ for (let i = 1;i < clean.length; i++)
42455
+ sum += clean[i];
42456
+ const oldVol = sum / (clean.length - 1);
42457
+ if (oldVol === 0)
42458
+ return 0;
42459
+ let momentum = (newVol - oldVol) / oldVol * 100;
42460
+ if (momentum > 100)
42461
+ momentum = 100;
42462
+ if (momentum < -100)
42463
+ momentum = -100;
42464
+ return finiteOut2(momentum);
42465
+ }
42466
+ volumeProfileHigh(prices, volumes) {
42467
+ if (prices.length === 0 || volumes.length === 0 || prices.length !== volumes.length)
42468
+ return 0;
42469
+ let maxVol = 0;
42470
+ let maxPrice = 0;
42471
+ for (let i = 0;i < prices.length; i++) {
42472
+ const v = volumes[i];
42473
+ if (v === null || !Number.isFinite(v) || !(v > maxVol))
42474
+ continue;
42475
+ maxVol = v;
42476
+ const p = prices[i];
42477
+ maxPrice = p !== null && Number.isFinite(p) ? p : 0;
42478
+ }
42479
+ return finiteOut2(maxPrice);
42480
+ }
42481
+ volumeProfileLow(site, close, volume, period, levels) {
42482
+ const p = this.asCount(period);
42483
+ const lv = this.asCount(levels);
42484
+ let st = this.volProfileLowSites.get(site);
42485
+ if (st === undefined) {
42486
+ st = { close: [], volume: [] };
42487
+ this.volProfileLowSites.set(site, st);
42488
+ }
42489
+ this.pushChrono(st.close, close);
42490
+ this.pushChrono(st.volume, volume);
42491
+ const oldest = st.close.length > 0 ? st.close[0] : null;
42492
+ const fallback = st.close.length === 0 ? 100 : oldest !== null && Number.isFinite(oldest) ? oldest : null;
42493
+ if (p === null || lv === null || p <= 0 || lv <= 0 || st.close.length < p)
42494
+ return fallback;
42495
+ const prices = [];
42496
+ const vols = [];
42497
+ for (let i = -p;i < 0; i++) {
42498
+ const c = this.nf(st.close, i);
42499
+ const v = this.nf(st.volume, i);
42500
+ if (c !== null && Number.isFinite(c) && v !== null && Number.isFinite(v)) {
42501
+ prices.push(c);
42502
+ vols.push(v);
42503
+ }
42504
+ }
42505
+ if (prices.length === 0)
42506
+ return fallback;
42507
+ let minP = prices[0];
42508
+ let maxP = prices[0];
42509
+ for (const c of prices) {
42510
+ if (c < minP)
42511
+ minP = c;
42512
+ if (c > maxP)
42513
+ maxP = c;
42514
+ }
42515
+ if (minP === maxP)
42516
+ return minP;
42517
+ const bucket = (maxP - minP) / lv;
42518
+ const buckets = new Array(lv).fill(0);
42519
+ for (let k = 0;k < prices.length; k++) {
42520
+ let idx = Math.trunc((prices[k] - minP) / bucket);
42521
+ if (idx > lv - 1)
42522
+ idx = lv - 1;
42523
+ if (idx < 0)
42524
+ idx = 0;
42525
+ buckets[idx] = (buckets[idx] ?? 0) + vols[k];
42526
+ }
42527
+ let minIdx = 0;
42528
+ for (let i = 1;i < lv; i++) {
42529
+ if ((buckets[i] ?? 0) < (buckets[minIdx] ?? 0))
42530
+ minIdx = i;
42531
+ }
42532
+ return finiteOut2(minP + minIdx * bucket);
42533
+ }
42534
+ volumeThrust(site, close, volume, volSma, sensitivity) {
42535
+ const sens = Number.isFinite(sensitivity) ? sensitivity : 0.3;
42536
+ let st = this.volThrustSites.get(site);
42537
+ if (st === undefined) {
42538
+ st = { close: [], volume: [], sma: [] };
42539
+ this.volThrustSites.set(site, st);
42540
+ }
42541
+ this.pushChrono(st.close, close);
42542
+ this.pushChrono(st.volume, volume);
42543
+ this.pushChrono(st.sma, volSma);
42544
+ if (st.close.length === 0 || st.volume.length === 0 || st.sma.length === 0)
42545
+ return 0;
42546
+ const numOr = (v, fallback) => v !== null && Number.isFinite(v) ? v : fallback;
42547
+ const cVal = numOr(this.nf(st.close, -1), 100);
42548
+ const cPrev = st.close.length > 1 ? numOr(this.nf(st.close, -2), 100) : 100;
42549
+ const vVal = numOr(this.nf(st.volume, -1), 1000);
42550
+ const vsVal = numOr(this.nf(st.sma, -1), 1000);
42551
+ const spike = vVal > vsVal * (1 + sens);
42552
+ const move = cPrev !== 0 ? Math.abs(cVal - cPrev) / cPrev > 0.01 : false;
42553
+ return spike && move ? 1 : 0;
42554
+ }
42194
42555
  }
42195
42556
  function spearmanRho(vals) {
42196
42557
  const n = vals.length;
@@ -42660,7 +43021,24 @@ var TA_METHODS = new Set([
42660
43021
  "emv",
42661
43022
  "fractal",
42662
43023
  "atr_stop",
42663
- "zigzag"
43024
+ "zigzag",
43025
+ "hammer",
43026
+ "gap_detector",
43027
+ "macd_signal",
43028
+ "acceleration_factor",
43029
+ "stoch_smooth",
43030
+ "engulfing",
43031
+ "inside_bar_pattern",
43032
+ "double_top_bottom",
43033
+ "voi",
43034
+ "bid_ask_imbalance",
43035
+ "rsi_oversold_overbought",
43036
+ "rsi_divergence",
43037
+ "cumulative_delta",
43038
+ "volume_momentum",
43039
+ "volume_profile_high",
43040
+ "volume_profile_low",
43041
+ "volume_thrust"
42664
43042
  ]);
42665
43043
  var TA_BARE_ATTRS = new Set([
42666
43044
  "accdist",
@@ -42862,8 +43240,17 @@ function emitCall2(ctx, node, visit) {
42862
43240
  const msg = pick(args, 0, ["message", "msg"], `"runtime.error"`);
42863
43241
  return `(() => { throw new Error(String(${msg})); })()`;
42864
43242
  }
42865
- if (name === "alertcondition")
43243
+ if (name === "max_bars_back")
42866
43244
  return "null";
43245
+ if (name === "timenow")
43246
+ return "__h.timenow(time_arr)";
43247
+ if (name === "alertcondition") {
43248
+ ctx.usesDrawings = true;
43249
+ const cond = pick(args, 0, ["condition"], "null");
43250
+ const title = hasArg(args, 1, ["title"]) ? pick(args, 1, ["title"], `"Alert"`) : `"Alert"`;
43251
+ const message = hasArg(args, 2, ["message"]) ? pick(args, 2, ["message"], `"Alert"`) : `"Alert"`;
43252
+ return `__h.draw.alertcondition(__bar_idx, ${cond}, ${title}, ${message})`;
43253
+ }
42867
43254
  if (name === "str_tostring" || name === "tostring") {
42868
43255
  const x = pick(args, 0, ["value", "source", "x"], "null");
42869
43256
  return `String(${x} ?? "")`;
@@ -43002,6 +43389,12 @@ function periodGate(expr, fb) {
43002
43389
  function finiteOr2(expr, fb) {
43003
43390
  return `((__v) => (__v != null && Number.isFinite(__v) ? __v : ${fb}))(${expr})`;
43004
43391
  }
43392
+ function cellOf(expr) {
43393
+ return `((__c) => (__c == null ? null : typeof __c === "boolean" ? (__c ? 1 : 0) : (typeof __c === "number" && Number.isFinite(__c) ? __c : null)))(${expr})`;
43394
+ }
43395
+ function cellList(expr) {
43396
+ return `(() => { const __v = ${expr}; const __cell = (e) => (e == null ? null : typeof e === "boolean" ? (e ? 1 : 0) : (typeof e === "number" && Number.isFinite(e) ? e : null)); if (__v != null && typeof __v.size === "function" && typeof __v.get === "function") { const __n = __v.size(); const __o = []; for (let __i = 0; __i < __n; __i++) __o.push(__cell(__v.get(__i))); return __o; } return [__cell(__v)]; })()`;
43397
+ }
43005
43398
  var DRAW_KINDS = new Set(["label", "line", "box", "table", "polyline", "linefill"]);
43006
43399
  var ARRAY_SIGS = {
43007
43400
  new: [["size"], ["initial_value", "initial"]],
@@ -43172,6 +43565,10 @@ function emitArray(name, args) {
43172
43565
  const raw = nsMethod(name, "array_");
43173
43566
  if (raw == null)
43174
43567
  return null;
43568
+ if (raw === "from") {
43569
+ const parts = args.pos.length > 0 ? args.pos : Object.values(args.kw);
43570
+ return `__h.array.from([${parts.join(", ")}])`;
43571
+ }
43175
43572
  const method = ctorMethod(raw);
43176
43573
  const params = ARRAY_SIGS[method];
43177
43574
  if (params == null)
@@ -43216,11 +43613,24 @@ var DRAW_METHODS = {
43216
43613
  label: {
43217
43614
  set_text: [["id"], ["text"]],
43218
43615
  set_xy: [["id"], ["x"], ["y"]],
43616
+ set_x: [["id"], ["x"]],
43617
+ set_y: [["id"], ["y"]],
43219
43618
  set_color: [["id"], ["color"]],
43220
43619
  set_style: [["id"], ["style"]],
43221
43620
  set_size: [["id"], ["size"]],
43222
43621
  set_tooltip: [["id"], ["tooltip"]],
43223
43622
  set_textalign: [["id"], ["textalign"]],
43623
+ set_textcolor: [["id"], ["color", "textcolor"]],
43624
+ set_text_font_family: [["id"], ["font_family", "text_font_family"]],
43625
+ set_text_halign: [["id"], ["halign", "text_halign"]],
43626
+ set_text_valign: [["id"], ["valign", "text_valign"]],
43627
+ set_text_size: [["id"], ["size", "text_size"]],
43628
+ set_text_formatting: [["id"], ["formatting", "text_formatting"]],
43629
+ set_border_color: [["id"], ["color"]],
43630
+ set_border_width: [["id"], ["width"]],
43631
+ set_border_style: [["id"], ["style"]],
43632
+ set_xloc: [["id"], ["xloc"]],
43633
+ set_yloc: [["id"], ["yloc"]],
43224
43634
  delete: [["id"]],
43225
43635
  get_text: [["id"]],
43226
43636
  get_x: [["id"]],
@@ -43228,12 +43638,17 @@ var DRAW_METHODS = {
43228
43638
  },
43229
43639
  line: {
43230
43640
  set_xy: [["id"], ["x1"], ["y1"], ["x2"], ["y2"]],
43231
- set_xy1: [["id"], ["x1"], ["y1"]],
43232
- set_xy2: [["id"], ["x2"], ["y2"]],
43641
+ set_xy1: [["id"], ["x1", "x"], ["y1", "y"]],
43642
+ set_xy2: [["id"], ["x2", "x"], ["y2", "y"]],
43643
+ set_x1: [["id"], ["x1", "x"]],
43644
+ set_y1: [["id"], ["y1", "y"]],
43645
+ set_x2: [["id"], ["x2", "x"]],
43646
+ set_y2: [["id"], ["y2", "y"]],
43233
43647
  set_color: [["id"], ["color"]],
43234
43648
  set_width: [["id"], ["width"]],
43235
43649
  set_style: [["id"], ["style"]],
43236
43650
  set_extend: [["id"], ["extend"]],
43651
+ set_xloc: [["id"], ["xloc"]],
43237
43652
  delete: [["id"]],
43238
43653
  get_price: [["id"], ["x"]],
43239
43654
  get_x1: [["id"]],
@@ -43244,44 +43659,137 @@ var DRAW_METHODS = {
43244
43659
  box: {
43245
43660
  set_corners: [["id"], ["left", "x1"], ["top", "y1"], ["right", "x2"], ["bottom", "y2"]],
43246
43661
  set_lefttop: [["id"], ["left", "x1"], ["top", "y1"], ["right", "x2"], ["bottom", "y2"]],
43662
+ set_left: [["id"], ["left"]],
43663
+ set_right: [["id"], ["right"]],
43664
+ set_top: [["id"], ["top"]],
43665
+ set_bottom: [["id"], ["bottom"]],
43247
43666
  set_bgcolor: [["id"], ["bgcolor", "color"]],
43248
43667
  set_border_color: [["id"], ["color", "border_color"]],
43668
+ set_border_width: [["id"], ["width"]],
43669
+ set_border_style: [["id"], ["style"]],
43249
43670
  set_text: [["id"], ["text"]],
43671
+ set_text_color: [["id"], ["color", "text_color"]],
43672
+ set_text_font_family: [["id"], ["font_family"]],
43673
+ set_text_halign: [["id"], ["halign"]],
43674
+ set_text_valign: [["id"], ["valign"]],
43675
+ set_text_size: [["id"], ["size"]],
43676
+ set_text_formatting: [["id"], ["formatting"]],
43677
+ set_text_wrap: [["id"], ["wrap"]],
43250
43678
  set_extend: [["id"], ["extend"]],
43679
+ set_closed: [["id"], ["closed"]],
43680
+ set_rightbottom: [["id"], ["right"], ["bottom"]],
43681
+ get_left: [["id"]],
43682
+ get_right: [["id"]],
43683
+ get_top: [["id"]],
43684
+ get_bottom: [["id"]],
43251
43685
  delete: [["id"]]
43252
43686
  },
43253
43687
  table: {
43254
43688
  cell: [["id"], ["column", "col"], ["row"], ["text"]],
43255
- cell_set_text: [["id"], ["column", "col"], ["row"], ["text"]],
43689
+ cell_set_text: [["id"], ["row"], ["column", "col"], ["text"]],
43690
+ cell_get_text: [["id"], ["row"], ["column", "col"]],
43691
+ cell_set_text_color: [["id"], ["row"], ["column", "col"], ["color", "text"]],
43692
+ cell_set_bgcolor: [["id"], ["row"], ["column", "col"], ["color"]],
43693
+ cell_set_border_color: [["id"], ["row"], ["column", "col"], ["color"]],
43694
+ cell_set_border_width: [["id"], ["row"], ["column", "col"], ["width"]],
43695
+ cell_set_tooltip: [["id"], ["row"], ["column", "col"], ["tooltip", "text"]],
43696
+ cell_set_width: [["id"], ["column", "col"], ["row"], ["width"]],
43697
+ cell_set_height: [["id"], ["column", "col"], ["row"], ["height"]],
43698
+ cell_set_text_halign: [["id"], ["column", "col"], ["row"], ["halign"]],
43699
+ cell_set_text_valign: [["id"], ["column", "col"], ["row"], ["valign"]],
43700
+ cell_set_text_size: [["id"], ["column", "col"], ["row"], ["size"]],
43701
+ cell_set_text_font_family: [["id"], ["column", "col"], ["row"], ["font_family"]],
43702
+ cell_set_text_formatting: [["id"], ["column", "col"], ["row"], ["formatting"]],
43256
43703
  set_position: [["id"], ["position"]],
43704
+ set_bgcolor: [["id"], ["color", "bgcolor"]],
43705
+ set_border_color: [["id"], ["color"]],
43706
+ set_border_width: [["id"], ["width"]],
43707
+ set_frame_color: [["id"], ["color"]],
43708
+ set_frame_width: [["id"], ["width"]],
43709
+ merge_cells: [["id"], ["start_row"], ["start_column", "start_col"], ["end_row"], ["end_column", "end_col"]],
43257
43710
  delete: [["id"]]
43258
43711
  },
43259
43712
  polyline: {
43260
- delete: [["id"]]
43713
+ delete: [["id"]],
43714
+ get_points: [["id"]],
43715
+ set_points: [["id"], ["points"]],
43716
+ set_line_color: [["id"], ["color"]],
43717
+ set_line_width: [["id"], ["width"]],
43718
+ set_line_style: [["id"], ["style"]],
43719
+ set_fill_color: [["id"], ["fill_color", "color"]],
43720
+ set_curved: [["id"], ["curved"]],
43721
+ set_force_overlay: [["id"], ["force_overlay"]],
43722
+ set_closed: [["id"], ["closed"]],
43723
+ set_xloc: [["id"], ["xloc"]]
43261
43724
  },
43262
43725
  linefill: {
43263
43726
  set_color: [["id"], ["color"]],
43264
- delete: [["id"]]
43727
+ delete: [["id"]],
43728
+ get_line1: [["id"]],
43729
+ get_line2: [["id"]]
43265
43730
  }
43266
43731
  };
43732
+ function emitChartPoint(name, args) {
43733
+ const meth = name.slice("chart_point_".length);
43734
+ if (meth === "new" || meth === "from_time") {
43735
+ return `__h.draw.point_new(${pick(args, 0, ["time"], "null")}, ${pick(args, 1, ["price"], "0")})`;
43736
+ }
43737
+ if (meth === "from_index") {
43738
+ return `__h.draw.point_from_index(${pick(args, 0, ["index"], "null")}, ${pick(args, 1, ["price"], "0")})`;
43739
+ }
43740
+ if (meth === "now") {
43741
+ return `__h.draw.point_now(__bar_idx, time, ${pick(args, 0, ["price"], "0")})`;
43742
+ }
43743
+ if (meth === "copy") {
43744
+ return `__h.draw.point_copy(${pick(args, 0, ["point"], "null")})`;
43745
+ }
43746
+ return null;
43747
+ }
43267
43748
  function emitDraw(ctx, name, methodSrc, args) {
43268
43749
  if (name === "alert" && methodSrc == null) {
43269
43750
  ctx.usesDrawings = true;
43270
43751
  return `__h.draw.alert(__bar_idx, ${pick(args, 0, ["message"], "null")})`;
43271
43752
  }
43753
+ if (name.startsWith("chart_point_")) {
43754
+ const point = emitChartPoint(name, args);
43755
+ if (point != null)
43756
+ ctx.usesDrawings = true;
43757
+ return point;
43758
+ }
43272
43759
  const parsed = drawKindAndMethod(name, methodSrc);
43273
43760
  if (parsed == null)
43274
43761
  return null;
43275
43762
  const { kind, method } = parsed;
43276
43763
  let code = null;
43277
- if (method === "new") {
43764
+ if (method === "all") {
43765
+ code = `__h.draw.all(${JSON.stringify(kind)})`;
43766
+ } else if (method === "copy" && (kind === "line" || kind === "label" || kind === "box" || kind === "polyline")) {
43767
+ code = `__h.draw.copy(${pick(args, 0, ["id"], "null")})`;
43768
+ } else if (method === "new") {
43278
43769
  if (kind === "label") {
43279
- code = `__h.draw.label_new(__bar_idx, ${pick(args, 2, ["text"], "null")})`;
43770
+ code = `__h.draw.label_new(__bar_idx, ${pick(args, 2, ["text"], "null")}, ${pick(args, 0, ["x"], "0")}, ${pick(args, 1, ["y"], "0")})`;
43771
+ } else if (kind === "line") {
43772
+ code = `__h.draw.line_new(__bar_idx, ${pick(args, 0, ["x1"], "0")}, ${pick(args, 1, ["y1"], "0")}, ${pick(args, 2, ["x2"], "0")}, ${pick(args, 3, ["y2"], "0")})`;
43773
+ } else if (kind === "box") {
43774
+ code = `__h.draw.box_new(__bar_idx, ${pick(args, 0, ["left"], "0")}, ${pick(args, 1, ["top"], "0")}, ${pick(args, 2, ["right"], "0")}, ${pick(args, 3, ["bottom"], "0")})`;
43775
+ } else if (kind === "polyline") {
43776
+ code = `__h.draw.polyline_new(__bar_idx, ${pick(args, 0, ["points"], "null")})`;
43280
43777
  } else if (kind === "linefill") {
43281
- code = `__h.draw.linefill_new(__bar_idx, ${pick(args, 0, ["id1"], "null")}, ${pick(args, 1, ["id2"], "null")})`;
43778
+ const color = hasArg(args, 2, ["color"]) ? pick(args, 2, ["color"], "null") : "null";
43779
+ code = `__h.draw.linefill_new(__bar_idx, ${pick(args, 0, ["id1", "line1"], "null")}, ${pick(args, 1, ["id2", "line2"], "null")}, ${color})`;
43282
43780
  } else if (DRAW_KINDS.has(kind)) {
43283
43781
  code = `__h.draw.${kind}_new(__bar_idx)`;
43284
43782
  }
43783
+ } else if (kind === "line" && method === "fill") {
43784
+ const color = hasArg(args, 2, ["color"]) ? pick(args, 2, ["color"], "null") : "null";
43785
+ code = `__h.draw.linefill_new(__bar_idx, ${pick(args, 0, ["id1", "line1"], "null")}, ${pick(args, 1, ["id2", "line2"], "null")}, ${color})`;
43786
+ } else if (kind === "line" && (method === "set_first_point" || method === "set_second_point") || kind === "label" && method === "set_point" || kind === "box" && (method === "set_top_left_point" || method === "set_bottom_right_point")) {
43787
+ code = `__h.draw.${kind}_${method}(${pick(args, 0, ["id"], "null")}, ${pick(args, 1, ["point"], "null")})`;
43788
+ } else if (kind === "box" && method === "set_xloc") {
43789
+ code = `__h.draw.box_set_xloc(${pick(args, 0, ["id"], "null")}, ${pick(args, 1, ["left"], "null")}, ${pick(args, 2, ["right"], "null")}, ${pick(args, 3, ["xloc"], "null")})`;
43790
+ } else if (kind === "table" && method === "clear") {
43791
+ const id = pick(args, 0, ["id", "table_id"], "null");
43792
+ code = hasArg(args, 1, ["start_row"]) ? `__h.draw.table_clear(${id}, ${pick(args, 1, ["start_row"], "null")}, ${pick(args, 2, ["start_column", "start_col"], "null")}, ${pick(args, 3, ["end_row"], "null")}, ${pick(args, 4, ["end_column", "end_col"], "null")})` : `__h.draw.table_clear(${id})`;
43285
43793
  } else {
43286
43794
  const aliased = kind === "box" && method === "set_lefttop" ? "set_corners" : method;
43287
43795
  const params = DRAW_METHODS[kind]?.[method] ?? DRAW_METHODS[kind]?.[aliased];
@@ -43330,6 +43838,7 @@ function emitUdt(ctx, name, methodSrc, args) {
43330
43838
  }
43331
43839
  var SECURITY_FUNCS = new Set([
43332
43840
  "security",
43841
+ "security_lower_tf",
43333
43842
  "request_security",
43334
43843
  "request_security_lower_tf",
43335
43844
  "request_seed"
@@ -43480,6 +43989,7 @@ function emitStrategyDecl(ctx, args) {
43480
43989
  add(["default_qty_type"], "default_qty_type");
43481
43990
  add(["default_qty_value"], "default_qty_value");
43482
43991
  add(["initial_capital"], "initial_capital");
43992
+ add(["currency"], "currency");
43483
43993
  return `__h.strategy.configure({${fields.join(", ")}})`;
43484
43994
  }
43485
43995
  function emitStrategyEntry(method, args) {
@@ -43550,8 +44060,48 @@ function emitStrategy(ctx, name, args) {
43550
44060
  case "margin_liquidation_price":
43551
44061
  case "position_avg_price":
43552
44062
  case "initial_capital":
44063
+ case "cash":
44064
+ case "position_entry_name":
44065
+ case "account_currency":
44066
+ case "max_contracts_held_all":
44067
+ case "max_contracts_held_long":
44068
+ case "max_contracts_held_short":
44069
+ case "wintrades":
44070
+ case "losstrades":
44071
+ case "eventrades":
44072
+ case "grossprofit":
44073
+ case "grossloss":
44074
+ case "avg_trade":
44075
+ case "avg_winning_trade":
44076
+ case "avg_losing_trade":
44077
+ case "netprofit_percent":
44078
+ case "openprofit_percent":
44079
+ case "grossprofit_percent":
44080
+ case "grossloss_percent":
44081
+ case "avg_trade_percent":
44082
+ case "avg_winning_trade_percent":
44083
+ case "avg_losing_trade_percent":
44084
+ case "max_drawdown":
44085
+ case "max_drawdown_percent":
44086
+ case "max_runup":
44087
+ case "max_runup_percent":
44088
+ case "percent_profitable":
44089
+ case "winrate":
44090
+ case "profitfactor":
44091
+ case "profit_factor":
44092
+ case "capital_held":
44093
+ case "closedtrades_first_index":
43553
44094
  ctx.usesStrategy = true;
43554
44095
  return `__h.strategy.${method}()`;
44096
+ case "commission":
44097
+ return "0";
44098
+ case "default_entry_qty":
44099
+ ctx.usesStrategy = true;
44100
+ return hasArg(args, 0, ["percent_equity"]) ? `__h.strategy.default_entry_qty(${pick(args, 0, ["percent_equity"], "null")})` : `__h.strategy.default_entry_qty()`;
44101
+ case "convert_to_account":
44102
+ case "convert_to_symbol":
44103
+ ctx.usesStrategy = true;
44104
+ return hasArg(args, 0, ["value"]) ? `__h.strategy.convert_to(${pick(args, 0, ["value"], "null")})` : "1";
43555
44105
  case "risk_allow_entry_in":
43556
44106
  ctx.usesStrategy = true;
43557
44107
  return `__h.strategy.risk_allow_entry_in(${pick(args, 0, ["value"], "null")})`;
@@ -43561,10 +44111,36 @@ function emitStrategy(ctx, name, args) {
43561
44111
  case "risk_max_drawdown":
43562
44112
  ctx.usesStrategy = true;
43563
44113
  return `__h.strategy.risk_max_drawdown(${pick(args, 0, ["value"], "null")}, ${pick(args, 1, ["type"], "null")})`;
43564
- default:
44114
+ default: {
44115
+ if (method.startsWith("direction_")) {
44116
+ const tail = method.slice("direction_".length);
44117
+ if (tail === "long" || tail === "short" || tail === "all")
44118
+ return JSON.stringify(tail);
44119
+ }
44120
+ if (method.startsWith("oca_")) {
44121
+ const tail = method.slice("oca_".length);
44122
+ if (tail === "none" || tail === "cancel" || tail === "reduce")
44123
+ return JSON.stringify(tail);
44124
+ }
44125
+ if (method.startsWith("commission_")) {
44126
+ const tail = method.slice("commission_".length);
44127
+ if (tail === "percent" || tail === "cash_per_order" || tail === "cash_per_contract") {
44128
+ return JSON.stringify(tail);
44129
+ }
44130
+ }
44131
+ if (method.startsWith("closedtrades_") || method.startsWith("opentrades_")) {
44132
+ ctx.usesStrategy = true;
44133
+ if (method === "opentrades_capital_held")
44134
+ return "__h.strategy.capital_held()";
44135
+ if (method === "closedtrades_first_index")
44136
+ return "__h.strategy.closedtrades_first_index()";
44137
+ const idx = hasArg(args, 0, ["trade_num", "trade_index", "index"]) ? pick(args, 0, ["trade_num", "trade_index", "index"], "0") : "0";
44138
+ return `__h.strategy.${method}(${idx})`;
44139
+ }
43565
44140
  if (isStrategyAction(name, method))
43566
44141
  ctx.usesStrategy = true;
43567
44142
  return "null";
44143
+ }
43568
44144
  }
43569
44145
  }
43570
44146
  function seriesNameRef(ctx, id) {
@@ -43624,7 +44200,7 @@ function emitPlot(ctx, fname, args) {
43624
44200
  const series = ohlc ? pick(args, 3, ["close"], "null") : pick(args, 0, ["series", "source", "price"], "null");
43625
44201
  const i = ctx.plots.length;
43626
44202
  ctx.plots.push({ title });
43627
- return `plot_${i}[__bar_idx] = __h.naNum(${series})`;
44203
+ return `plot_${i}[__bar_idx] = __h.plotNum(${series})`;
43628
44204
  }
43629
44205
  function emitColor(name, args) {
43630
44206
  if (name === "color_r")
@@ -44180,6 +44756,79 @@ function emitTa(ctx, method, args) {
44180
44756
  ]);
44181
44757
  return `(() => { const __r = ${call}; return [__r.high, __r.low, __r.dir]; })()`;
44182
44758
  }
44759
+ if (method === "hammer") {
44760
+ return `__h.ta.hammer(${cellOf(pick(args, 0, ["open"], "null"))}, ${cellOf(pick(args, 1, ["high"], "null"))}, ${cellOf(pick(args, 2, ["low"], "null"))}, ${cellOf(pick(args, 3, ["close"], "null"))})`;
44761
+ }
44762
+ if (method === "gap_detector") {
44763
+ return `__h.ta.gapDetector(${cellOf(pick(args, 0, ["high"], "null"))}, ${cellOf(pick(args, 1, ["low"], "null"))}, ${cellOf(pick(args, 2, ["prev_close", "prev"], "null"))})`;
44764
+ }
44765
+ if (method === "macd_signal") {
44766
+ return `__h.ta.macdSignal(${cellOf(pick(args, 0, ["macd_line", "macd"], "null"))}, ${cellOf(pick(args, 1, ["signal_line", "signal"], "null"))})`;
44767
+ }
44768
+ if (method === "acceleration_factor") {
44769
+ return taCall("accelerationFactor", site, [
44770
+ cellOf(pick(args, 0, ["momentum_list", "momentum", "source", "series"], "null")),
44771
+ cellOf(pick(args, 1, ["period", "length"], "null"))
44772
+ ]);
44773
+ }
44774
+ if (method === "stoch_smooth") {
44775
+ return `__h.ta.stochSmooth(${cellOf(pick(args, 0, ["high"], "null"))}, ${cellOf(pick(args, 1, ["low"], "null"))}, ${cellOf(pick(args, 2, ["close"], "null"))}, ${cellOf(pick(args, 3, ["period", "length"], "null"))}, ${cellOf(pick(args, 4, ["smooth_k", "k"], "null"))}, ${cellOf(pick(args, 5, ["smooth_d", "d"], "null"))})`;
44776
+ }
44777
+ if (method === "engulfing") {
44778
+ return `(() => { ${cellOf(pick(args, 0, ["open"], "null"))}; ${cellOf(pick(args, 1, ["high"], "null"))}; ${cellOf(pick(args, 2, ["low"], "null"))}; ${cellOf(pick(args, 3, ["close"], "null"))}; return __h.ta.engulfing(); })()`;
44779
+ }
44780
+ if (method === "inside_bar_pattern") {
44781
+ return `(() => { ${cellOf(pick(args, 0, ["high"], "null"))}; ${cellOf(pick(args, 1, ["low"], "null"))}; return __h.ta.insideBarPattern(); })()`;
44782
+ }
44783
+ if (method === "double_top_bottom") {
44784
+ return `(() => { ${cellOf(pick(args, 0, ["high"], "null"))}; ${cellOf(pick(args, 1, ["low"], "null"))}; return __h.ta.doubleTopBottom(${cellOf(pick(args, 2, ["period", "length"], "null"))}); })()`;
44785
+ }
44786
+ if (method === "voi") {
44787
+ return `__h.ta.voi(${cellOf(pick(args, 0, ["buy_volume", "buy"], "null"))}, ${cellOf(pick(args, 1, ["sell_volume", "sell"], "null"))})`;
44788
+ }
44789
+ if (method === "bid_ask_imbalance") {
44790
+ return `__h.ta.bidAskImbalance(${cellOf(pick(args, 0, ["bid_size", "bid"], "null"))}, ${cellOf(pick(args, 1, ["ask_size", "ask"], "null"))}, ${cellOf(pick(args, 2, ["bid_price"], "null"))}, ${cellOf(pick(args, 3, ["ask_price"], "null"))})`;
44791
+ }
44792
+ if (method === "rsi_oversold_overbought") {
44793
+ return `__h.ta.rsiOversoldOverbought(${cellOf(pick(args, 0, ["rsi_series", "rsi", "source"], "null"))}, ${cellOf(pick(args, 1, ["oversold_level", "oversold"], "null"))}, ${cellOf(pick(args, 2, ["overbought_level", "overbought"], "null"))})`;
44794
+ }
44795
+ if (method === "rsi_divergence") {
44796
+ const period = `((__n) => (__n == null ? 0 : __n))(${cellOf(pick(args, 1, ["period", "length"], "null"))})`;
44797
+ return `__h.ta.rsiDivergence(${cellList(pick(args, 0, ["rsi_series", "series", "source"], "null"))}, ${period})`;
44798
+ }
44799
+ if (method === "cumulative_delta") {
44800
+ return taCall("cumulativeDelta", site, [
44801
+ cellOf(pick(args, 0, ["close", "source"], "null")),
44802
+ cellOf(pick(args, 1, ["volume"], "null")),
44803
+ cellOf(pick(args, 2, ["period", "length"], "null"))
44804
+ ]);
44805
+ }
44806
+ if (method === "volume_momentum") {
44807
+ return taCall("volumeMomentum", site, [
44808
+ cellOf(pick(args, 0, ["volume", "source"], "null")),
44809
+ cellOf(pick(args, 1, ["period", "length"], "null"))
44810
+ ]);
44811
+ }
44812
+ if (method === "volume_profile_high") {
44813
+ return `__h.ta.volumeProfileHigh(${cellList(pick(args, 0, ["close", "price", "source", "series"], "null"))}, ${cellList(pick(args, 1, ["volume"], "null"))})`;
44814
+ }
44815
+ if (method === "volume_profile_low") {
44816
+ return taCall("volumeProfileLow", site, [
44817
+ cellOf(pick(args, 0, ["close", "source"], "null")),
44818
+ cellOf(pick(args, 1, ["volume"], "null")),
44819
+ cellOf(pick(args, 2, ["period", "length"], "null")),
44820
+ cellOf(pick(args, 3, ["levels"], "null"))
44821
+ ]);
44822
+ }
44823
+ if (method === "volume_thrust") {
44824
+ const sens = cellOf(pick(args, 3, ["sensitivity"], "null"));
44825
+ return taCall("volumeThrust", site, [
44826
+ cellOf(pick(args, 0, ["close", "source"], "null")),
44827
+ cellOf(pick(args, 1, ["volume"], "null")),
44828
+ cellOf(pick(args, 2, ["volume_sma", "vol_sma", "sma"], "null")),
44829
+ `((__n) => (__n == null ? 0.3 : __n))(${sens})`
44830
+ ]);
44831
+ }
44183
44832
  return "null";
44184
44833
  }
44185
44834
 
@@ -44557,6 +45206,8 @@ function emitName(state, node) {
44557
45206
  return id;
44558
45207
  if (state.ctx.enumTypes.has(id))
44559
45208
  return JSON.stringify(id);
45209
+ if (id === "timenow")
45210
+ return "__h.timenow(time_arr)";
44560
45211
  return safeIdent2(id);
44561
45212
  }
44562
45213
  function emitConstant2(node) {
@@ -44673,8 +45324,53 @@ var STRATEGY_QUERY_ATTRS = new Set([
44673
45324
  "leverage",
44674
45325
  "margin_liquidation_price",
44675
45326
  "position_avg_price",
44676
- "initial_capital"
45327
+ "initial_capital",
45328
+ "cash",
45329
+ "position_entry_name",
45330
+ "account_currency",
45331
+ "default_entry_qty",
45332
+ "max_contracts_held_all",
45333
+ "max_contracts_held_long",
45334
+ "max_contracts_held_short",
45335
+ "wintrades",
45336
+ "losstrades",
45337
+ "eventrades",
45338
+ "grossprofit",
45339
+ "grossloss",
45340
+ "avg_trade",
45341
+ "avg_winning_trade",
45342
+ "avg_losing_trade",
45343
+ "netprofit_percent",
45344
+ "openprofit_percent",
45345
+ "grossprofit_percent",
45346
+ "grossloss_percent",
45347
+ "avg_trade_percent",
45348
+ "avg_winning_trade_percent",
45349
+ "avg_losing_trade_percent",
45350
+ "max_drawdown",
45351
+ "max_drawdown_percent",
45352
+ "max_runup",
45353
+ "max_runup_percent",
45354
+ "percent_profitable",
45355
+ "winrate",
45356
+ "profitfactor",
45357
+ "profit_factor"
44677
45358
  ]);
45359
+ var STRATEGY_NESTED_CONSTS = {
45360
+ "strategy.direction.long": "long",
45361
+ "strategy.direction.short": "short",
45362
+ "strategy.direction.all": "all",
45363
+ "strategy.oca.none": "none",
45364
+ "strategy.oca.cancel": "cancel",
45365
+ "strategy.oca.reduce": "reduce",
45366
+ "strategy.commission.percent": "percent",
45367
+ "strategy.commission.cash_per_order": "cash_per_order",
45368
+ "strategy.commission.cash_per_contract": "cash_per_contract"
45369
+ };
45370
+ var STRATEGY_NESTED_CALLS = {
45371
+ "strategy.closedtrades.first_index": "closedtrades_first_index",
45372
+ "strategy.opentrades.capital_held": "capital_held"
45373
+ };
44678
45374
  var ATTR_NAMESPACES = new Set([
44679
45375
  "ta",
44680
45376
  "math",
@@ -44778,6 +45474,9 @@ var ATTR_CONSTANTS = {
44778
45474
  "hline.style_solid": "solid",
44779
45475
  "hline.style_dashed": "dashed",
44780
45476
  "hline.style_dotted": "dotted",
45477
+ "plot.linestyle_solid": "linestyle_solid",
45478
+ "plot.linestyle_dashed": "linestyle_dashed",
45479
+ "plot.linestyle_dotted": "linestyle_dotted",
44781
45480
  "dayofweek.sunday": 1,
44782
45481
  "dayofweek.monday": 2,
44783
45482
  "dayofweek.tuesday": 3,
@@ -44813,6 +45512,7 @@ var ATTR_CONST_NS = new Set([
44813
45512
  "display",
44814
45513
  "position",
44815
45514
  "hline",
45515
+ "plot",
44816
45516
  "dayofweek",
44817
45517
  "month"
44818
45518
  ]);
@@ -44959,16 +45659,24 @@ function emitAttribute(state, node) {
44959
45659
  return `"futures"`;
44960
45660
  if (attr === "avg_price_inverse")
44961
45661
  return `"inverse"`;
44962
- if (attr === "cash")
44963
- return `"cash"`;
44964
45662
  if (attr === "fixed")
44965
45663
  return `"fixed"`;
44966
45664
  if (attr === "percent_of_equity")
44967
45665
  return `"percent_of_equity"`;
45666
+ if (attr === "commission")
45667
+ return "0";
44968
45668
  if (STRATEGY_QUERY_ATTRS.has(attr)) {
44969
45669
  state.ctx.usesStrategy = true;
44970
45670
  return `__h.strategy.${attr}()`;
44971
45671
  }
45672
+ return "null";
45673
+ }
45674
+ if (node.attr === "all" && node.value.kind === "Name") {
45675
+ const kind = node.value.id;
45676
+ if (kind === "line" || kind === "label" || kind === "box" || kind === "table" || kind === "polyline" || kind === "linefill") {
45677
+ state.ctx.usesDrawings = true;
45678
+ return `__h.draw.all(${JSON.stringify(kind)})`;
45679
+ }
44972
45680
  }
44973
45681
  if (node.value.kind === "Name") {
44974
45682
  const members = state.ctx.enumTypes.get(node.value.id);
@@ -44978,6 +45686,16 @@ function emitAttribute(state, node) {
44978
45686
  }
44979
45687
  const qn = attrQualifiedName(node);
44980
45688
  if (qn != null) {
45689
+ const nested = STRATEGY_NESTED_CONSTS[qn];
45690
+ if (nested !== undefined)
45691
+ return JSON.stringify(nested);
45692
+ const nestedCall = STRATEGY_NESTED_CALLS[qn];
45693
+ if (nestedCall != null) {
45694
+ state.ctx.usesStrategy = true;
45695
+ return `__h.strategy.${nestedCall}()`;
45696
+ }
45697
+ if (qn.startsWith("strategy.") && qn.split(".").length > 2)
45698
+ return "null";
44981
45699
  const dot = qn.indexOf(".");
44982
45700
  const root = dot < 0 ? qn : qn.slice(0, dot);
44983
45701
  if (ATTR_CONST_NS.has(root)) {
@@ -45737,6 +46455,9 @@ var compileArray = {
45737
46455
  new(size, initial) {
45738
46456
  return new PineArray(n2(size, 0), store(initial));
45739
46457
  },
46458
+ from(values) {
46459
+ return wrapCells(Array.isArray(values) ? values : []) ?? new PineArray;
46460
+ },
45740
46461
  get(id, index) {
45741
46462
  return asArray(id)?.get(n2(index, 0)) ?? null;
45742
46463
  },
@@ -46177,26 +46898,114 @@ function n3(v, fallback = 0) {
46177
46898
  function idOf(v) {
46178
46899
  return n3(v, -1);
46179
46900
  }
46901
+ function idNum(v) {
46902
+ if (typeof v === "boolean")
46903
+ return v ? 1 : 0;
46904
+ if (typeof v === "number" && Number.isFinite(v))
46905
+ return Math.trunc(v);
46906
+ return null;
46907
+ }
46908
+ function putNum(extra, key, v) {
46909
+ const x = naNum(v);
46910
+ if (x != null)
46911
+ extra[key] = x;
46912
+ }
46913
+ function pointsOf(v) {
46914
+ if (v instanceof PineArray)
46915
+ return v.toValues().filter((p) => p != null);
46916
+ if (Array.isArray(v))
46917
+ return v.filter((p) => p != null);
46918
+ return [];
46919
+ }
46920
+ function isPoint(v) {
46921
+ return typeof v === "object" && v !== null && v.__chartPoint === true;
46922
+ }
46923
+ function makePoint(index, time, price) {
46924
+ return { __chartPoint: true, index, time, x: index ?? time, y: price, price };
46925
+ }
46926
+ function pointXY(v) {
46927
+ if (!isPoint(v))
46928
+ return null;
46929
+ return { x: v.index ?? v.time ?? v.x ?? 0, y: v.price ?? v.y ?? 0 };
46930
+ }
46931
+ function truthy(v) {
46932
+ if (typeof v === "boolean")
46933
+ return v;
46934
+ if (typeof v === "number")
46935
+ return Number.isFinite(v) && v !== 0;
46936
+ return false;
46937
+ }
46938
+ function alertText(v, fallback) {
46939
+ if (v == null)
46940
+ return fallback;
46941
+ if (typeof v === "string")
46942
+ return v;
46943
+ if (typeof v === "boolean")
46944
+ return v ? "1" : "0";
46945
+ if (typeof v === "number")
46946
+ return Number.isFinite(v) ? String(v) : fallback;
46947
+ return fallback;
46948
+ }
46949
+ var DRAW_KINDS2 = new Set(["line", "label", "box", "table", "polyline", "linefill"]);
46180
46950
 
46181
46951
  class CompileDraw {
46182
46952
  book = new DrawingBook;
46183
- label_new(bar, text) {
46184
- return this.book.labelNew(n3(bar, 0), text == null ? undefined : String(text));
46953
+ alertKeys = new Map;
46954
+ label_new(bar, text, x, y) {
46955
+ const extra = {};
46956
+ putNum(extra, "x", x);
46957
+ putNum(extra, "y", y);
46958
+ const t = text == null ? "" : String(text);
46959
+ return this.book.labelNew(n3(bar, 0), t, Object.keys(extra).length ? extra : undefined);
46185
46960
  }
46186
- line_new(bar) {
46187
- return this.book.lineNew(n3(bar, 0));
46961
+ line_new(bar, x1, y1, x2, y2) {
46962
+ const extra = {};
46963
+ putNum(extra, "x1", x1);
46964
+ putNum(extra, "y1", y1);
46965
+ putNum(extra, "x2", x2);
46966
+ putNum(extra, "y2", y2);
46967
+ return this.book.lineNew(n3(bar, 0), Object.keys(extra).length ? extra : undefined);
46188
46968
  }
46189
- box_new(bar) {
46190
- return this.book.boxNew(n3(bar, 0));
46969
+ box_new(bar, left, top, right, bottom) {
46970
+ const extra = {};
46971
+ putNum(extra, "left", left);
46972
+ putNum(extra, "top", top);
46973
+ putNum(extra, "right", right);
46974
+ putNum(extra, "bottom", bottom);
46975
+ return this.book.boxNew(n3(bar, 0), Object.keys(extra).length ? extra : undefined);
46191
46976
  }
46192
46977
  table_new(bar) {
46193
46978
  return this.book.tableNew(n3(bar, 0));
46194
46979
  }
46195
- polyline_new(bar) {
46196
- return this.book.polylineNew(n3(bar, 0));
46980
+ polyline_new(bar, points) {
46981
+ const pts = pointsOf(points);
46982
+ return this.book.polylineNew(n3(bar, 0), pts.length ? { points: pts } : undefined);
46197
46983
  }
46198
- linefill_new(bar, extra) {
46199
- return this.book.linefillNew(n3(bar, 0), extra);
46984
+ linefill_new(bar, id1, id2, color) {
46985
+ const extra = {};
46986
+ const a = idNum(id1);
46987
+ const b = idNum(id2);
46988
+ if (a != null)
46989
+ extra.id1 = a;
46990
+ if (b != null)
46991
+ extra.id2 = b;
46992
+ if (color != null)
46993
+ extra.color = color;
46994
+ return this.book.linefillNew(n3(bar, 0), Object.keys(extra).length ? extra : undefined);
46995
+ }
46996
+ all(kind) {
46997
+ const arr = new PineArray;
46998
+ if (typeof kind === "string" && DRAW_KINDS2.has(kind)) {
46999
+ for (const id of this.book.allIds(kind))
47000
+ arr.push(id);
47001
+ }
47002
+ return arr;
47003
+ }
47004
+ copy(id) {
47005
+ const i = idNum(id);
47006
+ if (i == null)
47007
+ return null;
47008
+ return this.book.copy(i);
46200
47009
  }
46201
47010
  label_set_text(id, text) {
46202
47011
  this.book.labelSetText(idOf(id), text == null ? "" : String(text));
@@ -46250,13 +47059,38 @@ class CompileDraw {
46250
47059
  this.book.labelSetTooltip(idOf(id), tooltip);
46251
47060
  }
46252
47061
  label_get_x(id) {
46253
- return this.book.labelGetX(idOf(id));
47062
+ const i = idNum(id);
47063
+ if (i == null)
47064
+ return 0;
47065
+ return this.book.labelGetX(i) ?? 0;
46254
47066
  }
46255
47067
  label_get_y(id) {
46256
- return this.book.labelGetY(idOf(id));
47068
+ const i = idNum(id);
47069
+ if (i == null)
47070
+ return 0;
47071
+ return this.book.labelGetY(i) ?? 0;
46257
47072
  }
46258
47073
  label_get_text(id) {
46259
- return this.book.labelGetText(idOf(id));
47074
+ const i = idNum(id);
47075
+ if (i == null)
47076
+ return "";
47077
+ return this.book.labelGetText(i) ?? "";
47078
+ }
47079
+ line_get_x1(id) {
47080
+ const i = idNum(id);
47081
+ return i == null ? null : this.book.lineGetX1(i);
47082
+ }
47083
+ line_get_y1(id) {
47084
+ const i = idNum(id);
47085
+ return i == null ? null : this.book.lineGetY1(i);
47086
+ }
47087
+ line_get_x2(id) {
47088
+ const i = idNum(id);
47089
+ return i == null ? null : this.book.lineGetX2(i);
47090
+ }
47091
+ line_get_y2(id) {
47092
+ const i = idNum(id);
47093
+ return i == null ? null : this.book.lineGetY2(i);
46260
47094
  }
46261
47095
  box_delete(id) {
46262
47096
  this.book.boxDelete(idOf(id));
@@ -46282,8 +47116,18 @@ class CompileDraw {
46282
47116
  table_cell(id, column, row, text) {
46283
47117
  this.book.tableCell(idOf(id), column, row, text);
46284
47118
  }
46285
- table_cell_set_text(id, column, row, text) {
46286
- this.book.tableCellSetText(idOf(id), column, row, text);
47119
+ table_cell_set_text(id, row, column, text) {
47120
+ const i = idNum(id);
47121
+ if (i == null)
47122
+ return null;
47123
+ this.book.tableCellSetText(i, column, row, text == null ? "" : String(text));
47124
+ return null;
47125
+ }
47126
+ table_cell_get_text(id, row, column) {
47127
+ const i = idNum(id);
47128
+ if (i == null)
47129
+ return "";
47130
+ return this.book.tableCellGetText(i, column, row) ?? "";
46287
47131
  }
46288
47132
  table_set_position(id, position) {
46289
47133
  this.book.tableSetPosition(idOf(id), position);
@@ -46294,6 +47138,361 @@ class CompileDraw {
46294
47138
  alert(bar, message) {
46295
47139
  this.book.alert(n3(bar, 0), message == null ? "" : String(message));
46296
47140
  }
47141
+ alertcondition(bar, condition, title, message) {
47142
+ if (!truthy(condition))
47143
+ return null;
47144
+ const t = alertText(title, "Alert");
47145
+ const m = alertText(message, "Alert");
47146
+ const b = n3(bar, 0);
47147
+ const key = `alertcondition|${t}|${m}|once_per_bar`;
47148
+ if (this.alertKeys.get(key) === b)
47149
+ return null;
47150
+ this.alertKeys.set(key, b);
47151
+ this.book.alert(b, m);
47152
+ const ev = this.book.items[this.book.items.length - 1];
47153
+ if (ev != null)
47154
+ ev.extra = { source: "alertcondition", title: t, freq: "once_per_bar" };
47155
+ return null;
47156
+ }
47157
+ line_set_x1(id, x) {
47158
+ return this.kindNum("lineSetX1", id, x);
47159
+ }
47160
+ line_set_y1(id, y) {
47161
+ return this.kindNum("lineSetY1", id, y);
47162
+ }
47163
+ line_set_x2(id, x) {
47164
+ return this.kindNum("lineSetX2", id, x);
47165
+ }
47166
+ line_set_y2(id, y) {
47167
+ return this.kindNum("lineSetY2", id, y);
47168
+ }
47169
+ line_set_xloc(id, xloc) {
47170
+ return this.kindAny("lineSetXloc", id, xloc);
47171
+ }
47172
+ line_set_first_point(id, point) {
47173
+ const i = idNum(id);
47174
+ const xy = pointXY(point);
47175
+ if (i != null && xy)
47176
+ this.book.lineSetXy1(i, xy.x, xy.y);
47177
+ return null;
47178
+ }
47179
+ line_set_second_point(id, point) {
47180
+ const i = idNum(id);
47181
+ const xy = pointXY(point);
47182
+ if (i != null && xy)
47183
+ this.book.lineSetXy2(i, xy.x, xy.y);
47184
+ return null;
47185
+ }
47186
+ label_set_x(id, x) {
47187
+ return this.kindAny("labelSetX", id, x);
47188
+ }
47189
+ label_set_y(id, y) {
47190
+ return this.kindAny("labelSetY", id, y);
47191
+ }
47192
+ label_set_textcolor(id, color) {
47193
+ return this.kindAny("labelSetTextcolor", id, color);
47194
+ }
47195
+ label_set_text_font_family(id, font) {
47196
+ return this.kindAny("labelSetTextFontFamily", id, font);
47197
+ }
47198
+ label_set_text_halign(id, halign) {
47199
+ return this.kindAny("labelSetTextHalign", id, halign);
47200
+ }
47201
+ label_set_text_valign(id, valign) {
47202
+ return this.kindAny("labelSetTextValign", id, valign);
47203
+ }
47204
+ label_set_text_size(id, size) {
47205
+ return this.kindAny("labelSetTextSize", id, size);
47206
+ }
47207
+ label_set_text_formatting(id, formatting) {
47208
+ return this.kindAny("labelSetTextFormatting", id, formatting);
47209
+ }
47210
+ label_set_border_color(id, color) {
47211
+ return this.kindAny("labelSetBorderColor", id, color);
47212
+ }
47213
+ label_set_border_width(id, width) {
47214
+ return this.kindAny("labelSetBorderWidth", id, width);
47215
+ }
47216
+ label_set_border_style(id, style) {
47217
+ return this.kindAny("labelSetBorderStyle", id, style);
47218
+ }
47219
+ label_set_xloc(id, xloc) {
47220
+ return this.kindAny("labelSetXloc", id, xloc);
47221
+ }
47222
+ label_set_yloc(id, yloc) {
47223
+ return this.kindAny("labelSetYloc", id, yloc);
47224
+ }
47225
+ label_set_point(id, point) {
47226
+ const i = idNum(id);
47227
+ const xy = pointXY(point);
47228
+ if (i != null && xy)
47229
+ this.book.labelSetXy(i, xy.x, xy.y);
47230
+ return null;
47231
+ }
47232
+ box_get_left(id) {
47233
+ return this.boxGet("boxGetLeft", id);
47234
+ }
47235
+ box_get_right(id) {
47236
+ return this.boxGet("boxGetRight", id);
47237
+ }
47238
+ box_get_top(id) {
47239
+ return this.boxGet("boxGetTop", id);
47240
+ }
47241
+ box_get_bottom(id) {
47242
+ return this.boxGet("boxGetBottom", id);
47243
+ }
47244
+ box_set_left(id, left) {
47245
+ return this.kindAny("boxSetLeft", id, left);
47246
+ }
47247
+ box_set_right(id, right) {
47248
+ return this.kindAny("boxSetRight", id, right);
47249
+ }
47250
+ box_set_top(id, top) {
47251
+ return this.kindAny("boxSetTop", id, top);
47252
+ }
47253
+ box_set_bottom(id, bottom) {
47254
+ return this.kindAny("boxSetBottom", id, bottom);
47255
+ }
47256
+ box_set_border_width(id, width) {
47257
+ return this.kindAny("boxSetBorderWidth", id, width);
47258
+ }
47259
+ box_set_border_style(id, style) {
47260
+ return this.kindAny("boxSetBorderStyle", id, style);
47261
+ }
47262
+ box_set_closed(id, closed) {
47263
+ return this.kindAny("boxSetClosed", id, closed);
47264
+ }
47265
+ box_set_rightbottom(id, right, bottom) {
47266
+ const i = idNum(id);
47267
+ if (i != null)
47268
+ this.book.boxSetRightBottom(i, right, bottom);
47269
+ return null;
47270
+ }
47271
+ box_set_text_color(id, color) {
47272
+ return this.kindAny("boxSetTextColor", id, color);
47273
+ }
47274
+ box_set_text_font_family(id, font) {
47275
+ return this.kindAny("boxSetTextFontFamily", id, font);
47276
+ }
47277
+ box_set_text_halign(id, halign) {
47278
+ return this.kindAny("boxSetTextHalign", id, halign);
47279
+ }
47280
+ box_set_text_valign(id, valign) {
47281
+ return this.kindAny("boxSetTextValign", id, valign);
47282
+ }
47283
+ box_set_text_size(id, size) {
47284
+ return this.kindAny("boxSetTextSize", id, size);
47285
+ }
47286
+ box_set_text_formatting(id, formatting) {
47287
+ return this.kindAny("boxSetTextFormatting", id, formatting);
47288
+ }
47289
+ box_set_text_wrap(id, wrap) {
47290
+ return this.kindAny("boxSetTextWrap", id, wrap);
47291
+ }
47292
+ box_set_xloc(id, left, right, xloc) {
47293
+ const i = idNum(id);
47294
+ if (i == null)
47295
+ return null;
47296
+ this.book.boxSetLeft(i, left);
47297
+ this.book.boxSetRight(i, right);
47298
+ this.book.boxSetXloc(i, xloc);
47299
+ return null;
47300
+ }
47301
+ box_set_top_left_point(id, point) {
47302
+ const i = idNum(id);
47303
+ const xy = pointXY(point);
47304
+ if (i != null && xy)
47305
+ this.book.boxSetLeftTop(i, xy.x, xy.y);
47306
+ return null;
47307
+ }
47308
+ box_set_bottom_right_point(id, point) {
47309
+ const i = idNum(id);
47310
+ const xy = pointXY(point);
47311
+ if (i != null && xy)
47312
+ this.book.boxSetRightBottom(i, xy.x, xy.y);
47313
+ return null;
47314
+ }
47315
+ table_delete(id) {
47316
+ const i = idNum(id);
47317
+ if (i != null)
47318
+ this.book.tableDelete(i);
47319
+ return null;
47320
+ }
47321
+ table_set_bgcolor(id, color) {
47322
+ return this.kindAny("tableSetBgcolor", id, color);
47323
+ }
47324
+ table_set_border_color(id, color) {
47325
+ return this.kindAny("tableSetBorderColor", id, color);
47326
+ }
47327
+ table_set_border_width(id, width) {
47328
+ return this.kindAny("tableSetBorderWidth", id, width);
47329
+ }
47330
+ table_set_frame_color(id, color) {
47331
+ return this.kindAny("tableSetFrameColor", id, color);
47332
+ }
47333
+ table_set_frame_width(id, width) {
47334
+ return this.kindAny("tableSetFrameWidth", id, width);
47335
+ }
47336
+ table_clear(id, startRow, startCol, endRow, endCol) {
47337
+ const i = idNum(id);
47338
+ if (i == null)
47339
+ return null;
47340
+ if (arguments.length < 2)
47341
+ this.book.tableClear(i);
47342
+ else
47343
+ this.book.tableClear(i, startRow, startCol, endRow, endCol);
47344
+ return null;
47345
+ }
47346
+ table_merge_cells(id, startRow, startCol, endRow, endCol) {
47347
+ const i = idNum(id);
47348
+ if (i != null)
47349
+ this.book.tableMergeCells(i, startRow, startCol, endRow, endCol);
47350
+ return null;
47351
+ }
47352
+ table_cell_set_text_color(id, row, column, value) {
47353
+ return this.cellField(id, column, row, "text_color", value);
47354
+ }
47355
+ table_cell_set_bgcolor(id, row, column, value) {
47356
+ return this.cellField(id, column, row, "bgcolor", value);
47357
+ }
47358
+ table_cell_set_border_color(id, row, column, value) {
47359
+ return this.cellField(id, column, row, "border_color", value);
47360
+ }
47361
+ table_cell_set_border_width(id, row, column, value) {
47362
+ return this.cellField(id, column, row, "border_width", value);
47363
+ }
47364
+ table_cell_set_tooltip(id, row, column, value) {
47365
+ return this.cellField(id, column, row, "tooltip", value);
47366
+ }
47367
+ table_cell_set_width(id, column, row, value) {
47368
+ return this.cellField(id, column, row, "width", value);
47369
+ }
47370
+ table_cell_set_height(id, column, row, value) {
47371
+ return this.cellField(id, column, row, "height", value);
47372
+ }
47373
+ table_cell_set_text_halign(id, column, row, value) {
47374
+ return this.cellField(id, column, row, "text_halign", value);
47375
+ }
47376
+ table_cell_set_text_valign(id, column, row, value) {
47377
+ return this.cellField(id, column, row, "text_valign", value);
47378
+ }
47379
+ table_cell_set_text_size(id, column, row, value) {
47380
+ return this.cellField(id, column, row, "text_size", value);
47381
+ }
47382
+ table_cell_set_text_font_family(id, column, row, value) {
47383
+ return this.cellField(id, column, row, "text_font_family", value);
47384
+ }
47385
+ table_cell_set_text_formatting(id, column, row, value) {
47386
+ return this.cellField(id, column, row, "text_formatting", value);
47387
+ }
47388
+ polyline_delete(id) {
47389
+ const i = idNum(id);
47390
+ if (i != null)
47391
+ this.book.polylineDelete(i);
47392
+ return null;
47393
+ }
47394
+ polyline_get_points(id) {
47395
+ const arr = new PineArray;
47396
+ const i = idNum(id);
47397
+ if (i == null)
47398
+ return arr;
47399
+ for (const p of this.book.polylineGetPoints(i))
47400
+ arr.push(p);
47401
+ return arr;
47402
+ }
47403
+ polyline_set_points(id, points) {
47404
+ const i = idNum(id);
47405
+ if (i != null)
47406
+ this.book.polylineSetPoints(i, pointsOf(points));
47407
+ return null;
47408
+ }
47409
+ polyline_set_line_color(id, color) {
47410
+ return this.kindAny("polylineSetLineColor", id, color);
47411
+ }
47412
+ polyline_set_line_width(id, width) {
47413
+ return this.kindAny("polylineSetLineWidth", id, width);
47414
+ }
47415
+ polyline_set_line_style(id, style) {
47416
+ return this.kindAny("polylineSetLineStyle", id, style);
47417
+ }
47418
+ polyline_set_fill_color(id, color) {
47419
+ return this.kindAny("polylineSetFillColor", id, color);
47420
+ }
47421
+ polyline_set_curved(id, curved) {
47422
+ return this.kindAny("polylineSetCurved", id, curved);
47423
+ }
47424
+ polyline_set_force_overlay(id, force) {
47425
+ return this.kindAny("polylineSetForceOverlay", id, force);
47426
+ }
47427
+ polyline_set_closed(id, closed) {
47428
+ return this.kindAny("polylineSetClosed", id, closed);
47429
+ }
47430
+ polyline_set_xloc(id, xloc) {
47431
+ return this.kindAny("polylineSetXloc", id, xloc);
47432
+ }
47433
+ linefill_delete(id) {
47434
+ const i = idNum(id);
47435
+ if (i != null)
47436
+ this.book.linefillDelete(i);
47437
+ return null;
47438
+ }
47439
+ linefill_get_line1(id) {
47440
+ const i = idNum(id);
47441
+ return i == null ? null : this.book.linefillGetLine1(i);
47442
+ }
47443
+ linefill_get_line2(id) {
47444
+ const i = idNum(id);
47445
+ return i == null ? null : this.book.linefillGetLine2(i);
47446
+ }
47447
+ point_new(time, price) {
47448
+ const p = naNum(price);
47449
+ if (p == null)
47450
+ return null;
47451
+ return makePoint(null, naNum(time), p);
47452
+ }
47453
+ point_from_index(index, price) {
47454
+ const ix = naNum(index);
47455
+ const p = naNum(price);
47456
+ if (ix == null || p == null)
47457
+ return null;
47458
+ return makePoint(Math.trunc(ix), null, p);
47459
+ }
47460
+ point_now(bar, time, price) {
47461
+ const p = naNum(price);
47462
+ if (p == null)
47463
+ return null;
47464
+ const ix = naNum(bar);
47465
+ return makePoint(ix == null ? null : Math.trunc(ix), naNum(time), p);
47466
+ }
47467
+ point_copy(raw) {
47468
+ if (isPoint(raw))
47469
+ return makePoint(raw.index, raw.time, raw.price);
47470
+ return makePoint(null, null, 0);
47471
+ }
47472
+ kindNum(method, id, value) {
47473
+ const i = idNum(id);
47474
+ if (i != null)
47475
+ this.book[method](i, value);
47476
+ return null;
47477
+ }
47478
+ kindAny(method, id, value) {
47479
+ const i = idNum(id);
47480
+ if (i != null)
47481
+ this.book[method](i, value);
47482
+ return null;
47483
+ }
47484
+ boxGet(method, id) {
47485
+ const i = idNum(id);
47486
+ if (i == null)
47487
+ return 0;
47488
+ return this.book[method](i) ?? 0;
47489
+ }
47490
+ cellField(id, column, row, field, value) {
47491
+ const i = idNum(id);
47492
+ if (i != null)
47493
+ this.book.tableCellSetField(i, column, row, field, value);
47494
+ return null;
47495
+ }
46297
47496
  extras() {
46298
47497
  return { __drawings: this.book.items.slice() };
46299
47498
  }
@@ -46388,11 +47587,14 @@ class CompileStrategy {
46388
47587
  const ms = optNum(rec.margin_short);
46389
47588
  if (ms != null)
46390
47589
  broker.margin_short = ms;
46391
- if (typeof rec.default_qty_type === "string")
47590
+ if (typeof rec.default_qty_type === "string" || isStrategyCashAmount(rec.default_qty_type)) {
46392
47591
  broker.default_qty_type = rec.default_qty_type;
47592
+ }
46393
47593
  const dqv = optNum(rec.default_qty_value);
46394
47594
  if (dqv != null)
46395
47595
  broker.default_qty_value = dqv;
47596
+ if (typeof rec.currency === "string" && rec.currency !== "")
47597
+ broker.currency = rec.currency;
46396
47598
  if (Object.keys(broker).length)
46397
47599
  this.book.configure(broker);
46398
47600
  const capital = optNum(rec.initial_capital);
@@ -46487,6 +47689,192 @@ class CompileStrategy {
46487
47689
  initial_capital() {
46488
47690
  return this.book.initialCapital;
46489
47691
  }
47692
+ cash() {
47693
+ return strategyCashAmount(this.book.cash(this.mark));
47694
+ }
47695
+ position_entry_name() {
47696
+ return this.book.position_entry_name;
47697
+ }
47698
+ account_currency() {
47699
+ return this.book.account_currency;
47700
+ }
47701
+ default_entry_qty(percent) {
47702
+ const pct = arguments.length === 0 || percent === undefined ? 100 : naNum(percent);
47703
+ if (pct == null)
47704
+ return null;
47705
+ return this.book.initialCapital * (pct / 100) / 100;
47706
+ }
47707
+ convert_to(value) {
47708
+ if (arguments.length === 0 || value === undefined)
47709
+ return 1;
47710
+ return naNum(value);
47711
+ }
47712
+ max_contracts_held_all() {
47713
+ return this.book.maxContractsHeldAll();
47714
+ }
47715
+ max_contracts_held_long() {
47716
+ return this.book.maxContractsHeldLong();
47717
+ }
47718
+ max_contracts_held_short() {
47719
+ return this.book.maxContractsHeldShort();
47720
+ }
47721
+ capital_held() {
47722
+ return this.book.capitalHeld();
47723
+ }
47724
+ closedtrades_first_index() {
47725
+ return this.book.closedtrades_first_index;
47726
+ }
47727
+ wintrades() {
47728
+ return this.book.wintrades;
47729
+ }
47730
+ losstrades() {
47731
+ return this.book.losstrades;
47732
+ }
47733
+ eventrades() {
47734
+ return this.book.eventrades;
47735
+ }
47736
+ grossprofit() {
47737
+ return this.book.grossprofit;
47738
+ }
47739
+ grossloss() {
47740
+ return this.book.grossloss;
47741
+ }
47742
+ avg_trade() {
47743
+ return this.book.avgTrade();
47744
+ }
47745
+ avg_winning_trade() {
47746
+ return this.book.avgWinningTrade();
47747
+ }
47748
+ avg_losing_trade() {
47749
+ return this.book.avgLosingTrade();
47750
+ }
47751
+ netprofit_percent() {
47752
+ return this.book.netprofitPercent(this.mark);
47753
+ }
47754
+ openprofit_percent() {
47755
+ return this.book.openprofitPercent(this.mark);
47756
+ }
47757
+ grossprofit_percent() {
47758
+ return this.book.grossprofitPercent();
47759
+ }
47760
+ grossloss_percent() {
47761
+ return this.book.grosslossPercent();
47762
+ }
47763
+ avg_trade_percent() {
47764
+ return this.book.avgTradePercent();
47765
+ }
47766
+ avg_winning_trade_percent() {
47767
+ return this.book.avgWinningTradePercent();
47768
+ }
47769
+ avg_losing_trade_percent() {
47770
+ return this.book.avgLosingTradePercent();
47771
+ }
47772
+ max_drawdown() {
47773
+ return this.book.maxDrawdown();
47774
+ }
47775
+ max_drawdown_percent() {
47776
+ return this.book.maxDrawdownPercent();
47777
+ }
47778
+ max_runup() {
47779
+ return this.book.maxRunup();
47780
+ }
47781
+ max_runup_percent() {
47782
+ return this.book.maxRunupPercent();
47783
+ }
47784
+ percent_profitable() {
47785
+ return this.book.percentProfitable();
47786
+ }
47787
+ winrate() {
47788
+ return this.book.percentProfitable();
47789
+ }
47790
+ profitfactor() {
47791
+ return this.book.profitFactor();
47792
+ }
47793
+ profit_factor() {
47794
+ return this.book.profitFactor();
47795
+ }
47796
+ closedtrades_entry_bar_index(i) {
47797
+ return this.book.closedEntryBar(this.idx(i)) ?? 0;
47798
+ }
47799
+ closedtrades_entry_price(i) {
47800
+ return this.book.closedEntryPrice(this.idx(i)) ?? 0;
47801
+ }
47802
+ closedtrades_exit_bar_index(i) {
47803
+ return this.book.closedExitBar(this.idx(i)) ?? 0;
47804
+ }
47805
+ closedtrades_exit_price(i) {
47806
+ return this.book.closedExitPrice(this.idx(i)) ?? 0;
47807
+ }
47808
+ closedtrades_profit(i) {
47809
+ return this.book.closedProfit(this.idx(i)) ?? 0;
47810
+ }
47811
+ closedtrades_size(i) {
47812
+ return this.book.closedSize(this.idx(i)) ?? 0;
47813
+ }
47814
+ closedtrades_entry_id(i) {
47815
+ return this.book.closedId(this.idx(i)) ?? "";
47816
+ }
47817
+ closedtrades_exit_id(i) {
47818
+ return this.book.closedId(this.idx(i)) ?? "";
47819
+ }
47820
+ closedtrades_commission(i) {
47821
+ return this.book.closedCommission(this.idx(i)) ?? 0;
47822
+ }
47823
+ closedtrades_entry_time(i) {
47824
+ return this.book.closedEntryTime(this.idx(i));
47825
+ }
47826
+ closedtrades_exit_time(i) {
47827
+ return this.book.closedExitTime(this.idx(i));
47828
+ }
47829
+ closedtrades_entry_comment(i) {
47830
+ return this.book.closedEntryComment(this.idx(i));
47831
+ }
47832
+ closedtrades_exit_comment(i) {
47833
+ return this.book.closedExitComment(this.idx(i));
47834
+ }
47835
+ closedtrades_max_drawdown(i) {
47836
+ return this.book.closedMaxDrawdown(this.idx(i));
47837
+ }
47838
+ closedtrades_max_runup(i) {
47839
+ return this.book.closedMaxRunup(this.idx(i));
47840
+ }
47841
+ opentrades_entry_bar_index(i) {
47842
+ return this.book.openEntryBar(this.idx(i)) ?? 0;
47843
+ }
47844
+ opentrades_entry_price(i) {
47845
+ return this.book.openEntryPrice(this.idx(i)) ?? 0;
47846
+ }
47847
+ opentrades_size(i) {
47848
+ return this.book.openSize(this.idx(i)) ?? 0;
47849
+ }
47850
+ opentrades_entry_id(i) {
47851
+ return this.book.openId(this.idx(i)) ?? "";
47852
+ }
47853
+ opentrades_profit(i) {
47854
+ return this.book.openProfit(this.idx(i), this.mark) ?? 0;
47855
+ }
47856
+ opentrades_entry_time(i) {
47857
+ return this.book.openEntryTime(this.idx(i));
47858
+ }
47859
+ opentrades_entry_comment(i) {
47860
+ return this.book.openEntryComment(this.idx(i));
47861
+ }
47862
+ opentrades_commission(i) {
47863
+ return this.book.openCommission(this.idx(i));
47864
+ }
47865
+ opentrades_max_drawdown(i) {
47866
+ return this.book.openMaxDrawdown(this.idx(i));
47867
+ }
47868
+ opentrades_max_runup(i) {
47869
+ return this.book.openMaxRunup(this.idx(i));
47870
+ }
47871
+ idx(i) {
47872
+ if (typeof i === "boolean")
47873
+ return i ? 1 : 0;
47874
+ if (typeof i === "number" && Number.isFinite(i))
47875
+ return Math.trunc(i);
47876
+ return 0;
47877
+ }
46490
47878
  risk_allow_entry_in(value) {
46491
47879
  this.book.riskAllowEntryIn(value);
46492
47880
  }
@@ -46556,6 +47944,8 @@ function createCompileHelpers(opts) {
46556
47944
  na: NA_FN,
46557
47945
  nz,
46558
47946
  naNum,
47947
+ plotNum,
47948
+ timenow,
46559
47949
  isNa: isNaCell,
46560
47950
  eq: pineEq,
46561
47951
  ne: pineNe,
@@ -46705,6 +48095,19 @@ function iff(cond, thenV, elseV) {
46705
48095
  return cond ? thenV : elseV;
46706
48096
  return mathIff(cond, thenV, elseV);
46707
48097
  }
48098
+ function plotNum(v) {
48099
+ if (isStrategyCashAmount(v))
48100
+ return Number.isFinite(v.value) ? v.value : null;
48101
+ return naNum(v);
48102
+ }
48103
+ function timenow(timeArr) {
48104
+ if (!Array.isArray(timeArr) || timeArr.length === 0)
48105
+ return 0;
48106
+ const last = timeArr[timeArr.length - 1];
48107
+ if (typeof last === "number" && Number.isFinite(last))
48108
+ return last;
48109
+ return (timeArr.length - 1) * 60000;
48110
+ }
46708
48111
  function NA_FN(v) {
46709
48112
  if (arguments.length === 0)
46710
48113
  return null;
@@ -50030,6 +51433,97 @@ function evalExtraTa(fname, node, env, site) {
50030
51433
  const z = env.ta.zigzag(site, srcArg(node, env), th);
50031
51434
  return tupleOf([z.high, z.low, z.dir]);
50032
51435
  }
51436
+ const wave10aArg = (index, names, message) => {
51437
+ const arg = callArg(node.args, index, names);
51438
+ if (arg == null)
51439
+ runtimeError(message);
51440
+ return arg;
51441
+ };
51442
+ if (fname === "ta.hammer" || fname === "hammer") {
51443
+ const msg = "ta.hammer() requires 4 arguments: open, high, low, close";
51444
+ return env.ta.hammer(unwrap2(evalExpr(wave10aArg(0, ["open"], msg), env)), unwrap2(evalExpr(wave10aArg(1, ["high"], msg), env)), unwrap2(evalExpr(wave10aArg(2, ["low"], msg), env)), unwrap2(evalExpr(wave10aArg(3, ["close"], msg), env)));
51445
+ }
51446
+ if (fname === "ta.engulfing" || fname === "engulfing") {
51447
+ const msg = "ta.engulfing() requires 4 arguments: open, high, low, close";
51448
+ unwrap2(evalExpr(wave10aArg(0, ["open"], msg), env));
51449
+ unwrap2(evalExpr(wave10aArg(1, ["high"], msg), env));
51450
+ unwrap2(evalExpr(wave10aArg(2, ["low"], msg), env));
51451
+ unwrap2(evalExpr(wave10aArg(3, ["close"], msg), env));
51452
+ return env.ta.engulfing();
51453
+ }
51454
+ if (fname === "ta.gap_detector" || fname === "gap_detector") {
51455
+ const msg = "ta.gap_detector() requires 3 arguments: high, low, prev_close";
51456
+ return env.ta.gapDetector(unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env)), unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env)), unwrap2(evalExpr(wave10aArg(2, ["prev_close", "prev"], msg), env)));
51457
+ }
51458
+ if (fname === "ta.double_top_bottom" || fname === "double_top_bottom") {
51459
+ const msg = "ta.double_top_bottom() requires 3 arguments";
51460
+ unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
51461
+ unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
51462
+ return env.ta.doubleTopBottom(unwrap2(evalExpr(wave10aArg(2, ["period", "length"], msg), env)));
51463
+ }
51464
+ if (fname === "ta.inside_bar_pattern" || fname === "inside_bar_pattern") {
51465
+ const msg = "ta.inside_bar_pattern() requires 2 arguments";
51466
+ unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env));
51467
+ unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env));
51468
+ return env.ta.insideBarPattern();
51469
+ }
51470
+ if (fname === "ta.macd_signal" || fname === "macd_signal") {
51471
+ const msg = "ta.macd_signal() requires 2 arguments: macd_line, signal_line";
51472
+ return env.ta.macdSignal(unwrap2(evalExpr(wave10aArg(0, ["macd_line", "macd"], msg), env)), unwrap2(evalExpr(wave10aArg(1, ["signal_line", "signal"], msg), env)));
51473
+ }
51474
+ if (fname === "ta.acceleration_factor" || fname === "acceleration_factor") {
51475
+ const msg = "ta.acceleration_factor() requires 2 arguments";
51476
+ return env.ta.accelerationFactor(site, unwrap2(evalExpr(wave10aArg(0, ["momentum_list", "momentum", "source", "series"], msg), env)), unwrap2(evalExpr(wave10aArg(1, ["period", "length"], msg), env)));
51477
+ }
51478
+ if (fname === "ta.stoch_smooth" || fname === "stoch_smooth") {
51479
+ const msg = "ta.stoch_smooth() requires 6 arguments: high, low, close, period, smooth_k, smooth_d";
51480
+ return env.ta.stochSmooth(unwrap2(evalExpr(wave10aArg(0, ["high"], msg), env)), unwrap2(evalExpr(wave10aArg(1, ["low"], msg), env)), unwrap2(evalExpr(wave10aArg(2, ["close"], msg), env)), unwrap2(evalExpr(wave10aArg(3, ["period", "length"], msg), env)), unwrap2(evalExpr(wave10aArg(4, ["smooth_k", "k"], msg), env)), unwrap2(evalExpr(wave10aArg(5, ["smooth_d", "d"], msg), env)));
51481
+ }
51482
+ const wave10bList = (index, names) => {
51483
+ const raw = evalExpr(callArg(node.args, index, names), env);
51484
+ const arr = asArray2(raw);
51485
+ if (arr == null)
51486
+ return [unwrap2(raw)];
51487
+ const out = [];
51488
+ for (let i = 0;i < arr.size(); i++)
51489
+ out.push(arr.get(i));
51490
+ return out;
51491
+ };
51492
+ if (fname === "ta.voi" || fname === "voi") {
51493
+ return env.ta.voi(unwrap2(evalExpr(callArg(node.args, 0, ["buy_volume", "buy"]), env)), unwrap2(evalExpr(callArg(node.args, 1, ["sell_volume", "sell"]), env)));
51494
+ }
51495
+ if (fname === "ta.bid_ask_imbalance" || fname === "bid_ask_imbalance") {
51496
+ return env.ta.bidAskImbalance(unwrap2(evalExpr(callArg(node.args, 0, ["bid_size", "bid"]), env)), unwrap2(evalExpr(callArg(node.args, 1, ["ask_size", "ask"]), env)), unwrap2(evalExpr(callArg(node.args, 2, ["bid_price"]), env)), unwrap2(evalExpr(callArg(node.args, 3, ["ask_price"]), env)));
51497
+ }
51498
+ if (fname === "ta.rsi_oversold_overbought" || fname === "rsi_oversold_overbought") {
51499
+ const os = unwrap2(evalExpr(callArg(node.args, 1, ["oversold_level", "oversold"]), env));
51500
+ const ob = unwrap2(evalExpr(callArg(node.args, 2, ["overbought_level", "overbought"]), env));
51501
+ return env.ta.rsiOversoldOverbought(unwrap2(evalExpr(callArg(node.args, 0, ["rsi_series", "rsi", "source"]), env)), os ?? Number.NaN, ob ?? Number.NaN);
51502
+ }
51503
+ if (fname === "ta.rsi_divergence" || fname === "rsi_divergence") {
51504
+ const period = unwrap2(evalExpr(callArg(node.args, 1, ["period", "length"]), env));
51505
+ return env.ta.rsiDivergence(wave10bList(0, ["rsi_series", "series", "source"]), period ?? 0);
51506
+ }
51507
+ if (fname === "ta.cumulative_delta" || fname === "cumulative_delta") {
51508
+ const period = unwrap2(evalExpr(callArg(node.args, 2, ["period", "length"]), env));
51509
+ return env.ta.cumulativeDelta(site, unwrap2(evalExpr(callArg(node.args, 0, ["close", "source"]), env)), unwrap2(evalExpr(callArg(node.args, 1, ["volume"]), env)), period ?? 0);
51510
+ }
51511
+ if (fname === "ta.volume_momentum" || fname === "volume_momentum") {
51512
+ const period = unwrap2(evalExpr(callArg(node.args, 1, ["period", "length"]), env));
51513
+ return env.ta.volumeMomentum(site, unwrap2(evalExpr(callArg(node.args, 0, ["volume", "source"]), env)), period ?? 0);
51514
+ }
51515
+ if (fname === "ta.volume_profile_high" || fname === "volume_profile_high") {
51516
+ return env.ta.volumeProfileHigh(wave10bList(0, ["close", "price", "source", "series"]), wave10bList(1, ["volume"]));
51517
+ }
51518
+ if (fname === "ta.volume_profile_low" || fname === "volume_profile_low") {
51519
+ const period = unwrap2(evalExpr(callArg(node.args, 2, ["period", "length"]), env));
51520
+ const levels = unwrap2(evalExpr(callArg(node.args, 3, ["levels"]), env));
51521
+ return env.ta.volumeProfileLow(site, unwrap2(evalExpr(callArg(node.args, 0, ["close", "source"]), env)), unwrap2(evalExpr(callArg(node.args, 1, ["volume"]), env)), period ?? 0, levels ?? 0);
51522
+ }
51523
+ if (fname === "ta.volume_thrust" || fname === "volume_thrust") {
51524
+ const sens = unwrap2(evalExpr(callArg(node.args, 3, ["sensitivity"]), env));
51525
+ return env.ta.volumeThrust(site, unwrap2(evalExpr(callArg(node.args, 0, ["close", "source"]), env)), unwrap2(evalExpr(callArg(node.args, 1, ["volume"]), env)), unwrap2(evalExpr(callArg(node.args, 2, ["volume_sma", "vol_sma", "sma"]), env)), sens ?? 0.3);
51526
+ }
50033
51527
  return;
50034
51528
  }
50035
51529
  function hlc3(env) {
@@ -50842,7 +52336,7 @@ function optionalCoord(node, env, index, names, fallback) {
50842
52336
  return fallback;
50843
52337
  return unwrap2(evalExpr(e, env));
50844
52338
  }
50845
- function pointXY(p) {
52339
+ function pointXY2(p) {
50846
52340
  const x = p.index ?? p.time ?? p.x ?? 0;
50847
52341
  const y = p.price ?? p.y ?? 0;
50848
52342
  return { x: x ?? 0, y: y ?? 0 };
@@ -50889,7 +52383,7 @@ function evalDrawingCall(fname, node, env) {
50889
52383
  const extra = {};
50890
52384
  let text;
50891
52385
  if (isChartPoint(v0)) {
50892
- const xy = pointXY(v0);
52386
+ const xy = pointXY2(v0);
50893
52387
  extra.x = xy.x;
50894
52388
  extra.y = xy.y;
50895
52389
  text = drawText(node, env, pointKw != null ? 0 : 1, ["text"]);
@@ -51170,7 +52664,7 @@ function evalDrawingCall(fname, node, env) {
51170
52664
  const id = drawId(node, env);
51171
52665
  const p = evalExpr(callArg(node.args, 1, ["point"]), env);
51172
52666
  if (id != null && isChartPoint(p)) {
51173
- const xy = pointXY(p);
52667
+ const xy = pointXY2(p);
51174
52668
  book.lineSetXy1(id, xy.x, xy.y);
51175
52669
  }
51176
52670
  return NA;
@@ -51179,7 +52673,7 @@ function evalDrawingCall(fname, node, env) {
51179
52673
  const id = drawId(node, env);
51180
52674
  const p = evalExpr(callArg(node.args, 1, ["point"]), env);
51181
52675
  if (id != null && isChartPoint(p)) {
51182
- const xy = pointXY(p);
52676
+ const xy = pointXY2(p);
51183
52677
  book.lineSetXy2(id, xy.x, xy.y);
51184
52678
  }
51185
52679
  return NA;
@@ -51308,7 +52802,7 @@ function evalDrawingCall(fname, node, env) {
51308
52802
  const id = drawId(node, env);
51309
52803
  const p = evalExpr(callArg(node.args, 1, ["point"]), env);
51310
52804
  if (id != null && isChartPoint(p)) {
51311
- const xy = pointXY(p);
52805
+ const xy = pointXY2(p);
51312
52806
  book.labelSetXy(id, xy.x, xy.y);
51313
52807
  }
51314
52808
  return NA;
@@ -51447,7 +52941,7 @@ function evalDrawingCall(fname, node, env) {
51447
52941
  const id = drawId(node, env);
51448
52942
  const p = evalExpr(callArg(node.args, 1, ["point"]), env);
51449
52943
  if (id != null && isChartPoint(p)) {
51450
- const xy = pointXY(p);
52944
+ const xy = pointXY2(p);
51451
52945
  book.boxSetLeftTop(id, xy.x, xy.y);
51452
52946
  }
51453
52947
  return NA;
@@ -51456,7 +52950,7 @@ function evalDrawingCall(fname, node, env) {
51456
52950
  const id = drawId(node, env);
51457
52951
  const p = evalExpr(callArg(node.args, 1, ["point"]), env);
51458
52952
  if (id != null && isChartPoint(p)) {
51459
- const xy = pointXY(p);
52953
+ const xy = pointXY2(p);
51460
52954
  book.boxSetRightBottom(id, xy.x, xy.y);
51461
52955
  }
51462
52956
  return NA;