@gbozee/ultimate 0.0.2-200 → 0.0.2-201

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.
@@ -653,7 +653,6 @@ class Signal {
653
653
  let potentials = new_result.filter((x) => condition(x["entry"], i["risk_sell"])).map((x) => x["entry"]);
654
654
  if (potentials.length && max_index) {
655
655
  if (kind === "long") {
656
- console.log("slice: ", potentials.slice(0, max_index));
657
656
  i["risk_sell"] = Math.max(...potentials.slice(0, max_index));
658
657
  } else {
659
658
  i["risk_sell"] = Math.min(...potentials.slice(0, max_index));
@@ -717,7 +716,6 @@ class Signal {
717
716
  }) {
718
717
  const margin_zones = [this.support, this.resistance];
719
718
  const distribution = this.distribution ? this.distribution[kind] : "geometric";
720
- console.log("margin_zones", { margin_zones, distribution });
721
719
  let _kind = distribution === "inverse-exponential" ? kind === "long" ? "short" : "long" : kind;
722
720
  const entries = distributions_default({
723
721
  margin_range: margin_zones,
@@ -936,7 +934,6 @@ class Signal {
936
934
  }
937
935
  });
938
936
  risk_to_use = theoretical_kelly * risk_per_trade / this.kelly_minimum_risk;
939
- console.log({ risk_per_trade, theoretical_kelly });
940
937
  }
941
938
  const y = this.build_trade_dict({
942
939
  entry: x,
@@ -1647,7 +1644,6 @@ function buildConfig(app_config, {
1647
1644
  }
1648
1645
  const condition = (kind === "long" ? entry > app_config.support : entry >= app_config.support) && stop >= app_config.support * 0.999;
1649
1646
  if (kind === "short") {}
1650
- console.log({ entry, stop, condition, working_risk, config });
1651
1647
  const result = entry === stop ? [] : condition ? instance.build_entry({
1652
1648
  current_price: entry,
1653
1649
  stop_loss: stop,
@@ -3337,13 +3333,423 @@ class Strategy {
3337
3333
  }
3338
3334
  }
3339
3335
  // src/helpers/compound.ts
3340
- var name = "";
3336
+ function buildTrades(payload) {
3337
+ const { appConfig, settings, kind } = payload;
3338
+ const kelly_config = settings.kelly;
3339
+ const current_app_config = { ...appConfig[kind] };
3340
+ const entryNum = parseFloat(settings.entry);
3341
+ const stopNum = parseFloat(settings.stop);
3342
+ current_app_config.entry = entryNum;
3343
+ current_app_config.stop = stopNum;
3344
+ current_app_config.risk_per_trade = parseFloat(settings.risk);
3345
+ current_app_config.risk_reward = parseFloat(settings.risk_reward);
3346
+ current_app_config.kind = kind;
3347
+ current_app_config.kelly = kelly_config;
3348
+ const options = {
3349
+ take_profit: null,
3350
+ entry: current_app_config.entry,
3351
+ stop: current_app_config.stop,
3352
+ raw_instance: null,
3353
+ risk: current_app_config.risk_per_trade,
3354
+ no_of_trades: undefined,
3355
+ risk_reward: current_app_config.risk_reward,
3356
+ kind: current_app_config.kind,
3357
+ increase: true,
3358
+ gap: current_app_config.gap,
3359
+ rr: current_app_config.rr,
3360
+ price_places: current_app_config.price_places,
3361
+ decimal_places: current_app_config.decimal_places,
3362
+ use_kelly: kelly_config?.use_kelly,
3363
+ kelly_confidence_factor: kelly_config?.kelly_confidence_factor,
3364
+ kelly_minimum_risk: kelly_config?.kelly_minimum_risk,
3365
+ kelly_prediction_model: kelly_config?.kelly_prediction_model,
3366
+ kelly_func: kelly_config?.kelly_func,
3367
+ distribution: settings.distribution
3368
+ };
3369
+ if (kind === "long" && entryNum <= stopNum) {
3370
+ return [];
3371
+ }
3372
+ if (kind === "short" && entryNum >= stopNum) {
3373
+ return [];
3374
+ }
3375
+ try {
3376
+ const generatedTrades = sortedBuildConfig(current_app_config, options);
3377
+ return generatedTrades ?? [];
3378
+ } catch (error) {
3379
+ console.error("Error generating orders:", error);
3380
+ return [];
3381
+ }
3382
+ }
3383
+ function generateSummary({
3384
+ trades,
3385
+ fee_percent = 0.05,
3386
+ anchor
3387
+ }) {
3388
+ const avg_entry = trades[0].avg_entry;
3389
+ const avg_size = trades[0].avg_size;
3390
+ const expected_fee = avg_entry * avg_size * fee_percent / 100;
3391
+ return {
3392
+ first_entry: trades.at(-1).entry,
3393
+ last_entry: trades[0].entry,
3394
+ quantity: avg_size,
3395
+ entry: avg_entry,
3396
+ loss: trades[0].neg_pnl,
3397
+ number_of_trades: trades.length,
3398
+ fee: to_f(expected_fee, "%.2f"),
3399
+ anchor_pnl: anchor?.target_pnl
3400
+ };
3401
+ }
3402
+ function helperFuncToBuildTrades({
3403
+ custom_b_config,
3404
+ symbol_config,
3405
+ app_config_kind,
3406
+ appConfig,
3407
+ force_exact_risk = true
3408
+ }) {
3409
+ const risk = custom_b_config.risk * (custom_b_config.risk_factor || 1);
3410
+ let result = getRiskReward({
3411
+ entry: custom_b_config.entry,
3412
+ stop: custom_b_config.stop,
3413
+ risk,
3414
+ global_config: symbol_config,
3415
+ force_exact_risk,
3416
+ target_loss: custom_b_config.risk * (custom_b_config.risk_factor || 1),
3417
+ distribution: custom_b_config.distribution
3418
+ });
3419
+ if (!force_exact_risk) {
3420
+ result = {
3421
+ risk_reward: result,
3422
+ risk
3423
+ };
3424
+ }
3425
+ const trades = result.risk_reward ? buildTrades({
3426
+ appConfig: { [app_config_kind]: appConfig },
3427
+ kind: app_config_kind,
3428
+ settings: {
3429
+ entry: custom_b_config.entry,
3430
+ stop: custom_b_config.stop,
3431
+ risk: result.risk || custom_b_config.risk,
3432
+ risk_reward: result.risk_reward,
3433
+ distribution: custom_b_config.distribution
3434
+ }
3435
+ }) : [];
3436
+ const summary = trades.length > 0 ? generateSummary({ trades }) : {};
3437
+ return { trades, result, summary };
3438
+ }
3439
+ function constructAppConfig2({
3440
+ config,
3441
+ global_config
3442
+ }) {
3443
+ const options = {
3444
+ entry: config?.entry,
3445
+ stop: config?.stop,
3446
+ risk_reward: config?.risk_reward,
3447
+ risk: config?.risk,
3448
+ symbol: config.symbol
3449
+ };
3450
+ const { entries: _entries, ...appConfig } = buildAppConfig(global_config, options);
3451
+ return appConfig;
3452
+ }
3453
+ function buildWithOptimumReward({
3454
+ config,
3455
+ settings,
3456
+ global_config
3457
+ }) {
3458
+ const kind = config.entry > config.stop ? "long" : "short";
3459
+ let stop = settings.stop;
3460
+ let entry = settings.entry;
3461
+ const risk = settings.risk;
3462
+ const stop_ratio = settings.stop_ratio || 1;
3463
+ const distribution = settings.distribution || config?.distribution;
3464
+ const custom_b_config = {
3465
+ entry,
3466
+ stop,
3467
+ risk,
3468
+ distribution
3469
+ };
3470
+ const appConfig = constructAppConfig2({
3471
+ config,
3472
+ global_config
3473
+ });
3474
+ const { trades, summary, result } = helperFuncToBuildTrades({
3475
+ custom_b_config,
3476
+ app_config_kind: kind,
3477
+ appConfig,
3478
+ symbol_config: global_config
3479
+ });
3480
+ const adjusted_size = summary.quantity;
3481
+ const symbol_config = global_config;
3482
+ const entryDetails = {
3483
+ entry: to_f(custom_b_config.entry, symbol_config.price_places),
3484
+ stop: to_f(custom_b_config.stop, symbol_config.price_places),
3485
+ risk: to_f(result.risk, "%.2f"),
3486
+ risk_reward: result.risk_reward,
3487
+ avg_entry: to_f(summary.entry, symbol_config.price_places),
3488
+ avg_size: to_f(adjusted_size, symbol_config.decimal_places),
3489
+ first_entry: to_f(summary.first_entry, symbol_config.price_places),
3490
+ pnl: to_f(custom_b_config.risk, "%.2f"),
3491
+ fee: to_f(summary.fee, "%.2f"),
3492
+ loss: to_f(summary.loss, "%.2f"),
3493
+ last_entry: to_f(summary.last_entry, symbol_config.price_places),
3494
+ margin: to_f(summary.entry * adjusted_size / symbol_config.leverage, "%.2f")
3495
+ };
3496
+ return {
3497
+ trades,
3498
+ summary: entryDetails,
3499
+ config: {
3500
+ ...custom_b_config,
3501
+ ...result,
3502
+ stop_ratio
3503
+ },
3504
+ stop_order: {
3505
+ quantity: entryDetails.avg_size * stop_ratio,
3506
+ price: entryDetails.stop
3507
+ },
3508
+ kind
3509
+ };
3510
+ }
3511
+ function generateOppositeOptimum({
3512
+ config,
3513
+ global_config,
3514
+ settings,
3515
+ ratio = 1,
3516
+ distribution,
3517
+ risk_factor = 1
3518
+ }) {
3519
+ const configKind = config.entry > config.stop ? "long" : "short";
3520
+ if (configKind === "long" && config.entry > config.stop) {
3521
+ if (settings.stop <= settings.entry) {
3522
+ throw new Error("Invalid input: For long config positions, opposite settings must have stop > entry");
3523
+ }
3524
+ } else if (configKind === "short" && config.entry < config.stop) {
3525
+ if (settings.stop >= settings.entry) {
3526
+ throw new Error("Invalid input: For short config positions, opposite settings must have stop < entry");
3527
+ }
3528
+ }
3529
+ const kind = config.entry > config.stop ? "long" : "short";
3530
+ const app_config_kind = kind === "long" ? "short" : "long";
3531
+ let risk = settings.risk;
3532
+ const custom_b_config = {
3533
+ entry: settings.entry,
3534
+ stop: settings.stop,
3535
+ risk: risk * ratio,
3536
+ distribution: distribution || "inverse-exponential",
3537
+ risk_factor
3538
+ };
3539
+ const appConfig = constructAppConfig2({
3540
+ config: {
3541
+ ...config,
3542
+ ...custom_b_config
3543
+ },
3544
+ global_config
3545
+ });
3546
+ const { result, trades, summary } = helperFuncToBuildTrades({
3547
+ custom_b_config,
3548
+ symbol_config: global_config,
3549
+ app_config_kind,
3550
+ appConfig
3551
+ });
3552
+ if (Object.keys(summary).length === 0) {
3553
+ return {
3554
+ trades,
3555
+ summary,
3556
+ config: custom_b_config,
3557
+ kind: app_config_kind
3558
+ };
3559
+ }
3560
+ const symbol_config = global_config;
3561
+ const entryDetails = {
3562
+ entry: to_f(custom_b_config.entry, symbol_config.price_places),
3563
+ stop: to_f(custom_b_config.stop, symbol_config.price_places),
3564
+ risk: to_f(result.risk, "%.2f"),
3565
+ risk_reward: result.risk_reward,
3566
+ avg_entry: to_f(summary.entry, symbol_config.price_places),
3567
+ avg_size: to_f(summary.quantity, symbol_config.decimal_places),
3568
+ first_entry: to_f(summary.first_entry, symbol_config.price_places),
3569
+ pnl: to_f(custom_b_config.risk, "%.2f"),
3570
+ fee: to_f(summary.fee, "%.2f"),
3571
+ loss: to_f(summary.loss, "%.2f"),
3572
+ last_entry: to_f(summary.last_entry, symbol_config.price_places),
3573
+ defaultEntry: settings.entry ? to_f(settings.entry, symbol_config.price_places) : null
3574
+ };
3575
+ return {
3576
+ trades,
3577
+ summary: entryDetails,
3578
+ config: {
3579
+ ...custom_b_config,
3580
+ ...result
3581
+ },
3582
+ kind: app_config_kind
3583
+ };
3584
+ }
3585
+ function defaultTradeFromCurrentState({
3586
+ config,
3587
+ global_config
3588
+ }) {
3589
+ const kind = config.entry > config.stop ? "long" : "short";
3590
+ const settings = {
3591
+ entry: config?.entry,
3592
+ stop: config?.stop,
3593
+ risk: config?.risk,
3594
+ distribution: config?.distribution,
3595
+ risk_reward: config?.risk_reward
3596
+ };
3597
+ const appConfig = constructAppConfig2({
3598
+ config,
3599
+ global_config
3600
+ });
3601
+ const trades = buildTrades({
3602
+ appConfig: { [kind]: appConfig },
3603
+ kind,
3604
+ settings
3605
+ });
3606
+ return {
3607
+ trades,
3608
+ summary: generateSummary({
3609
+ trades,
3610
+ fee_percent: global_config.fee_percent
3611
+ })
3612
+ };
3613
+ }
3614
+ function increaseTradeHelper({
3615
+ increase_qty,
3616
+ stop,
3617
+ config,
3618
+ global_config,
3619
+ style,
3620
+ entry,
3621
+ position: position2,
3622
+ stop_ratio = 1,
3623
+ distribution: default_distribution
3624
+ }) {
3625
+ const symbol_config = global_config;
3626
+ const kind = config.entry > config.stop ? "long" : "short";
3627
+ const distribution = default_distribution || config.distribution || "inverse-exponential";
3628
+ const appConfig = constructAppConfig2({
3629
+ config,
3630
+ global_config
3631
+ });
3632
+ const currentState = defaultTradeFromCurrentState({
3633
+ config,
3634
+ global_config
3635
+ });
3636
+ const { optimal_risk, neg_pnl } = getOptimumStopAndRisk(appConfig, {
3637
+ max_size: increase_qty,
3638
+ target_stop: stop,
3639
+ distribution
3640
+ });
3641
+ if (neg_pnl === 0) {
3642
+ return {
3643
+ trades: [],
3644
+ summary: {},
3645
+ config: {},
3646
+ kind,
3647
+ current: currentState
3648
+ };
3649
+ }
3650
+ const custom_b_config = {
3651
+ entry,
3652
+ stop,
3653
+ risk: style === "minimum" ? Math.abs(neg_pnl) : optimal_risk,
3654
+ distribution
3655
+ };
3656
+ const { result, trades, summary } = helperFuncToBuildTrades({
3657
+ custom_b_config,
3658
+ symbol_config,
3659
+ appConfig,
3660
+ app_config_kind: kind
3661
+ });
3662
+ if (Object.keys(summary).length === 0) {
3663
+ return {
3664
+ trades,
3665
+ summary,
3666
+ config: {
3667
+ ...custom_b_config,
3668
+ ...result
3669
+ },
3670
+ kind,
3671
+ current: currentState
3672
+ };
3673
+ }
3674
+ const new_avg_values = determine_average_entry_and_size([
3675
+ {
3676
+ price: position2.entry,
3677
+ quantity: position2.quantity
3678
+ },
3679
+ {
3680
+ price: summary?.entry,
3681
+ quantity: summary?.quantity
3682
+ }
3683
+ ], symbol_config.decimal_places, symbol_config.price_places);
3684
+ summary.entry = new_avg_values.entry;
3685
+ summary.quantity = new_avg_values.quantity;
3686
+ const loss = Math.abs(summary.entry - custom_b_config.stop) * summary.quantity;
3687
+ const entryDetails = {
3688
+ entry: to_f(custom_b_config.entry, symbol_config.price_places),
3689
+ stop: to_f(custom_b_config.stop, symbol_config.price_places),
3690
+ risk: to_f(result.risk, symbol_config.price_places),
3691
+ risk_reward: result.risk_reward,
3692
+ avg_entry: to_f(summary.entry, symbol_config.price_places),
3693
+ avg_size: to_f(summary.quantity, symbol_config.decimal_places),
3694
+ first_entry: to_f(summary.first_entry, symbol_config.price_places),
3695
+ pnl: to_f(custom_b_config.risk, "%.2f"),
3696
+ fee: to_f(summary.fee, "%.2f"),
3697
+ loss: to_f(loss, "%.2f"),
3698
+ last_entry: to_f(summary.last_entry, symbol_config.price_places),
3699
+ margin: to_f(summary.entry * summary.quantity / global_config.leverage, "%.2f")
3700
+ };
3701
+ return {
3702
+ trades,
3703
+ summary: entryDetails,
3704
+ stop_order: {
3705
+ quantity: entryDetails.avg_size * stop_ratio,
3706
+ price: entryDetails.stop
3707
+ },
3708
+ config: {
3709
+ ...custom_b_config,
3710
+ ...result
3711
+ },
3712
+ kind,
3713
+ current: currentState
3714
+ };
3715
+ }
3716
+ function generatePositionIncreaseTrade({
3717
+ account,
3718
+ zoneAccount,
3719
+ ratio = 0.1,
3720
+ config,
3721
+ global_config,
3722
+ style = "minimum",
3723
+ distribution = "inverse-exponential"
3724
+ }) {
3725
+ const kind = config.entry > config.stop ? "long" : "short";
3726
+ const target_max_quantity = kind === "long" ? account.short.quantity : account.long.quantity;
3727
+ const increase_qty = target_max_quantity * ratio;
3728
+ const entry = zoneAccount.entry;
3729
+ const stop = zoneAccount.stop;
3730
+ return increaseTradeHelper({
3731
+ config,
3732
+ position: account[kind],
3733
+ global_config,
3734
+ entry,
3735
+ stop,
3736
+ style,
3737
+ increase_qty,
3738
+ distribution
3739
+ });
3740
+ }
3741
+ var compoundAPI = {
3742
+ buildWithOptimumReward,
3743
+ constructAppConfig: constructAppConfig2,
3744
+ generateOppositeOptimum,
3745
+ increaseTradeHelper,
3746
+ generatePositionIncreaseTrade
3747
+ };
3341
3748
  export {
3342
3749
  to_f,
3343
3750
  sortedBuildConfig,
3344
3751
  range,
3345
3752
  profitHelper,
3346
- name,
3347
3753
  logWithLineNumber,
3348
3754
  groupIntoPairsWithSumLessThan,
3349
3755
  groupIntoPairs,
@@ -3383,6 +3789,7 @@ export {
3383
3789
  computeSellZones,
3384
3790
  computeRiskReward,
3385
3791
  computeProfitDetail,
3792
+ compoundAPI,
3386
3793
  calculateFactorFromTakeProfit,
3387
3794
  calculateFactorFromSellQuantity,
3388
3795
  buildConfig,