@hoox-sh/pynets 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +1 -1
- package/dist/browser.js +63 -63
- package/dist/index.js +1051 -38
- package/package.json +1 -1
- package/src/cli/rich.ts +1 -1
- package/src/runtime/compile/emit_call.ts +202 -10
- package/src/runtime/interpret.ts +280 -27
- package/src/runtime/ta.ts +753 -12
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(
|
|
43512
|
-
const
|
|
43513
|
-
|
|
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
|
|
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
|
|
43556
|
-
const
|
|
43557
|
-
const
|
|
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,613 @@ 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
|
+
}
|
|
44192
|
+
gammaLevels(volatility, currentPrice, period) {
|
|
44193
|
+
const v = finiteCell2(volatility) ?? 0.02;
|
|
44194
|
+
const p = finiteCell2(currentPrice) ?? 100;
|
|
44195
|
+
const n = this.coerceTaInt(period, "period must be integer");
|
|
44196
|
+
const volAdjusted = v * Math.sqrt(n);
|
|
44197
|
+
const distance = p * volAdjusted;
|
|
44198
|
+
const out = new PineArray;
|
|
44199
|
+
out.push(finiteOut2(p + distance));
|
|
44200
|
+
out.push(finiteOut2(p - distance));
|
|
44201
|
+
return out;
|
|
44202
|
+
}
|
|
44203
|
+
intelligentStrategySynthesizer(site, trend, momentum, volatility, volume, marketCondition, riskProfile) {
|
|
44204
|
+
const th = this.windowFor(`${site}:trend`, trend);
|
|
44205
|
+
const mh = this.windowFor(`${site}:momentum`, momentum);
|
|
44206
|
+
const vh = this.windowFor(`${site}:volatility`, volatility);
|
|
44207
|
+
const volh = this.windowFor(`${site}:volume`, volume);
|
|
44208
|
+
const regime = typeof marketCondition === "string" ? marketCondition : "ranging";
|
|
44209
|
+
const profile = typeof riskProfile === "string" ? riskProfile : "balanced";
|
|
44210
|
+
const nums = (h) => h.filter((v) => v !== null);
|
|
44211
|
+
const trendVals = nums(th);
|
|
44212
|
+
const momentumVals = nums(mh);
|
|
44213
|
+
const volatilityVals = nums(vh);
|
|
44214
|
+
const volumeVals = nums(volh);
|
|
44215
|
+
const avg = (vals, fallback) => vals.length === 0 ? fallback : vals.reduce((a, b) => a + b, 0) / vals.length;
|
|
44216
|
+
const trendAvg = avg(trendVals, 0);
|
|
44217
|
+
const momentumAvg = avg(momentumVals, 0);
|
|
44218
|
+
const volatilityAvg = avg(volatilityVals, 0.5);
|
|
44219
|
+
const volumeAvg = avg(volumeVals, 0);
|
|
44220
|
+
const volatilityNormalized = Math.max(0, Math.min(1, volatilityAvg));
|
|
44221
|
+
const composite = trendAvg * 0.4 + momentumAvg * 0.35 + volumeAvg * 0.25;
|
|
44222
|
+
const compositeSignal = Math.max(-1, Math.min(1, composite));
|
|
44223
|
+
let agreement = 0;
|
|
44224
|
+
if (Math.abs(trendAvg) > 0.3)
|
|
44225
|
+
agreement += 1;
|
|
44226
|
+
if (Math.abs(momentumAvg) > 0.3)
|
|
44227
|
+
agreement += 1;
|
|
44228
|
+
if (Math.abs(volumeAvg) > 0.3)
|
|
44229
|
+
agreement += 1;
|
|
44230
|
+
const baseConfidence = agreement / 3;
|
|
44231
|
+
const confidence = Math.max(0.1, Math.min(0.99, baseConfidence - volatilityNormalized * 0.3));
|
|
44232
|
+
let recommendation;
|
|
44233
|
+
if (compositeSignal > 0.6) {
|
|
44234
|
+
recommendation = profile === "aggressive" ? "aggressive_long" : "conservative_long";
|
|
44235
|
+
} else if (compositeSignal > 0.2) {
|
|
44236
|
+
recommendation = "conservative_long";
|
|
44237
|
+
} else if (compositeSignal < -0.6) {
|
|
44238
|
+
recommendation = profile === "aggressive" ? "aggressive_short" : "conservative_short";
|
|
44239
|
+
} else if (compositeSignal < -0.2) {
|
|
44240
|
+
recommendation = "conservative_short";
|
|
44241
|
+
} else {
|
|
44242
|
+
recommendation = "hold";
|
|
44243
|
+
}
|
|
44244
|
+
const riskMult = profile === "conservative" ? 0.5 : profile === "aggressive" ? 1.5 : 1;
|
|
44245
|
+
const riskLevel = volatilityNormalized * 50 * riskMult;
|
|
44246
|
+
const absSignal = Math.abs(compositeSignal);
|
|
44247
|
+
const expectedReturn = absSignal * 3;
|
|
44248
|
+
let holdingPeriod;
|
|
44249
|
+
if (volatilityNormalized > 0.7)
|
|
44250
|
+
holdingPeriod = "scalp";
|
|
44251
|
+
else if (volatilityNormalized > 0.5)
|
|
44252
|
+
holdingPeriod = "day_trade";
|
|
44253
|
+
else if (absSignal > 0.5)
|
|
44254
|
+
holdingPeriod = "swing";
|
|
44255
|
+
else
|
|
44256
|
+
holdingPeriod = "position";
|
|
44257
|
+
const shortRec = recommendation === "aggressive_short" || recommendation === "conservative_short";
|
|
44258
|
+
const longRec = recommendation === "aggressive_long" || recommendation === "conservative_long";
|
|
44259
|
+
const stopLoss = shortRec ? -0.7 : longRec ? -0.2 : -0.15;
|
|
44260
|
+
const takeProfit = recommendation === "aggressive_long" || recommendation === "aggressive_short" ? 1.5 : longRec || shortRec ? 1 : 0.5;
|
|
44261
|
+
let alignment = 50;
|
|
44262
|
+
if (regime === "trending_up") {
|
|
44263
|
+
if (compositeSignal > 0)
|
|
44264
|
+
alignment = 90;
|
|
44265
|
+
else if (compositeSignal > -0.3)
|
|
44266
|
+
alignment = 60;
|
|
44267
|
+
else
|
|
44268
|
+
alignment = 30;
|
|
44269
|
+
} else if (regime === "trending_down") {
|
|
44270
|
+
if (compositeSignal < 0)
|
|
44271
|
+
alignment = 90;
|
|
44272
|
+
else if (compositeSignal < 0.3)
|
|
44273
|
+
alignment = 60;
|
|
44274
|
+
else
|
|
44275
|
+
alignment = 30;
|
|
44276
|
+
} else if (regime === "ranging") {
|
|
44277
|
+
alignment = 50 + (1 - absSignal) * 30;
|
|
44278
|
+
} else if (regime === "volatile") {
|
|
44279
|
+
alignment = 30 + absSignal * 40;
|
|
44280
|
+
} else {
|
|
44281
|
+
alignment = 40;
|
|
44282
|
+
}
|
|
44283
|
+
return taRec({
|
|
44284
|
+
composite_signal: finiteOut2(compositeSignal) ?? 0,
|
|
44285
|
+
confidence_level: finiteOut2(confidence) ?? 0,
|
|
44286
|
+
strategy_recommendation: recommendation,
|
|
44287
|
+
risk_level: finiteOut2(Math.max(0, Math.min(100, riskLevel))) ?? 0,
|
|
44288
|
+
expected_return: finiteOut2(expectedReturn) ?? 0,
|
|
44289
|
+
holding_period: holdingPeriod,
|
|
44290
|
+
stop_loss_priority: stopLoss,
|
|
44291
|
+
take_profit_priority: takeProfit,
|
|
44292
|
+
regime_alignment: finiteOut2(Math.max(0, Math.min(100, alignment))) ?? 0
|
|
44293
|
+
});
|
|
44294
|
+
}
|
|
44295
|
+
signalConfluence(signals) {
|
|
44296
|
+
let vals = [];
|
|
44297
|
+
if (signals != null && typeof signals === "object") {
|
|
44298
|
+
const obj = signals;
|
|
44299
|
+
if (typeof obj.values === "function") {
|
|
44300
|
+
const got = obj.values();
|
|
44301
|
+
vals = Array.isArray(got) ? got : [];
|
|
44302
|
+
} else if (!Array.isArray(signals)) {
|
|
44303
|
+
vals = Object.entries(signals).filter(([k]) => k !== "__taRecord").map(([, v]) => v);
|
|
44304
|
+
}
|
|
44305
|
+
}
|
|
44306
|
+
let signalCount = 0;
|
|
44307
|
+
let bullish = 0;
|
|
44308
|
+
let bearish = 0;
|
|
44309
|
+
for (const v of vals) {
|
|
44310
|
+
if (typeof v === "boolean") {
|
|
44311
|
+
if (v) {
|
|
44312
|
+
bullish += 1;
|
|
44313
|
+
signalCount += 1;
|
|
44314
|
+
}
|
|
44315
|
+
continue;
|
|
44316
|
+
}
|
|
44317
|
+
if (typeof v === "number" && Number.isFinite(v)) {
|
|
44318
|
+
if (v > 0) {
|
|
44319
|
+
bullish += 1;
|
|
44320
|
+
signalCount += 1;
|
|
44321
|
+
} else if (v < 0) {
|
|
44322
|
+
bearish += 1;
|
|
44323
|
+
signalCount += 1;
|
|
44324
|
+
}
|
|
44325
|
+
}
|
|
44326
|
+
}
|
|
44327
|
+
const total = vals.length > 0 ? vals.length : 1;
|
|
44328
|
+
const confluence = signalCount / total;
|
|
44329
|
+
const primary = bullish > bearish ? "buy" : bearish > bullish ? "sell" : "neutral";
|
|
44330
|
+
return taRec({
|
|
44331
|
+
signal_count: signalCount,
|
|
44332
|
+
confluence_level: finiteOut2(confluence) ?? 0,
|
|
44333
|
+
primary_signal: primary
|
|
44334
|
+
});
|
|
44335
|
+
}
|
|
43655
44336
|
volumeProfileHigh(prices, volumes) {
|
|
43656
44337
|
if (prices.length === 0 || volumes.length === 0 || prices.length !== volumes.length)
|
|
43657
44338
|
return 0;
|
|
@@ -44275,7 +44956,28 @@ var TA_METHODS = new Set([
|
|
|
44275
44956
|
"market_timing_index",
|
|
44276
44957
|
"regime_adaptive_signal",
|
|
44277
44958
|
"strategy_score",
|
|
44278
|
-
"breakout_detection"
|
|
44959
|
+
"breakout_detection",
|
|
44960
|
+
"ema_cross_signal",
|
|
44961
|
+
"momentum_filter",
|
|
44962
|
+
"volatility_regime",
|
|
44963
|
+
"economic_impact_score",
|
|
44964
|
+
"contrarian_signal",
|
|
44965
|
+
"drawdown_recovery_level",
|
|
44966
|
+
"pivot_point_levels",
|
|
44967
|
+
"volatility_regime_score",
|
|
44968
|
+
"correlation_filter",
|
|
44969
|
+
"advanced_breakout_detector",
|
|
44970
|
+
"pullback_bounce_level",
|
|
44971
|
+
"divergence_detector",
|
|
44972
|
+
"momentum_divergence",
|
|
44973
|
+
"spread_analysis",
|
|
44974
|
+
"employment_cycle_indicator",
|
|
44975
|
+
"gdp_growth_proxy",
|
|
44976
|
+
"inflation_proxy_indicator",
|
|
44977
|
+
"expected_value",
|
|
44978
|
+
"gamma_levels",
|
|
44979
|
+
"intelligent_strategy_synthesizer",
|
|
44980
|
+
"signal_confluence"
|
|
44279
44981
|
]);
|
|
44280
44982
|
var TA_BARE_ATTRS = new Set([
|
|
44281
44983
|
"accdist",
|
|
@@ -44463,6 +45165,13 @@ function emitCall2(ctx, node, visit) {
|
|
|
44463
45165
|
ctx.needsHeikinashi = true;
|
|
44464
45166
|
return `"__HEIKINASHI__"`;
|
|
44465
45167
|
}
|
|
45168
|
+
if (name === "ticker_inherit") {
|
|
45169
|
+
const fallback = pick(args, 0, ["ticker", "tickerid", "from", "source"], `"SYMBOL"`);
|
|
45170
|
+
return pick(args, 1, ["symbol", "ticker"], fallback);
|
|
45171
|
+
}
|
|
45172
|
+
if (name === "renko" || name === "kagi" || name === "linebreak" || name === "pointfigure") {
|
|
45173
|
+
return pick(args, 0, ["ticker", "tickerid", "symbol"], `"SYMBOL"`);
|
|
45174
|
+
}
|
|
44466
45175
|
if (name.startsWith("ticker_")) {
|
|
44467
45176
|
return pick(args, 0, ["symbol", "ticker", "tickerid"], `"SYMBOL"`);
|
|
44468
45177
|
}
|
|
@@ -44637,6 +45346,9 @@ function hasSeriesArg(args) {
|
|
|
44637
45346
|
const isSeries = (n) => n.kind === "Name" && BARE_SERIES_NAMES.has(n.id);
|
|
44638
45347
|
return args.posNodes.some(isSeries) || Object.values(args.kwNodes).some(isSeries);
|
|
44639
45348
|
}
|
|
45349
|
+
function isSeriesNode(n) {
|
|
45350
|
+
return n != null && n.kind === "Name" && BARE_SERIES_NAMES.has(n.id);
|
|
45351
|
+
}
|
|
44640
45352
|
function hasAnyKw(args, names) {
|
|
44641
45353
|
return names.some((n) => Object.hasOwn(args.kw, n));
|
|
44642
45354
|
}
|
|
@@ -44649,6 +45361,9 @@ function finiteOr2(expr, fb) {
|
|
|
44649
45361
|
function cellOf(expr) {
|
|
44650
45362
|
return `((__c) => (__c == null ? null : typeof __c === "boolean" ? (__c ? 1 : 0) : (typeof __c === "number" && Number.isFinite(__c) ? __c : null)))(${expr})`;
|
|
44651
45363
|
}
|
|
45364
|
+
function arrOrCell(expr) {
|
|
45365
|
+
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})`;
|
|
45366
|
+
}
|
|
44652
45367
|
function cellList(expr) {
|
|
44653
45368
|
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
45369
|
}
|
|
@@ -46317,8 +47032,11 @@ function emitTa(ctx, method, args) {
|
|
|
46317
47032
|
]);
|
|
46318
47033
|
}
|
|
46319
47034
|
if (method === "market_structure_pivot") {
|
|
46320
|
-
return
|
|
46321
|
-
|
|
47035
|
+
return taCall("marketStructurePivot", site, [
|
|
47036
|
+
arrOrCell(pick(args, 0, ["high_list", "high"], "null")),
|
|
47037
|
+
arrOrCell(pick(args, 1, ["low_list", "low"], "null")),
|
|
47038
|
+
cellOf(pick(args, 3, ["period", "left", "left_bars"], "null")),
|
|
47039
|
+
cellOf(pick(args, 4, ["mode", "right", "right_bars"], "null"))
|
|
46322
47040
|
]);
|
|
46323
47041
|
}
|
|
46324
47042
|
if (method === "position_sizing_score") {
|
|
@@ -46339,13 +47057,13 @@ function emitTa(ctx, method, args) {
|
|
|
46339
47057
|
]);
|
|
46340
47058
|
}
|
|
46341
47059
|
if (method === "optimal_entry_zone") {
|
|
46342
|
-
return
|
|
47060
|
+
return taCall("optimalEntryZone", site, [arrOrCell(pick(args, 2, ["close"], "null"))]);
|
|
46343
47061
|
}
|
|
46344
47062
|
if (method === "mean_reversion_entry") {
|
|
46345
|
-
return
|
|
46346
|
-
|
|
46347
|
-
|
|
46348
|
-
|
|
47063
|
+
return taCall("meanReversionEntry", site, [
|
|
47064
|
+
arrOrCell(pick(args, 0, ["price", "source"], "null")),
|
|
47065
|
+
arrOrCell(pick(args, 1, ["sma"], "null")),
|
|
47066
|
+
arrOrCell(pick(args, 2, ["stdev", "std_dev"], "null")),
|
|
46349
47067
|
cellOf(pick(args, 4, ["threshold"], "null"))
|
|
46350
47068
|
]);
|
|
46351
47069
|
}
|
|
@@ -46383,12 +47101,159 @@ function emitTa(ctx, method, args) {
|
|
|
46383
47101
|
]);
|
|
46384
47102
|
}
|
|
46385
47103
|
if (method === "breakout_detection") {
|
|
47104
|
+
const arg = (i, names) => isSeriesNode(args.posNodes[i]) ? "null" : cellOf(pick(args, i, names, "null"));
|
|
46386
47105
|
return taPure("breakoutDetection", [
|
|
46387
|
-
|
|
46388
|
-
|
|
46389
|
-
|
|
47106
|
+
arg(0, ["close", "source"]),
|
|
47107
|
+
arg(1, ["resistance"]),
|
|
47108
|
+
arg(2, ["support"])
|
|
46390
47109
|
]);
|
|
46391
47110
|
}
|
|
47111
|
+
if (method === "ema_cross_signal") {
|
|
47112
|
+
return taCall("emaCrossSignal", site, [
|
|
47113
|
+
cellOf(pick(args, 0, ["fast_ema", "fast"], "null")),
|
|
47114
|
+
cellOf(pick(args, 1, ["slow_ema", "slow"], "null")),
|
|
47115
|
+
cellOf(pick(args, 2, ["threshold"], "null"))
|
|
47116
|
+
]);
|
|
47117
|
+
}
|
|
47118
|
+
if (method === "momentum_filter") {
|
|
47119
|
+
return taCall("momentumFilter", site, [
|
|
47120
|
+
cellOf(pick(args, 0, ["momentum_raw", "momentum"], "null")),
|
|
47121
|
+
cellOf(pick(args, 1, ["volume"], "null")),
|
|
47122
|
+
cellOf(pick(args, 2, ["period", "length"], "null"))
|
|
47123
|
+
]);
|
|
47124
|
+
}
|
|
47125
|
+
if (method === "volatility_regime") {
|
|
47126
|
+
return taCall("volatilityRegime", site, [
|
|
47127
|
+
cellOf(pick(args, 0, ["atr_series", "atr", "source"], "null")),
|
|
47128
|
+
cellOf(pick(args, 1, ["period", "length"], "null"))
|
|
47129
|
+
]);
|
|
47130
|
+
}
|
|
47131
|
+
if (method === "economic_impact_score") {
|
|
47132
|
+
return taPure("economicImpactScore", [
|
|
47133
|
+
cellOf(pick(args, 0, ["price_change"], "null")),
|
|
47134
|
+
cellOf(pick(args, 1, ["volatility"], "null")),
|
|
47135
|
+
cellOf(pick(args, 2, ["volume_change"], "null"))
|
|
47136
|
+
]);
|
|
47137
|
+
}
|
|
47138
|
+
if (method === "contrarian_signal") {
|
|
47139
|
+
return taPure("contrarianSignal", [
|
|
47140
|
+
cellOf(pick(args, 0, ["sentiment"], "null")),
|
|
47141
|
+
cellOf(pick(args, 1, ["volatility"], "null")),
|
|
47142
|
+
cellOf(pick(args, 2, ["time_since_extreme", "time_extreme"], "null"))
|
|
47143
|
+
]);
|
|
47144
|
+
}
|
|
47145
|
+
if (method === "drawdown_recovery_level") {
|
|
47146
|
+
return taPure("drawdownRecoveryLevel", [
|
|
47147
|
+
cellOf(pick(args, 0, ["peak"], "null")),
|
|
47148
|
+
cellOf(pick(args, 1, ["current", "current_price"], "null")),
|
|
47149
|
+
cellOf(pick(args, 2, ["recovery_factor", "factor"], "null")),
|
|
47150
|
+
cellOf(pick(args, 3, ["period", "length"], "null"))
|
|
47151
|
+
]);
|
|
47152
|
+
}
|
|
47153
|
+
if (method === "pivot_point_levels") {
|
|
47154
|
+
return taPure("pivotPointLevels", [
|
|
47155
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
47156
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
47157
|
+
cellOf(pick(args, 2, ["close"], "null")),
|
|
47158
|
+
pick(args, 3, ["traditional"], "true")
|
|
47159
|
+
]);
|
|
47160
|
+
}
|
|
47161
|
+
if (method === "volatility_regime_score") {
|
|
47162
|
+
return taCall("volatilityRegimeScore", site, [
|
|
47163
|
+
arrOrCell(pick(args, 0, ["atr_list", "atr"], "null")),
|
|
47164
|
+
arrOrCell(pick(args, 1, ["volatility_list", "volatility"], "null")),
|
|
47165
|
+
arrOrCell(pick(args, 2, ["vix_list", "vix"], "null")),
|
|
47166
|
+
cellOf(pick(args, 3, ["threshold"], "null"))
|
|
47167
|
+
]);
|
|
47168
|
+
}
|
|
47169
|
+
if (method === "correlation_filter") {
|
|
47170
|
+
return taCall("correlationFilter", site, [
|
|
47171
|
+
arrOrCell(pick(args, 0, ["signal1_list", "signal1", "s1"], "null")),
|
|
47172
|
+
arrOrCell(pick(args, 1, ["signal2_list", "signal2", "s2"], "null")),
|
|
47173
|
+
arrOrCell(pick(args, 2, ["signal3_list", "signal3", "s3"], "null")),
|
|
47174
|
+
cellOf(pick(args, 4, ["threshold"], "null"))
|
|
47175
|
+
]);
|
|
47176
|
+
}
|
|
47177
|
+
if (method === "advanced_breakout_detector") {
|
|
47178
|
+
return taCall("advancedBreakoutDetector", site, [
|
|
47179
|
+
arrOrCell(pick(args, 0, ["price_list", "price"], "null")),
|
|
47180
|
+
arrOrCell(pick(args, 1, ["volume_list", "volume"], "null")),
|
|
47181
|
+
cellOf(pick(args, 2, ["level"], "null")),
|
|
47182
|
+
cellOf(pick(args, 3, ["lookback"], "null")),
|
|
47183
|
+
cellOf(pick(args, 4, ["volume_multiplier", "vol_mult"], "null"))
|
|
47184
|
+
]);
|
|
47185
|
+
}
|
|
47186
|
+
if (method === "pullback_bounce_level") {
|
|
47187
|
+
return taCall("pullbackBounceLevel", site, [
|
|
47188
|
+
arrOrCell(pick(args, 0, ["high_list", "high"], "null")),
|
|
47189
|
+
arrOrCell(pick(args, 1, ["low_list", "low"], "null")),
|
|
47190
|
+
cellOf(pick(args, 3, ["trend_direction", "trend_dir"], "null")),
|
|
47191
|
+
cellOf(pick(args, 4, ["lookback"], "null"))
|
|
47192
|
+
]);
|
|
47193
|
+
}
|
|
47194
|
+
if (method === "divergence_detector") {
|
|
47195
|
+
return taCall("divergenceDetector", site, [
|
|
47196
|
+
arrOrCell(pick(args, 0, ["price_list", "price"], "null")),
|
|
47197
|
+
arrOrCell(pick(args, 1, ["indicator_list", "indicator"], "null")),
|
|
47198
|
+
cellOf(pick(args, 2, ["lookback"], "null"))
|
|
47199
|
+
]);
|
|
47200
|
+
}
|
|
47201
|
+
if (method === "momentum_divergence") {
|
|
47202
|
+
return taCall("momentumDivergence", site, [
|
|
47203
|
+
arrOrCell(pick(args, 0, ["price"], "null")),
|
|
47204
|
+
arrOrCell(pick(args, 1, ["momentum_fast", "mom_fast"], "null")),
|
|
47205
|
+
arrOrCell(pick(args, 2, ["momentum_slow", "mom_slow"], "null"))
|
|
47206
|
+
]);
|
|
47207
|
+
}
|
|
47208
|
+
if (method === "spread_analysis") {
|
|
47209
|
+
return taCall("spreadAnalysis", site, [
|
|
47210
|
+
arrOrCell(pick(args, 0, ["bid"], "null")),
|
|
47211
|
+
arrOrCell(pick(args, 1, ["ask"], "null")),
|
|
47212
|
+
cellOf(pick(args, 2, ["period", "length"], "null"))
|
|
47213
|
+
]);
|
|
47214
|
+
}
|
|
47215
|
+
if (method === "employment_cycle_indicator") {
|
|
47216
|
+
return taCall("employmentCycleIndicator", site, [
|
|
47217
|
+
arrOrCell(pick(args, 0, ["cyclical_stocks", "cyclical"], "null")),
|
|
47218
|
+
arrOrCell(pick(args, 1, ["defensive_stocks", "defensive"], "null")),
|
|
47219
|
+
arrOrCell(pick(args, 2, ["unemployment_proxy", "unemployment"], "null"))
|
|
47220
|
+
]);
|
|
47221
|
+
}
|
|
47222
|
+
if (method === "gdp_growth_proxy") {
|
|
47223
|
+
return taCall("gdpGrowthProxy", site, [
|
|
47224
|
+
arrOrCell(pick(args, 0, ["market_breadth", "breadth"], "null")),
|
|
47225
|
+
arrOrCell(pick(args, 1, ["market_volume", "volume"], "null")),
|
|
47226
|
+
arrOrCell(pick(args, 2, ["price_momentum", "momentum"], "null"))
|
|
47227
|
+
]);
|
|
47228
|
+
}
|
|
47229
|
+
if (method === "inflation_proxy_indicator") {
|
|
47230
|
+
return taCall("inflationProxyIndicator", site, [
|
|
47231
|
+
arrOrCell(pick(args, 0, ["usd_index", "usd"], "null")),
|
|
47232
|
+
arrOrCell(pick(args, 1, ["commodity_prices", "commodities"], "null")),
|
|
47233
|
+
arrOrCell(pick(args, 2, ["bond_yields", "yields"], "null"))
|
|
47234
|
+
]);
|
|
47235
|
+
}
|
|
47236
|
+
if (method === "expected_value") {
|
|
47237
|
+
return `__h.ta.expectedValue(${cellList(pick(args, 0, ["returns"], "null"))}, ${cellList(pick(args, 1, ["probabilities", "probs"], "null"))})`;
|
|
47238
|
+
}
|
|
47239
|
+
if (method === "gamma_levels") {
|
|
47240
|
+
const vol = isSeriesNode(args.posNodes[0]) ? "null" : cellOf(pick(args, 0, ["volatility"], "null"));
|
|
47241
|
+
const price = isSeriesNode(args.posNodes[1]) ? "null" : cellOf(pick(args, 1, ["current_price", "price"], "null"));
|
|
47242
|
+
return taPure("gammaLevels", [vol, price, cellOf(pick(args, 2, ["period", "length"], "null"))]);
|
|
47243
|
+
}
|
|
47244
|
+
if (method === "intelligent_strategy_synthesizer") {
|
|
47245
|
+
return taCall("intelligentStrategySynthesizer", site, [
|
|
47246
|
+
arrOrCell(pick(args, 0, ["trend_indicators", "trend"], "null")),
|
|
47247
|
+
arrOrCell(pick(args, 1, ["momentum_indicators", "momentum"], "null")),
|
|
47248
|
+
arrOrCell(pick(args, 2, ["volatility_indicators", "volatility"], "null")),
|
|
47249
|
+
arrOrCell(pick(args, 3, ["volume_indicators", "volume"], "null")),
|
|
47250
|
+
pick(args, 4, ["market_condition", "market_regime"], '"ranging"'),
|
|
47251
|
+
pick(args, 5, ["risk_profile"], '"balanced"')
|
|
47252
|
+
]);
|
|
47253
|
+
}
|
|
47254
|
+
if (method === "signal_confluence") {
|
|
47255
|
+
return taPure("signalConfluence", [pick(args, 0, ["signals"], "null")]);
|
|
47256
|
+
}
|
|
46392
47257
|
return "null";
|
|
46393
47258
|
}
|
|
46394
47259
|
|
|
@@ -51723,6 +52588,33 @@ function evalCall(node, env) {
|
|
|
51723
52588
|
adjust: evalAsString(callArg(node.args, 3, ["adjust", "adjustment"]), env) ?? undefined
|
|
51724
52589
|
});
|
|
51725
52590
|
}
|
|
52591
|
+
if (fname === "ticker.inherit") {
|
|
52592
|
+
const first = evalExpr(callArg(node.args, 0, ["ticker", "tickerid", "from", "source"]), env);
|
|
52593
|
+
const secondArg = callArg(node.args, 1, ["symbol", "ticker"]);
|
|
52594
|
+
if (secondArg != null) {
|
|
52595
|
+
const target = evalExpr(secondArg, env);
|
|
52596
|
+
const sym = target instanceof TickerId ? target.symbol : typeof target === "string" ? target : env.symbol;
|
|
52597
|
+
if (first instanceof TickerId)
|
|
52598
|
+
return tickerNew(sym, first.session, first.adjust);
|
|
52599
|
+
return tickerNew(sym);
|
|
52600
|
+
}
|
|
52601
|
+
if (first instanceof TickerId) {
|
|
52602
|
+
return tickerNew(first.symbol, first.session, first.adjust);
|
|
52603
|
+
}
|
|
52604
|
+
const sym = typeof first === "string" ? first : env.symbol;
|
|
52605
|
+
return tickerNew(sym);
|
|
52606
|
+
}
|
|
52607
|
+
if (fname === "renko" || fname === "kagi" || fname === "linebreak" || fname === "pointfigure") {
|
|
52608
|
+
const raw = evalExpr(callArg(node.args, 0, ["ticker", "tickerid", "symbol"]), env);
|
|
52609
|
+
const sym = raw instanceof TickerId ? raw.symbol : typeof raw === "string" ? raw : env.symbol;
|
|
52610
|
+
if (fname === "renko")
|
|
52611
|
+
return tickerRenko(sym);
|
|
52612
|
+
if (fname === "kagi")
|
|
52613
|
+
return tickerKagi(sym);
|
|
52614
|
+
if (fname === "linebreak")
|
|
52615
|
+
return tickerLinebreak(sym);
|
|
52616
|
+
return tickerPointfigure(sym);
|
|
52617
|
+
}
|
|
51726
52618
|
const mapVal = evalMapCall(fname, node, env);
|
|
51727
52619
|
if (mapVal !== undefined)
|
|
51728
52620
|
return mapVal;
|
|
@@ -53043,12 +53935,12 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
53043
53935
|
return NA;
|
|
53044
53936
|
return ta.percentrank.call(env.ta, site, srcArg(node, env), lenArg(node, env, 1));
|
|
53045
53937
|
}
|
|
53046
|
-
if (fname === "ta.percentile_nearest_rank") {
|
|
53938
|
+
if (fname === "ta.percentile_nearest_rank" || fname === "percentile_nearest_rank") {
|
|
53047
53939
|
if (typeof ta.percentileNearest !== "function")
|
|
53048
53940
|
return NA;
|
|
53049
53941
|
return ta.percentileNearest.call(env.ta, site, srcArg(node, env), lenArg(node, env, 1), lenOrDefault(node, env, 2, ["percentage", "percent"], 50));
|
|
53050
53942
|
}
|
|
53051
|
-
if (fname === "ta.percentile_linear_interpolation") {
|
|
53943
|
+
if (fname === "ta.percentile_linear_interpolation" || fname === "percentile_linear_interpolation") {
|
|
53052
53944
|
if (typeof ta.percentileLinear !== "function")
|
|
53053
53945
|
return NA;
|
|
53054
53946
|
return ta.percentileLinear.call(env.ta, site, srcArg(node, env), lenArg(node, env, 1), lenOrDefault(node, env, 2, ["percentage", "percent"], 50));
|
|
@@ -53163,12 +54055,6 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
53163
54055
|
const r = env.ta.aroon(site, num2(env.ctx.high), num2(env.ctx.low), length ?? 14);
|
|
53164
54056
|
return tupleOf([r.down, r.up]);
|
|
53165
54057
|
}
|
|
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
54058
|
if (fname === "ta.uo" || fname === "uo") {
|
|
53173
54059
|
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
54060
|
}
|
|
@@ -53304,6 +54190,7 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
53304
54190
|
}
|
|
53305
54191
|
const wave11 = (index, names, message) => unwrap2(evalExpr(wave10aArg(index, names, message), env));
|
|
53306
54192
|
const wave11n = (index, names, message) => num2(wave11(index, names, message));
|
|
54193
|
+
const wave13v = (index, names, message) => evalExpr(wave10aArg(index, names, message), env);
|
|
53307
54194
|
if (fname === "ta.sma_weighted" || fname === "sma_weighted") {
|
|
53308
54195
|
const msg = "ta.sma_weighted() requires at least 2 arguments: series, period";
|
|
53309
54196
|
const weightArg = callArg(node.args, 2, ["weight_type", "weight"]);
|
|
@@ -53433,12 +54320,12 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
53433
54320
|
}
|
|
53434
54321
|
if (fname === "ta.market_structure_pivot" || fname === "market_structure_pivot") {
|
|
53435
54322
|
const msg = "ta.market_structure_pivot() requires 5 arguments";
|
|
53436
|
-
|
|
53437
|
-
|
|
53438
|
-
|
|
53439
|
-
wave11n(3, ["left", "left_bars"], msg);
|
|
53440
|
-
wave11n(4, ["right", "right_bars"], msg);
|
|
53441
|
-
return env.ta.marketStructurePivot(
|
|
54323
|
+
const high = wave13v(0, ["high_list", "high"], msg);
|
|
54324
|
+
const low = wave13v(1, ["low_list", "low"], msg);
|
|
54325
|
+
wave13v(2, ["close_list", "close"], msg);
|
|
54326
|
+
const period = wave11n(3, ["period", "left", "left_bars"], msg);
|
|
54327
|
+
const mode = wave11n(4, ["mode", "right", "right_bars"], msg);
|
|
54328
|
+
return env.ta.marketStructurePivot(site, high, low, period, mode);
|
|
53442
54329
|
}
|
|
53443
54330
|
if (fname === "ta.position_sizing_score" || fname === "position_sizing_score") {
|
|
53444
54331
|
const msg = "ta.position_sizing_score() requires 4 arguments";
|
|
@@ -53452,13 +54339,13 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
53452
54339
|
const msg = "ta.optimal_entry_zone() requires 4 arguments";
|
|
53453
54340
|
wave11n(0, ["high"], msg);
|
|
53454
54341
|
wave11n(1, ["low"], msg);
|
|
53455
|
-
const close =
|
|
54342
|
+
const close = wave13v(2, ["close"], msg);
|
|
53456
54343
|
wave11n(3, ["period", "length"], msg);
|
|
53457
|
-
return env.ta.optimalEntryZone(close);
|
|
54344
|
+
return env.ta.optimalEntryZone(site, close);
|
|
53458
54345
|
}
|
|
53459
54346
|
if (fname === "ta.mean_reversion_entry" || fname === "mean_reversion_entry") {
|
|
53460
54347
|
const msg = "ta.mean_reversion_entry() requires 5 arguments";
|
|
53461
|
-
return env.ta.meanReversionEntry(
|
|
54348
|
+
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
54349
|
}
|
|
53463
54350
|
if (fname === "ta.multi_timeframe_signal" || fname === "multi_timeframe_signal") {
|
|
53464
54351
|
const msg = "ta.multi_timeframe_signal() requires 6 arguments";
|
|
@@ -53482,7 +54369,119 @@ function evalExtraTa(fname, node, env, site) {
|
|
|
53482
54369
|
}
|
|
53483
54370
|
if (fname === "ta.breakout_detection" || fname === "breakout_detection") {
|
|
53484
54371
|
const msg = "ta.breakout_detection() requires 3 arguments";
|
|
53485
|
-
|
|
54372
|
+
const arg = (i, names) => {
|
|
54373
|
+
const e = wave10aArg(i, names, msg);
|
|
54374
|
+
return isSeriesExpr(e, env) ? NA : num2(evalExpr(e, env));
|
|
54375
|
+
};
|
|
54376
|
+
return env.ta.breakoutDetection(arg(0, ["close", "source"]), arg(1, ["resistance"]), arg(2, ["support"]));
|
|
54377
|
+
}
|
|
54378
|
+
if (fname === "ta.ema_cross_signal" || fname === "ema_cross_signal") {
|
|
54379
|
+
const msg = "ta.ema_cross_signal() requires 3 arguments";
|
|
54380
|
+
return env.ta.emaCrossSignal(site, wave11n(0, ["fast_ema", "fast"], msg), wave11n(1, ["slow_ema", "slow"], msg), wave11n(2, ["threshold"], msg));
|
|
54381
|
+
}
|
|
54382
|
+
if (fname === "ta.momentum_filter" || fname === "momentum_filter") {
|
|
54383
|
+
const msg = "ta.momentum_filter() requires 3 arguments";
|
|
54384
|
+
return env.ta.momentumFilter(site, wave11n(0, ["momentum_raw", "momentum"], msg), wave11n(1, ["volume"], msg), wave11n(2, ["period", "length"], msg));
|
|
54385
|
+
}
|
|
54386
|
+
if (fname === "ta.volatility_regime" || fname === "volatility_regime") {
|
|
54387
|
+
const msg = "ta.volatility_regime() requires 2 arguments";
|
|
54388
|
+
return env.ta.volatilityRegime(site, wave11n(0, ["atr_series", "atr", "source"], msg), wave11n(1, ["period", "length"], msg));
|
|
54389
|
+
}
|
|
54390
|
+
if (fname === "ta.economic_impact_score" || fname === "economic_impact_score") {
|
|
54391
|
+
const msg = "ta.economic_impact_score() requires 3 arguments";
|
|
54392
|
+
return env.ta.economicImpactScore(wave11n(0, ["price_change"], msg), wave11n(1, ["volatility"], msg), wave11n(2, ["volume_change"], msg));
|
|
54393
|
+
}
|
|
54394
|
+
if (fname === "ta.contrarian_signal" || fname === "contrarian_signal") {
|
|
54395
|
+
const msg = "ta.contrarian_signal() requires 3 arguments";
|
|
54396
|
+
return env.ta.contrarianSignal(wave11n(0, ["sentiment"], msg), wave11n(1, ["volatility"], msg), wave11n(2, ["time_since_extreme", "time_extreme"], msg));
|
|
54397
|
+
}
|
|
54398
|
+
if (fname === "ta.drawdown_recovery_level" || fname === "drawdown_recovery_level") {
|
|
54399
|
+
const msg = "ta.drawdown_recovery_level() requires 4 arguments";
|
|
54400
|
+
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));
|
|
54401
|
+
}
|
|
54402
|
+
if (fname === "ta.pivot_point_levels" || fname === "pivot_point_levels") {
|
|
54403
|
+
const msg = "ta.pivot_point_levels() requires type+anchor or high, low, close";
|
|
54404
|
+
const first = wave11(0, ["type", "high"], msg);
|
|
54405
|
+
if (typeof first === "string") {
|
|
54406
|
+
if (typeof env.ta.pivotPoints !== "function")
|
|
54407
|
+
return NA;
|
|
54408
|
+
const r = env.ta.pivotPoints.call(env.ta, site, num2(env.ctx.high), num2(env.ctx.low), num2(env.ctx.close));
|
|
54409
|
+
return tupleOf([r.pp, r.r1, r.s1, r.r2, r.s2]);
|
|
54410
|
+
}
|
|
54411
|
+
const tradArg = callArg(node.args, 3, ["traditional"]);
|
|
54412
|
+
const traditional = tradArg == null ? true : unwrap2(evalExpr(tradArg, env)) !== 0;
|
|
54413
|
+
return env.ta.pivotPointLevels(num2(first), wave11n(1, ["low"], msg), wave11n(2, ["close"], msg), traditional);
|
|
54414
|
+
}
|
|
54415
|
+
if (fname === "ta.volatility_regime_score" || fname === "volatility_regime_score") {
|
|
54416
|
+
const msg = "ta.volatility_regime_score() requires 4 arguments";
|
|
54417
|
+
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));
|
|
54418
|
+
}
|
|
54419
|
+
if (fname === "ta.correlation_filter" || fname === "correlation_filter") {
|
|
54420
|
+
const msg = "ta.correlation_filter() requires 5 arguments";
|
|
54421
|
+
const s1 = wave13v(0, ["signal1_list", "signal1", "s1"], msg);
|
|
54422
|
+
const s2 = wave13v(1, ["signal2_list", "signal2", "s2"], msg);
|
|
54423
|
+
const s3 = wave13v(2, ["signal3_list", "signal3", "s3"], msg);
|
|
54424
|
+
wave11n(3, ["num_signals"], msg);
|
|
54425
|
+
return env.ta.correlationFilter(site, s1, s2, s3, wave11n(4, ["threshold"], msg));
|
|
54426
|
+
}
|
|
54427
|
+
if (fname === "ta.advanced_breakout_detector" || fname === "advanced_breakout_detector") {
|
|
54428
|
+
const msg = "ta.advanced_breakout_detector() requires 5 arguments";
|
|
54429
|
+
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));
|
|
54430
|
+
}
|
|
54431
|
+
if (fname === "ta.pullback_bounce_level" || fname === "pullback_bounce_level") {
|
|
54432
|
+
const msg = "ta.pullback_bounce_level() requires 5 arguments";
|
|
54433
|
+
const high = wave13v(0, ["high_list", "high"], msg);
|
|
54434
|
+
const low = wave13v(1, ["low_list", "low"], msg);
|
|
54435
|
+
wave13v(2, ["close_list", "close"], msg);
|
|
54436
|
+
return env.ta.pullbackBounceLevel(site, high, low, wave11n(3, ["trend_direction", "trend_dir"], msg), wave11n(4, ["lookback"], msg));
|
|
54437
|
+
}
|
|
54438
|
+
if (fname === "ta.divergence_detector" || fname === "divergence_detector") {
|
|
54439
|
+
const msg = "ta.divergence_detector() requires 3 arguments";
|
|
54440
|
+
return env.ta.divergenceDetector(site, wave13v(0, ["price_list", "price"], msg), wave13v(1, ["indicator_list", "indicator"], msg), wave11n(2, ["lookback"], msg));
|
|
54441
|
+
}
|
|
54442
|
+
if (fname === "ta.momentum_divergence" || fname === "momentum_divergence") {
|
|
54443
|
+
const msg = "ta.momentum_divergence() requires 3 arguments";
|
|
54444
|
+
return env.ta.momentumDivergence(site, wave13v(0, ["price"], msg), wave13v(1, ["momentum_fast", "mom_fast"], msg), wave13v(2, ["momentum_slow", "mom_slow"], msg));
|
|
54445
|
+
}
|
|
54446
|
+
if (fname === "ta.spread_analysis" || fname === "spread_analysis") {
|
|
54447
|
+
const msg = "ta.spread_analysis() requires 3 arguments";
|
|
54448
|
+
return env.ta.spreadAnalysis(site, wave13v(0, ["bid"], msg), wave13v(1, ["ask"], msg), wave11n(2, ["period", "length"], msg));
|
|
54449
|
+
}
|
|
54450
|
+
if (fname === "ta.employment_cycle_indicator" || fname === "employment_cycle_indicator") {
|
|
54451
|
+
const msg = "ta.employment_cycle_indicator() requires 3 arguments";
|
|
54452
|
+
return env.ta.employmentCycleIndicator(site, wave13v(0, ["cyclical_stocks", "cyclical"], msg), wave13v(1, ["defensive_stocks", "defensive"], msg), wave13v(2, ["unemployment_proxy", "unemployment"], msg));
|
|
54453
|
+
}
|
|
54454
|
+
if (fname === "ta.gdp_growth_proxy" || fname === "gdp_growth_proxy") {
|
|
54455
|
+
const msg = "ta.gdp_growth_proxy() requires 3 arguments";
|
|
54456
|
+
return env.ta.gdpGrowthProxy(site, wave13v(0, ["market_breadth", "breadth"], msg), wave13v(1, ["market_volume", "volume"], msg), wave13v(2, ["price_momentum", "momentum"], msg));
|
|
54457
|
+
}
|
|
54458
|
+
if (fname === "ta.inflation_proxy_indicator" || fname === "inflation_proxy_indicator") {
|
|
54459
|
+
const msg = "ta.inflation_proxy_indicator() requires 3 arguments";
|
|
54460
|
+
return env.ta.inflationProxyIndicator(site, wave13v(0, ["usd_index", "usd"], msg), wave13v(1, ["commodity_prices", "commodities"], msg), wave13v(2, ["bond_yields", "yields"], msg));
|
|
54461
|
+
}
|
|
54462
|
+
if (fname === "ta.expected_value" || fname === "expected_value") {
|
|
54463
|
+
const msg = "ta.expected_value() requires 2 arguments: returns, probabilities";
|
|
54464
|
+
const returns = numericList(evalExpr(wave10aArg(0, ["returns"], msg), env));
|
|
54465
|
+
const probs = numericList(evalExpr(wave10aArg(1, ["probabilities", "probs"], msg), env));
|
|
54466
|
+
if (returns.length !== probs.length)
|
|
54467
|
+
runtimeError("Returns and probabilities must have same length");
|
|
54468
|
+
return env.ta.expectedValue(returns, probs);
|
|
54469
|
+
}
|
|
54470
|
+
if (fname === "ta.gamma_levels" || fname === "gamma_levels") {
|
|
54471
|
+
const msg = "ta.gamma_levels() requires 3 arguments";
|
|
54472
|
+
const volArg = wave10aArg(0, ["volatility"], msg);
|
|
54473
|
+
const priceArg = wave10aArg(1, ["current_price", "price"], msg);
|
|
54474
|
+
const vol = isSeriesExpr(volArg, env) ? NA : num2(evalExpr(volArg, env));
|
|
54475
|
+
const price = isSeriesExpr(priceArg, env) ? NA : num2(evalExpr(priceArg, env));
|
|
54476
|
+
return env.ta.gammaLevels(vol, price, wave11n(2, ["period", "length"], msg));
|
|
54477
|
+
}
|
|
54478
|
+
if (fname === "ta.intelligent_strategy_synthesizer" || fname === "intelligent_strategy_synthesizer") {
|
|
54479
|
+
const msg = "ta.intelligent_strategy_synthesizer() requires 6 arguments";
|
|
54480
|
+
return env.ta.intelligentStrategySynthesizer(site, wave13v(0, ["trend_indicators", "trend"], msg), wave13v(1, ["momentum_indicators", "momentum"], msg), wave13v(2, ["volatility_indicators", "volatility"], msg), wave13v(3, ["volume_indicators", "volume"], msg), wave13v(4, ["market_condition", "market_regime"], msg), wave13v(5, ["risk_profile"], msg));
|
|
54481
|
+
}
|
|
54482
|
+
if (fname === "ta.signal_confluence" || fname === "signal_confluence") {
|
|
54483
|
+
const msg = "ta.signal_confluence() requires 1 argument";
|
|
54484
|
+
return env.ta.signalConfluence(wave13v(0, ["signals"], msg));
|
|
53486
54485
|
}
|
|
53487
54486
|
return;
|
|
53488
54487
|
}
|
|
@@ -53502,6 +54501,20 @@ function seriesLastCell(value) {
|
|
|
53502
54501
|
const v = unwrap2(value);
|
|
53503
54502
|
return typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
53504
54503
|
}
|
|
54504
|
+
function numericList(value) {
|
|
54505
|
+
const arr = asArray2(value);
|
|
54506
|
+
if (arr == null) {
|
|
54507
|
+
const v = unwrap2(value);
|
|
54508
|
+
return typeof v === "number" && Number.isFinite(v) ? [v] : [];
|
|
54509
|
+
}
|
|
54510
|
+
const out = [];
|
|
54511
|
+
for (let i = 0;i < arr.size(); i++) {
|
|
54512
|
+
const v = arr.get(i);
|
|
54513
|
+
if (typeof v === "number" && Number.isFinite(v))
|
|
54514
|
+
out.push(v);
|
|
54515
|
+
}
|
|
54516
|
+
return out;
|
|
54517
|
+
}
|
|
53505
54518
|
function asArray2(value) {
|
|
53506
54519
|
if (value instanceof PineArray)
|
|
53507
54520
|
return value;
|