@hoox-sh/pynets 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +1 -1
- package/dist/browser.js +63 -63
- package/dist/index.js +858 -34
- package/package.json +1 -1
- package/src/cli/rich.ts +1 -1
- package/src/runtime/compile/emit_call.ts +168 -7
- package/src/runtime/interpret.ts +244 -24
- package/src/runtime/ta.ts +589 -12
package/package.json
CHANGED
package/src/cli/rich.ts
CHANGED
|
@@ -193,6 +193,24 @@ 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",
|
|
196
214
|
]);
|
|
197
215
|
|
|
198
216
|
/**
|
|
@@ -405,6 +423,13 @@ export function emitCall(ctx: EmitCtx, node: Call, visit: VisitFn): string {
|
|
|
405
423
|
ctx.needsHeikinashi = true;
|
|
406
424
|
return `"__HEIKINASHI__"`;
|
|
407
425
|
}
|
|
426
|
+
if (name === "ticker_inherit") {
|
|
427
|
+
const fallback = pick(args, 0, ["ticker", "tickerid", "from", "source"], `"SYMBOL"`);
|
|
428
|
+
return pick(args, 1, ["symbol", "ticker"], fallback);
|
|
429
|
+
}
|
|
430
|
+
if (name === "renko" || name === "kagi" || name === "linebreak" || name === "pointfigure") {
|
|
431
|
+
return pick(args, 0, ["ticker", "tickerid", "symbol"], `"SYMBOL"`);
|
|
432
|
+
}
|
|
408
433
|
// ticker.new / standard / modify / renko / kagi / linebreak / pointfigure → first arg or "SYMBOL"
|
|
409
434
|
if (name.startsWith("ticker_")) {
|
|
410
435
|
return pick(args, 0, ["symbol", "ticker", "tickerid"], `"SYMBOL"`);
|
|
@@ -617,6 +642,11 @@ function cellOf(expr: string): string {
|
|
|
617
642
|
return `((__c) => (__c == null ? null : typeof __c === "boolean" ? (__c ? 1 : 0) : (typeof __c === "number" && Number.isFinite(__c) ? __c : null)))(${expr})`;
|
|
618
643
|
}
|
|
619
644
|
|
|
645
|
+
/** Cell or array/object (history-based TA args keep arrays intact). */
|
|
646
|
+
function arrOrCell(expr: string): string {
|
|
647
|
+
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})`;
|
|
648
|
+
}
|
|
649
|
+
|
|
620
650
|
/**
|
|
621
651
|
* Interpret `wave10bList`: a Pine array becomes its cells; a scalar is a
|
|
622
652
|
* one-element list. Bar-mode series stay one element.
|
|
@@ -2394,8 +2424,11 @@ function emitTa(ctx: EmitCtx, method: string, args: CallArgs): string {
|
|
|
2394
2424
|
]);
|
|
2395
2425
|
}
|
|
2396
2426
|
if (method === "market_structure_pivot") {
|
|
2397
|
-
return
|
|
2398
|
-
|
|
2427
|
+
return taCall("marketStructurePivot", site, [
|
|
2428
|
+
arrOrCell(pick(args, 0, ["high_list", "high"], "null")),
|
|
2429
|
+
arrOrCell(pick(args, 1, ["low_list", "low"], "null")),
|
|
2430
|
+
cellOf(pick(args, 3, ["period", "left", "left_bars"], "null")),
|
|
2431
|
+
cellOf(pick(args, 4, ["mode", "right", "right_bars"], "null")),
|
|
2399
2432
|
]);
|
|
2400
2433
|
}
|
|
2401
2434
|
if (method === "position_sizing_score") {
|
|
@@ -2416,13 +2449,13 @@ function emitTa(ctx: EmitCtx, method: string, args: CallArgs): string {
|
|
|
2416
2449
|
]);
|
|
2417
2450
|
}
|
|
2418
2451
|
if (method === "optimal_entry_zone") {
|
|
2419
|
-
return
|
|
2452
|
+
return taCall("optimalEntryZone", site, [arrOrCell(pick(args, 2, ["close"], "null"))]);
|
|
2420
2453
|
}
|
|
2421
2454
|
if (method === "mean_reversion_entry") {
|
|
2422
|
-
return
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2455
|
+
return taCall("meanReversionEntry", site, [
|
|
2456
|
+
arrOrCell(pick(args, 0, ["price", "source"], "null")),
|
|
2457
|
+
arrOrCell(pick(args, 1, ["sma"], "null")),
|
|
2458
|
+
arrOrCell(pick(args, 2, ["stdev", "std_dev"], "null")),
|
|
2426
2459
|
cellOf(pick(args, 4, ["threshold"], "null")),
|
|
2427
2460
|
]);
|
|
2428
2461
|
}
|
|
@@ -2466,5 +2499,133 @@ function emitTa(ctx: EmitCtx, method: string, args: CallArgs): string {
|
|
|
2466
2499
|
cellOf(pick(args, 2, ["support"], "null")),
|
|
2467
2500
|
]);
|
|
2468
2501
|
}
|
|
2502
|
+
if (method === "ema_cross_signal") {
|
|
2503
|
+
return taCall("emaCrossSignal", site, [
|
|
2504
|
+
cellOf(pick(args, 0, ["fast_ema", "fast"], "null")),
|
|
2505
|
+
cellOf(pick(args, 1, ["slow_ema", "slow"], "null")),
|
|
2506
|
+
cellOf(pick(args, 2, ["threshold"], "null")),
|
|
2507
|
+
]);
|
|
2508
|
+
}
|
|
2509
|
+
if (method === "momentum_filter") {
|
|
2510
|
+
return taCall("momentumFilter", site, [
|
|
2511
|
+
cellOf(pick(args, 0, ["momentum_raw", "momentum"], "null")),
|
|
2512
|
+
cellOf(pick(args, 1, ["volume"], "null")),
|
|
2513
|
+
cellOf(pick(args, 2, ["period", "length"], "null")),
|
|
2514
|
+
]);
|
|
2515
|
+
}
|
|
2516
|
+
if (method === "volatility_regime") {
|
|
2517
|
+
return taCall("volatilityRegime", site, [
|
|
2518
|
+
cellOf(pick(args, 0, ["atr_series", "atr", "source"], "null")),
|
|
2519
|
+
cellOf(pick(args, 1, ["period", "length"], "null")),
|
|
2520
|
+
]);
|
|
2521
|
+
}
|
|
2522
|
+
if (method === "economic_impact_score") {
|
|
2523
|
+
return taPure("economicImpactScore", [
|
|
2524
|
+
cellOf(pick(args, 0, ["price_change"], "null")),
|
|
2525
|
+
cellOf(pick(args, 1, ["volatility"], "null")),
|
|
2526
|
+
cellOf(pick(args, 2, ["volume_change"], "null")),
|
|
2527
|
+
]);
|
|
2528
|
+
}
|
|
2529
|
+
if (method === "contrarian_signal") {
|
|
2530
|
+
return taPure("contrarianSignal", [
|
|
2531
|
+
cellOf(pick(args, 0, ["sentiment"], "null")),
|
|
2532
|
+
cellOf(pick(args, 1, ["volatility"], "null")),
|
|
2533
|
+
cellOf(pick(args, 2, ["time_since_extreme", "time_extreme"], "null")),
|
|
2534
|
+
]);
|
|
2535
|
+
}
|
|
2536
|
+
if (method === "drawdown_recovery_level") {
|
|
2537
|
+
return taPure("drawdownRecoveryLevel", [
|
|
2538
|
+
cellOf(pick(args, 0, ["peak"], "null")),
|
|
2539
|
+
cellOf(pick(args, 1, ["current", "current_price"], "null")),
|
|
2540
|
+
cellOf(pick(args, 2, ["recovery_factor", "factor"], "null")),
|
|
2541
|
+
cellOf(pick(args, 3, ["period", "length"], "null")),
|
|
2542
|
+
]);
|
|
2543
|
+
}
|
|
2544
|
+
if (method === "pivot_point_levels") {
|
|
2545
|
+
return taPure("pivotPointLevels", [
|
|
2546
|
+
cellOf(pick(args, 0, ["high"], "null")),
|
|
2547
|
+
cellOf(pick(args, 1, ["low"], "null")),
|
|
2548
|
+
cellOf(pick(args, 2, ["close"], "null")),
|
|
2549
|
+
pick(args, 3, ["traditional"], "true"),
|
|
2550
|
+
]);
|
|
2551
|
+
}
|
|
2552
|
+
if (method === "volatility_regime_score") {
|
|
2553
|
+
return taCall("volatilityRegimeScore", site, [
|
|
2554
|
+
arrOrCell(pick(args, 0, ["atr_list", "atr"], "null")),
|
|
2555
|
+
arrOrCell(pick(args, 1, ["volatility_list", "volatility"], "null")),
|
|
2556
|
+
arrOrCell(pick(args, 2, ["vix_list", "vix"], "null")),
|
|
2557
|
+
cellOf(pick(args, 3, ["threshold"], "null")),
|
|
2558
|
+
]);
|
|
2559
|
+
}
|
|
2560
|
+
if (method === "correlation_filter") {
|
|
2561
|
+
return taCall("correlationFilter", site, [
|
|
2562
|
+
arrOrCell(pick(args, 0, ["signal1_list", "signal1", "s1"], "null")),
|
|
2563
|
+
arrOrCell(pick(args, 1, ["signal2_list", "signal2", "s2"], "null")),
|
|
2564
|
+
arrOrCell(pick(args, 2, ["signal3_list", "signal3", "s3"], "null")),
|
|
2565
|
+
cellOf(pick(args, 4, ["threshold"], "null")),
|
|
2566
|
+
]);
|
|
2567
|
+
}
|
|
2568
|
+
if (method === "advanced_breakout_detector") {
|
|
2569
|
+
return taCall("advancedBreakoutDetector", site, [
|
|
2570
|
+
arrOrCell(pick(args, 0, ["price_list", "price"], "null")),
|
|
2571
|
+
arrOrCell(pick(args, 1, ["volume_list", "volume"], "null")),
|
|
2572
|
+
cellOf(pick(args, 2, ["level"], "null")),
|
|
2573
|
+
cellOf(pick(args, 3, ["lookback"], "null")),
|
|
2574
|
+
cellOf(pick(args, 4, ["volume_multiplier", "vol_mult"], "null")),
|
|
2575
|
+
]);
|
|
2576
|
+
}
|
|
2577
|
+
if (method === "pullback_bounce_level") {
|
|
2578
|
+
return taCall("pullbackBounceLevel", site, [
|
|
2579
|
+
arrOrCell(pick(args, 0, ["high_list", "high"], "null")),
|
|
2580
|
+
arrOrCell(pick(args, 1, ["low_list", "low"], "null")),
|
|
2581
|
+
cellOf(pick(args, 3, ["trend_direction", "trend_dir"], "null")),
|
|
2582
|
+
cellOf(pick(args, 4, ["lookback"], "null")),
|
|
2583
|
+
]);
|
|
2584
|
+
}
|
|
2585
|
+
if (method === "divergence_detector") {
|
|
2586
|
+
return taCall("divergenceDetector", site, [
|
|
2587
|
+
arrOrCell(pick(args, 0, ["price_list", "price"], "null")),
|
|
2588
|
+
arrOrCell(pick(args, 1, ["indicator_list", "indicator"], "null")),
|
|
2589
|
+
cellOf(pick(args, 2, ["lookback"], "null")),
|
|
2590
|
+
]);
|
|
2591
|
+
}
|
|
2592
|
+
if (method === "momentum_divergence") {
|
|
2593
|
+
return taCall("momentumDivergence", site, [
|
|
2594
|
+
arrOrCell(pick(args, 0, ["price"], "null")),
|
|
2595
|
+
arrOrCell(pick(args, 1, ["momentum_fast", "mom_fast"], "null")),
|
|
2596
|
+
arrOrCell(pick(args, 2, ["momentum_slow", "mom_slow"], "null")),
|
|
2597
|
+
]);
|
|
2598
|
+
}
|
|
2599
|
+
if (method === "spread_analysis") {
|
|
2600
|
+
return taCall("spreadAnalysis", site, [
|
|
2601
|
+
arrOrCell(pick(args, 0, ["bid"], "null")),
|
|
2602
|
+
arrOrCell(pick(args, 1, ["ask"], "null")),
|
|
2603
|
+
cellOf(pick(args, 2, ["period", "length"], "null")),
|
|
2604
|
+
]);
|
|
2605
|
+
}
|
|
2606
|
+
if (method === "employment_cycle_indicator") {
|
|
2607
|
+
return taCall("employmentCycleIndicator", site, [
|
|
2608
|
+
arrOrCell(pick(args, 0, ["cyclical_stocks", "cyclical"], "null")),
|
|
2609
|
+
arrOrCell(pick(args, 1, ["defensive_stocks", "defensive"], "null")),
|
|
2610
|
+
arrOrCell(pick(args, 2, ["unemployment_proxy", "unemployment"], "null")),
|
|
2611
|
+
]);
|
|
2612
|
+
}
|
|
2613
|
+
if (method === "gdp_growth_proxy") {
|
|
2614
|
+
return taCall("gdpGrowthProxy", site, [
|
|
2615
|
+
arrOrCell(pick(args, 0, ["market_breadth", "breadth"], "null")),
|
|
2616
|
+
arrOrCell(pick(args, 1, ["market_volume", "volume"], "null")),
|
|
2617
|
+
arrOrCell(pick(args, 2, ["price_momentum", "momentum"], "null")),
|
|
2618
|
+
]);
|
|
2619
|
+
}
|
|
2620
|
+
if (method === "inflation_proxy_indicator") {
|
|
2621
|
+
return taCall("inflationProxyIndicator", site, [
|
|
2622
|
+
arrOrCell(pick(args, 0, ["usd_index", "usd"], "null")),
|
|
2623
|
+
arrOrCell(pick(args, 1, ["commodity_prices", "commodities"], "null")),
|
|
2624
|
+
arrOrCell(pick(args, 2, ["bond_yields", "yields"], "null")),
|
|
2625
|
+
]);
|
|
2626
|
+
}
|
|
2627
|
+
if (method === "expected_value") {
|
|
2628
|
+
return `__h.ta.expectedValue(${cellList(pick(args, 0, ["returns"], "null"))}, ${cellList(pick(args, 1, ["probabilities", "probs"], "null"))})`;
|
|
2629
|
+
}
|
|
2469
2630
|
return "null";
|
|
2470
2631
|
}
|
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
|
}
|
|
@@ -4655,6 +4680,186 @@ function evalExtraTa(fname: string | null, node: Call, env: Env, site: string):
|
|
|
4655
4680
|
);
|
|
4656
4681
|
}
|
|
4657
4682
|
// wave12-end
|
|
4683
|
+
// wave13-start — history / sentiment / macro analytics
|
|
4684
|
+
if (fname === "ta.ema_cross_signal" || fname === "ema_cross_signal") {
|
|
4685
|
+
const msg = "ta.ema_cross_signal() requires 3 arguments";
|
|
4686
|
+
return env.ta.emaCrossSignal(
|
|
4687
|
+
site,
|
|
4688
|
+
wave11n(0, ["fast_ema", "fast"], msg),
|
|
4689
|
+
wave11n(1, ["slow_ema", "slow"], msg),
|
|
4690
|
+
wave11n(2, ["threshold"], msg),
|
|
4691
|
+
);
|
|
4692
|
+
}
|
|
4693
|
+
if (fname === "ta.momentum_filter" || fname === "momentum_filter") {
|
|
4694
|
+
const msg = "ta.momentum_filter() requires 3 arguments";
|
|
4695
|
+
return env.ta.momentumFilter(
|
|
4696
|
+
site,
|
|
4697
|
+
wave11n(0, ["momentum_raw", "momentum"], msg),
|
|
4698
|
+
wave11n(1, ["volume"], msg),
|
|
4699
|
+
wave11n(2, ["period", "length"], msg),
|
|
4700
|
+
);
|
|
4701
|
+
}
|
|
4702
|
+
if (fname === "ta.volatility_regime" || fname === "volatility_regime") {
|
|
4703
|
+
const msg = "ta.volatility_regime() requires 2 arguments";
|
|
4704
|
+
return env.ta.volatilityRegime(
|
|
4705
|
+
site,
|
|
4706
|
+
wave11n(0, ["atr_series", "atr", "source"], msg),
|
|
4707
|
+
wave11n(1, ["period", "length"], msg),
|
|
4708
|
+
);
|
|
4709
|
+
}
|
|
4710
|
+
if (fname === "ta.economic_impact_score" || fname === "economic_impact_score") {
|
|
4711
|
+
const msg = "ta.economic_impact_score() requires 3 arguments";
|
|
4712
|
+
return env.ta.economicImpactScore(
|
|
4713
|
+
wave11n(0, ["price_change"], msg),
|
|
4714
|
+
wave11n(1, ["volatility"], msg),
|
|
4715
|
+
wave11n(2, ["volume_change"], msg),
|
|
4716
|
+
);
|
|
4717
|
+
}
|
|
4718
|
+
if (fname === "ta.contrarian_signal" || fname === "contrarian_signal") {
|
|
4719
|
+
const msg = "ta.contrarian_signal() requires 3 arguments";
|
|
4720
|
+
return env.ta.contrarianSignal(
|
|
4721
|
+
wave11n(0, ["sentiment"], msg),
|
|
4722
|
+
wave11n(1, ["volatility"], msg),
|
|
4723
|
+
wave11n(2, ["time_since_extreme", "time_extreme"], msg),
|
|
4724
|
+
);
|
|
4725
|
+
}
|
|
4726
|
+
if (fname === "ta.drawdown_recovery_level" || fname === "drawdown_recovery_level") {
|
|
4727
|
+
const msg = "ta.drawdown_recovery_level() requires 4 arguments";
|
|
4728
|
+
return env.ta.drawdownRecoveryLevel(
|
|
4729
|
+
wave11n(0, ["peak"], msg),
|
|
4730
|
+
wave11n(1, ["current", "current_price"], msg),
|
|
4731
|
+
wave11n(2, ["recovery_factor", "factor"], msg),
|
|
4732
|
+
wave11n(3, ["period", "length"], msg),
|
|
4733
|
+
);
|
|
4734
|
+
}
|
|
4735
|
+
if (fname === "ta.pivot_point_levels" || fname === "pivot_point_levels") {
|
|
4736
|
+
const msg = "ta.pivot_point_levels() requires type+anchor or high, low, close";
|
|
4737
|
+
const first = wave11(0, ["type", "high"], msg);
|
|
4738
|
+
if (typeof first === "string") {
|
|
4739
|
+
// Reference Pine type+anchor form → context pivot-point tuple.
|
|
4740
|
+
if (typeof env.ta.pivotPoints !== "function") return NA;
|
|
4741
|
+
const r = (env.ta.pivotPoints as TaEngine["pivotPoints"]).call(
|
|
4742
|
+
env.ta,
|
|
4743
|
+
site,
|
|
4744
|
+
num(env.ctx.high),
|
|
4745
|
+
num(env.ctx.low),
|
|
4746
|
+
num(env.ctx.close),
|
|
4747
|
+
);
|
|
4748
|
+
return tupleOf([r.pp, r.r1, r.s1, r.r2, r.s2]);
|
|
4749
|
+
}
|
|
4750
|
+
const tradArg = callArg(node.args, 3, ["traditional"]);
|
|
4751
|
+
const traditional = tradArg == null ? true : unwrap(evalExpr(tradArg, env)) !== 0;
|
|
4752
|
+
return env.ta.pivotPointLevels(
|
|
4753
|
+
num(first),
|
|
4754
|
+
wave11n(1, ["low"], msg),
|
|
4755
|
+
wave11n(2, ["close"], msg),
|
|
4756
|
+
traditional,
|
|
4757
|
+
);
|
|
4758
|
+
}
|
|
4759
|
+
if (fname === "ta.volatility_regime_score" || fname === "volatility_regime_score") {
|
|
4760
|
+
const msg = "ta.volatility_regime_score() requires 4 arguments";
|
|
4761
|
+
return env.ta.volatilityRegimeScore(
|
|
4762
|
+
site,
|
|
4763
|
+
wave13v(0, ["atr_list", "atr"], msg),
|
|
4764
|
+
wave13v(1, ["volatility_list", "volatility"], msg),
|
|
4765
|
+
wave13v(2, ["vix_list", "vix"], msg),
|
|
4766
|
+
wave11n(3, ["threshold"], msg),
|
|
4767
|
+
);
|
|
4768
|
+
}
|
|
4769
|
+
if (fname === "ta.correlation_filter" || fname === "correlation_filter") {
|
|
4770
|
+
const msg = "ta.correlation_filter() requires 5 arguments";
|
|
4771
|
+
const s1 = wave13v(0, ["signal1_list", "signal1", "s1"], msg);
|
|
4772
|
+
const s2 = wave13v(1, ["signal2_list", "signal2", "s2"], msg);
|
|
4773
|
+
const s3 = wave13v(2, ["signal3_list", "signal3", "s3"], msg);
|
|
4774
|
+
wave11n(3, ["num_signals"], msg);
|
|
4775
|
+
return env.ta.correlationFilter(site, s1, s2, s3, wave11n(4, ["threshold"], msg));
|
|
4776
|
+
}
|
|
4777
|
+
if (fname === "ta.advanced_breakout_detector" || fname === "advanced_breakout_detector") {
|
|
4778
|
+
const msg = "ta.advanced_breakout_detector() requires 5 arguments";
|
|
4779
|
+
return env.ta.advancedBreakoutDetector(
|
|
4780
|
+
site,
|
|
4781
|
+
wave13v(0, ["price_list", "price"], msg),
|
|
4782
|
+
wave13v(1, ["volume_list", "volume"], msg),
|
|
4783
|
+
wave11n(2, ["level"], msg),
|
|
4784
|
+
wave11n(3, ["lookback"], msg),
|
|
4785
|
+
wave11n(4, ["volume_multiplier", "vol_mult"], msg),
|
|
4786
|
+
);
|
|
4787
|
+
}
|
|
4788
|
+
if (fname === "ta.pullback_bounce_level" || fname === "pullback_bounce_level") {
|
|
4789
|
+
const msg = "ta.pullback_bounce_level() requires 5 arguments";
|
|
4790
|
+
const high = wave13v(0, ["high_list", "high"], msg);
|
|
4791
|
+
const low = wave13v(1, ["low_list", "low"], msg);
|
|
4792
|
+
wave13v(2, ["close_list", "close"], msg);
|
|
4793
|
+
return env.ta.pullbackBounceLevel(
|
|
4794
|
+
site,
|
|
4795
|
+
high,
|
|
4796
|
+
low,
|
|
4797
|
+
wave11n(3, ["trend_direction", "trend_dir"], msg),
|
|
4798
|
+
wave11n(4, ["lookback"], msg),
|
|
4799
|
+
);
|
|
4800
|
+
}
|
|
4801
|
+
if (fname === "ta.divergence_detector" || fname === "divergence_detector") {
|
|
4802
|
+
const msg = "ta.divergence_detector() requires 3 arguments";
|
|
4803
|
+
return env.ta.divergenceDetector(
|
|
4804
|
+
site,
|
|
4805
|
+
wave13v(0, ["price_list", "price"], msg),
|
|
4806
|
+
wave13v(1, ["indicator_list", "indicator"], msg),
|
|
4807
|
+
wave11n(2, ["lookback"], msg),
|
|
4808
|
+
);
|
|
4809
|
+
}
|
|
4810
|
+
if (fname === "ta.momentum_divergence" || fname === "momentum_divergence") {
|
|
4811
|
+
const msg = "ta.momentum_divergence() requires 3 arguments";
|
|
4812
|
+
return env.ta.momentumDivergence(
|
|
4813
|
+
site,
|
|
4814
|
+
wave13v(0, ["price"], msg),
|
|
4815
|
+
wave13v(1, ["momentum_fast", "mom_fast"], msg),
|
|
4816
|
+
wave13v(2, ["momentum_slow", "mom_slow"], msg),
|
|
4817
|
+
);
|
|
4818
|
+
}
|
|
4819
|
+
if (fname === "ta.spread_analysis" || fname === "spread_analysis") {
|
|
4820
|
+
const msg = "ta.spread_analysis() requires 3 arguments";
|
|
4821
|
+
return env.ta.spreadAnalysis(
|
|
4822
|
+
site,
|
|
4823
|
+
wave13v(0, ["bid"], msg),
|
|
4824
|
+
wave13v(1, ["ask"], msg),
|
|
4825
|
+
wave11n(2, ["period", "length"], msg),
|
|
4826
|
+
);
|
|
4827
|
+
}
|
|
4828
|
+
if (fname === "ta.employment_cycle_indicator" || fname === "employment_cycle_indicator") {
|
|
4829
|
+
const msg = "ta.employment_cycle_indicator() requires 3 arguments";
|
|
4830
|
+
return env.ta.employmentCycleIndicator(
|
|
4831
|
+
site,
|
|
4832
|
+
wave13v(0, ["cyclical_stocks", "cyclical"], msg),
|
|
4833
|
+
wave13v(1, ["defensive_stocks", "defensive"], msg),
|
|
4834
|
+
wave13v(2, ["unemployment_proxy", "unemployment"], msg),
|
|
4835
|
+
);
|
|
4836
|
+
}
|
|
4837
|
+
if (fname === "ta.gdp_growth_proxy" || fname === "gdp_growth_proxy") {
|
|
4838
|
+
const msg = "ta.gdp_growth_proxy() requires 3 arguments";
|
|
4839
|
+
return env.ta.gdpGrowthProxy(
|
|
4840
|
+
site,
|
|
4841
|
+
wave13v(0, ["market_breadth", "breadth"], msg),
|
|
4842
|
+
wave13v(1, ["market_volume", "volume"], msg),
|
|
4843
|
+
wave13v(2, ["price_momentum", "momentum"], msg),
|
|
4844
|
+
);
|
|
4845
|
+
}
|
|
4846
|
+
if (fname === "ta.inflation_proxy_indicator" || fname === "inflation_proxy_indicator") {
|
|
4847
|
+
const msg = "ta.inflation_proxy_indicator() requires 3 arguments";
|
|
4848
|
+
return env.ta.inflationProxyIndicator(
|
|
4849
|
+
site,
|
|
4850
|
+
wave13v(0, ["usd_index", "usd"], msg),
|
|
4851
|
+
wave13v(1, ["commodity_prices", "commodities"], msg),
|
|
4852
|
+
wave13v(2, ["bond_yields", "yields"], msg),
|
|
4853
|
+
);
|
|
4854
|
+
}
|
|
4855
|
+
if (fname === "ta.expected_value" || fname === "expected_value") {
|
|
4856
|
+
const msg = "ta.expected_value() requires 2 arguments: returns, probabilities";
|
|
4857
|
+
const returns = numericList(evalExpr(wave10aArg(0, ["returns"], msg), env));
|
|
4858
|
+
const probs = numericList(evalExpr(wave10aArg(1, ["probabilities", "probs"], msg), env));
|
|
4859
|
+
if (returns.length !== probs.length) runtimeError("Returns and probabilities must have same length");
|
|
4860
|
+
return env.ta.expectedValue(returns, probs);
|
|
4861
|
+
}
|
|
4862
|
+
// wave13-end
|
|
4658
4863
|
return undefined;
|
|
4659
4864
|
}
|
|
4660
4865
|
|
|
@@ -4676,6 +4881,21 @@ function seriesLastCell(value: Value): number | null {
|
|
|
4676
4881
|
return typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
4677
4882
|
}
|
|
4678
4883
|
|
|
4884
|
+
/** Python `_expect_list` for array-valued args: numeric cells only. */
|
|
4885
|
+
function numericList(value: Value): number[] {
|
|
4886
|
+
const arr = asArray(value);
|
|
4887
|
+
if (arr == null) {
|
|
4888
|
+
const v = unwrap(value);
|
|
4889
|
+
return typeof v === "number" && Number.isFinite(v) ? [v] : [];
|
|
4890
|
+
}
|
|
4891
|
+
const out: number[] = [];
|
|
4892
|
+
for (let i = 0; i < arr.size(); i++) {
|
|
4893
|
+
const v = arr.get(i);
|
|
4894
|
+
if (typeof v === "number" && Number.isFinite(v)) out.push(v);
|
|
4895
|
+
}
|
|
4896
|
+
return out;
|
|
4897
|
+
}
|
|
4898
|
+
|
|
4679
4899
|
function asArray(value: Value): PineArray | null {
|
|
4680
4900
|
if (value instanceof PineArray) return value;
|
|
4681
4901
|
if (value && typeof value === "object" && "__array" in value) {
|