@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/package.json
CHANGED
package/src/cli/rich.ts
CHANGED
|
@@ -193,6 +193,27 @@ const TA_METHODS = new Set([
|
|
|
193
193
|
"regime_adaptive_signal",
|
|
194
194
|
"strategy_score",
|
|
195
195
|
"breakout_detection",
|
|
196
|
+
"ema_cross_signal",
|
|
197
|
+
"momentum_filter",
|
|
198
|
+
"volatility_regime",
|
|
199
|
+
"economic_impact_score",
|
|
200
|
+
"contrarian_signal",
|
|
201
|
+
"drawdown_recovery_level",
|
|
202
|
+
"pivot_point_levels",
|
|
203
|
+
"volatility_regime_score",
|
|
204
|
+
"correlation_filter",
|
|
205
|
+
"advanced_breakout_detector",
|
|
206
|
+
"pullback_bounce_level",
|
|
207
|
+
"divergence_detector",
|
|
208
|
+
"momentum_divergence",
|
|
209
|
+
"spread_analysis",
|
|
210
|
+
"employment_cycle_indicator",
|
|
211
|
+
"gdp_growth_proxy",
|
|
212
|
+
"inflation_proxy_indicator",
|
|
213
|
+
"expected_value",
|
|
214
|
+
"gamma_levels",
|
|
215
|
+
"intelligent_strategy_synthesizer",
|
|
216
|
+
"signal_confluence",
|
|
196
217
|
]);
|
|
197
218
|
|
|
198
219
|
/**
|
|
@@ -405,6 +426,13 @@ export function emitCall(ctx: EmitCtx, node: Call, visit: VisitFn): string {
|
|
|
405
426
|
ctx.needsHeikinashi = true;
|
|
406
427
|
return `"__HEIKINASHI__"`;
|
|
407
428
|
}
|
|
429
|
+
if (name === "ticker_inherit") {
|
|
430
|
+
const fallback = pick(args, 0, ["ticker", "tickerid", "from", "source"], `"SYMBOL"`);
|
|
431
|
+
return pick(args, 1, ["symbol", "ticker"], fallback);
|
|
432
|
+
}
|
|
433
|
+
if (name === "renko" || name === "kagi" || name === "linebreak" || name === "pointfigure") {
|
|
434
|
+
return pick(args, 0, ["ticker", "tickerid", "symbol"], `"SYMBOL"`);
|
|
435
|
+
}
|
|
408
436
|
// ticker.new / standard / modify / renko / kagi / linebreak / pointfigure → first arg or "SYMBOL"
|
|
409
437
|
if (name.startsWith("ticker_")) {
|
|
410
438
|
return pick(args, 0, ["symbol", "ticker", "tickerid"], `"SYMBOL"`);
|
|
@@ -588,6 +616,10 @@ function hasSeriesArg(args: CallArgs): boolean {
|
|
|
588
616
|
return args.posNodes.some(isSeries) || Object.values(args.kwNodes).some(isSeries);
|
|
589
617
|
}
|
|
590
618
|
|
|
619
|
+
function isSeriesNode(n: expr | undefined): boolean {
|
|
620
|
+
return n != null && n.kind === "Name" && BARE_SERIES_NAMES.has(n.id);
|
|
621
|
+
}
|
|
622
|
+
|
|
591
623
|
/** True when a keyword argument named one of *names* is present (interpret hasKwarg). */
|
|
592
624
|
function hasAnyKw(args: CallArgs, names: string[]): boolean {
|
|
593
625
|
return names.some((n) => Object.hasOwn(args.kw, n));
|
|
@@ -617,6 +649,11 @@ function cellOf(expr: string): string {
|
|
|
617
649
|
return `((__c) => (__c == null ? null : typeof __c === "boolean" ? (__c ? 1 : 0) : (typeof __c === "number" && Number.isFinite(__c) ? __c : null)))(${expr})`;
|
|
618
650
|
}
|
|
619
651
|
|
|
652
|
+
/** Cell or array/object (history-based TA args keep arrays intact). */
|
|
653
|
+
function arrOrCell(expr: string): string {
|
|
654
|
+
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})`;
|
|
655
|
+
}
|
|
656
|
+
|
|
620
657
|
/**
|
|
621
658
|
* Interpret `wave10bList`: a Pine array becomes its cells; a scalar is a
|
|
622
659
|
* one-element list. Bar-mode series stay one element.
|
|
@@ -2394,8 +2431,11 @@ function emitTa(ctx: EmitCtx, method: string, args: CallArgs): string {
|
|
|
2394
2431
|
]);
|
|
2395
2432
|
}
|
|
2396
2433
|
if (method === "market_structure_pivot") {
|
|
2397
|
-
return
|
|
2398
|
-
|
|
2434
|
+
return taCall("marketStructurePivot", site, [
|
|
2435
|
+
arrOrCell(pick(args, 0, ["high_list", "high"], "null")),
|
|
2436
|
+
arrOrCell(pick(args, 1, ["low_list", "low"], "null")),
|
|
2437
|
+
cellOf(pick(args, 3, ["period", "left", "left_bars"], "null")),
|
|
2438
|
+
cellOf(pick(args, 4, ["mode", "right", "right_bars"], "null")),
|
|
2399
2439
|
]);
|
|
2400
2440
|
}
|
|
2401
2441
|
if (method === "position_sizing_score") {
|
|
@@ -2416,13 +2456,13 @@ function emitTa(ctx: EmitCtx, method: string, args: CallArgs): string {
|
|
|
2416
2456
|
]);
|
|
2417
2457
|
}
|
|
2418
2458
|
if (method === "optimal_entry_zone") {
|
|
2419
|
-
return
|
|
2459
|
+
return taCall("optimalEntryZone", site, [arrOrCell(pick(args, 2, ["close"], "null"))]);
|
|
2420
2460
|
}
|
|
2421
2461
|
if (method === "mean_reversion_entry") {
|
|
2422
|
-
return
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2462
|
+
return taCall("meanReversionEntry", site, [
|
|
2463
|
+
arrOrCell(pick(args, 0, ["price", "source"], "null")),
|
|
2464
|
+
arrOrCell(pick(args, 1, ["sma"], "null")),
|
|
2465
|
+
arrOrCell(pick(args, 2, ["stdev", "std_dev"], "null")),
|
|
2426
2466
|
cellOf(pick(args, 4, ["threshold"], "null")),
|
|
2427
2467
|
]);
|
|
2428
2468
|
}
|
|
@@ -2460,11 +2500,163 @@ function emitTa(ctx: EmitCtx, method: string, args: CallArgs): string {
|
|
|
2460
2500
|
]);
|
|
2461
2501
|
}
|
|
2462
2502
|
if (method === "breakout_detection") {
|
|
2503
|
+
const arg = (i: number, names: string[]): string =>
|
|
2504
|
+
isSeriesNode(args.posNodes[i]) ? "null" : cellOf(pick(args, i, names, "null"));
|
|
2463
2505
|
return taPure("breakoutDetection", [
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2506
|
+
arg(0, ["close", "source"]),
|
|
2507
|
+
arg(1, ["resistance"]),
|
|
2508
|
+
arg(2, ["support"]),
|
|
2509
|
+
]);
|
|
2510
|
+
}
|
|
2511
|
+
if (method === "ema_cross_signal") {
|
|
2512
|
+
return taCall("emaCrossSignal", site, [
|
|
2513
|
+
cellOf(pick(args, 0, ["fast_ema", "fast"], "null")),
|
|
2514
|
+
cellOf(pick(args, 1, ["slow_ema", "slow"], "null")),
|
|
2515
|
+
cellOf(pick(args, 2, ["threshold"], "null")),
|
|
2516
|
+
]);
|
|
2517
|
+
}
|
|
2518
|
+
if (method === "momentum_filter") {
|
|
2519
|
+
return taCall("momentumFilter", site, [
|
|
2520
|
+
cellOf(pick(args, 0, ["momentum_raw", "momentum"], "null")),
|
|
2521
|
+
cellOf(pick(args, 1, ["volume"], "null")),
|
|
2522
|
+
cellOf(pick(args, 2, ["period", "length"], "null")),
|
|
2523
|
+
]);
|
|
2524
|
+
}
|
|
2525
|
+
if (method === "volatility_regime") {
|
|
2526
|
+
return taCall("volatilityRegime", site, [
|
|
2527
|
+
cellOf(pick(args, 0, ["atr_series", "atr", "source"], "null")),
|
|
2528
|
+
cellOf(pick(args, 1, ["period", "length"], "null")),
|
|
2529
|
+
]);
|
|
2530
|
+
}
|
|
2531
|
+
if (method === "economic_impact_score") {
|
|
2532
|
+
return taPure("economicImpactScore", [
|
|
2533
|
+
cellOf(pick(args, 0, ["price_change"], "null")),
|
|
2534
|
+
cellOf(pick(args, 1, ["volatility"], "null")),
|
|
2535
|
+
cellOf(pick(args, 2, ["volume_change"], "null")),
|
|
2536
|
+
]);
|
|
2537
|
+
}
|
|
2538
|
+
if (method === "contrarian_signal") {
|
|
2539
|
+
return taPure("contrarianSignal", [
|
|
2540
|
+
cellOf(pick(args, 0, ["sentiment"], "null")),
|
|
2541
|
+
cellOf(pick(args, 1, ["volatility"], "null")),
|
|
2542
|
+
cellOf(pick(args, 2, ["time_since_extreme", "time_extreme"], "null")),
|
|
2543
|
+
]);
|
|
2544
|
+
}
|
|
2545
|
+
if (method === "drawdown_recovery_level") {
|
|
2546
|
+
return taPure("drawdownRecoveryLevel", [
|
|
2547
|
+
cellOf(pick(args, 0, ["peak"], "null")),
|
|
2548
|
+
cellOf(pick(args, 1, ["current", "current_price"], "null")),
|
|
2549
|
+
cellOf(pick(args, 2, ["recovery_factor", "factor"], "null")),
|
|
2550
|
+
cellOf(pick(args, 3, ["period", "length"], "null")),
|
|
2467
2551
|
]);
|
|
2468
2552
|
}
|
|
2553
|
+
if (method === "pivot_point_levels") {
|
|
2554
|
+
return taPure("pivotPointLevels", [
|
|
2555
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
2556
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
2557
|
+
cellOf(pick(args, 2, ["close"], "null")),
|
|
2558
|
+
pick(args, 3, ["traditional"], "true"),
|
|
2559
|
+
]);
|
|
2560
|
+
}
|
|
2561
|
+
if (method === "volatility_regime_score") {
|
|
2562
|
+
return taCall("volatilityRegimeScore", site, [
|
|
2563
|
+
arrOrCell(pick(args, 0, ["atr_list", "atr"], "null")),
|
|
2564
|
+
arrOrCell(pick(args, 1, ["volatility_list", "volatility"], "null")),
|
|
2565
|
+
arrOrCell(pick(args, 2, ["vix_list", "vix"], "null")),
|
|
2566
|
+
cellOf(pick(args, 3, ["threshold"], "null")),
|
|
2567
|
+
]);
|
|
2568
|
+
}
|
|
2569
|
+
if (method === "correlation_filter") {
|
|
2570
|
+
return taCall("correlationFilter", site, [
|
|
2571
|
+
arrOrCell(pick(args, 0, ["signal1_list", "signal1", "s1"], "null")),
|
|
2572
|
+
arrOrCell(pick(args, 1, ["signal2_list", "signal2", "s2"], "null")),
|
|
2573
|
+
arrOrCell(pick(args, 2, ["signal3_list", "signal3", "s3"], "null")),
|
|
2574
|
+
cellOf(pick(args, 4, ["threshold"], "null")),
|
|
2575
|
+
]);
|
|
2576
|
+
}
|
|
2577
|
+
if (method === "advanced_breakout_detector") {
|
|
2578
|
+
return taCall("advancedBreakoutDetector", site, [
|
|
2579
|
+
arrOrCell(pick(args, 0, ["price_list", "price"], "null")),
|
|
2580
|
+
arrOrCell(pick(args, 1, ["volume_list", "volume"], "null")),
|
|
2581
|
+
cellOf(pick(args, 2, ["level"], "null")),
|
|
2582
|
+
cellOf(pick(args, 3, ["lookback"], "null")),
|
|
2583
|
+
cellOf(pick(args, 4, ["volume_multiplier", "vol_mult"], "null")),
|
|
2584
|
+
]);
|
|
2585
|
+
}
|
|
2586
|
+
if (method === "pullback_bounce_level") {
|
|
2587
|
+
return taCall("pullbackBounceLevel", site, [
|
|
2588
|
+
arrOrCell(pick(args, 0, ["high_list", "high"], "null")),
|
|
2589
|
+
arrOrCell(pick(args, 1, ["low_list", "low"], "null")),
|
|
2590
|
+
cellOf(pick(args, 3, ["trend_direction", "trend_dir"], "null")),
|
|
2591
|
+
cellOf(pick(args, 4, ["lookback"], "null")),
|
|
2592
|
+
]);
|
|
2593
|
+
}
|
|
2594
|
+
if (method === "divergence_detector") {
|
|
2595
|
+
return taCall("divergenceDetector", site, [
|
|
2596
|
+
arrOrCell(pick(args, 0, ["price_list", "price"], "null")),
|
|
2597
|
+
arrOrCell(pick(args, 1, ["indicator_list", "indicator"], "null")),
|
|
2598
|
+
cellOf(pick(args, 2, ["lookback"], "null")),
|
|
2599
|
+
]);
|
|
2600
|
+
}
|
|
2601
|
+
if (method === "momentum_divergence") {
|
|
2602
|
+
return taCall("momentumDivergence", site, [
|
|
2603
|
+
arrOrCell(pick(args, 0, ["price"], "null")),
|
|
2604
|
+
arrOrCell(pick(args, 1, ["momentum_fast", "mom_fast"], "null")),
|
|
2605
|
+
arrOrCell(pick(args, 2, ["momentum_slow", "mom_slow"], "null")),
|
|
2606
|
+
]);
|
|
2607
|
+
}
|
|
2608
|
+
if (method === "spread_analysis") {
|
|
2609
|
+
return taCall("spreadAnalysis", site, [
|
|
2610
|
+
arrOrCell(pick(args, 0, ["bid"], "null")),
|
|
2611
|
+
arrOrCell(pick(args, 1, ["ask"], "null")),
|
|
2612
|
+
cellOf(pick(args, 2, ["period", "length"], "null")),
|
|
2613
|
+
]);
|
|
2614
|
+
}
|
|
2615
|
+
if (method === "employment_cycle_indicator") {
|
|
2616
|
+
return taCall("employmentCycleIndicator", site, [
|
|
2617
|
+
arrOrCell(pick(args, 0, ["cyclical_stocks", "cyclical"], "null")),
|
|
2618
|
+
arrOrCell(pick(args, 1, ["defensive_stocks", "defensive"], "null")),
|
|
2619
|
+
arrOrCell(pick(args, 2, ["unemployment_proxy", "unemployment"], "null")),
|
|
2620
|
+
]);
|
|
2621
|
+
}
|
|
2622
|
+
if (method === "gdp_growth_proxy") {
|
|
2623
|
+
return taCall("gdpGrowthProxy", site, [
|
|
2624
|
+
arrOrCell(pick(args, 0, ["market_breadth", "breadth"], "null")),
|
|
2625
|
+
arrOrCell(pick(args, 1, ["market_volume", "volume"], "null")),
|
|
2626
|
+
arrOrCell(pick(args, 2, ["price_momentum", "momentum"], "null")),
|
|
2627
|
+
]);
|
|
2628
|
+
}
|
|
2629
|
+
if (method === "inflation_proxy_indicator") {
|
|
2630
|
+
return taCall("inflationProxyIndicator", site, [
|
|
2631
|
+
arrOrCell(pick(args, 0, ["usd_index", "usd"], "null")),
|
|
2632
|
+
arrOrCell(pick(args, 1, ["commodity_prices", "commodities"], "null")),
|
|
2633
|
+
arrOrCell(pick(args, 2, ["bond_yields", "yields"], "null")),
|
|
2634
|
+
]);
|
|
2635
|
+
}
|
|
2636
|
+
if (method === "expected_value") {
|
|
2637
|
+
return `__h.ta.expectedValue(${cellList(pick(args, 0, ["returns"], "null"))}, ${cellList(pick(args, 1, ["probabilities", "probs"], "null"))})`;
|
|
2638
|
+
}
|
|
2639
|
+
if (method === "gamma_levels") {
|
|
2640
|
+
const vol = isSeriesNode(args.posNodes[0])
|
|
2641
|
+
? "null"
|
|
2642
|
+
: cellOf(pick(args, 0, ["volatility"], "null"));
|
|
2643
|
+
const price = isSeriesNode(args.posNodes[1])
|
|
2644
|
+
? "null"
|
|
2645
|
+
: cellOf(pick(args, 1, ["current_price", "price"], "null"));
|
|
2646
|
+
return taPure("gammaLevels", [vol, price, cellOf(pick(args, 2, ["period", "length"], "null"))]);
|
|
2647
|
+
}
|
|
2648
|
+
if (method === "intelligent_strategy_synthesizer") {
|
|
2649
|
+
return taCall("intelligentStrategySynthesizer", site, [
|
|
2650
|
+
arrOrCell(pick(args, 0, ["trend_indicators", "trend"], "null")),
|
|
2651
|
+
arrOrCell(pick(args, 1, ["momentum_indicators", "momentum"], "null")),
|
|
2652
|
+
arrOrCell(pick(args, 2, ["volatility_indicators", "volatility"], "null")),
|
|
2653
|
+
arrOrCell(pick(args, 3, ["volume_indicators", "volume"], "null")),
|
|
2654
|
+
pick(args, 4, ["market_condition", "market_regime"], '"ranging"'),
|
|
2655
|
+
pick(args, 5, ["risk_profile"], '"balanced"'),
|
|
2656
|
+
]);
|
|
2657
|
+
}
|
|
2658
|
+
if (method === "signal_confluence") {
|
|
2659
|
+
return taPure("signalConfluence", [pick(args, 0, ["signals"], "null")]);
|
|
2660
|
+
}
|
|
2469
2661
|
return "null";
|
|
2470
2662
|
}
|
package/src/runtime/interpret.ts
CHANGED
|
@@ -2105,6 +2105,39 @@ function evalCall(node: Call, env: Env): Value {
|
|
|
2105
2105
|
evalAsString(callArg(node.args, 3, ["adjust", "adjustment"]), env) ?? undefined,
|
|
2106
2106
|
});
|
|
2107
2107
|
}
|
|
2108
|
+
if (fname === "ticker.inherit") {
|
|
2109
|
+
const first = evalExpr(callArg(node.args, 0, ["ticker", "tickerid", "from", "source"]), env);
|
|
2110
|
+
const secondArg = callArg(node.args, 1, ["symbol", "ticker"]);
|
|
2111
|
+
if (secondArg != null) {
|
|
2112
|
+
const target = evalExpr(secondArg, env);
|
|
2113
|
+
const sym =
|
|
2114
|
+
target instanceof TickerId
|
|
2115
|
+
? target.symbol
|
|
2116
|
+
: typeof target === "string"
|
|
2117
|
+
? target
|
|
2118
|
+
: env.symbol;
|
|
2119
|
+
if (first instanceof TickerId) return tickerNew(sym, first.session, first.adjust);
|
|
2120
|
+
return tickerNew(sym);
|
|
2121
|
+
}
|
|
2122
|
+
if (first instanceof TickerId) {
|
|
2123
|
+
return tickerNew(first.symbol, first.session, first.adjust);
|
|
2124
|
+
}
|
|
2125
|
+
const sym = typeof first === "string" ? first : env.symbol;
|
|
2126
|
+
return tickerNew(sym);
|
|
2127
|
+
}
|
|
2128
|
+
if (
|
|
2129
|
+
fname === "renko" ||
|
|
2130
|
+
fname === "kagi" ||
|
|
2131
|
+
fname === "linebreak" ||
|
|
2132
|
+
fname === "pointfigure"
|
|
2133
|
+
) {
|
|
2134
|
+
const raw = evalExpr(callArg(node.args, 0, ["ticker", "tickerid", "symbol"]), env);
|
|
2135
|
+
const sym = raw instanceof TickerId ? raw.symbol : typeof raw === "string" ? raw : env.symbol;
|
|
2136
|
+
if (fname === "renko") return tickerRenko(sym);
|
|
2137
|
+
if (fname === "kagi") return tickerKagi(sym);
|
|
2138
|
+
if (fname === "linebreak") return tickerLinebreak(sym);
|
|
2139
|
+
return tickerPointfigure(sym);
|
|
2140
|
+
}
|
|
2108
2141
|
const mapVal = evalMapCall(fname, node, env);
|
|
2109
2142
|
if (mapVal !== undefined) return mapVal;
|
|
2110
2143
|
const matrixVal = evalMatrixCall(fname, node, env);
|
|
@@ -3841,7 +3874,7 @@ function evalExtraTa(fname: string | null, node: Call, env: Env, site: string):
|
|
|
3841
3874
|
lenArg(node, env, 1),
|
|
3842
3875
|
);
|
|
3843
3876
|
}
|
|
3844
|
-
if (fname === "ta.percentile_nearest_rank") {
|
|
3877
|
+
if (fname === "ta.percentile_nearest_rank" || fname === "percentile_nearest_rank") {
|
|
3845
3878
|
if (typeof ta.percentileNearest !== "function") return NA;
|
|
3846
3879
|
return (ta.percentileNearest as TaEngine["percentileNearest"]).call(
|
|
3847
3880
|
env.ta,
|
|
@@ -3851,7 +3884,7 @@ function evalExtraTa(fname: string | null, node: Call, env: Env, site: string):
|
|
|
3851
3884
|
lenOrDefault(node, env, 2, ["percentage", "percent"], 50),
|
|
3852
3885
|
);
|
|
3853
3886
|
}
|
|
3854
|
-
if (fname === "ta.percentile_linear_interpolation") {
|
|
3887
|
+
if (fname === "ta.percentile_linear_interpolation" || fname === "percentile_linear_interpolation") {
|
|
3855
3888
|
if (typeof ta.percentileLinear !== "function") return NA;
|
|
3856
3889
|
return (ta.percentileLinear as TaEngine["percentileLinear"]).call(
|
|
3857
3890
|
env.ta,
|
|
@@ -4049,17 +4082,6 @@ function evalExtraTa(fname: string | null, node: Call, env: Env, site: string):
|
|
|
4049
4082
|
const r = env.ta.aroon(site, num(env.ctx.high), num(env.ctx.low), length ?? 14);
|
|
4050
4083
|
return tupleOf([r.down, r.up]);
|
|
4051
4084
|
}
|
|
4052
|
-
if (fname === "ta.pivot_point_levels") {
|
|
4053
|
-
if (typeof ta.pivotPoints !== "function") return NA;
|
|
4054
|
-
const r = (ta.pivotPoints as TaEngine["pivotPoints"]).call(
|
|
4055
|
-
env.ta,
|
|
4056
|
-
site,
|
|
4057
|
-
num(env.ctx.high),
|
|
4058
|
-
num(env.ctx.low),
|
|
4059
|
-
num(env.ctx.close),
|
|
4060
|
-
);
|
|
4061
|
-
return tupleOf([r.pp, r.r1, r.s1, r.r2, r.s2]);
|
|
4062
|
-
}
|
|
4063
4085
|
if (fname === "ta.uo" || fname === "uo") {
|
|
4064
4086
|
return env.ta.uo(
|
|
4065
4087
|
site,
|
|
@@ -4300,6 +4322,8 @@ function evalExtraTa(fname: string | null, node: Call, env: Env, site: string):
|
|
|
4300
4322
|
unwrap(evalExpr(wave10aArg(index, names, message), env));
|
|
4301
4323
|
const wave11n = (index: number, names: string[], message: string): Cell =>
|
|
4302
4324
|
num(wave11(index, names, message));
|
|
4325
|
+
const wave13v = (index: number, names: string[], message: string): Value =>
|
|
4326
|
+
evalExpr(wave10aArg(index, names, message), env);
|
|
4303
4327
|
if (fname === "ta.sma_weighted" || fname === "sma_weighted") {
|
|
4304
4328
|
const msg = "ta.sma_weighted() requires at least 2 arguments: series, period";
|
|
4305
4329
|
const weightArg = callArg(node.args, 2, ["weight_type", "weight"]);
|
|
@@ -4566,12 +4590,12 @@ function evalExtraTa(fname: string | null, node: Call, env: Env, site: string):
|
|
|
4566
4590
|
}
|
|
4567
4591
|
if (fname === "ta.market_structure_pivot" || fname === "market_structure_pivot") {
|
|
4568
4592
|
const msg = "ta.market_structure_pivot() requires 5 arguments";
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
wave11n(3, ["left", "left_bars"], msg);
|
|
4573
|
-
wave11n(4, ["right", "right_bars"], msg);
|
|
4574
|
-
return env.ta.marketStructurePivot(
|
|
4593
|
+
const high = wave13v(0, ["high_list", "high"], msg);
|
|
4594
|
+
const low = wave13v(1, ["low_list", "low"], msg);
|
|
4595
|
+
wave13v(2, ["close_list", "close"], msg);
|
|
4596
|
+
const period = wave11n(3, ["period", "left", "left_bars"], msg);
|
|
4597
|
+
const mode = wave11n(4, ["mode", "right", "right_bars"], msg);
|
|
4598
|
+
return env.ta.marketStructurePivot(site, high, low, period, mode);
|
|
4575
4599
|
}
|
|
4576
4600
|
if (fname === "ta.position_sizing_score" || fname === "position_sizing_score") {
|
|
4577
4601
|
const msg = "ta.position_sizing_score() requires 4 arguments";
|
|
@@ -4596,16 +4620,17 @@ function evalExtraTa(fname: string | null, node: Call, env: Env, site: string):
|
|
|
4596
4620
|
const msg = "ta.optimal_entry_zone() requires 4 arguments";
|
|
4597
4621
|
wave11n(0, ["high"], msg);
|
|
4598
4622
|
wave11n(1, ["low"], msg);
|
|
4599
|
-
const close =
|
|
4623
|
+
const close = wave13v(2, ["close"], msg);
|
|
4600
4624
|
wave11n(3, ["period", "length"], msg);
|
|
4601
|
-
return env.ta.optimalEntryZone(close);
|
|
4625
|
+
return env.ta.optimalEntryZone(site, close);
|
|
4602
4626
|
}
|
|
4603
4627
|
if (fname === "ta.mean_reversion_entry" || fname === "mean_reversion_entry") {
|
|
4604
4628
|
const msg = "ta.mean_reversion_entry() requires 5 arguments";
|
|
4605
4629
|
return env.ta.meanReversionEntry(
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4630
|
+
site,
|
|
4631
|
+
wave13v(0, ["price", "source"], msg),
|
|
4632
|
+
wave13v(1, ["sma"], msg),
|
|
4633
|
+
wave13v(2, ["stdev", "std_dev"], msg),
|
|
4609
4634
|
wave11n(4, ["threshold"], msg),
|
|
4610
4635
|
);
|
|
4611
4636
|
}
|
|
@@ -4648,13 +4673,226 @@ function evalExtraTa(fname: string | null, node: Call, env: Env, site: string):
|
|
|
4648
4673
|
}
|
|
4649
4674
|
if (fname === "ta.breakout_detection" || fname === "breakout_detection") {
|
|
4650
4675
|
const msg = "ta.breakout_detection() requires 3 arguments";
|
|
4676
|
+
const arg = (i: number, names: string[]): Cell => {
|
|
4677
|
+
const e = wave10aArg(i, names, msg);
|
|
4678
|
+
return isSeriesExpr(e, env) ? NA : num(evalExpr(e, env));
|
|
4679
|
+
};
|
|
4651
4680
|
return env.ta.breakoutDetection(
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4681
|
+
arg(0, ["close", "source"]),
|
|
4682
|
+
arg(1, ["resistance"]),
|
|
4683
|
+
arg(2, ["support"]),
|
|
4655
4684
|
);
|
|
4656
4685
|
}
|
|
4657
4686
|
// wave12-end
|
|
4687
|
+
// wave13-start — history / sentiment / macro analytics
|
|
4688
|
+
if (fname === "ta.ema_cross_signal" || fname === "ema_cross_signal") {
|
|
4689
|
+
const msg = "ta.ema_cross_signal() requires 3 arguments";
|
|
4690
|
+
return env.ta.emaCrossSignal(
|
|
4691
|
+
site,
|
|
4692
|
+
wave11n(0, ["fast_ema", "fast"], msg),
|
|
4693
|
+
wave11n(1, ["slow_ema", "slow"], msg),
|
|
4694
|
+
wave11n(2, ["threshold"], msg),
|
|
4695
|
+
);
|
|
4696
|
+
}
|
|
4697
|
+
if (fname === "ta.momentum_filter" || fname === "momentum_filter") {
|
|
4698
|
+
const msg = "ta.momentum_filter() requires 3 arguments";
|
|
4699
|
+
return env.ta.momentumFilter(
|
|
4700
|
+
site,
|
|
4701
|
+
wave11n(0, ["momentum_raw", "momentum"], msg),
|
|
4702
|
+
wave11n(1, ["volume"], msg),
|
|
4703
|
+
wave11n(2, ["period", "length"], msg),
|
|
4704
|
+
);
|
|
4705
|
+
}
|
|
4706
|
+
if (fname === "ta.volatility_regime" || fname === "volatility_regime") {
|
|
4707
|
+
const msg = "ta.volatility_regime() requires 2 arguments";
|
|
4708
|
+
return env.ta.volatilityRegime(
|
|
4709
|
+
site,
|
|
4710
|
+
wave11n(0, ["atr_series", "atr", "source"], msg),
|
|
4711
|
+
wave11n(1, ["period", "length"], msg),
|
|
4712
|
+
);
|
|
4713
|
+
}
|
|
4714
|
+
if (fname === "ta.economic_impact_score" || fname === "economic_impact_score") {
|
|
4715
|
+
const msg = "ta.economic_impact_score() requires 3 arguments";
|
|
4716
|
+
return env.ta.economicImpactScore(
|
|
4717
|
+
wave11n(0, ["price_change"], msg),
|
|
4718
|
+
wave11n(1, ["volatility"], msg),
|
|
4719
|
+
wave11n(2, ["volume_change"], msg),
|
|
4720
|
+
);
|
|
4721
|
+
}
|
|
4722
|
+
if (fname === "ta.contrarian_signal" || fname === "contrarian_signal") {
|
|
4723
|
+
const msg = "ta.contrarian_signal() requires 3 arguments";
|
|
4724
|
+
return env.ta.contrarianSignal(
|
|
4725
|
+
wave11n(0, ["sentiment"], msg),
|
|
4726
|
+
wave11n(1, ["volatility"], msg),
|
|
4727
|
+
wave11n(2, ["time_since_extreme", "time_extreme"], msg),
|
|
4728
|
+
);
|
|
4729
|
+
}
|
|
4730
|
+
if (fname === "ta.drawdown_recovery_level" || fname === "drawdown_recovery_level") {
|
|
4731
|
+
const msg = "ta.drawdown_recovery_level() requires 4 arguments";
|
|
4732
|
+
return env.ta.drawdownRecoveryLevel(
|
|
4733
|
+
wave11n(0, ["peak"], msg),
|
|
4734
|
+
wave11n(1, ["current", "current_price"], msg),
|
|
4735
|
+
wave11n(2, ["recovery_factor", "factor"], msg),
|
|
4736
|
+
wave11n(3, ["period", "length"], msg),
|
|
4737
|
+
);
|
|
4738
|
+
}
|
|
4739
|
+
if (fname === "ta.pivot_point_levels" || fname === "pivot_point_levels") {
|
|
4740
|
+
const msg = "ta.pivot_point_levels() requires type+anchor or high, low, close";
|
|
4741
|
+
const first = wave11(0, ["type", "high"], msg);
|
|
4742
|
+
if (typeof first === "string") {
|
|
4743
|
+
// Reference Pine type+anchor form → context pivot-point tuple.
|
|
4744
|
+
if (typeof env.ta.pivotPoints !== "function") return NA;
|
|
4745
|
+
const r = (env.ta.pivotPoints as TaEngine["pivotPoints"]).call(
|
|
4746
|
+
env.ta,
|
|
4747
|
+
site,
|
|
4748
|
+
num(env.ctx.high),
|
|
4749
|
+
num(env.ctx.low),
|
|
4750
|
+
num(env.ctx.close),
|
|
4751
|
+
);
|
|
4752
|
+
return tupleOf([r.pp, r.r1, r.s1, r.r2, r.s2]);
|
|
4753
|
+
}
|
|
4754
|
+
const tradArg = callArg(node.args, 3, ["traditional"]);
|
|
4755
|
+
const traditional = tradArg == null ? true : unwrap(evalExpr(tradArg, env)) !== 0;
|
|
4756
|
+
return env.ta.pivotPointLevels(
|
|
4757
|
+
num(first),
|
|
4758
|
+
wave11n(1, ["low"], msg),
|
|
4759
|
+
wave11n(2, ["close"], msg),
|
|
4760
|
+
traditional,
|
|
4761
|
+
);
|
|
4762
|
+
}
|
|
4763
|
+
if (fname === "ta.volatility_regime_score" || fname === "volatility_regime_score") {
|
|
4764
|
+
const msg = "ta.volatility_regime_score() requires 4 arguments";
|
|
4765
|
+
return env.ta.volatilityRegimeScore(
|
|
4766
|
+
site,
|
|
4767
|
+
wave13v(0, ["atr_list", "atr"], msg),
|
|
4768
|
+
wave13v(1, ["volatility_list", "volatility"], msg),
|
|
4769
|
+
wave13v(2, ["vix_list", "vix"], msg),
|
|
4770
|
+
wave11n(3, ["threshold"], msg),
|
|
4771
|
+
);
|
|
4772
|
+
}
|
|
4773
|
+
if (fname === "ta.correlation_filter" || fname === "correlation_filter") {
|
|
4774
|
+
const msg = "ta.correlation_filter() requires 5 arguments";
|
|
4775
|
+
const s1 = wave13v(0, ["signal1_list", "signal1", "s1"], msg);
|
|
4776
|
+
const s2 = wave13v(1, ["signal2_list", "signal2", "s2"], msg);
|
|
4777
|
+
const s3 = wave13v(2, ["signal3_list", "signal3", "s3"], msg);
|
|
4778
|
+
wave11n(3, ["num_signals"], msg);
|
|
4779
|
+
return env.ta.correlationFilter(site, s1, s2, s3, wave11n(4, ["threshold"], msg));
|
|
4780
|
+
}
|
|
4781
|
+
if (fname === "ta.advanced_breakout_detector" || fname === "advanced_breakout_detector") {
|
|
4782
|
+
const msg = "ta.advanced_breakout_detector() requires 5 arguments";
|
|
4783
|
+
return env.ta.advancedBreakoutDetector(
|
|
4784
|
+
site,
|
|
4785
|
+
wave13v(0, ["price_list", "price"], msg),
|
|
4786
|
+
wave13v(1, ["volume_list", "volume"], msg),
|
|
4787
|
+
wave11n(2, ["level"], msg),
|
|
4788
|
+
wave11n(3, ["lookback"], msg),
|
|
4789
|
+
wave11n(4, ["volume_multiplier", "vol_mult"], msg),
|
|
4790
|
+
);
|
|
4791
|
+
}
|
|
4792
|
+
if (fname === "ta.pullback_bounce_level" || fname === "pullback_bounce_level") {
|
|
4793
|
+
const msg = "ta.pullback_bounce_level() requires 5 arguments";
|
|
4794
|
+
const high = wave13v(0, ["high_list", "high"], msg);
|
|
4795
|
+
const low = wave13v(1, ["low_list", "low"], msg);
|
|
4796
|
+
wave13v(2, ["close_list", "close"], msg);
|
|
4797
|
+
return env.ta.pullbackBounceLevel(
|
|
4798
|
+
site,
|
|
4799
|
+
high,
|
|
4800
|
+
low,
|
|
4801
|
+
wave11n(3, ["trend_direction", "trend_dir"], msg),
|
|
4802
|
+
wave11n(4, ["lookback"], msg),
|
|
4803
|
+
);
|
|
4804
|
+
}
|
|
4805
|
+
if (fname === "ta.divergence_detector" || fname === "divergence_detector") {
|
|
4806
|
+
const msg = "ta.divergence_detector() requires 3 arguments";
|
|
4807
|
+
return env.ta.divergenceDetector(
|
|
4808
|
+
site,
|
|
4809
|
+
wave13v(0, ["price_list", "price"], msg),
|
|
4810
|
+
wave13v(1, ["indicator_list", "indicator"], msg),
|
|
4811
|
+
wave11n(2, ["lookback"], msg),
|
|
4812
|
+
);
|
|
4813
|
+
}
|
|
4814
|
+
if (fname === "ta.momentum_divergence" || fname === "momentum_divergence") {
|
|
4815
|
+
const msg = "ta.momentum_divergence() requires 3 arguments";
|
|
4816
|
+
return env.ta.momentumDivergence(
|
|
4817
|
+
site,
|
|
4818
|
+
wave13v(0, ["price"], msg),
|
|
4819
|
+
wave13v(1, ["momentum_fast", "mom_fast"], msg),
|
|
4820
|
+
wave13v(2, ["momentum_slow", "mom_slow"], msg),
|
|
4821
|
+
);
|
|
4822
|
+
}
|
|
4823
|
+
if (fname === "ta.spread_analysis" || fname === "spread_analysis") {
|
|
4824
|
+
const msg = "ta.spread_analysis() requires 3 arguments";
|
|
4825
|
+
return env.ta.spreadAnalysis(
|
|
4826
|
+
site,
|
|
4827
|
+
wave13v(0, ["bid"], msg),
|
|
4828
|
+
wave13v(1, ["ask"], msg),
|
|
4829
|
+
wave11n(2, ["period", "length"], msg),
|
|
4830
|
+
);
|
|
4831
|
+
}
|
|
4832
|
+
if (fname === "ta.employment_cycle_indicator" || fname === "employment_cycle_indicator") {
|
|
4833
|
+
const msg = "ta.employment_cycle_indicator() requires 3 arguments";
|
|
4834
|
+
return env.ta.employmentCycleIndicator(
|
|
4835
|
+
site,
|
|
4836
|
+
wave13v(0, ["cyclical_stocks", "cyclical"], msg),
|
|
4837
|
+
wave13v(1, ["defensive_stocks", "defensive"], msg),
|
|
4838
|
+
wave13v(2, ["unemployment_proxy", "unemployment"], msg),
|
|
4839
|
+
);
|
|
4840
|
+
}
|
|
4841
|
+
if (fname === "ta.gdp_growth_proxy" || fname === "gdp_growth_proxy") {
|
|
4842
|
+
const msg = "ta.gdp_growth_proxy() requires 3 arguments";
|
|
4843
|
+
return env.ta.gdpGrowthProxy(
|
|
4844
|
+
site,
|
|
4845
|
+
wave13v(0, ["market_breadth", "breadth"], msg),
|
|
4846
|
+
wave13v(1, ["market_volume", "volume"], msg),
|
|
4847
|
+
wave13v(2, ["price_momentum", "momentum"], msg),
|
|
4848
|
+
);
|
|
4849
|
+
}
|
|
4850
|
+
if (fname === "ta.inflation_proxy_indicator" || fname === "inflation_proxy_indicator") {
|
|
4851
|
+
const msg = "ta.inflation_proxy_indicator() requires 3 arguments";
|
|
4852
|
+
return env.ta.inflationProxyIndicator(
|
|
4853
|
+
site,
|
|
4854
|
+
wave13v(0, ["usd_index", "usd"], msg),
|
|
4855
|
+
wave13v(1, ["commodity_prices", "commodities"], msg),
|
|
4856
|
+
wave13v(2, ["bond_yields", "yields"], msg),
|
|
4857
|
+
);
|
|
4858
|
+
}
|
|
4859
|
+
if (fname === "ta.expected_value" || fname === "expected_value") {
|
|
4860
|
+
const msg = "ta.expected_value() requires 2 arguments: returns, probabilities";
|
|
4861
|
+
const returns = numericList(evalExpr(wave10aArg(0, ["returns"], msg), env));
|
|
4862
|
+
const probs = numericList(evalExpr(wave10aArg(1, ["probabilities", "probs"], msg), env));
|
|
4863
|
+
if (returns.length !== probs.length) runtimeError("Returns and probabilities must have same length");
|
|
4864
|
+
return env.ta.expectedValue(returns, probs);
|
|
4865
|
+
}
|
|
4866
|
+
// wave13-end
|
|
4867
|
+
// wave14-start — list-return + capstone synthesis
|
|
4868
|
+
if (fname === "ta.gamma_levels" || fname === "gamma_levels") {
|
|
4869
|
+
const msg = "ta.gamma_levels() requires 3 arguments";
|
|
4870
|
+
const volArg = wave10aArg(0, ["volatility"], msg);
|
|
4871
|
+
const priceArg = wave10aArg(1, ["current_price", "price"], msg);
|
|
4872
|
+
const vol = isSeriesExpr(volArg, env) ? NA : num(evalExpr(volArg, env));
|
|
4873
|
+
const price = isSeriesExpr(priceArg, env) ? NA : num(evalExpr(priceArg, env));
|
|
4874
|
+
return env.ta.gammaLevels(vol, price, wave11n(2, ["period", "length"], msg));
|
|
4875
|
+
}
|
|
4876
|
+
if (
|
|
4877
|
+
fname === "ta.intelligent_strategy_synthesizer" ||
|
|
4878
|
+
fname === "intelligent_strategy_synthesizer"
|
|
4879
|
+
) {
|
|
4880
|
+
const msg = "ta.intelligent_strategy_synthesizer() requires 6 arguments";
|
|
4881
|
+
return env.ta.intelligentStrategySynthesizer(
|
|
4882
|
+
site,
|
|
4883
|
+
wave13v(0, ["trend_indicators", "trend"], msg),
|
|
4884
|
+
wave13v(1, ["momentum_indicators", "momentum"], msg),
|
|
4885
|
+
wave13v(2, ["volatility_indicators", "volatility"], msg),
|
|
4886
|
+
wave13v(3, ["volume_indicators", "volume"], msg),
|
|
4887
|
+
wave13v(4, ["market_condition", "market_regime"], msg),
|
|
4888
|
+
wave13v(5, ["risk_profile"], msg),
|
|
4889
|
+
);
|
|
4890
|
+
}
|
|
4891
|
+
if (fname === "ta.signal_confluence" || fname === "signal_confluence") {
|
|
4892
|
+
const msg = "ta.signal_confluence() requires 1 argument";
|
|
4893
|
+
return env.ta.signalConfluence(wave13v(0, ["signals"], msg));
|
|
4894
|
+
}
|
|
4895
|
+
// wave14-end
|
|
4658
4896
|
return undefined;
|
|
4659
4897
|
}
|
|
4660
4898
|
|
|
@@ -4676,6 +4914,21 @@ function seriesLastCell(value: Value): number | null {
|
|
|
4676
4914
|
return typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
4677
4915
|
}
|
|
4678
4916
|
|
|
4917
|
+
/** Python `_expect_list` for array-valued args: numeric cells only. */
|
|
4918
|
+
function numericList(value: Value): number[] {
|
|
4919
|
+
const arr = asArray(value);
|
|
4920
|
+
if (arr == null) {
|
|
4921
|
+
const v = unwrap(value);
|
|
4922
|
+
return typeof v === "number" && Number.isFinite(v) ? [v] : [];
|
|
4923
|
+
}
|
|
4924
|
+
const out: number[] = [];
|
|
4925
|
+
for (let i = 0; i < arr.size(); i++) {
|
|
4926
|
+
const v = arr.get(i);
|
|
4927
|
+
if (typeof v === "number" && Number.isFinite(v)) out.push(v);
|
|
4928
|
+
}
|
|
4929
|
+
return out;
|
|
4930
|
+
}
|
|
4931
|
+
|
|
4679
4932
|
function asArray(value: Value): PineArray | null {
|
|
4680
4933
|
if (value instanceof PineArray) return value;
|
|
4681
4934
|
if (value && typeof value === "object" && "__array" in value) {
|