@hoox-sh/pynets 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -40534,6 +40534,10 @@ class TaEngine {
40534
40534
  marketConditionSites = new Map;
40535
40535
  orderFlowSites = new Map;
40536
40536
  liquiditySites = new Map;
40537
+ emaCrossSites = new Map;
40538
+ historySites = new Map;
40539
+ momentumFilterSites = new Map;
40540
+ volatilityRegimeSites = new Map;
40537
40541
  sma(site, source, period) {
40538
40542
  const n = pinePeriod(period);
40539
40543
  if (n === null)
@@ -42865,6 +42869,39 @@ class TaEngine {
42865
42869
  const v = buf[-i - 1];
42866
42870
  return v === undefined ? null : v;
42867
42871
  }
42872
+ hist(site, value) {
42873
+ let h = this.historySites.get(site);
42874
+ if (h === undefined) {
42875
+ h = [];
42876
+ this.historySites.set(site, h);
42877
+ }
42878
+ h.unshift(finiteCell2(value));
42879
+ if (h.length > 1000)
42880
+ h.pop();
42881
+ return h;
42882
+ }
42883
+ windowFor(site, value) {
42884
+ if (Array.isArray(value)) {
42885
+ return value.map((v) => typeof v === "number" ? finiteCell2(v) : null);
42886
+ }
42887
+ if (value != null && typeof value === "object" && typeof value.size === "function" && typeof value.get === "function") {
42888
+ const arr = value;
42889
+ const out = [];
42890
+ const n = arr.size();
42891
+ for (let i = 0;i < n; i++) {
42892
+ const v = arr.get(i);
42893
+ out.push(typeof v === "number" ? finiteCell2(v) : null);
42894
+ }
42895
+ return out;
42896
+ }
42897
+ return this.hist(site, typeof value === "number" ? value : null);
42898
+ }
42899
+ static oldest(h) {
42900
+ return h.length === 0 ? null : h[h.length - 1];
42901
+ }
42902
+ static secondOldest(h) {
42903
+ return h.length < 2 ? null : h[h.length - 2];
42904
+ }
42868
42905
  voi(buy, sell) {
42869
42906
  const b = buy !== null && Number.isFinite(buy) ? buy : 0;
42870
42907
  const s = sell !== null && Number.isFinite(sell) ? sell : 0;
@@ -43508,9 +43545,42 @@ class TaEngine {
43508
43545
  move_required_percent: finiteOut2(move) ?? 0
43509
43546
  });
43510
43547
  }
43511
- marketStructurePivot(close) {
43512
- const c = finiteCell2(close) ?? 0;
43513
- return taRec({ pivot_price: c, structure: "fractal", type: "high" });
43548
+ marketStructurePivot(site, high, low, period, mode) {
43549
+ const hh = this.windowFor(`${site}:high`, high);
43550
+ const ll = this.windowFor(`${site}:low`, low);
43551
+ const n = this.coerceTaInt(period, "ta.market_structure_pivot() requires 5 arguments");
43552
+ const m = this.coerceTaInt(mode, "ta.market_structure_pivot() requires 5 arguments");
43553
+ const off = taRec({ pivot_price: 100, strength: 50, structure: "neutral" });
43554
+ if (hh.length === 0 || ll.length === 0 || hh.length < n || n <= 0)
43555
+ return off;
43556
+ const hVals = hh.slice(-n).filter((v) => v !== null);
43557
+ const lVals = ll.slice(-n).filter((v) => v !== null);
43558
+ if (hVals.length === 0 || lVals.length === 0)
43559
+ return off;
43560
+ let pivotHigh = hVals[0];
43561
+ let pivotLow = lVals[0];
43562
+ for (const v of hVals)
43563
+ if (v > pivotHigh)
43564
+ pivotHigh = v;
43565
+ for (const v of lVals)
43566
+ if (v < pivotLow)
43567
+ pivotLow = v;
43568
+ const price = (pivotHigh + pivotLow) / 2;
43569
+ const range = pivotHigh - pivotLow;
43570
+ let structure = "block";
43571
+ let strength = Math.min(100, range * 0.5);
43572
+ if (m === 0) {
43573
+ structure = "fractal";
43574
+ strength = Math.min(100, range * 2);
43575
+ } else if (m === 1) {
43576
+ structure = "swing";
43577
+ strength = Math.min(100, range * 1.5);
43578
+ }
43579
+ return taRec({
43580
+ pivot_price: finiteOut2(price) ?? 0,
43581
+ strength: finiteOut2(strength) ?? 0,
43582
+ structure
43583
+ });
43514
43584
  }
43515
43585
  positionSizingScore(risk, volatility, conviction, correlation) {
43516
43586
  const r = finiteCell2(risk) ?? 0;
@@ -43539,8 +43609,9 @@ class TaEngine {
43539
43609
  risk_reward_current: a > 0 ? finiteOut2(Math.abs(c - e) / a) ?? 0 : 0
43540
43610
  });
43541
43611
  }
43542
- optimalEntryZone(close) {
43543
- const c = finiteCell2(close) ?? 0;
43612
+ optimalEntryZone(site, close) {
43613
+ const h = this.windowFor(`${site}:close`, close);
43614
+ const c = TaEngine.oldest(h) ?? 0;
43544
43615
  return taRec({
43545
43616
  min: finiteOut2(c * 0.99) ?? 0,
43546
43617
  max: finiteOut2(c * 1.01) ?? 0,
@@ -43551,10 +43622,13 @@ class TaEngine {
43551
43622
  zone_strength: 85
43552
43623
  });
43553
43624
  }
43554
- meanReversionEntry(price, sma, stdev, threshold) {
43555
- const p = finiteCell2(price) ?? 0;
43556
- const s = finiteCell2(sma) ?? 0;
43557
- const sd = finiteCell2(stdev) ?? 1;
43625
+ meanReversionEntry(site, price, sma, stdev, threshold) {
43626
+ const ph = this.windowFor(`${site}:price`, price);
43627
+ const sh = this.windowFor(`${site}:sma`, sma);
43628
+ const dh = this.windowFor(`${site}:stdev`, stdev);
43629
+ const p = TaEngine.oldest(ph) ?? 0;
43630
+ const s = TaEngine.oldest(sh) ?? 0;
43631
+ const sd = TaEngine.oldest(dh) ?? 1;
43558
43632
  const th = finiteCell2(threshold) ?? 0;
43559
43633
  const z = sd !== 0 ? (p - s) / sd : 0;
43560
43634
  return taRec({
@@ -43652,6 +43726,469 @@ class TaEngine {
43652
43726
  }
43653
43727
  return taRec({ is_breakout: false, breakout_type: "none", breakout_strength: 0 });
43654
43728
  }
43729
+ emaCrossSignal(site, fast, slow, threshold) {
43730
+ const off = taRec({ signal: "neutral", strength: 0, trend_direction: 0 });
43731
+ let st = this.emaCrossSites.get(site);
43732
+ if (st === undefined) {
43733
+ st = { prevFast: null, prevSlow: null, count: 0 };
43734
+ this.emaCrossSites.set(site, st);
43735
+ }
43736
+ const f = finiteCell2(fast) ?? 0;
43737
+ const s = finiteCell2(slow) ?? 0;
43738
+ const th = finiteCell2(threshold) ?? 0;
43739
+ st.count += 1;
43740
+ const prevFast = st.prevFast;
43741
+ const prevSlow = st.prevSlow;
43742
+ if (st.count < 2 || prevFast === null || prevSlow === null) {
43743
+ st.prevFast = f;
43744
+ st.prevSlow = s;
43745
+ return off;
43746
+ }
43747
+ const diff = f - s;
43748
+ const prevDiff = prevFast - prevSlow;
43749
+ const crossover = prevDiff <= 0 && diff > 0;
43750
+ const crossunder = prevDiff >= 0 && diff < 0;
43751
+ const strength = Math.abs(diff);
43752
+ const trend = diff > 0 ? 1 : -1;
43753
+ let signal = "neutral";
43754
+ if (crossover && strength > th)
43755
+ signal = "buy";
43756
+ else if (crossunder && strength > th)
43757
+ signal = "sell";
43758
+ st.prevFast = f;
43759
+ st.prevSlow = s;
43760
+ return taRec({ signal, strength: finiteOut2(strength) ?? 0, trend_direction: trend });
43761
+ }
43762
+ momentumFilter(site, momentum, volume, period) {
43763
+ const n = this.coerceTaInt(period, "ta.momentum_filter() requires 3 arguments");
43764
+ if (n <= 0)
43765
+ return 0;
43766
+ let st = this.momentumFilterSites.get(`${site}:${n}`);
43767
+ if (st === undefined) {
43768
+ st = { momentum: [], volume: [] };
43769
+ this.momentumFilterSites.set(`${site}:${n}`, st);
43770
+ }
43771
+ pushCap(st.momentum, finiteCell2(momentum), n);
43772
+ pushCap(st.volume, finiteCell2(volume), n);
43773
+ if (st.momentum.length < n || st.volume.length < n)
43774
+ return 0;
43775
+ let volSum = 0;
43776
+ for (const v of st.volume)
43777
+ if (v !== null)
43778
+ volSum += v;
43779
+ if (volSum === 0)
43780
+ return 0;
43781
+ let numerator = 0;
43782
+ let paired = false;
43783
+ for (let i = 0;i < n; i++) {
43784
+ const m = st.momentum[i];
43785
+ const v = st.volume[i];
43786
+ if (m !== null && v !== null) {
43787
+ numerator += m * v;
43788
+ paired = true;
43789
+ }
43790
+ }
43791
+ if (!paired)
43792
+ return 0;
43793
+ return finiteOut2(numerator / volSum) ?? 0;
43794
+ }
43795
+ volatilityRegime(site, atr, period) {
43796
+ const n = this.coerceTaInt(period, "period must be integer");
43797
+ if (n < 1)
43798
+ return "medium";
43799
+ let w = this.volatilityRegimeSites.get(`${site}:${n}`);
43800
+ if (w === undefined) {
43801
+ w = [];
43802
+ this.volatilityRegimeSites.set(`${site}:${n}`, w);
43803
+ }
43804
+ pushCap(w, finiteCell2(atr), n);
43805
+ if (w.length < n)
43806
+ return "medium";
43807
+ const recent = [];
43808
+ for (const v of w)
43809
+ if (v !== null)
43810
+ recent.push(v);
43811
+ if (recent.length === 0)
43812
+ return "medium";
43813
+ const current = recent[recent.length - 1];
43814
+ let sum = 0;
43815
+ for (const v of recent)
43816
+ sum += v;
43817
+ const avg = sum / recent.length;
43818
+ if (current < avg * 0.5)
43819
+ return "low";
43820
+ if (current > avg * 2)
43821
+ return "extreme";
43822
+ if (current > avg * 1.3)
43823
+ return "high";
43824
+ return "medium";
43825
+ }
43826
+ economicImpactScore(priceChange, volatility, volumeChange) {
43827
+ const pc = finiteCell2(priceChange) ?? 0;
43828
+ const vol = finiteCell2(volatility) ?? 0;
43829
+ const vc = finiteCell2(volumeChange) ?? 0;
43830
+ const pcScore = Math.min(100, Math.abs(pc) * 20);
43831
+ const volScore = Math.min(100, vol * 30);
43832
+ const vcScore = Math.min(100, vc * 25);
43833
+ return Math.max(0, Math.min(100, (pcScore + volScore + vcScore) / 3));
43834
+ }
43835
+ contrarianSignal(sentiment, volatility, timeSinceExtreme) {
43836
+ const sent = finiteCell2(sentiment) ?? 50;
43837
+ const vol = finiteCell2(volatility) ?? 1;
43838
+ const time = finiteCell2(timeSinceExtreme) ?? 10;
43839
+ let signal = "neutral";
43840
+ let strength = 0.5;
43841
+ let confidence = 0.5;
43842
+ if ((sent > 80 || sent < 20) && vol > 2 && time < 5) {
43843
+ signal = "strong_contrarian";
43844
+ strength = 0.9;
43845
+ confidence = 0.8;
43846
+ } else if (sent > 65 || sent < 35) {
43847
+ signal = "mild_contrarian";
43848
+ strength = 0.6;
43849
+ confidence = 0.6;
43850
+ } else if (sent > 45 && sent < 55) {
43851
+ signal = "follow_crowd";
43852
+ strength = 0.3;
43853
+ confidence = 0.4;
43854
+ }
43855
+ return taRec({ signal, strength, confidence });
43856
+ }
43857
+ drawdownRecoveryLevel(peak, current, factor, period) {
43858
+ const p = finiteCell2(peak) ?? 0;
43859
+ const c = finiteCell2(current) ?? 0;
43860
+ const f = finiteCell2(factor) ?? 0;
43861
+ const n = this.coerceTaInt(period, "ta.drawdown_recovery_level() requires 4 arguments");
43862
+ const drawdown = p > 0 ? (p - c) / p : 0;
43863
+ const recovery = drawdown < 1 ? drawdown / (1 - drawdown) : 0;
43864
+ return taRec({
43865
+ recovery_level: p,
43866
+ percent_needed: finiteOut2(recovery * 100) ?? 0,
43867
+ estimated_time: finiteOut2(n * f) ?? 0,
43868
+ confidence: 80,
43869
+ drawdown_percent: finiteOut2(drawdown * 100) ?? 0,
43870
+ recovery_timeframe: finiteOut2(n * f) ?? 0,
43871
+ recovery_confidence: 0.8
43872
+ });
43873
+ }
43874
+ pivotPointLevels(high, low, close, traditional) {
43875
+ const h = finiteCell2(high) ?? 0;
43876
+ const l = finiteCell2(low) ?? 0;
43877
+ const c = finiteCell2(close) ?? 0;
43878
+ const pivot = (h + l + c) / 3;
43879
+ let r1;
43880
+ let s1;
43881
+ let r2;
43882
+ let s2;
43883
+ let r3;
43884
+ let s3;
43885
+ if (traditional) {
43886
+ r1 = 2 * pivot - l;
43887
+ s1 = 2 * pivot - h;
43888
+ r2 = pivot + (h - l);
43889
+ s2 = pivot - (h - l);
43890
+ r3 = h + 2 * (pivot - l);
43891
+ s3 = l - 2 * (h - pivot);
43892
+ } else {
43893
+ const diff = h - l;
43894
+ r1 = pivot + 0.382 * diff;
43895
+ s1 = pivot - 0.382 * diff;
43896
+ r2 = pivot + 0.618 * diff;
43897
+ s2 = pivot - 0.618 * diff;
43898
+ r3 = pivot + diff;
43899
+ s3 = pivot - diff;
43900
+ }
43901
+ return taRec({
43902
+ pivot: finiteOut2(pivot) ?? 0,
43903
+ r1: finiteOut2(r1) ?? 0,
43904
+ s1: finiteOut2(s1) ?? 0,
43905
+ r2: finiteOut2(r2) ?? 0,
43906
+ s2: finiteOut2(s2) ?? 0,
43907
+ r3: finiteOut2(r3) ?? 0,
43908
+ s3: finiteOut2(s3) ?? 0
43909
+ });
43910
+ }
43911
+ volatilityRegimeScore(site, atr, volatility, vix, threshold) {
43912
+ const a = this.windowFor(`${site}:atr`, atr);
43913
+ const v = this.windowFor(`${site}:vol`, volatility);
43914
+ const x = this.windowFor(`${site}:vix`, vix);
43915
+ const th = finiteCell2(threshold) ?? 50;
43916
+ if (a.length === 0 || v.length === 0 || x.length === 0) {
43917
+ return taRec({ regime: "normal", volatility_score: 50, momentum: "stable" });
43918
+ }
43919
+ const atrVal = TaEngine.oldest(a) ?? 2;
43920
+ const volVal = TaEngine.oldest(v) ?? 0.02;
43921
+ const vixVal = TaEngine.oldest(x) ?? 15;
43922
+ const atrScore = Math.min(100, atrVal * 20);
43923
+ const volScore = Math.min(100, volVal * 100);
43924
+ const vixScore = Math.min(100, vixVal * 2);
43925
+ const score = atrScore * 0.4 + volScore * 0.3 + vixScore * 0.3;
43926
+ let regime;
43927
+ if (score < th * 0.5)
43928
+ regime = "low";
43929
+ else if (score < th)
43930
+ regime = "normal";
43931
+ else if (score < th * 1.5)
43932
+ regime = "high";
43933
+ else
43934
+ regime = "extreme";
43935
+ let momentum = "stable";
43936
+ const prevAtr = TaEngine.secondOldest(a);
43937
+ if (a.length > 1 && prevAtr !== null) {
43938
+ if (atrVal > prevAtr * 1.05)
43939
+ momentum = "accelerating";
43940
+ else if (atrVal < prevAtr * 0.95)
43941
+ momentum = "decelerating";
43942
+ }
43943
+ return taRec({ regime, volatility_score: finiteOut2(score) ?? 0, momentum });
43944
+ }
43945
+ correlationFilter(site, s1, s2, s3, threshold) {
43946
+ const h1 = this.windowFor(`${site}:s1`, s1);
43947
+ const h2 = this.windowFor(`${site}:s2`, s2);
43948
+ const h3 = this.windowFor(`${site}:s3`, s3);
43949
+ const histories = [h1, h2, h3].filter((h) => h.length > 0);
43950
+ const off = taRec({ is_correlated: false, signal_agreement: 0, divergence_count: 0 });
43951
+ if (histories.length < 2)
43952
+ return off;
43953
+ const lastVals = [];
43954
+ for (const h of histories) {
43955
+ const v = TaEngine.oldest(h);
43956
+ if (v !== null)
43957
+ lastVals.push(v);
43958
+ }
43959
+ if (lastVals.length === 0)
43960
+ return off;
43961
+ let agreement = 0;
43962
+ let divergence = 0;
43963
+ for (let i = 0;i < lastVals.length - 1; i++) {
43964
+ for (let j = i + 1;j < lastVals.length; j++) {
43965
+ if (lastVals[i] * lastVals[j] > 0)
43966
+ agreement += 1;
43967
+ else
43968
+ divergence += 1;
43969
+ }
43970
+ }
43971
+ const pairs = lastVals.length * (lastVals.length - 1) / 2;
43972
+ const pct = pairs > 0 ? agreement / pairs * 100 : 0;
43973
+ const th = finiteCell2(threshold) ?? 0.7;
43974
+ return taRec({
43975
+ is_correlated: pct / 100 >= th,
43976
+ signal_agreement: finiteOut2(pct) ?? 0,
43977
+ divergence_count: divergence
43978
+ });
43979
+ }
43980
+ advancedBreakoutDetector(site, price, volume, level, lookback, volumeMultiplier) {
43981
+ const ph = this.windowFor(`${site}:price`, price);
43982
+ const vh = this.windowFor(`${site}:vol`, volume);
43983
+ const lvl = finiteCell2(level) ?? 100;
43984
+ const n = this.coerceTaInt(lookback, "ta.advanced_breakout_detector() requires 5 arguments");
43985
+ const mult = finiteCell2(volumeMultiplier) ?? 0.5;
43986
+ const off = taRec({ breakout_detected: false, breakout_type: "none", pullback_probability: 0.5 });
43987
+ if (ph.length === 0 || vh.length === 0 || ph.length < 2 || n <= 0)
43988
+ return off;
43989
+ const currentPrice = TaEngine.oldest(ph) ?? 100;
43990
+ const prevPrice = TaEngine.secondOldest(ph) ?? 100;
43991
+ const currentVol = TaEngine.oldest(vh) ?? 1000;
43992
+ const recentVol = vh.slice(-n).filter((v) => v !== null);
43993
+ const avgVol = recentVol.length > 0 ? recentVol.reduce((a, b) => a + b, 0) / recentVol.length : 1000;
43994
+ const gap = currentPrice > lvl && prevPrice <= lvl;
43995
+ const closeBreak = currentPrice > lvl && Math.abs(currentPrice - lvl) < 0.5;
43996
+ const volumeBreak = currentVol > avgVol * (1 + mult);
43997
+ const detected = gap || closeBreak || volumeBreak;
43998
+ let type = "none";
43999
+ if (gap)
44000
+ type = "gap";
44001
+ else if (closeBreak && volumeBreak)
44002
+ type = "volume_break";
44003
+ else if (closeBreak)
44004
+ type = "close_above";
44005
+ const pullback = avgVol !== 0 ? Math.max(0.1, 0.8 - (currentVol / avgVol - 1) * 0.3) : 0.8;
44006
+ return taRec({
44007
+ breakout_detected: detected,
44008
+ breakout_type: type,
44009
+ pullback_probability: finiteOut2(pullback) ?? 0.5
44010
+ });
44011
+ }
44012
+ pullbackBounceLevel(site, high, low, trendDirection, lookback) {
44013
+ const hh = this.windowFor(`${site}:high`, high);
44014
+ const ll = this.windowFor(`${site}:low`, low);
44015
+ const trend = this.coerceTaInt(trendDirection, "trend direction must be integer");
44016
+ const n = this.coerceTaInt(lookback, "ta.pullback_bounce_level() requires 5 arguments");
44017
+ const off = taRec({ primary_level: 100, bounce_probability: 0.5, support_strength: 50 });
44018
+ if (hh.length === 0 || ll.length === 0 || n <= 0)
44019
+ return off;
44020
+ const hVals = hh.slice(-n).filter((v) => v !== null);
44021
+ const lVals = ll.slice(-n).filter((v) => v !== null);
44022
+ if (hVals.length === 0 || lVals.length === 0)
44023
+ return off;
44024
+ let swingHigh = hVals[0];
44025
+ let swingLow = lVals[0];
44026
+ for (const v of hVals)
44027
+ if (v > swingHigh)
44028
+ swingHigh = v;
44029
+ for (const v of lVals)
44030
+ if (v < swingLow)
44031
+ swingLow = v;
44032
+ const range = swingHigh - swingLow;
44033
+ const fib = trend > 0 ? swingLow + range * 0.382 : swingHigh - range * 0.382;
44034
+ const bounce = swingHigh !== 0 ? Math.min(0.95, 0.5 + range / swingHigh * 1) : 0.5;
44035
+ const strength = swingHigh !== 0 ? Math.min(100, range / swingHigh * 100) : 0;
44036
+ return taRec({
44037
+ primary_level: finiteOut2(fib) ?? 0,
44038
+ bounce_probability: finiteOut2(bounce) ?? 0.5,
44039
+ support_strength: finiteOut2(strength) ?? 0
44040
+ });
44041
+ }
44042
+ divergenceDetector(site, price, indicator, lookback) {
44043
+ const ph = this.windowFor(`${site}:price`, price);
44044
+ const ih = this.windowFor(`${site}:ind`, indicator);
44045
+ const n = this.coerceTaInt(lookback, "lookback must be integer");
44046
+ const off = taRec({ is_bullish: false, is_bearish: false, strength: 0 });
44047
+ if (ph.length < n || ih.length < n)
44048
+ return off;
44049
+ const pv = ph.slice(-n).filter((v) => v !== null);
44050
+ const iv = ih.slice(-n).filter((v) => v !== null);
44051
+ if (pv.length < 2 || iv.length < 2)
44052
+ return off;
44053
+ const priceLower = pv[pv.length - 1] < pv[0];
44054
+ const indHigher = iv[iv.length - 1] > iv[0];
44055
+ const bullish = priceLower && indHigher;
44056
+ const priceHigher = pv[pv.length - 1] > pv[0];
44057
+ const indLower = iv[iv.length - 1] < iv[0];
44058
+ const bearish = priceHigher && indLower;
44059
+ const strength = Math.min(1, Math.abs(iv[iv.length - 1] - iv[0]) / 100);
44060
+ return taRec({
44061
+ is_bullish: bullish,
44062
+ is_bearish: bearish,
44063
+ strength: finiteOut2(strength) ?? 0
44064
+ });
44065
+ }
44066
+ momentumDivergence(site, price, momentumFast, momentumSlow) {
44067
+ const ph = this.windowFor(`${site}:price`, price);
44068
+ const fh = this.windowFor(`${site}:fast`, momentumFast);
44069
+ const sh = this.windowFor(`${site}:slow`, momentumSlow);
44070
+ const off = taRec({ divergence_type: "none", strength: 0, bars_since: 0 });
44071
+ if (ph.length < 2 || fh.length < 2 || sh.length < 2)
44072
+ return off;
44073
+ const pv = ph.slice(-2).filter((v) => v !== null);
44074
+ const fv = fh.slice(-2).filter((v) => v !== null);
44075
+ const sv = sh.slice(-2).filter((v) => v !== null);
44076
+ if (pv.length < 2 || fv.length < 2 || sv.length < 2)
44077
+ return off;
44078
+ const priceLower = pv[1] < pv[0];
44079
+ const fastHigher = fv[1] > fv[0];
44080
+ const slowHigher = sv[1] > sv[0];
44081
+ const bullish = priceLower && fastHigher && slowHigher;
44082
+ const bearish = !priceLower && !fastHigher && !slowHigher;
44083
+ const type = bullish ? "bullish" : bearish ? "bearish" : "none";
44084
+ const strength = Math.min(1, Math.abs(fv[1] - fv[0]) / 100);
44085
+ return taRec({ divergence_type: type, strength: finiteOut2(strength) ?? 0, bars_since: 1 });
44086
+ }
44087
+ spreadAnalysis(site, bid, ask, period) {
44088
+ const bh = this.windowFor(`${site}:bid`, bid);
44089
+ const ah = this.windowFor(`${site}:ask`, ask);
44090
+ const n = this.coerceTaInt(period, "ta.spread_analysis() requires 3 arguments");
44091
+ const off = taRec({ avg_spread: 0, spread_percent: 0, spread_trend: "stable" });
44092
+ if (bh.length < n || ah.length < n || n <= 0)
44093
+ return off;
44094
+ const bSlice = bh.slice(-n);
44095
+ const aSlice = ah.slice(-n);
44096
+ const spreads = [];
44097
+ for (let i = 0;i < n; i++) {
44098
+ const b = bSlice[i] ?? 0;
44099
+ const a = aSlice[i] ?? 0;
44100
+ if (a > b && b > 0)
44101
+ spreads.push(a - b);
44102
+ }
44103
+ if (spreads.length === 0)
44104
+ return off;
44105
+ const avg = spreads.reduce((a, b) => a + b, 0) / spreads.length;
44106
+ const askOld = TaEngine.oldest(ah);
44107
+ const bidOld = TaEngine.oldest(bh);
44108
+ const mid = askOld !== null && bidOld !== null ? (askOld + bidOld) / 2 : 100;
44109
+ const pct = mid > 0 ? avg / mid * 100 : 0;
44110
+ let trend = "stable";
44111
+ if (spreads.length >= 2) {
44112
+ const first = spreads[0];
44113
+ const last = spreads[spreads.length - 1];
44114
+ if (last > first * 1.1)
44115
+ trend = "increasing";
44116
+ else if (last < first * 0.9)
44117
+ trend = "decreasing";
44118
+ }
44119
+ return taRec({
44120
+ avg_spread: finiteOut2(avg) ?? 0,
44121
+ spread_percent: finiteOut2(pct) ?? 0,
44122
+ spread_trend: trend
44123
+ });
44124
+ }
44125
+ employmentCycleIndicator(site, cyclical, defensive, unemployment) {
44126
+ const ch = this.windowFor(`${site}:cyc`, cyclical);
44127
+ const dh = this.windowFor(`${site}:def`, defensive);
44128
+ const uh = this.windowFor(`${site}:unemp`, unemployment);
44129
+ if (ch.length === 0 || dh.length === 0 || uh.length === 0)
44130
+ return "mid_cycle";
44131
+ const cNew = ch[0];
44132
+ const cOld = TaEngine.oldest(ch);
44133
+ const dNew = dh[0];
44134
+ const dOld = TaEngine.oldest(dh);
44135
+ const cycPerf = cNew !== null && cOld !== null && cNew !== 0 ? (cOld - cNew) / cNew : 0;
44136
+ const defPerf = dNew !== null && dOld !== null && dNew !== 0 ? (dOld - dNew) / dNew : 0;
44137
+ const unemp = TaEngine.oldest(uh) ?? 0.05;
44138
+ if (cycPerf > defPerf && unemp < 0.04)
44139
+ return "early_cycle";
44140
+ if (cycPerf > defPerf && unemp < 0.06)
44141
+ return "mid_cycle";
44142
+ if (cycPerf < defPerf && unemp > 0.05)
44143
+ return "late_cycle";
44144
+ return "recession";
44145
+ }
44146
+ gdpGrowthProxy(site, breadth, volume, momentum) {
44147
+ const bh = this.windowFor(`${site}:breadth`, breadth);
44148
+ const vh = this.windowFor(`${site}:volume`, volume);
44149
+ const mh = this.windowFor(`${site}:momentum`, momentum);
44150
+ if (bh.length === 0 || vh.length === 0 || mh.length === 0)
44151
+ return 0;
44152
+ const b = TaEngine.oldest(bh) ?? 0.5;
44153
+ const bScore = b * 2 - 1;
44154
+ const vNew = vh[0];
44155
+ const vOld = TaEngine.oldest(vh);
44156
+ const vChange = vNew !== null && vOld !== null && vNew !== 0 ? (vOld - vNew) / vNew * 100 : 0;
44157
+ const m = TaEngine.oldest(mh) ?? 0;
44158
+ const gdp = bScore * 1.5 + vChange / 100 + m / 100;
44159
+ return Math.max(-2, Math.min(4, gdp));
44160
+ }
44161
+ inflationProxyIndicator(site, usdIndex, commodities, bondYields) {
44162
+ const uh = this.windowFor(`${site}:usd`, usdIndex);
44163
+ const ch = this.windowFor(`${site}:comm`, commodities);
44164
+ const yh = this.windowFor(`${site}:yield`, bondYields);
44165
+ if (uh.length === 0 || ch.length === 0 || yh.length === 0)
44166
+ return 0;
44167
+ const uNew = uh[0];
44168
+ const uOld = TaEngine.oldest(uh);
44169
+ const usdChange = uNew !== null && uOld !== null && uNew !== 0 ? -((uOld - uNew) / uNew) * 100 : 0;
44170
+ const cNew = ch[0];
44171
+ const cOld = TaEngine.oldest(ch);
44172
+ const commChange = cNew !== null && cOld !== null && cNew !== 0 ? (cOld - cNew) / cNew * 100 : 0;
44173
+ const yNew = yh[0];
44174
+ const yOld = TaEngine.oldest(yh);
44175
+ const yieldsChange = yNew !== null && yOld !== null ? yOld - yNew : 0;
44176
+ const pressure = usdChange * 0.3 + commChange * 0.4 + yieldsChange * 0.3;
44177
+ return Math.max(-100, Math.min(100, pressure * 10));
44178
+ }
44179
+ expectedValue(returns, probabilities) {
44180
+ if (returns.length !== probabilities.length)
44181
+ return 0;
44182
+ let totalProb = 0;
44183
+ for (const p of probabilities)
44184
+ totalProb += p;
44185
+ if (totalProb === 0)
44186
+ return 0;
44187
+ let ev = 0;
44188
+ for (let i = 0;i < returns.length; i++)
44189
+ ev += returns[i] * probabilities[i];
44190
+ return finiteOut2(ev / totalProb) ?? 0;
44191
+ }
43655
44192
  volumeProfileHigh(prices, volumes) {
43656
44193
  if (prices.length === 0 || volumes.length === 0 || prices.length !== volumes.length)
43657
44194
  return 0;
@@ -44275,7 +44812,25 @@ var TA_METHODS = new Set([
44275
44812
  "market_timing_index",
44276
44813
  "regime_adaptive_signal",
44277
44814
  "strategy_score",
44278
- "breakout_detection"
44815
+ "breakout_detection",
44816
+ "ema_cross_signal",
44817
+ "momentum_filter",
44818
+ "volatility_regime",
44819
+ "economic_impact_score",
44820
+ "contrarian_signal",
44821
+ "drawdown_recovery_level",
44822
+ "pivot_point_levels",
44823
+ "volatility_regime_score",
44824
+ "correlation_filter",
44825
+ "advanced_breakout_detector",
44826
+ "pullback_bounce_level",
44827
+ "divergence_detector",
44828
+ "momentum_divergence",
44829
+ "spread_analysis",
44830
+ "employment_cycle_indicator",
44831
+ "gdp_growth_proxy",
44832
+ "inflation_proxy_indicator",
44833
+ "expected_value"
44279
44834
  ]);
44280
44835
  var TA_BARE_ATTRS = new Set([
44281
44836
  "accdist",
@@ -44463,6 +45018,13 @@ function emitCall2(ctx, node, visit) {
44463
45018
  ctx.needsHeikinashi = true;
44464
45019
  return `"__HEIKINASHI__"`;
44465
45020
  }
45021
+ if (name === "ticker_inherit") {
45022
+ const fallback = pick(args, 0, ["ticker", "tickerid", "from", "source"], `"SYMBOL"`);
45023
+ return pick(args, 1, ["symbol", "ticker"], fallback);
45024
+ }
45025
+ if (name === "renko" || name === "kagi" || name === "linebreak" || name === "pointfigure") {
45026
+ return pick(args, 0, ["ticker", "tickerid", "symbol"], `"SYMBOL"`);
45027
+ }
44466
45028
  if (name.startsWith("ticker_")) {
44467
45029
  return pick(args, 0, ["symbol", "ticker", "tickerid"], `"SYMBOL"`);
44468
45030
  }
@@ -44649,6 +45211,9 @@ function finiteOr2(expr, fb) {
44649
45211
  function cellOf(expr) {
44650
45212
  return `((__c) => (__c == null ? null : typeof __c === "boolean" ? (__c ? 1 : 0) : (typeof __c === "number" && Number.isFinite(__c) ? __c : null)))(${expr})`;
44651
45213
  }
45214
+ function arrOrCell(expr) {
45215
+ return `((__v) => (__v != null && typeof __v === "object" ? __v : (__v == null ? null : typeof __v === "boolean" ? (__v ? 1 : 0) : (typeof __v === "number" && Number.isFinite(__v) ? __v : null))))(${expr})`;
45216
+ }
44652
45217
  function cellList(expr) {
44653
45218
  return `(() => { const __v = ${expr}; const __cell = (e) => (e == null ? null : typeof e === "boolean" ? (e ? 1 : 0) : (typeof e === "number" && Number.isFinite(e) ? e : null)); if (__v != null && typeof __v.size === "function" && typeof __v.get === "function") { const __n = __v.size(); const __o = []; for (let __i = 0; __i < __n; __i++) __o.push(__cell(__v.get(__i))); return __o; } return [__cell(__v)]; })()`;
44654
45219
  }
@@ -46317,8 +46882,11 @@ function emitTa(ctx, method, args) {
46317
46882
  ]);
46318
46883
  }
46319
46884
  if (method === "market_structure_pivot") {
46320
- return taPure("marketStructurePivot", [
46321
- cellOf(pick(args, 2, ["close"], "null"))
46885
+ return taCall("marketStructurePivot", site, [
46886
+ arrOrCell(pick(args, 0, ["high_list", "high"], "null")),
46887
+ arrOrCell(pick(args, 1, ["low_list", "low"], "null")),
46888
+ cellOf(pick(args, 3, ["period", "left", "left_bars"], "null")),
46889
+ cellOf(pick(args, 4, ["mode", "right", "right_bars"], "null"))
46322
46890
  ]);
46323
46891
  }
46324
46892
  if (method === "position_sizing_score") {
@@ -46339,13 +46907,13 @@ function emitTa(ctx, method, args) {
46339
46907
  ]);
46340
46908
  }
46341
46909
  if (method === "optimal_entry_zone") {
46342
- return taPure("optimalEntryZone", [cellOf(pick(args, 2, ["close"], "null"))]);
46910
+ return taCall("optimalEntryZone", site, [arrOrCell(pick(args, 2, ["close"], "null"))]);
46343
46911
  }
46344
46912
  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")),
46913
+ return taCall("meanReversionEntry", site, [
46914
+ arrOrCell(pick(args, 0, ["price", "source"], "null")),
46915
+ arrOrCell(pick(args, 1, ["sma"], "null")),
46916
+ arrOrCell(pick(args, 2, ["stdev", "std_dev"], "null")),
46349
46917
  cellOf(pick(args, 4, ["threshold"], "null"))
46350
46918
  ]);
46351
46919
  }
@@ -46389,6 +46957,134 @@ function emitTa(ctx, method, args) {
46389
46957
  cellOf(pick(args, 2, ["support"], "null"))
46390
46958
  ]);
46391
46959
  }
46960
+ if (method === "ema_cross_signal") {
46961
+ return taCall("emaCrossSignal", site, [
46962
+ cellOf(pick(args, 0, ["fast_ema", "fast"], "null")),
46963
+ cellOf(pick(args, 1, ["slow_ema", "slow"], "null")),
46964
+ cellOf(pick(args, 2, ["threshold"], "null"))
46965
+ ]);
46966
+ }
46967
+ if (method === "momentum_filter") {
46968
+ return taCall("momentumFilter", site, [
46969
+ cellOf(pick(args, 0, ["momentum_raw", "momentum"], "null")),
46970
+ cellOf(pick(args, 1, ["volume"], "null")),
46971
+ cellOf(pick(args, 2, ["period", "length"], "null"))
46972
+ ]);
46973
+ }
46974
+ if (method === "volatility_regime") {
46975
+ return taCall("volatilityRegime", site, [
46976
+ cellOf(pick(args, 0, ["atr_series", "atr", "source"], "null")),
46977
+ cellOf(pick(args, 1, ["period", "length"], "null"))
46978
+ ]);
46979
+ }
46980
+ if (method === "economic_impact_score") {
46981
+ return taPure("economicImpactScore", [
46982
+ cellOf(pick(args, 0, ["price_change"], "null")),
46983
+ cellOf(pick(args, 1, ["volatility"], "null")),
46984
+ cellOf(pick(args, 2, ["volume_change"], "null"))
46985
+ ]);
46986
+ }
46987
+ if (method === "contrarian_signal") {
46988
+ return taPure("contrarianSignal", [
46989
+ cellOf(pick(args, 0, ["sentiment"], "null")),
46990
+ cellOf(pick(args, 1, ["volatility"], "null")),
46991
+ cellOf(pick(args, 2, ["time_since_extreme", "time_extreme"], "null"))
46992
+ ]);
46993
+ }
46994
+ if (method === "drawdown_recovery_level") {
46995
+ return taPure("drawdownRecoveryLevel", [
46996
+ cellOf(pick(args, 0, ["peak"], "null")),
46997
+ cellOf(pick(args, 1, ["current", "current_price"], "null")),
46998
+ cellOf(pick(args, 2, ["recovery_factor", "factor"], "null")),
46999
+ cellOf(pick(args, 3, ["period", "length"], "null"))
47000
+ ]);
47001
+ }
47002
+ if (method === "pivot_point_levels") {
47003
+ return taPure("pivotPointLevels", [
47004
+ cellOf(pick(args, 0, ["high"], "null")),
47005
+ cellOf(pick(args, 1, ["low"], "null")),
47006
+ cellOf(pick(args, 2, ["close"], "null")),
47007
+ pick(args, 3, ["traditional"], "true")
47008
+ ]);
47009
+ }
47010
+ if (method === "volatility_regime_score") {
47011
+ return taCall("volatilityRegimeScore", site, [
47012
+ arrOrCell(pick(args, 0, ["atr_list", "atr"], "null")),
47013
+ arrOrCell(pick(args, 1, ["volatility_list", "volatility"], "null")),
47014
+ arrOrCell(pick(args, 2, ["vix_list", "vix"], "null")),
47015
+ cellOf(pick(args, 3, ["threshold"], "null"))
47016
+ ]);
47017
+ }
47018
+ if (method === "correlation_filter") {
47019
+ return taCall("correlationFilter", site, [
47020
+ arrOrCell(pick(args, 0, ["signal1_list", "signal1", "s1"], "null")),
47021
+ arrOrCell(pick(args, 1, ["signal2_list", "signal2", "s2"], "null")),
47022
+ arrOrCell(pick(args, 2, ["signal3_list", "signal3", "s3"], "null")),
47023
+ cellOf(pick(args, 4, ["threshold"], "null"))
47024
+ ]);
47025
+ }
47026
+ if (method === "advanced_breakout_detector") {
47027
+ return taCall("advancedBreakoutDetector", site, [
47028
+ arrOrCell(pick(args, 0, ["price_list", "price"], "null")),
47029
+ arrOrCell(pick(args, 1, ["volume_list", "volume"], "null")),
47030
+ cellOf(pick(args, 2, ["level"], "null")),
47031
+ cellOf(pick(args, 3, ["lookback"], "null")),
47032
+ cellOf(pick(args, 4, ["volume_multiplier", "vol_mult"], "null"))
47033
+ ]);
47034
+ }
47035
+ if (method === "pullback_bounce_level") {
47036
+ return taCall("pullbackBounceLevel", site, [
47037
+ arrOrCell(pick(args, 0, ["high_list", "high"], "null")),
47038
+ arrOrCell(pick(args, 1, ["low_list", "low"], "null")),
47039
+ cellOf(pick(args, 3, ["trend_direction", "trend_dir"], "null")),
47040
+ cellOf(pick(args, 4, ["lookback"], "null"))
47041
+ ]);
47042
+ }
47043
+ if (method === "divergence_detector") {
47044
+ return taCall("divergenceDetector", site, [
47045
+ arrOrCell(pick(args, 0, ["price_list", "price"], "null")),
47046
+ arrOrCell(pick(args, 1, ["indicator_list", "indicator"], "null")),
47047
+ cellOf(pick(args, 2, ["lookback"], "null"))
47048
+ ]);
47049
+ }
47050
+ if (method === "momentum_divergence") {
47051
+ return taCall("momentumDivergence", site, [
47052
+ arrOrCell(pick(args, 0, ["price"], "null")),
47053
+ arrOrCell(pick(args, 1, ["momentum_fast", "mom_fast"], "null")),
47054
+ arrOrCell(pick(args, 2, ["momentum_slow", "mom_slow"], "null"))
47055
+ ]);
47056
+ }
47057
+ if (method === "spread_analysis") {
47058
+ return taCall("spreadAnalysis", site, [
47059
+ arrOrCell(pick(args, 0, ["bid"], "null")),
47060
+ arrOrCell(pick(args, 1, ["ask"], "null")),
47061
+ cellOf(pick(args, 2, ["period", "length"], "null"))
47062
+ ]);
47063
+ }
47064
+ if (method === "employment_cycle_indicator") {
47065
+ return taCall("employmentCycleIndicator", site, [
47066
+ arrOrCell(pick(args, 0, ["cyclical_stocks", "cyclical"], "null")),
47067
+ arrOrCell(pick(args, 1, ["defensive_stocks", "defensive"], "null")),
47068
+ arrOrCell(pick(args, 2, ["unemployment_proxy", "unemployment"], "null"))
47069
+ ]);
47070
+ }
47071
+ if (method === "gdp_growth_proxy") {
47072
+ return taCall("gdpGrowthProxy", site, [
47073
+ arrOrCell(pick(args, 0, ["market_breadth", "breadth"], "null")),
47074
+ arrOrCell(pick(args, 1, ["market_volume", "volume"], "null")),
47075
+ arrOrCell(pick(args, 2, ["price_momentum", "momentum"], "null"))
47076
+ ]);
47077
+ }
47078
+ if (method === "inflation_proxy_indicator") {
47079
+ return taCall("inflationProxyIndicator", site, [
47080
+ arrOrCell(pick(args, 0, ["usd_index", "usd"], "null")),
47081
+ arrOrCell(pick(args, 1, ["commodity_prices", "commodities"], "null")),
47082
+ arrOrCell(pick(args, 2, ["bond_yields", "yields"], "null"))
47083
+ ]);
47084
+ }
47085
+ if (method === "expected_value") {
47086
+ return `__h.ta.expectedValue(${cellList(pick(args, 0, ["returns"], "null"))}, ${cellList(pick(args, 1, ["probabilities", "probs"], "null"))})`;
47087
+ }
46392
47088
  return "null";
46393
47089
  }
46394
47090
 
@@ -51723,6 +52419,33 @@ function evalCall(node, env) {
51723
52419
  adjust: evalAsString(callArg(node.args, 3, ["adjust", "adjustment"]), env) ?? undefined
51724
52420
  });
51725
52421
  }
52422
+ if (fname === "ticker.inherit") {
52423
+ const first = evalExpr(callArg(node.args, 0, ["ticker", "tickerid", "from", "source"]), env);
52424
+ const secondArg = callArg(node.args, 1, ["symbol", "ticker"]);
52425
+ if (secondArg != null) {
52426
+ const target = evalExpr(secondArg, env);
52427
+ const sym = target instanceof TickerId ? target.symbol : typeof target === "string" ? target : env.symbol;
52428
+ if (first instanceof TickerId)
52429
+ return tickerNew(sym, first.session, first.adjust);
52430
+ return tickerNew(sym);
52431
+ }
52432
+ if (first instanceof TickerId) {
52433
+ return tickerNew(first.symbol, first.session, first.adjust);
52434
+ }
52435
+ const sym = typeof first === "string" ? first : env.symbol;
52436
+ return tickerNew(sym);
52437
+ }
52438
+ if (fname === "renko" || fname === "kagi" || fname === "linebreak" || fname === "pointfigure") {
52439
+ const raw = evalExpr(callArg(node.args, 0, ["ticker", "tickerid", "symbol"]), env);
52440
+ const sym = raw instanceof TickerId ? raw.symbol : typeof raw === "string" ? raw : env.symbol;
52441
+ if (fname === "renko")
52442
+ return tickerRenko(sym);
52443
+ if (fname === "kagi")
52444
+ return tickerKagi(sym);
52445
+ if (fname === "linebreak")
52446
+ return tickerLinebreak(sym);
52447
+ return tickerPointfigure(sym);
52448
+ }
51726
52449
  const mapVal = evalMapCall(fname, node, env);
51727
52450
  if (mapVal !== undefined)
51728
52451
  return mapVal;
@@ -53043,12 +53766,12 @@ function evalExtraTa(fname, node, env, site) {
53043
53766
  return NA;
53044
53767
  return ta.percentrank.call(env.ta, site, srcArg(node, env), lenArg(node, env, 1));
53045
53768
  }
53046
- if (fname === "ta.percentile_nearest_rank") {
53769
+ if (fname === "ta.percentile_nearest_rank" || fname === "percentile_nearest_rank") {
53047
53770
  if (typeof ta.percentileNearest !== "function")
53048
53771
  return NA;
53049
53772
  return ta.percentileNearest.call(env.ta, site, srcArg(node, env), lenArg(node, env, 1), lenOrDefault(node, env, 2, ["percentage", "percent"], 50));
53050
53773
  }
53051
- if (fname === "ta.percentile_linear_interpolation") {
53774
+ if (fname === "ta.percentile_linear_interpolation" || fname === "percentile_linear_interpolation") {
53052
53775
  if (typeof ta.percentileLinear !== "function")
53053
53776
  return NA;
53054
53777
  return ta.percentileLinear.call(env.ta, site, srcArg(node, env), lenArg(node, env, 1), lenOrDefault(node, env, 2, ["percentage", "percent"], 50));
@@ -53163,12 +53886,6 @@ function evalExtraTa(fname, node, env, site) {
53163
53886
  const r = env.ta.aroon(site, num2(env.ctx.high), num2(env.ctx.low), length ?? 14);
53164
53887
  return tupleOf([r.down, r.up]);
53165
53888
  }
53166
- if (fname === "ta.pivot_point_levels") {
53167
- if (typeof ta.pivotPoints !== "function")
53168
- return NA;
53169
- const r = ta.pivotPoints.call(env.ta, site, num2(env.ctx.high), num2(env.ctx.low), num2(env.ctx.close));
53170
- return tupleOf([r.pp, r.r1, r.s1, r.r2, r.s2]);
53171
- }
53172
53889
  if (fname === "ta.uo" || fname === "uo") {
53173
53890
  return env.ta.uo(site, num2(env.ctx.high), num2(env.ctx.low), num2(env.ctx.close), lenArg(node, env, 0), lenArg(node, env, 1), lenArg(node, env, 2));
53174
53891
  }
@@ -53304,6 +54021,7 @@ function evalExtraTa(fname, node, env, site) {
53304
54021
  }
53305
54022
  const wave11 = (index, names, message) => unwrap2(evalExpr(wave10aArg(index, names, message), env));
53306
54023
  const wave11n = (index, names, message) => num2(wave11(index, names, message));
54024
+ const wave13v = (index, names, message) => evalExpr(wave10aArg(index, names, message), env);
53307
54025
  if (fname === "ta.sma_weighted" || fname === "sma_weighted") {
53308
54026
  const msg = "ta.sma_weighted() requires at least 2 arguments: series, period";
53309
54027
  const weightArg = callArg(node.args, 2, ["weight_type", "weight"]);
@@ -53433,12 +54151,12 @@ function evalExtraTa(fname, node, env, site) {
53433
54151
  }
53434
54152
  if (fname === "ta.market_structure_pivot" || fname === "market_structure_pivot") {
53435
54153
  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);
54154
+ const high = wave13v(0, ["high_list", "high"], msg);
54155
+ const low = wave13v(1, ["low_list", "low"], msg);
54156
+ wave13v(2, ["close_list", "close"], msg);
54157
+ const period = wave11n(3, ["period", "left", "left_bars"], msg);
54158
+ const mode = wave11n(4, ["mode", "right", "right_bars"], msg);
54159
+ return env.ta.marketStructurePivot(site, high, low, period, mode);
53442
54160
  }
53443
54161
  if (fname === "ta.position_sizing_score" || fname === "position_sizing_score") {
53444
54162
  const msg = "ta.position_sizing_score() requires 4 arguments";
@@ -53452,13 +54170,13 @@ function evalExtraTa(fname, node, env, site) {
53452
54170
  const msg = "ta.optimal_entry_zone() requires 4 arguments";
53453
54171
  wave11n(0, ["high"], msg);
53454
54172
  wave11n(1, ["low"], msg);
53455
- const close = wave11n(2, ["close"], msg);
54173
+ const close = wave13v(2, ["close"], msg);
53456
54174
  wave11n(3, ["period", "length"], msg);
53457
- return env.ta.optimalEntryZone(close);
54175
+ return env.ta.optimalEntryZone(site, close);
53458
54176
  }
53459
54177
  if (fname === "ta.mean_reversion_entry" || fname === "mean_reversion_entry") {
53460
54178
  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));
54179
+ return env.ta.meanReversionEntry(site, wave13v(0, ["price", "source"], msg), wave13v(1, ["sma"], msg), wave13v(2, ["stdev", "std_dev"], msg), wave11n(4, ["threshold"], msg));
53462
54180
  }
53463
54181
  if (fname === "ta.multi_timeframe_signal" || fname === "multi_timeframe_signal") {
53464
54182
  const msg = "ta.multi_timeframe_signal() requires 6 arguments";
@@ -53484,6 +54202,98 @@ function evalExtraTa(fname, node, env, site) {
53484
54202
  const msg = "ta.breakout_detection() requires 3 arguments";
53485
54203
  return env.ta.breakoutDetection(wave11n(0, ["close", "source"], msg), wave11n(1, ["resistance"], msg), wave11n(2, ["support"], msg));
53486
54204
  }
54205
+ if (fname === "ta.ema_cross_signal" || fname === "ema_cross_signal") {
54206
+ const msg = "ta.ema_cross_signal() requires 3 arguments";
54207
+ return env.ta.emaCrossSignal(site, wave11n(0, ["fast_ema", "fast"], msg), wave11n(1, ["slow_ema", "slow"], msg), wave11n(2, ["threshold"], msg));
54208
+ }
54209
+ if (fname === "ta.momentum_filter" || fname === "momentum_filter") {
54210
+ const msg = "ta.momentum_filter() requires 3 arguments";
54211
+ return env.ta.momentumFilter(site, wave11n(0, ["momentum_raw", "momentum"], msg), wave11n(1, ["volume"], msg), wave11n(2, ["period", "length"], msg));
54212
+ }
54213
+ if (fname === "ta.volatility_regime" || fname === "volatility_regime") {
54214
+ const msg = "ta.volatility_regime() requires 2 arguments";
54215
+ return env.ta.volatilityRegime(site, wave11n(0, ["atr_series", "atr", "source"], msg), wave11n(1, ["period", "length"], msg));
54216
+ }
54217
+ if (fname === "ta.economic_impact_score" || fname === "economic_impact_score") {
54218
+ const msg = "ta.economic_impact_score() requires 3 arguments";
54219
+ return env.ta.economicImpactScore(wave11n(0, ["price_change"], msg), wave11n(1, ["volatility"], msg), wave11n(2, ["volume_change"], msg));
54220
+ }
54221
+ if (fname === "ta.contrarian_signal" || fname === "contrarian_signal") {
54222
+ const msg = "ta.contrarian_signal() requires 3 arguments";
54223
+ return env.ta.contrarianSignal(wave11n(0, ["sentiment"], msg), wave11n(1, ["volatility"], msg), wave11n(2, ["time_since_extreme", "time_extreme"], msg));
54224
+ }
54225
+ if (fname === "ta.drawdown_recovery_level" || fname === "drawdown_recovery_level") {
54226
+ const msg = "ta.drawdown_recovery_level() requires 4 arguments";
54227
+ return env.ta.drawdownRecoveryLevel(wave11n(0, ["peak"], msg), wave11n(1, ["current", "current_price"], msg), wave11n(2, ["recovery_factor", "factor"], msg), wave11n(3, ["period", "length"], msg));
54228
+ }
54229
+ if (fname === "ta.pivot_point_levels" || fname === "pivot_point_levels") {
54230
+ const msg = "ta.pivot_point_levels() requires type+anchor or high, low, close";
54231
+ const first = wave11(0, ["type", "high"], msg);
54232
+ if (typeof first === "string") {
54233
+ if (typeof env.ta.pivotPoints !== "function")
54234
+ return NA;
54235
+ const r = env.ta.pivotPoints.call(env.ta, site, num2(env.ctx.high), num2(env.ctx.low), num2(env.ctx.close));
54236
+ return tupleOf([r.pp, r.r1, r.s1, r.r2, r.s2]);
54237
+ }
54238
+ const tradArg = callArg(node.args, 3, ["traditional"]);
54239
+ const traditional = tradArg == null ? true : unwrap2(evalExpr(tradArg, env)) !== 0;
54240
+ return env.ta.pivotPointLevels(num2(first), wave11n(1, ["low"], msg), wave11n(2, ["close"], msg), traditional);
54241
+ }
54242
+ if (fname === "ta.volatility_regime_score" || fname === "volatility_regime_score") {
54243
+ const msg = "ta.volatility_regime_score() requires 4 arguments";
54244
+ return env.ta.volatilityRegimeScore(site, wave13v(0, ["atr_list", "atr"], msg), wave13v(1, ["volatility_list", "volatility"], msg), wave13v(2, ["vix_list", "vix"], msg), wave11n(3, ["threshold"], msg));
54245
+ }
54246
+ if (fname === "ta.correlation_filter" || fname === "correlation_filter") {
54247
+ const msg = "ta.correlation_filter() requires 5 arguments";
54248
+ const s1 = wave13v(0, ["signal1_list", "signal1", "s1"], msg);
54249
+ const s2 = wave13v(1, ["signal2_list", "signal2", "s2"], msg);
54250
+ const s3 = wave13v(2, ["signal3_list", "signal3", "s3"], msg);
54251
+ wave11n(3, ["num_signals"], msg);
54252
+ return env.ta.correlationFilter(site, s1, s2, s3, wave11n(4, ["threshold"], msg));
54253
+ }
54254
+ if (fname === "ta.advanced_breakout_detector" || fname === "advanced_breakout_detector") {
54255
+ const msg = "ta.advanced_breakout_detector() requires 5 arguments";
54256
+ return env.ta.advancedBreakoutDetector(site, wave13v(0, ["price_list", "price"], msg), wave13v(1, ["volume_list", "volume"], msg), wave11n(2, ["level"], msg), wave11n(3, ["lookback"], msg), wave11n(4, ["volume_multiplier", "vol_mult"], msg));
54257
+ }
54258
+ if (fname === "ta.pullback_bounce_level" || fname === "pullback_bounce_level") {
54259
+ const msg = "ta.pullback_bounce_level() requires 5 arguments";
54260
+ const high = wave13v(0, ["high_list", "high"], msg);
54261
+ const low = wave13v(1, ["low_list", "low"], msg);
54262
+ wave13v(2, ["close_list", "close"], msg);
54263
+ return env.ta.pullbackBounceLevel(site, high, low, wave11n(3, ["trend_direction", "trend_dir"], msg), wave11n(4, ["lookback"], msg));
54264
+ }
54265
+ if (fname === "ta.divergence_detector" || fname === "divergence_detector") {
54266
+ const msg = "ta.divergence_detector() requires 3 arguments";
54267
+ return env.ta.divergenceDetector(site, wave13v(0, ["price_list", "price"], msg), wave13v(1, ["indicator_list", "indicator"], msg), wave11n(2, ["lookback"], msg));
54268
+ }
54269
+ if (fname === "ta.momentum_divergence" || fname === "momentum_divergence") {
54270
+ const msg = "ta.momentum_divergence() requires 3 arguments";
54271
+ return env.ta.momentumDivergence(site, wave13v(0, ["price"], msg), wave13v(1, ["momentum_fast", "mom_fast"], msg), wave13v(2, ["momentum_slow", "mom_slow"], msg));
54272
+ }
54273
+ if (fname === "ta.spread_analysis" || fname === "spread_analysis") {
54274
+ const msg = "ta.spread_analysis() requires 3 arguments";
54275
+ return env.ta.spreadAnalysis(site, wave13v(0, ["bid"], msg), wave13v(1, ["ask"], msg), wave11n(2, ["period", "length"], msg));
54276
+ }
54277
+ if (fname === "ta.employment_cycle_indicator" || fname === "employment_cycle_indicator") {
54278
+ const msg = "ta.employment_cycle_indicator() requires 3 arguments";
54279
+ return env.ta.employmentCycleIndicator(site, wave13v(0, ["cyclical_stocks", "cyclical"], msg), wave13v(1, ["defensive_stocks", "defensive"], msg), wave13v(2, ["unemployment_proxy", "unemployment"], msg));
54280
+ }
54281
+ if (fname === "ta.gdp_growth_proxy" || fname === "gdp_growth_proxy") {
54282
+ const msg = "ta.gdp_growth_proxy() requires 3 arguments";
54283
+ return env.ta.gdpGrowthProxy(site, wave13v(0, ["market_breadth", "breadth"], msg), wave13v(1, ["market_volume", "volume"], msg), wave13v(2, ["price_momentum", "momentum"], msg));
54284
+ }
54285
+ if (fname === "ta.inflation_proxy_indicator" || fname === "inflation_proxy_indicator") {
54286
+ const msg = "ta.inflation_proxy_indicator() requires 3 arguments";
54287
+ return env.ta.inflationProxyIndicator(site, wave13v(0, ["usd_index", "usd"], msg), wave13v(1, ["commodity_prices", "commodities"], msg), wave13v(2, ["bond_yields", "yields"], msg));
54288
+ }
54289
+ if (fname === "ta.expected_value" || fname === "expected_value") {
54290
+ const msg = "ta.expected_value() requires 2 arguments: returns, probabilities";
54291
+ const returns = numericList(evalExpr(wave10aArg(0, ["returns"], msg), env));
54292
+ const probs = numericList(evalExpr(wave10aArg(1, ["probabilities", "probs"], msg), env));
54293
+ if (returns.length !== probs.length)
54294
+ runtimeError("Returns and probabilities must have same length");
54295
+ return env.ta.expectedValue(returns, probs);
54296
+ }
53487
54297
  return;
53488
54298
  }
53489
54299
  function hlc3(env) {
@@ -53502,6 +54312,20 @@ function seriesLastCell(value) {
53502
54312
  const v = unwrap2(value);
53503
54313
  return typeof v === "number" && Number.isFinite(v) ? v : null;
53504
54314
  }
54315
+ function numericList(value) {
54316
+ const arr = asArray2(value);
54317
+ if (arr == null) {
54318
+ const v = unwrap2(value);
54319
+ return typeof v === "number" && Number.isFinite(v) ? [v] : [];
54320
+ }
54321
+ const out = [];
54322
+ for (let i = 0;i < arr.size(); i++) {
54323
+ const v = arr.get(i);
54324
+ if (typeof v === "number" && Number.isFinite(v))
54325
+ out.push(v);
54326
+ }
54327
+ return out;
54328
+ }
53505
54329
  function asArray2(value) {
53506
54330
  if (value instanceof PineArray)
53507
54331
  return value;