@hoox-sh/pynets 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +5 -5
- package/dist/browser.js +66 -66
- package/dist/index.js +1532 -38
- package/package.json +1 -1
- package/src/cli/rich.ts +1 -1
- package/src/runtime/compile/collections.ts +4 -0
- package/src/runtime/compile/draw.ts +609 -19
- package/src/runtime/compile/emit.ts +81 -1
- package/src/runtime/compile/emit_call.ts +312 -9
- package/src/runtime/compile/runtime.ts +20 -0
- package/src/runtime/compile/strategy.ts +253 -1
- package/src/runtime/interpret.ts +151 -0
- package/src/runtime/ta.ts +392 -0
|
@@ -6,15 +6,19 @@
|
|
|
6
6
|
* Injected as `__h.strategy`. Wraps StrategyBook (fills + ledger + risk).
|
|
7
7
|
*/
|
|
8
8
|
import {
|
|
9
|
+
isStrategyCashAmount,
|
|
10
|
+
strategyCashAmount,
|
|
9
11
|
StrategyBook,
|
|
10
12
|
type BarOhlc,
|
|
11
13
|
type BrokerSettings,
|
|
12
14
|
type PlaceEntryOpts,
|
|
13
15
|
type PlaceExitOpts,
|
|
16
|
+
type StrategyCashAmount,
|
|
14
17
|
type StrategyDirection,
|
|
15
18
|
type StrategyEvent,
|
|
16
19
|
type StrategySummary,
|
|
17
20
|
} from "../strategy.ts";
|
|
21
|
+
import { naNum } from "./helpers.ts";
|
|
18
22
|
|
|
19
23
|
function asDir(v: unknown): StrategyDirection | number | string {
|
|
20
24
|
if (v == null) return "long";
|
|
@@ -92,9 +96,13 @@ export class CompileStrategy {
|
|
|
92
96
|
if (ml != null) broker.margin_long = ml;
|
|
93
97
|
const ms = optNum(rec.margin_short);
|
|
94
98
|
if (ms != null) broker.margin_short = ms;
|
|
95
|
-
|
|
99
|
+
// String sentinel or tagged free-cash (`strategy.cash`) both select cash sizing.
|
|
100
|
+
if (typeof rec.default_qty_type === "string" || isStrategyCashAmount(rec.default_qty_type)) {
|
|
101
|
+
broker.default_qty_type = rec.default_qty_type;
|
|
102
|
+
}
|
|
96
103
|
const dqv = optNum(rec.default_qty_value);
|
|
97
104
|
if (dqv != null) broker.default_qty_value = dqv;
|
|
105
|
+
if (typeof rec.currency === "string" && rec.currency !== "") broker.currency = rec.currency;
|
|
98
106
|
if (Object.keys(broker).length) this.book.configure(broker);
|
|
99
107
|
const capital = optNum(rec.initial_capital);
|
|
100
108
|
if (capital != null) this.book.initialCapital = capital;
|
|
@@ -212,6 +220,250 @@ export class CompileStrategy {
|
|
|
212
220
|
return this.book.initialCapital;
|
|
213
221
|
}
|
|
214
222
|
|
|
223
|
+
/** Free cash tagged so `default_qty_type=strategy.cash` still selects cash sizing. */
|
|
224
|
+
cash(): StrategyCashAmount {
|
|
225
|
+
return strategyCashAmount(this.book.cash(this.mark));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
position_entry_name(): string {
|
|
229
|
+
return this.book.position_entry_name;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
account_currency(): string {
|
|
233
|
+
return this.book.account_currency;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** Zero-arg form is `percent_equity=100` (interpret `strategy.default_entry_qty`). */
|
|
237
|
+
default_entry_qty(percent?: unknown): number | null {
|
|
238
|
+
const pct = arguments.length === 0 || percent === undefined ? 100 : naNum(percent);
|
|
239
|
+
if (pct == null) return null;
|
|
240
|
+
return (this.book.initialCapital * (pct / 100)) / 100;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** Identity FX stub. Missing arg → 1; na / non-finite → na. */
|
|
244
|
+
convert_to(value?: unknown): number | null {
|
|
245
|
+
if (arguments.length === 0 || value === undefined) return 1;
|
|
246
|
+
return naNum(value);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
max_contracts_held_all(): number {
|
|
250
|
+
return this.book.maxContractsHeldAll();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
max_contracts_held_long(): number {
|
|
254
|
+
return this.book.maxContractsHeldLong();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
max_contracts_held_short(): number {
|
|
258
|
+
return this.book.maxContractsHeldShort();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
capital_held(): number {
|
|
262
|
+
return this.book.capitalHeld();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
closedtrades_first_index(): number {
|
|
266
|
+
return this.book.closedtrades_first_index;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
wintrades(): number {
|
|
270
|
+
return this.book.wintrades;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
losstrades(): number {
|
|
274
|
+
return this.book.losstrades;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
eventrades(): number {
|
|
278
|
+
return this.book.eventrades;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
grossprofit(): number {
|
|
282
|
+
return this.book.grossprofit;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
grossloss(): number {
|
|
286
|
+
return this.book.grossloss;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
avg_trade(): number {
|
|
290
|
+
return this.book.avgTrade();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
avg_winning_trade(): number {
|
|
294
|
+
return this.book.avgWinningTrade();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
avg_losing_trade(): number {
|
|
298
|
+
return this.book.avgLosingTrade();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
netprofit_percent(): number {
|
|
302
|
+
return this.book.netprofitPercent(this.mark);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
openprofit_percent(): number {
|
|
306
|
+
return this.book.openprofitPercent(this.mark);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
grossprofit_percent(): number {
|
|
310
|
+
return this.book.grossprofitPercent();
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
grossloss_percent(): number {
|
|
314
|
+
return this.book.grosslossPercent();
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
avg_trade_percent(): number {
|
|
318
|
+
return this.book.avgTradePercent();
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
avg_winning_trade_percent(): number {
|
|
322
|
+
return this.book.avgWinningTradePercent();
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
avg_losing_trade_percent(): number {
|
|
326
|
+
return this.book.avgLosingTradePercent();
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
max_drawdown(): number {
|
|
330
|
+
return this.book.maxDrawdown();
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
max_drawdown_percent(): number {
|
|
334
|
+
return this.book.maxDrawdownPercent();
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
max_runup(): number {
|
|
338
|
+
return this.book.maxRunup();
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
max_runup_percent(): number {
|
|
342
|
+
return this.book.maxRunupPercent();
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
percent_profitable(): number {
|
|
346
|
+
return this.book.percentProfitable();
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
winrate(): number {
|
|
350
|
+
return this.book.percentProfitable();
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
profitfactor(): number {
|
|
354
|
+
return this.book.profitFactor();
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
profit_factor(): number {
|
|
358
|
+
return this.book.profitFactor();
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
closedtrades_entry_bar_index(i?: unknown): number {
|
|
362
|
+
return this.book.closedEntryBar(this.idx(i)) ?? 0;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
closedtrades_entry_price(i?: unknown): number {
|
|
366
|
+
return this.book.closedEntryPrice(this.idx(i)) ?? 0;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
closedtrades_exit_bar_index(i?: unknown): number {
|
|
370
|
+
return this.book.closedExitBar(this.idx(i)) ?? 0;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
closedtrades_exit_price(i?: unknown): number {
|
|
374
|
+
return this.book.closedExitPrice(this.idx(i)) ?? 0;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
closedtrades_profit(i?: unknown): number {
|
|
378
|
+
return this.book.closedProfit(this.idx(i)) ?? 0;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
closedtrades_size(i?: unknown): number {
|
|
382
|
+
return this.book.closedSize(this.idx(i)) ?? 0;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
closedtrades_entry_id(i?: unknown): string {
|
|
386
|
+
return this.book.closedId(this.idx(i)) ?? "";
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
closedtrades_exit_id(i?: unknown): string {
|
|
390
|
+
return this.book.closedId(this.idx(i)) ?? "";
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
closedtrades_commission(i?: unknown): number {
|
|
394
|
+
return this.book.closedCommission(this.idx(i)) ?? 0;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
closedtrades_entry_time(i?: unknown): number {
|
|
398
|
+
return this.book.closedEntryTime(this.idx(i));
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
closedtrades_exit_time(i?: unknown): number {
|
|
402
|
+
return this.book.closedExitTime(this.idx(i));
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
closedtrades_entry_comment(i?: unknown): string {
|
|
406
|
+
return this.book.closedEntryComment(this.idx(i));
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
closedtrades_exit_comment(i?: unknown): string {
|
|
410
|
+
return this.book.closedExitComment(this.idx(i));
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
closedtrades_max_drawdown(i?: unknown): number {
|
|
414
|
+
return this.book.closedMaxDrawdown(this.idx(i));
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
closedtrades_max_runup(i?: unknown): number {
|
|
418
|
+
return this.book.closedMaxRunup(this.idx(i));
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
opentrades_entry_bar_index(i?: unknown): number {
|
|
422
|
+
return this.book.openEntryBar(this.idx(i)) ?? 0;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
opentrades_entry_price(i?: unknown): number {
|
|
426
|
+
return this.book.openEntryPrice(this.idx(i)) ?? 0;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
opentrades_size(i?: unknown): number {
|
|
430
|
+
return this.book.openSize(this.idx(i)) ?? 0;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
opentrades_entry_id(i?: unknown): string {
|
|
434
|
+
return this.book.openId(this.idx(i)) ?? "";
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
opentrades_profit(i?: unknown): number {
|
|
438
|
+
return this.book.openProfit(this.idx(i), this.mark) ?? 0;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
opentrades_entry_time(i?: unknown): number {
|
|
442
|
+
return this.book.openEntryTime(this.idx(i));
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
opentrades_entry_comment(i?: unknown): string {
|
|
446
|
+
return this.book.openEntryComment(this.idx(i));
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
opentrades_commission(i?: unknown): number {
|
|
450
|
+
return this.book.openCommission(this.idx(i));
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
opentrades_max_drawdown(i?: unknown): number {
|
|
454
|
+
return this.book.openMaxDrawdown(this.idx(i));
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
opentrades_max_runup(i?: unknown): number {
|
|
458
|
+
return this.book.openMaxRunup(this.idx(i));
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
private idx(i: unknown): number {
|
|
462
|
+
if (typeof i === "boolean") return i ? 1 : 0;
|
|
463
|
+
if (typeof i === "number" && Number.isFinite(i)) return Math.trunc(i);
|
|
464
|
+
return 0;
|
|
465
|
+
}
|
|
466
|
+
|
|
215
467
|
risk_allow_entry_in(value?: unknown): void {
|
|
216
468
|
this.book.riskAllowEntryIn(value);
|
|
217
469
|
}
|
package/src/runtime/interpret.ts
CHANGED
|
@@ -3951,6 +3951,157 @@ function evalExtraTa(fname: string | null, node: Call, env: Env, site: string):
|
|
|
3951
3951
|
const z = env.ta.zigzag(site, srcArg(node, env), th);
|
|
3952
3952
|
return tupleOf([z.high, z.low, z.dir]);
|
|
3953
3953
|
}
|
|
3954
|
+
// wave10a-start
|
|
3955
|
+
const wave10aArg = (index: number, names: string[], message: string): expr => {
|
|
3956
|
+
const arg = callArg(node.args, index, names);
|
|
3957
|
+
if (arg == null) runtimeError(message);
|
|
3958
|
+
return arg;
|
|
3959
|
+
};
|
|
3960
|
+
if (fname === "ta.hammer" || fname === "hammer") {
|
|
3961
|
+
const msg = "ta.hammer() requires 4 arguments: open, high, low, close";
|
|
3962
|
+
return env.ta.hammer(
|
|
3963
|
+
unwrap(evalExpr(wave10aArg(0, ["open"], msg), env)),
|
|
3964
|
+
unwrap(evalExpr(wave10aArg(1, ["high"], msg), env)),
|
|
3965
|
+
unwrap(evalExpr(wave10aArg(2, ["low"], msg), env)),
|
|
3966
|
+
unwrap(evalExpr(wave10aArg(3, ["close"], msg), env)),
|
|
3967
|
+
);
|
|
3968
|
+
}
|
|
3969
|
+
if (fname === "ta.engulfing" || fname === "engulfing") {
|
|
3970
|
+
const msg = "ta.engulfing() requires 4 arguments: open, high, low, close";
|
|
3971
|
+
unwrap(evalExpr(wave10aArg(0, ["open"], msg), env));
|
|
3972
|
+
unwrap(evalExpr(wave10aArg(1, ["high"], msg), env));
|
|
3973
|
+
unwrap(evalExpr(wave10aArg(2, ["low"], msg), env));
|
|
3974
|
+
unwrap(evalExpr(wave10aArg(3, ["close"], msg), env));
|
|
3975
|
+
return env.ta.engulfing();
|
|
3976
|
+
}
|
|
3977
|
+
if (fname === "ta.gap_detector" || fname === "gap_detector") {
|
|
3978
|
+
const msg = "ta.gap_detector() requires 3 arguments: high, low, prev_close";
|
|
3979
|
+
return env.ta.gapDetector(
|
|
3980
|
+
unwrap(evalExpr(wave10aArg(0, ["high"], msg), env)),
|
|
3981
|
+
unwrap(evalExpr(wave10aArg(1, ["low"], msg), env)),
|
|
3982
|
+
unwrap(evalExpr(wave10aArg(2, ["prev_close", "prev"], msg), env)),
|
|
3983
|
+
);
|
|
3984
|
+
}
|
|
3985
|
+
if (fname === "ta.double_top_bottom" || fname === "double_top_bottom") {
|
|
3986
|
+
const msg = "ta.double_top_bottom() requires 3 arguments";
|
|
3987
|
+
unwrap(evalExpr(wave10aArg(0, ["high"], msg), env));
|
|
3988
|
+
unwrap(evalExpr(wave10aArg(1, ["low"], msg), env));
|
|
3989
|
+
return env.ta.doubleTopBottom(unwrap(evalExpr(wave10aArg(2, ["period", "length"], msg), env)));
|
|
3990
|
+
}
|
|
3991
|
+
if (fname === "ta.inside_bar_pattern" || fname === "inside_bar_pattern") {
|
|
3992
|
+
const msg = "ta.inside_bar_pattern() requires 2 arguments";
|
|
3993
|
+
unwrap(evalExpr(wave10aArg(0, ["high"], msg), env));
|
|
3994
|
+
unwrap(evalExpr(wave10aArg(1, ["low"], msg), env));
|
|
3995
|
+
return env.ta.insideBarPattern();
|
|
3996
|
+
}
|
|
3997
|
+
if (fname === "ta.macd_signal" || fname === "macd_signal") {
|
|
3998
|
+
const msg = "ta.macd_signal() requires 2 arguments: macd_line, signal_line";
|
|
3999
|
+
return env.ta.macdSignal(
|
|
4000
|
+
unwrap(evalExpr(wave10aArg(0, ["macd_line", "macd"], msg), env)),
|
|
4001
|
+
unwrap(evalExpr(wave10aArg(1, ["signal_line", "signal"], msg), env)),
|
|
4002
|
+
);
|
|
4003
|
+
}
|
|
4004
|
+
if (fname === "ta.acceleration_factor" || fname === "acceleration_factor") {
|
|
4005
|
+
const msg = "ta.acceleration_factor() requires 2 arguments";
|
|
4006
|
+
return env.ta.accelerationFactor(
|
|
4007
|
+
site,
|
|
4008
|
+
unwrap(evalExpr(wave10aArg(0, ["momentum_list", "momentum", "source", "series"], msg), env)),
|
|
4009
|
+
unwrap(evalExpr(wave10aArg(1, ["period", "length"], msg), env)),
|
|
4010
|
+
);
|
|
4011
|
+
}
|
|
4012
|
+
if (fname === "ta.stoch_smooth" || fname === "stoch_smooth") {
|
|
4013
|
+
const msg = "ta.stoch_smooth() requires 6 arguments: high, low, close, period, smooth_k, smooth_d";
|
|
4014
|
+
return env.ta.stochSmooth(
|
|
4015
|
+
unwrap(evalExpr(wave10aArg(0, ["high"], msg), env)),
|
|
4016
|
+
unwrap(evalExpr(wave10aArg(1, ["low"], msg), env)),
|
|
4017
|
+
unwrap(evalExpr(wave10aArg(2, ["close"], msg), env)),
|
|
4018
|
+
unwrap(evalExpr(wave10aArg(3, ["period", "length"], msg), env)),
|
|
4019
|
+
unwrap(evalExpr(wave10aArg(4, ["smooth_k", "k"], msg), env)),
|
|
4020
|
+
unwrap(evalExpr(wave10aArg(5, ["smooth_d", "d"], msg), env)),
|
|
4021
|
+
);
|
|
4022
|
+
}
|
|
4023
|
+
// wave10a-end
|
|
4024
|
+
// wave10b-start
|
|
4025
|
+
const wave10bList = (index: number, names: string[]): Array<number | null> => {
|
|
4026
|
+
const raw = evalExpr(callArg(node.args, index, names), env);
|
|
4027
|
+
const arr = asArray(raw);
|
|
4028
|
+
if (arr == null) return [unwrap(raw)];
|
|
4029
|
+
const out: Array<number | null> = [];
|
|
4030
|
+
for (let i = 0; i < arr.size(); i++) out.push(arr.get(i));
|
|
4031
|
+
return out;
|
|
4032
|
+
};
|
|
4033
|
+
if (fname === "ta.voi" || fname === "voi") {
|
|
4034
|
+
return env.ta.voi(
|
|
4035
|
+
unwrap(evalExpr(callArg(node.args, 0, ["buy_volume", "buy"]), env)),
|
|
4036
|
+
unwrap(evalExpr(callArg(node.args, 1, ["sell_volume", "sell"]), env)),
|
|
4037
|
+
);
|
|
4038
|
+
}
|
|
4039
|
+
if (fname === "ta.bid_ask_imbalance" || fname === "bid_ask_imbalance") {
|
|
4040
|
+
return env.ta.bidAskImbalance(
|
|
4041
|
+
unwrap(evalExpr(callArg(node.args, 0, ["bid_size", "bid"]), env)),
|
|
4042
|
+
unwrap(evalExpr(callArg(node.args, 1, ["ask_size", "ask"]), env)),
|
|
4043
|
+
unwrap(evalExpr(callArg(node.args, 2, ["bid_price"]), env)),
|
|
4044
|
+
unwrap(evalExpr(callArg(node.args, 3, ["ask_price"]), env)),
|
|
4045
|
+
);
|
|
4046
|
+
}
|
|
4047
|
+
if (fname === "ta.rsi_oversold_overbought" || fname === "rsi_oversold_overbought") {
|
|
4048
|
+
const os = unwrap(evalExpr(callArg(node.args, 1, ["oversold_level", "oversold"]), env));
|
|
4049
|
+
const ob = unwrap(evalExpr(callArg(node.args, 2, ["overbought_level", "overbought"]), env));
|
|
4050
|
+
return env.ta.rsiOversoldOverbought(
|
|
4051
|
+
unwrap(evalExpr(callArg(node.args, 0, ["rsi_series", "rsi", "source"]), env)),
|
|
4052
|
+
os ?? Number.NaN,
|
|
4053
|
+
ob ?? Number.NaN,
|
|
4054
|
+
);
|
|
4055
|
+
}
|
|
4056
|
+
if (fname === "ta.rsi_divergence" || fname === "rsi_divergence") {
|
|
4057
|
+
const period = unwrap(evalExpr(callArg(node.args, 1, ["period", "length"]), env));
|
|
4058
|
+
return env.ta.rsiDivergence(wave10bList(0, ["rsi_series", "series", "source"]), period ?? 0);
|
|
4059
|
+
}
|
|
4060
|
+
if (fname === "ta.cumulative_delta" || fname === "cumulative_delta") {
|
|
4061
|
+
const period = unwrap(evalExpr(callArg(node.args, 2, ["period", "length"]), env));
|
|
4062
|
+
return env.ta.cumulativeDelta(
|
|
4063
|
+
site,
|
|
4064
|
+
unwrap(evalExpr(callArg(node.args, 0, ["close", "source"]), env)),
|
|
4065
|
+
unwrap(evalExpr(callArg(node.args, 1, ["volume"]), env)),
|
|
4066
|
+
period ?? 0,
|
|
4067
|
+
);
|
|
4068
|
+
}
|
|
4069
|
+
if (fname === "ta.volume_momentum" || fname === "volume_momentum") {
|
|
4070
|
+
const period = unwrap(evalExpr(callArg(node.args, 1, ["period", "length"]), env));
|
|
4071
|
+
return env.ta.volumeMomentum(
|
|
4072
|
+
site,
|
|
4073
|
+
unwrap(evalExpr(callArg(node.args, 0, ["volume", "source"]), env)),
|
|
4074
|
+
period ?? 0,
|
|
4075
|
+
);
|
|
4076
|
+
}
|
|
4077
|
+
if (fname === "ta.volume_profile_high" || fname === "volume_profile_high") {
|
|
4078
|
+
return env.ta.volumeProfileHigh(
|
|
4079
|
+
wave10bList(0, ["close", "price", "source", "series"]),
|
|
4080
|
+
wave10bList(1, ["volume"]),
|
|
4081
|
+
);
|
|
4082
|
+
}
|
|
4083
|
+
if (fname === "ta.volume_profile_low" || fname === "volume_profile_low") {
|
|
4084
|
+
const period = unwrap(evalExpr(callArg(node.args, 2, ["period", "length"]), env));
|
|
4085
|
+
const levels = unwrap(evalExpr(callArg(node.args, 3, ["levels"]), env));
|
|
4086
|
+
return env.ta.volumeProfileLow(
|
|
4087
|
+
site,
|
|
4088
|
+
unwrap(evalExpr(callArg(node.args, 0, ["close", "source"]), env)),
|
|
4089
|
+
unwrap(evalExpr(callArg(node.args, 1, ["volume"]), env)),
|
|
4090
|
+
period ?? 0,
|
|
4091
|
+
levels ?? 0,
|
|
4092
|
+
);
|
|
4093
|
+
}
|
|
4094
|
+
if (fname === "ta.volume_thrust" || fname === "volume_thrust") {
|
|
4095
|
+
const sens = unwrap(evalExpr(callArg(node.args, 3, ["sensitivity"]), env));
|
|
4096
|
+
return env.ta.volumeThrust(
|
|
4097
|
+
site,
|
|
4098
|
+
unwrap(evalExpr(callArg(node.args, 0, ["close", "source"]), env)),
|
|
4099
|
+
unwrap(evalExpr(callArg(node.args, 1, ["volume"]), env)),
|
|
4100
|
+
unwrap(evalExpr(callArg(node.args, 2, ["volume_sma", "vol_sma", "sma"]), env)),
|
|
4101
|
+
sens ?? 0.3,
|
|
4102
|
+
);
|
|
4103
|
+
}
|
|
4104
|
+
// wave10b-end
|
|
3954
4105
|
return undefined;
|
|
3955
4106
|
}
|
|
3956
4107
|
|