@gbozee/ultimate 0.0.2-73 → 0.0.2-74

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.
@@ -438,6 +438,9 @@ export declare class Strategy {
438
438
  get short_tp(): number;
439
439
  generateGapClosingAlgorithm(payload: {
440
440
  kind: "long" | "short";
441
+ ignore_entries?: boolean;
442
+ reduce_ratio?: number;
443
+ sell_factor?: number;
441
444
  }): {
442
445
  [x: string]: any;
443
446
  risk: number;
@@ -445,11 +448,17 @@ export declare class Strategy {
445
448
  last_entry: any;
446
449
  first_entry: any;
447
450
  threshold: any;
451
+ spread: number;
452
+ gap_loss: number;
453
+ net_profit: number;
448
454
  };
449
455
  runIterations(payload: {
450
456
  kind: "long" | "short";
451
457
  iterations: number;
452
458
  risk_reward?: number;
459
+ ignore_entries?: boolean;
460
+ reduce_ratio?: number;
461
+ sell_factor?: number;
453
462
  }): {
454
463
  [x: string]: any;
455
464
  risk: number;
@@ -457,6 +466,9 @@ export declare class Strategy {
457
466
  last_entry: any;
458
467
  first_entry: any;
459
468
  threshold: any;
469
+ spread: number;
470
+ gap_loss: number;
471
+ net_profit: number;
460
472
  }[];
461
473
  getPositionAfterTp(payload: {
462
474
  kind: "long" | "short";
@@ -1830,7 +1830,12 @@ class Strategy {
1830
1830
  return this.tp("short");
1831
1831
  }
1832
1832
  generateGapClosingAlgorithm(payload) {
1833
- const { kind } = payload;
1833
+ const {
1834
+ kind,
1835
+ ignore_entries = false,
1836
+ reduce_ratio = 1,
1837
+ sell_factor = 1
1838
+ } = payload;
1834
1839
  const { entry, quantity } = this.position[kind];
1835
1840
  const focus_position = this.position[kind];
1836
1841
  const reverse_kind = kind == "long" ? "short" : "long";
@@ -1857,7 +1862,10 @@ class Strategy {
1857
1862
  if (!app_config) {
1858
1863
  return null;
1859
1864
  }
1860
- const { entries, ...rest } = app_config;
1865
+ let { entries, ...rest } = app_config;
1866
+ if (ignore_entries) {
1867
+ entries = [];
1868
+ }
1861
1869
  const risk = this.to_f(rest.risk_per_trade);
1862
1870
  const adjusted_focus_entries = entries.map((entry2) => {
1863
1871
  let adjusted_price = entry2.price;
@@ -1879,7 +1887,7 @@ class Strategy {
1879
1887
  quantity
1880
1888
  }
1881
1889
  ]), rest.decimal_places, rest.price_places);
1882
- const focus_loss = this.to_f((avg.price - second_payload.stop) * avg.quantity);
1890
+ const focus_loss = this.to_f(Math.abs(avg.price - second_payload.stop) * avg.quantity);
1883
1891
  let below_reverse_entries = kind === "long" ? entries.filter((u) => {
1884
1892
  return u.entry < (reverse_position.entry || focus_position.entry);
1885
1893
  }) : entries.filter((u) => {
@@ -1906,18 +1914,20 @@ class Strategy {
1906
1914
  quantity: reverse_position.quantity
1907
1915
  }
1908
1916
  ]), rest.decimal_places, rest.price_places);
1909
- const reverse_pnl = this.to_f((reverse_avg.price - second_payload.stop) * reverse_avg.quantity);
1917
+ const sell_quantity = this.to_df(reverse_avg.quantity * sell_factor);
1918
+ const reverse_pnl = this.to_f(Math.abs(reverse_avg.price - second_payload.stop) * sell_quantity);
1910
1919
  const fee_to_pay = this.calculate_fee({
1911
1920
  price: avg.entry,
1912
1921
  quantity: avg.quantity
1913
1922
  }) + this.calculate_fee({
1914
1923
  price: reverse_avg.entry,
1915
- quantity: reverse_avg.quantity
1924
+ quantity: sell_quantity
1916
1925
  });
1917
1926
  const net_reverse_pnl = reverse_pnl - fee_to_pay;
1918
- const ratio = net_reverse_pnl / focus_loss;
1927
+ const ratio = net_reverse_pnl * reduce_ratio / focus_loss;
1919
1928
  const quantity_to_sell = this.to_df(ratio * avg.quantity);
1920
1929
  const remaining_quantity = this.to_df(avg.quantity - quantity_to_sell);
1930
+ const incurred_loss = this.to_f((avg.price - second_payload.stop) * quantity_to_sell);
1921
1931
  return {
1922
1932
  risk,
1923
1933
  risk_reward: this.config.risk_reward,
@@ -1929,7 +1939,8 @@ class Strategy {
1929
1939
  stop_quantity: quantity_to_sell,
1930
1940
  re_entry_quantity: remaining_quantity,
1931
1941
  initial_pnl: this.pnl(kind),
1932
- tp: second_payload.entry
1942
+ tp: second_payload.entry,
1943
+ incurred_loss
1933
1944
  },
1934
1945
  [reverse_kind]: {
1935
1946
  avg_entry: reverse_avg.entry,
@@ -1937,32 +1948,48 @@ class Strategy {
1937
1948
  pnl: reverse_pnl,
1938
1949
  tp: second_payload.stop,
1939
1950
  re_entry_quantity: remaining_quantity,
1940
- initial_pnl: this.pnl(reverse_kind)
1951
+ initial_pnl: this.pnl(reverse_kind),
1952
+ remaining_quantity: this.to_df(reverse_avg.quantity - sell_quantity)
1941
1953
  },
1942
1954
  last_entry: rest.last_value.entry,
1943
- first_entry: entries.at(-1).entry,
1944
- threshold
1955
+ first_entry: entries.at(-1)?.entry,
1956
+ threshold,
1957
+ spread: Math.abs(avg.entry - reverse_avg.entry),
1958
+ gap_loss: to_f(Math.abs(avg.entry - reverse_avg.entry) * reverse_avg.quantity, "%.2f"),
1959
+ net_profit: incurred_loss + reverse_pnl
1945
1960
  };
1946
1961
  }
1947
1962
  runIterations(payload) {
1948
- const { kind, iterations } = payload;
1963
+ const {
1964
+ kind,
1965
+ iterations,
1966
+ ignore_entries = false,
1967
+ reduce_ratio = 1,
1968
+ sell_factor = 1
1969
+ } = payload;
1949
1970
  const reverse_kind = kind == "long" ? "short" : "long";
1950
1971
  const result = [];
1951
1972
  let position2 = {
1952
1973
  long: this.position.long,
1953
1974
  short: this.position.short
1954
1975
  };
1976
+ let tp_percent_multiplier = 1;
1977
+ let short_tp_factor_multiplier = 1;
1955
1978
  for (let i = 0;i < iterations; i++) {
1956
1979
  const instance = new Strategy({
1957
1980
  long: position2.long,
1958
1981
  short: position2.short,
1959
1982
  config: {
1960
1983
  ...this.config,
1961
- tp_percent: this.config.tp_percent + i * 4
1984
+ tp_percent: this.config.tp_percent * tp_percent_multiplier,
1985
+ short_tp_factor: this.config.short_tp_factor * short_tp_factor_multiplier
1962
1986
  }
1963
1987
  });
1964
1988
  const algorithm = instance.generateGapClosingAlgorithm({
1965
- kind
1989
+ kind,
1990
+ ignore_entries,
1991
+ reduce_ratio,
1992
+ sell_factor
1966
1993
  });
1967
1994
  if (!algorithm) {
1968
1995
  console.log("No algorithm found");
@@ -1974,9 +2001,31 @@ class Strategy {
1974
2001
  entry: algorithm[kind].avg_entry,
1975
2002
  quantity: algorithm[kind].re_entry_quantity
1976
2003
  };
2004
+ let reverse_entry = algorithm[reverse_kind].tp;
2005
+ let reverse_quantity = algorithm[reverse_kind].re_entry_quantity;
2006
+ if (algorithm[reverse_kind].remaining_quantity > 0) {
2007
+ const purchase_to_occur = {
2008
+ price: reverse_entry,
2009
+ quantity: algorithm[reverse_kind].remaining_quantity
2010
+ };
2011
+ const avg = determine_average_entry_and_size([
2012
+ purchase_to_occur,
2013
+ {
2014
+ price: algorithm[reverse_kind].avg_entry,
2015
+ quantity: reverse_quantity - algorithm[reverse_kind].remaining_quantity
2016
+ }
2017
+ ], this.config.global_config.decimal_places, this.config.global_config.price_places);
2018
+ reverse_entry = avg.entry;
2019
+ reverse_quantity = avg.quantity;
2020
+ if (reverse_kind === "short") {
2021
+ short_tp_factor_multiplier = 2;
2022
+ } else {
2023
+ tp_percent_multiplier = 2;
2024
+ }
2025
+ }
1977
2026
  position2[reverse_kind] = {
1978
- entry: algorithm[reverse_kind].tp,
1979
- quantity: algorithm[reverse_kind].re_entry_quantity
2027
+ entry: reverse_entry,
2028
+ quantity: reverse_quantity
1980
2029
  };
1981
2030
  }
1982
2031
  return result;
package/dist/index.cjs CHANGED
@@ -53890,7 +53890,12 @@ class Strategy {
53890
53890
  return this.tp("short");
53891
53891
  }
53892
53892
  generateGapClosingAlgorithm(payload) {
53893
- const { kind } = payload;
53893
+ const {
53894
+ kind,
53895
+ ignore_entries = false,
53896
+ reduce_ratio = 1,
53897
+ sell_factor = 1
53898
+ } = payload;
53894
53899
  const { entry, quantity } = this.position[kind];
53895
53900
  const focus_position = this.position[kind];
53896
53901
  const reverse_kind = kind == "long" ? "short" : "long";
@@ -53917,7 +53922,10 @@ class Strategy {
53917
53922
  if (!app_config) {
53918
53923
  return null;
53919
53924
  }
53920
- const { entries, ...rest } = app_config;
53925
+ let { entries, ...rest } = app_config;
53926
+ if (ignore_entries) {
53927
+ entries = [];
53928
+ }
53921
53929
  const risk = this.to_f(rest.risk_per_trade);
53922
53930
  const adjusted_focus_entries = entries.map((entry2) => {
53923
53931
  let adjusted_price = entry2.price;
@@ -53939,7 +53947,7 @@ class Strategy {
53939
53947
  quantity
53940
53948
  }
53941
53949
  ]), rest.decimal_places, rest.price_places);
53942
- const focus_loss = this.to_f((avg.price - second_payload.stop) * avg.quantity);
53950
+ const focus_loss = this.to_f(Math.abs(avg.price - second_payload.stop) * avg.quantity);
53943
53951
  let below_reverse_entries = kind === "long" ? entries.filter((u) => {
53944
53952
  return u.entry < (reverse_position.entry || focus_position.entry);
53945
53953
  }) : entries.filter((u) => {
@@ -53966,18 +53974,20 @@ class Strategy {
53966
53974
  quantity: reverse_position.quantity
53967
53975
  }
53968
53976
  ]), rest.decimal_places, rest.price_places);
53969
- const reverse_pnl = this.to_f((reverse_avg.price - second_payload.stop) * reverse_avg.quantity);
53977
+ const sell_quantity = this.to_df(reverse_avg.quantity * sell_factor);
53978
+ const reverse_pnl = this.to_f(Math.abs(reverse_avg.price - second_payload.stop) * sell_quantity);
53970
53979
  const fee_to_pay = this.calculate_fee({
53971
53980
  price: avg.entry,
53972
53981
  quantity: avg.quantity
53973
53982
  }) + this.calculate_fee({
53974
53983
  price: reverse_avg.entry,
53975
- quantity: reverse_avg.quantity
53984
+ quantity: sell_quantity
53976
53985
  });
53977
53986
  const net_reverse_pnl = reverse_pnl - fee_to_pay;
53978
- const ratio = net_reverse_pnl / focus_loss;
53987
+ const ratio = net_reverse_pnl * reduce_ratio / focus_loss;
53979
53988
  const quantity_to_sell = this.to_df(ratio * avg.quantity);
53980
53989
  const remaining_quantity = this.to_df(avg.quantity - quantity_to_sell);
53990
+ const incurred_loss = this.to_f((avg.price - second_payload.stop) * quantity_to_sell);
53981
53991
  return {
53982
53992
  risk,
53983
53993
  risk_reward: this.config.risk_reward,
@@ -53989,7 +53999,8 @@ class Strategy {
53989
53999
  stop_quantity: quantity_to_sell,
53990
54000
  re_entry_quantity: remaining_quantity,
53991
54001
  initial_pnl: this.pnl(kind),
53992
- tp: second_payload.entry
54002
+ tp: second_payload.entry,
54003
+ incurred_loss
53993
54004
  },
53994
54005
  [reverse_kind]: {
53995
54006
  avg_entry: reverse_avg.entry,
@@ -53997,32 +54008,48 @@ class Strategy {
53997
54008
  pnl: reverse_pnl,
53998
54009
  tp: second_payload.stop,
53999
54010
  re_entry_quantity: remaining_quantity,
54000
- initial_pnl: this.pnl(reverse_kind)
54011
+ initial_pnl: this.pnl(reverse_kind),
54012
+ remaining_quantity: this.to_df(reverse_avg.quantity - sell_quantity)
54001
54013
  },
54002
54014
  last_entry: rest.last_value.entry,
54003
- first_entry: entries.at(-1).entry,
54004
- threshold
54015
+ first_entry: entries.at(-1)?.entry,
54016
+ threshold,
54017
+ spread: Math.abs(avg.entry - reverse_avg.entry),
54018
+ gap_loss: to_f2(Math.abs(avg.entry - reverse_avg.entry) * reverse_avg.quantity, "%.2f"),
54019
+ net_profit: incurred_loss + reverse_pnl
54005
54020
  };
54006
54021
  }
54007
54022
  runIterations(payload) {
54008
- const { kind, iterations } = payload;
54023
+ const {
54024
+ kind,
54025
+ iterations,
54026
+ ignore_entries = false,
54027
+ reduce_ratio = 1,
54028
+ sell_factor = 1
54029
+ } = payload;
54009
54030
  const reverse_kind = kind == "long" ? "short" : "long";
54010
54031
  const result = [];
54011
54032
  let position2 = {
54012
54033
  long: this.position.long,
54013
54034
  short: this.position.short
54014
54035
  };
54036
+ let tp_percent_multiplier = 1;
54037
+ let short_tp_factor_multiplier = 1;
54015
54038
  for (let i2 = 0;i2 < iterations; i2++) {
54016
54039
  const instance = new Strategy({
54017
54040
  long: position2.long,
54018
54041
  short: position2.short,
54019
54042
  config: {
54020
54043
  ...this.config,
54021
- tp_percent: this.config.tp_percent + i2 * 4
54044
+ tp_percent: this.config.tp_percent * tp_percent_multiplier,
54045
+ short_tp_factor: this.config.short_tp_factor * short_tp_factor_multiplier
54022
54046
  }
54023
54047
  });
54024
54048
  const algorithm = instance.generateGapClosingAlgorithm({
54025
- kind
54049
+ kind,
54050
+ ignore_entries,
54051
+ reduce_ratio,
54052
+ sell_factor
54026
54053
  });
54027
54054
  if (!algorithm) {
54028
54055
  console.log("No algorithm found");
@@ -54034,9 +54061,31 @@ class Strategy {
54034
54061
  entry: algorithm[kind].avg_entry,
54035
54062
  quantity: algorithm[kind].re_entry_quantity
54036
54063
  };
54064
+ let reverse_entry = algorithm[reverse_kind].tp;
54065
+ let reverse_quantity = algorithm[reverse_kind].re_entry_quantity;
54066
+ if (algorithm[reverse_kind].remaining_quantity > 0) {
54067
+ const purchase_to_occur = {
54068
+ price: reverse_entry,
54069
+ quantity: algorithm[reverse_kind].remaining_quantity
54070
+ };
54071
+ const avg = determine_average_entry_and_size([
54072
+ purchase_to_occur,
54073
+ {
54074
+ price: algorithm[reverse_kind].avg_entry,
54075
+ quantity: reverse_quantity - algorithm[reverse_kind].remaining_quantity
54076
+ }
54077
+ ], this.config.global_config.decimal_places, this.config.global_config.price_places);
54078
+ reverse_entry = avg.entry;
54079
+ reverse_quantity = avg.quantity;
54080
+ if (reverse_kind === "short") {
54081
+ short_tp_factor_multiplier = 2;
54082
+ } else {
54083
+ tp_percent_multiplier = 2;
54084
+ }
54085
+ }
54037
54086
  position2[reverse_kind] = {
54038
- entry: algorithm[reverse_kind].tp,
54039
- quantity: algorithm[reverse_kind].re_entry_quantity
54087
+ entry: reverse_entry,
54088
+ quantity: reverse_quantity
54040
54089
  };
54041
54090
  }
54042
54091
  return result;
@@ -57669,6 +57718,9 @@ class ExchangeAccount {
57669
57718
  if (threshold_qty > 0 && track_position.quantity >= threshold_qty) {
57670
57719
  should_place_order = true;
57671
57720
  }
57721
+ if (focus_position.quantity === 0) {
57722
+ should_place_order = true;
57723
+ }
57672
57724
  if (track_position.quantity !== focus_position.quantity && focus_position.quantity < track_position.quantity && should_place_order) {
57673
57725
  const remaining_quantity = Math.abs(track_position.quantity - focus_position.quantity);
57674
57726
  await this.placeMarketOrder({
package/dist/index.d.ts CHANGED
@@ -564,6 +564,9 @@ export declare class Strategy {
564
564
  get short_tp(): number;
565
565
  generateGapClosingAlgorithm(payload: {
566
566
  kind: "long" | "short";
567
+ ignore_entries?: boolean;
568
+ reduce_ratio?: number;
569
+ sell_factor?: number;
567
570
  }): {
568
571
  [x: string]: any;
569
572
  risk: number;
@@ -571,11 +574,17 @@ export declare class Strategy {
571
574
  last_entry: any;
572
575
  first_entry: any;
573
576
  threshold: any;
577
+ spread: number;
578
+ gap_loss: number;
579
+ net_profit: number;
574
580
  };
575
581
  runIterations(payload: {
576
582
  kind: "long" | "short";
577
583
  iterations: number;
578
584
  risk_reward?: number;
585
+ ignore_entries?: boolean;
586
+ reduce_ratio?: number;
587
+ sell_factor?: number;
579
588
  }): {
580
589
  [x: string]: any;
581
590
  risk: number;
@@ -583,6 +592,9 @@ export declare class Strategy {
583
592
  last_entry: any;
584
593
  first_entry: any;
585
594
  threshold: any;
595
+ spread: number;
596
+ gap_loss: number;
597
+ net_profit: number;
586
598
  }[];
587
599
  getPositionAfterTp(payload: {
588
600
  kind: "long" | "short";
@@ -1463,6 +1475,9 @@ declare class ExchangeAccount$1 {
1463
1475
  last_entry: any;
1464
1476
  first_entry: any;
1465
1477
  threshold: any;
1478
+ spread: number;
1479
+ gap_loss: number;
1480
+ net_profit: number;
1466
1481
  }[]>;
1467
1482
  getCurrentRun(payload: {
1468
1483
  symbol: string;
package/dist/index.js CHANGED
@@ -53845,7 +53845,12 @@ class Strategy {
53845
53845
  return this.tp("short");
53846
53846
  }
53847
53847
  generateGapClosingAlgorithm(payload) {
53848
- const { kind } = payload;
53848
+ const {
53849
+ kind,
53850
+ ignore_entries = false,
53851
+ reduce_ratio = 1,
53852
+ sell_factor = 1
53853
+ } = payload;
53849
53854
  const { entry, quantity } = this.position[kind];
53850
53855
  const focus_position = this.position[kind];
53851
53856
  const reverse_kind = kind == "long" ? "short" : "long";
@@ -53872,7 +53877,10 @@ class Strategy {
53872
53877
  if (!app_config) {
53873
53878
  return null;
53874
53879
  }
53875
- const { entries, ...rest } = app_config;
53880
+ let { entries, ...rest } = app_config;
53881
+ if (ignore_entries) {
53882
+ entries = [];
53883
+ }
53876
53884
  const risk = this.to_f(rest.risk_per_trade);
53877
53885
  const adjusted_focus_entries = entries.map((entry2) => {
53878
53886
  let adjusted_price = entry2.price;
@@ -53894,7 +53902,7 @@ class Strategy {
53894
53902
  quantity
53895
53903
  }
53896
53904
  ]), rest.decimal_places, rest.price_places);
53897
- const focus_loss = this.to_f((avg.price - second_payload.stop) * avg.quantity);
53905
+ const focus_loss = this.to_f(Math.abs(avg.price - second_payload.stop) * avg.quantity);
53898
53906
  let below_reverse_entries = kind === "long" ? entries.filter((u) => {
53899
53907
  return u.entry < (reverse_position.entry || focus_position.entry);
53900
53908
  }) : entries.filter((u) => {
@@ -53921,18 +53929,20 @@ class Strategy {
53921
53929
  quantity: reverse_position.quantity
53922
53930
  }
53923
53931
  ]), rest.decimal_places, rest.price_places);
53924
- const reverse_pnl = this.to_f((reverse_avg.price - second_payload.stop) * reverse_avg.quantity);
53932
+ const sell_quantity = this.to_df(reverse_avg.quantity * sell_factor);
53933
+ const reverse_pnl = this.to_f(Math.abs(reverse_avg.price - second_payload.stop) * sell_quantity);
53925
53934
  const fee_to_pay = this.calculate_fee({
53926
53935
  price: avg.entry,
53927
53936
  quantity: avg.quantity
53928
53937
  }) + this.calculate_fee({
53929
53938
  price: reverse_avg.entry,
53930
- quantity: reverse_avg.quantity
53939
+ quantity: sell_quantity
53931
53940
  });
53932
53941
  const net_reverse_pnl = reverse_pnl - fee_to_pay;
53933
- const ratio = net_reverse_pnl / focus_loss;
53942
+ const ratio = net_reverse_pnl * reduce_ratio / focus_loss;
53934
53943
  const quantity_to_sell = this.to_df(ratio * avg.quantity);
53935
53944
  const remaining_quantity = this.to_df(avg.quantity - quantity_to_sell);
53945
+ const incurred_loss = this.to_f((avg.price - second_payload.stop) * quantity_to_sell);
53936
53946
  return {
53937
53947
  risk,
53938
53948
  risk_reward: this.config.risk_reward,
@@ -53944,7 +53954,8 @@ class Strategy {
53944
53954
  stop_quantity: quantity_to_sell,
53945
53955
  re_entry_quantity: remaining_quantity,
53946
53956
  initial_pnl: this.pnl(kind),
53947
- tp: second_payload.entry
53957
+ tp: second_payload.entry,
53958
+ incurred_loss
53948
53959
  },
53949
53960
  [reverse_kind]: {
53950
53961
  avg_entry: reverse_avg.entry,
@@ -53952,32 +53963,48 @@ class Strategy {
53952
53963
  pnl: reverse_pnl,
53953
53964
  tp: second_payload.stop,
53954
53965
  re_entry_quantity: remaining_quantity,
53955
- initial_pnl: this.pnl(reverse_kind)
53966
+ initial_pnl: this.pnl(reverse_kind),
53967
+ remaining_quantity: this.to_df(reverse_avg.quantity - sell_quantity)
53956
53968
  },
53957
53969
  last_entry: rest.last_value.entry,
53958
- first_entry: entries.at(-1).entry,
53959
- threshold
53970
+ first_entry: entries.at(-1)?.entry,
53971
+ threshold,
53972
+ spread: Math.abs(avg.entry - reverse_avg.entry),
53973
+ gap_loss: to_f2(Math.abs(avg.entry - reverse_avg.entry) * reverse_avg.quantity, "%.2f"),
53974
+ net_profit: incurred_loss + reverse_pnl
53960
53975
  };
53961
53976
  }
53962
53977
  runIterations(payload) {
53963
- const { kind, iterations } = payload;
53978
+ const {
53979
+ kind,
53980
+ iterations,
53981
+ ignore_entries = false,
53982
+ reduce_ratio = 1,
53983
+ sell_factor = 1
53984
+ } = payload;
53964
53985
  const reverse_kind = kind == "long" ? "short" : "long";
53965
53986
  const result = [];
53966
53987
  let position2 = {
53967
53988
  long: this.position.long,
53968
53989
  short: this.position.short
53969
53990
  };
53991
+ let tp_percent_multiplier = 1;
53992
+ let short_tp_factor_multiplier = 1;
53970
53993
  for (let i2 = 0;i2 < iterations; i2++) {
53971
53994
  const instance = new Strategy({
53972
53995
  long: position2.long,
53973
53996
  short: position2.short,
53974
53997
  config: {
53975
53998
  ...this.config,
53976
- tp_percent: this.config.tp_percent + i2 * 4
53999
+ tp_percent: this.config.tp_percent * tp_percent_multiplier,
54000
+ short_tp_factor: this.config.short_tp_factor * short_tp_factor_multiplier
53977
54001
  }
53978
54002
  });
53979
54003
  const algorithm = instance.generateGapClosingAlgorithm({
53980
- kind
54004
+ kind,
54005
+ ignore_entries,
54006
+ reduce_ratio,
54007
+ sell_factor
53981
54008
  });
53982
54009
  if (!algorithm) {
53983
54010
  console.log("No algorithm found");
@@ -53989,9 +54016,31 @@ class Strategy {
53989
54016
  entry: algorithm[kind].avg_entry,
53990
54017
  quantity: algorithm[kind].re_entry_quantity
53991
54018
  };
54019
+ let reverse_entry = algorithm[reverse_kind].tp;
54020
+ let reverse_quantity = algorithm[reverse_kind].re_entry_quantity;
54021
+ if (algorithm[reverse_kind].remaining_quantity > 0) {
54022
+ const purchase_to_occur = {
54023
+ price: reverse_entry,
54024
+ quantity: algorithm[reverse_kind].remaining_quantity
54025
+ };
54026
+ const avg = determine_average_entry_and_size([
54027
+ purchase_to_occur,
54028
+ {
54029
+ price: algorithm[reverse_kind].avg_entry,
54030
+ quantity: reverse_quantity - algorithm[reverse_kind].remaining_quantity
54031
+ }
54032
+ ], this.config.global_config.decimal_places, this.config.global_config.price_places);
54033
+ reverse_entry = avg.entry;
54034
+ reverse_quantity = avg.quantity;
54035
+ if (reverse_kind === "short") {
54036
+ short_tp_factor_multiplier = 2;
54037
+ } else {
54038
+ tp_percent_multiplier = 2;
54039
+ }
54040
+ }
53992
54041
  position2[reverse_kind] = {
53993
- entry: algorithm[reverse_kind].tp,
53994
- quantity: algorithm[reverse_kind].re_entry_quantity
54042
+ entry: reverse_entry,
54043
+ quantity: reverse_quantity
53995
54044
  };
53996
54045
  }
53997
54046
  return result;
@@ -57624,6 +57673,9 @@ class ExchangeAccount {
57624
57673
  if (threshold_qty > 0 && track_position.quantity >= threshold_qty) {
57625
57674
  should_place_order = true;
57626
57675
  }
57676
+ if (focus_position.quantity === 0) {
57677
+ should_place_order = true;
57678
+ }
57627
57679
  if (track_position.quantity !== focus_position.quantity && focus_position.quantity < track_position.quantity && should_place_order) {
57628
57680
  const remaining_quantity = Math.abs(track_position.quantity - focus_position.quantity);
57629
57681
  await this.placeMarketOrder({
@@ -60581,7 +60581,12 @@ class Strategy {
60581
60581
  return this.tp("short");
60582
60582
  }
60583
60583
  generateGapClosingAlgorithm(payload) {
60584
- const { kind } = payload;
60584
+ const {
60585
+ kind,
60586
+ ignore_entries = false,
60587
+ reduce_ratio = 1,
60588
+ sell_factor = 1
60589
+ } = payload;
60585
60590
  const { entry, quantity } = this.position[kind];
60586
60591
  const focus_position = this.position[kind];
60587
60592
  const reverse_kind = kind == "long" ? "short" : "long";
@@ -60608,7 +60613,10 @@ class Strategy {
60608
60613
  if (!app_config) {
60609
60614
  return null;
60610
60615
  }
60611
- const { entries, ...rest } = app_config;
60616
+ let { entries, ...rest } = app_config;
60617
+ if (ignore_entries) {
60618
+ entries = [];
60619
+ }
60612
60620
  const risk = this.to_f(rest.risk_per_trade);
60613
60621
  const adjusted_focus_entries = entries.map((entry2) => {
60614
60622
  let adjusted_price = entry2.price;
@@ -60630,7 +60638,7 @@ class Strategy {
60630
60638
  quantity
60631
60639
  }
60632
60640
  ]), rest.decimal_places, rest.price_places);
60633
- const focus_loss = this.to_f((avg.price - second_payload.stop) * avg.quantity);
60641
+ const focus_loss = this.to_f(Math.abs(avg.price - second_payload.stop) * avg.quantity);
60634
60642
  let below_reverse_entries = kind === "long" ? entries.filter((u) => {
60635
60643
  return u.entry < (reverse_position.entry || focus_position.entry);
60636
60644
  }) : entries.filter((u) => {
@@ -60657,18 +60665,20 @@ class Strategy {
60657
60665
  quantity: reverse_position.quantity
60658
60666
  }
60659
60667
  ]), rest.decimal_places, rest.price_places);
60660
- const reverse_pnl = this.to_f((reverse_avg.price - second_payload.stop) * reverse_avg.quantity);
60668
+ const sell_quantity = this.to_df(reverse_avg.quantity * sell_factor);
60669
+ const reverse_pnl = this.to_f(Math.abs(reverse_avg.price - second_payload.stop) * sell_quantity);
60661
60670
  const fee_to_pay = this.calculate_fee({
60662
60671
  price: avg.entry,
60663
60672
  quantity: avg.quantity
60664
60673
  }) + this.calculate_fee({
60665
60674
  price: reverse_avg.entry,
60666
- quantity: reverse_avg.quantity
60675
+ quantity: sell_quantity
60667
60676
  });
60668
60677
  const net_reverse_pnl = reverse_pnl - fee_to_pay;
60669
- const ratio = net_reverse_pnl / focus_loss;
60678
+ const ratio = net_reverse_pnl * reduce_ratio / focus_loss;
60670
60679
  const quantity_to_sell = this.to_df(ratio * avg.quantity);
60671
60680
  const remaining_quantity = this.to_df(avg.quantity - quantity_to_sell);
60681
+ const incurred_loss = this.to_f((avg.price - second_payload.stop) * quantity_to_sell);
60672
60682
  return {
60673
60683
  risk,
60674
60684
  risk_reward: this.config.risk_reward,
@@ -60680,7 +60690,8 @@ class Strategy {
60680
60690
  stop_quantity: quantity_to_sell,
60681
60691
  re_entry_quantity: remaining_quantity,
60682
60692
  initial_pnl: this.pnl(kind),
60683
- tp: second_payload.entry
60693
+ tp: second_payload.entry,
60694
+ incurred_loss
60684
60695
  },
60685
60696
  [reverse_kind]: {
60686
60697
  avg_entry: reverse_avg.entry,
@@ -60688,32 +60699,48 @@ class Strategy {
60688
60699
  pnl: reverse_pnl,
60689
60700
  tp: second_payload.stop,
60690
60701
  re_entry_quantity: remaining_quantity,
60691
- initial_pnl: this.pnl(reverse_kind)
60702
+ initial_pnl: this.pnl(reverse_kind),
60703
+ remaining_quantity: this.to_df(reverse_avg.quantity - sell_quantity)
60692
60704
  },
60693
60705
  last_entry: rest.last_value.entry,
60694
- first_entry: entries.at(-1).entry,
60695
- threshold
60706
+ first_entry: entries.at(-1)?.entry,
60707
+ threshold,
60708
+ spread: Math.abs(avg.entry - reverse_avg.entry),
60709
+ gap_loss: to_f2(Math.abs(avg.entry - reverse_avg.entry) * reverse_avg.quantity, "%.2f"),
60710
+ net_profit: incurred_loss + reverse_pnl
60696
60711
  };
60697
60712
  }
60698
60713
  runIterations(payload) {
60699
- const { kind, iterations } = payload;
60714
+ const {
60715
+ kind,
60716
+ iterations,
60717
+ ignore_entries = false,
60718
+ reduce_ratio = 1,
60719
+ sell_factor = 1
60720
+ } = payload;
60700
60721
  const reverse_kind = kind == "long" ? "short" : "long";
60701
60722
  const result = [];
60702
60723
  let position2 = {
60703
60724
  long: this.position.long,
60704
60725
  short: this.position.short
60705
60726
  };
60727
+ let tp_percent_multiplier = 1;
60728
+ let short_tp_factor_multiplier = 1;
60706
60729
  for (let i2 = 0;i2 < iterations; i2++) {
60707
60730
  const instance = new Strategy({
60708
60731
  long: position2.long,
60709
60732
  short: position2.short,
60710
60733
  config: {
60711
60734
  ...this.config,
60712
- tp_percent: this.config.tp_percent + i2 * 4
60735
+ tp_percent: this.config.tp_percent * tp_percent_multiplier,
60736
+ short_tp_factor: this.config.short_tp_factor * short_tp_factor_multiplier
60713
60737
  }
60714
60738
  });
60715
60739
  const algorithm = instance.generateGapClosingAlgorithm({
60716
- kind
60740
+ kind,
60741
+ ignore_entries,
60742
+ reduce_ratio,
60743
+ sell_factor
60717
60744
  });
60718
60745
  if (!algorithm) {
60719
60746
  console.log("No algorithm found");
@@ -60725,9 +60752,31 @@ class Strategy {
60725
60752
  entry: algorithm[kind].avg_entry,
60726
60753
  quantity: algorithm[kind].re_entry_quantity
60727
60754
  };
60755
+ let reverse_entry = algorithm[reverse_kind].tp;
60756
+ let reverse_quantity = algorithm[reverse_kind].re_entry_quantity;
60757
+ if (algorithm[reverse_kind].remaining_quantity > 0) {
60758
+ const purchase_to_occur = {
60759
+ price: reverse_entry,
60760
+ quantity: algorithm[reverse_kind].remaining_quantity
60761
+ };
60762
+ const avg = determine_average_entry_and_size([
60763
+ purchase_to_occur,
60764
+ {
60765
+ price: algorithm[reverse_kind].avg_entry,
60766
+ quantity: reverse_quantity - algorithm[reverse_kind].remaining_quantity
60767
+ }
60768
+ ], this.config.global_config.decimal_places, this.config.global_config.price_places);
60769
+ reverse_entry = avg.entry;
60770
+ reverse_quantity = avg.quantity;
60771
+ if (reverse_kind === "short") {
60772
+ short_tp_factor_multiplier = 2;
60773
+ } else {
60774
+ tp_percent_multiplier = 2;
60775
+ }
60776
+ }
60728
60777
  position2[reverse_kind] = {
60729
- entry: algorithm[reverse_kind].tp,
60730
- quantity: algorithm[reverse_kind].re_entry_quantity
60778
+ entry: reverse_entry,
60779
+ quantity: reverse_quantity
60731
60780
  };
60732
60781
  }
60733
60782
  return result;
@@ -64360,6 +64409,9 @@ class ExchangeAccount {
64360
64409
  if (threshold_qty > 0 && track_position.quantity >= threshold_qty) {
64361
64410
  should_place_order = true;
64362
64411
  }
64412
+ if (focus_position.quantity === 0) {
64413
+ should_place_order = true;
64414
+ }
64363
64415
  if (track_position.quantity !== focus_position.quantity && focus_position.quantity < track_position.quantity && should_place_order) {
64364
64416
  const remaining_quantity = Math.abs(track_position.quantity - focus_position.quantity);
64365
64417
  await this.placeMarketOrder({
@@ -60558,7 +60558,12 @@ class Strategy {
60558
60558
  return this.tp("short");
60559
60559
  }
60560
60560
  generateGapClosingAlgorithm(payload) {
60561
- const { kind } = payload;
60561
+ const {
60562
+ kind,
60563
+ ignore_entries = false,
60564
+ reduce_ratio = 1,
60565
+ sell_factor = 1
60566
+ } = payload;
60562
60567
  const { entry, quantity } = this.position[kind];
60563
60568
  const focus_position = this.position[kind];
60564
60569
  const reverse_kind = kind == "long" ? "short" : "long";
@@ -60585,7 +60590,10 @@ class Strategy {
60585
60590
  if (!app_config) {
60586
60591
  return null;
60587
60592
  }
60588
- const { entries, ...rest } = app_config;
60593
+ let { entries, ...rest } = app_config;
60594
+ if (ignore_entries) {
60595
+ entries = [];
60596
+ }
60589
60597
  const risk = this.to_f(rest.risk_per_trade);
60590
60598
  const adjusted_focus_entries = entries.map((entry2) => {
60591
60599
  let adjusted_price = entry2.price;
@@ -60607,7 +60615,7 @@ class Strategy {
60607
60615
  quantity
60608
60616
  }
60609
60617
  ]), rest.decimal_places, rest.price_places);
60610
- const focus_loss = this.to_f((avg.price - second_payload.stop) * avg.quantity);
60618
+ const focus_loss = this.to_f(Math.abs(avg.price - second_payload.stop) * avg.quantity);
60611
60619
  let below_reverse_entries = kind === "long" ? entries.filter((u) => {
60612
60620
  return u.entry < (reverse_position.entry || focus_position.entry);
60613
60621
  }) : entries.filter((u) => {
@@ -60634,18 +60642,20 @@ class Strategy {
60634
60642
  quantity: reverse_position.quantity
60635
60643
  }
60636
60644
  ]), rest.decimal_places, rest.price_places);
60637
- const reverse_pnl = this.to_f((reverse_avg.price - second_payload.stop) * reverse_avg.quantity);
60645
+ const sell_quantity = this.to_df(reverse_avg.quantity * sell_factor);
60646
+ const reverse_pnl = this.to_f(Math.abs(reverse_avg.price - second_payload.stop) * sell_quantity);
60638
60647
  const fee_to_pay = this.calculate_fee({
60639
60648
  price: avg.entry,
60640
60649
  quantity: avg.quantity
60641
60650
  }) + this.calculate_fee({
60642
60651
  price: reverse_avg.entry,
60643
- quantity: reverse_avg.quantity
60652
+ quantity: sell_quantity
60644
60653
  });
60645
60654
  const net_reverse_pnl = reverse_pnl - fee_to_pay;
60646
- const ratio = net_reverse_pnl / focus_loss;
60655
+ const ratio = net_reverse_pnl * reduce_ratio / focus_loss;
60647
60656
  const quantity_to_sell = this.to_df(ratio * avg.quantity);
60648
60657
  const remaining_quantity = this.to_df(avg.quantity - quantity_to_sell);
60658
+ const incurred_loss = this.to_f((avg.price - second_payload.stop) * quantity_to_sell);
60649
60659
  return {
60650
60660
  risk,
60651
60661
  risk_reward: this.config.risk_reward,
@@ -60657,7 +60667,8 @@ class Strategy {
60657
60667
  stop_quantity: quantity_to_sell,
60658
60668
  re_entry_quantity: remaining_quantity,
60659
60669
  initial_pnl: this.pnl(kind),
60660
- tp: second_payload.entry
60670
+ tp: second_payload.entry,
60671
+ incurred_loss
60661
60672
  },
60662
60673
  [reverse_kind]: {
60663
60674
  avg_entry: reverse_avg.entry,
@@ -60665,32 +60676,48 @@ class Strategy {
60665
60676
  pnl: reverse_pnl,
60666
60677
  tp: second_payload.stop,
60667
60678
  re_entry_quantity: remaining_quantity,
60668
- initial_pnl: this.pnl(reverse_kind)
60679
+ initial_pnl: this.pnl(reverse_kind),
60680
+ remaining_quantity: this.to_df(reverse_avg.quantity - sell_quantity)
60669
60681
  },
60670
60682
  last_entry: rest.last_value.entry,
60671
- first_entry: entries.at(-1).entry,
60672
- threshold
60683
+ first_entry: entries.at(-1)?.entry,
60684
+ threshold,
60685
+ spread: Math.abs(avg.entry - reverse_avg.entry),
60686
+ gap_loss: to_f2(Math.abs(avg.entry - reverse_avg.entry) * reverse_avg.quantity, "%.2f"),
60687
+ net_profit: incurred_loss + reverse_pnl
60673
60688
  };
60674
60689
  }
60675
60690
  runIterations(payload) {
60676
- const { kind, iterations } = payload;
60691
+ const {
60692
+ kind,
60693
+ iterations,
60694
+ ignore_entries = false,
60695
+ reduce_ratio = 1,
60696
+ sell_factor = 1
60697
+ } = payload;
60677
60698
  const reverse_kind = kind == "long" ? "short" : "long";
60678
60699
  const result = [];
60679
60700
  let position2 = {
60680
60701
  long: this.position.long,
60681
60702
  short: this.position.short
60682
60703
  };
60704
+ let tp_percent_multiplier = 1;
60705
+ let short_tp_factor_multiplier = 1;
60683
60706
  for (let i2 = 0;i2 < iterations; i2++) {
60684
60707
  const instance = new Strategy({
60685
60708
  long: position2.long,
60686
60709
  short: position2.short,
60687
60710
  config: {
60688
60711
  ...this.config,
60689
- tp_percent: this.config.tp_percent + i2 * 4
60712
+ tp_percent: this.config.tp_percent * tp_percent_multiplier,
60713
+ short_tp_factor: this.config.short_tp_factor * short_tp_factor_multiplier
60690
60714
  }
60691
60715
  });
60692
60716
  const algorithm = instance.generateGapClosingAlgorithm({
60693
- kind
60717
+ kind,
60718
+ ignore_entries,
60719
+ reduce_ratio,
60720
+ sell_factor
60694
60721
  });
60695
60722
  if (!algorithm) {
60696
60723
  console.log("No algorithm found");
@@ -60702,9 +60729,31 @@ class Strategy {
60702
60729
  entry: algorithm[kind].avg_entry,
60703
60730
  quantity: algorithm[kind].re_entry_quantity
60704
60731
  };
60732
+ let reverse_entry = algorithm[reverse_kind].tp;
60733
+ let reverse_quantity = algorithm[reverse_kind].re_entry_quantity;
60734
+ if (algorithm[reverse_kind].remaining_quantity > 0) {
60735
+ const purchase_to_occur = {
60736
+ price: reverse_entry,
60737
+ quantity: algorithm[reverse_kind].remaining_quantity
60738
+ };
60739
+ const avg = determine_average_entry_and_size([
60740
+ purchase_to_occur,
60741
+ {
60742
+ price: algorithm[reverse_kind].avg_entry,
60743
+ quantity: reverse_quantity - algorithm[reverse_kind].remaining_quantity
60744
+ }
60745
+ ], this.config.global_config.decimal_places, this.config.global_config.price_places);
60746
+ reverse_entry = avg.entry;
60747
+ reverse_quantity = avg.quantity;
60748
+ if (reverse_kind === "short") {
60749
+ short_tp_factor_multiplier = 2;
60750
+ } else {
60751
+ tp_percent_multiplier = 2;
60752
+ }
60753
+ }
60705
60754
  position2[reverse_kind] = {
60706
- entry: algorithm[reverse_kind].tp,
60707
- quantity: algorithm[reverse_kind].re_entry_quantity
60755
+ entry: reverse_entry,
60756
+ quantity: reverse_quantity
60708
60757
  };
60709
60758
  }
60710
60759
  return result;
@@ -64337,6 +64386,9 @@ class ExchangeAccount {
64337
64386
  if (threshold_qty > 0 && track_position.quantity >= threshold_qty) {
64338
64387
  should_place_order = true;
64339
64388
  }
64389
+ if (focus_position.quantity === 0) {
64390
+ should_place_order = true;
64391
+ }
64340
64392
  if (track_position.quantity !== focus_position.quantity && focus_position.quantity < track_position.quantity && should_place_order) {
64341
64393
  const remaining_quantity = Math.abs(track_position.quantity - focus_position.quantity);
64342
64394
  await this.placeMarketOrder({
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gbozee/ultimate",
3
3
  "type": "module",
4
- "version": "0.0.2-73",
4
+ "version": "0.0.2-74",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",