@gbozee/ultimate 0.0.2-57 → 0.0.2-60

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.
@@ -73,6 +73,11 @@ export declare function createGapPairs<T>(arr: T[], gap: number, item?: T): [
73
73
  T
74
74
  ][];
75
75
  export declare function logWithLineNumber(...args: any[]): void;
76
+ export declare function computeSellZones(payload: {
77
+ entry: number;
78
+ exit: number;
79
+ zones?: number;
80
+ }): number[];
76
81
  export type SignalConfigType = {
77
82
  focus: number;
78
83
  budget: number;
@@ -372,6 +377,7 @@ export type Config = {
372
377
  fee_percent?: number;
373
378
  budget: number;
374
379
  risk_reward: number;
380
+ reduce_ratio: number;
375
381
  global_config: GlobalConfig;
376
382
  };
377
383
  export declare class Strategy {
@@ -389,7 +395,7 @@ export declare class Strategy {
389
395
  get decimal_places(): string;
390
396
  to_f(price: number): number;
391
397
  to_df(quantity: number): number;
392
- pnl(kind: "long" | "short"): number;
398
+ pnl(kind: "long" | "short", _position?: StrategyPosition): number;
393
399
  tp(kind: "long" | "short"): number;
394
400
  calculate_fee(position: {
395
401
  price: number;
@@ -419,6 +425,41 @@ export declare class Strategy {
419
425
  first_entry: any;
420
426
  threshold: any;
421
427
  }[];
428
+ getPositionAfterTp(payload: {
429
+ kind: "long" | "short";
430
+ include_fees?: boolean;
431
+ }): {
432
+ [x: string]: number | {
433
+ entry: number;
434
+ quantity: number;
435
+ } | {
436
+ [x: string]: number;
437
+ entry?: undefined;
438
+ quantity?: undefined;
439
+ };
440
+ pnl: {
441
+ [x: string]: number;
442
+ };
443
+ spread: number;
444
+ };
445
+ getPositionAfterIteration(payload: {
446
+ kind: "long" | "short";
447
+ iterations: number;
448
+ with_fees?: boolean;
449
+ }): {
450
+ [x: string]: number | {
451
+ entry: number;
452
+ quantity: number;
453
+ } | {
454
+ [x: string]: number;
455
+ entry?: undefined;
456
+ quantity?: undefined;
457
+ };
458
+ pnl: {
459
+ [x: string]: number;
460
+ };
461
+ spread: number;
462
+ }[];
422
463
  }
423
464
 
424
465
  export {};
@@ -1146,6 +1146,13 @@ function logWithLineNumber(...args) {
1146
1146
  const lineNumber = lines?.[0]?.split(":").pop();
1147
1147
  console.log(`${lineNumber}:`, ...args);
1148
1148
  }
1149
+ function computeSellZones(payload) {
1150
+ const { entry, exit, zones = 10 } = payload;
1151
+ const gap = exit / entry;
1152
+ const factor = Math.pow(gap, 1 / zones);
1153
+ const spread = factor - 1;
1154
+ return Array.from({ length: zones }, (_, i) => entry * Math.pow(1 + spread, i));
1155
+ }
1149
1156
  // src/helpers/shared.ts
1150
1157
  function buildConfig(app_config, {
1151
1158
  take_profit,
@@ -1663,8 +1670,8 @@ class Strategy {
1663
1670
  to_df(quantity) {
1664
1671
  return to_f(quantity, this.decimal_places);
1665
1672
  }
1666
- pnl(kind) {
1667
- const position2 = this.position[kind];
1673
+ pnl(kind, _position) {
1674
+ const position2 = _position || this.position[kind];
1668
1675
  const { entry, quantity } = position2;
1669
1676
  const notional = entry * quantity;
1670
1677
  let tp_percent = this.config.tp_percent;
@@ -1675,10 +1682,14 @@ class Strategy {
1675
1682
  return this.to_f(profit);
1676
1683
  }
1677
1684
  tp(kind) {
1678
- const position2 = this.position[kind];
1685
+ let position2 = this.position[kind];
1686
+ if (position2.quantity == 0) {
1687
+ const reverse_kind = kind == "long" ? "short" : "long";
1688
+ position2 = this.position[reverse_kind];
1689
+ }
1679
1690
  const { entry, quantity } = position2;
1680
- const profit = this.pnl(kind);
1681
- const diff = profit / quantity;
1691
+ const profit = this.pnl(kind, position2);
1692
+ const diff = profit / (quantity || 1);
1682
1693
  return this.to_f(kind == "long" ? entry + diff : entry - diff);
1683
1694
  }
1684
1695
  calculate_fee(position2) {
@@ -1744,9 +1755,9 @@ class Strategy {
1744
1755
  ]), rest.decimal_places, rest.price_places);
1745
1756
  const focus_loss = this.to_f((avg.price - second_payload.stop) * avg.quantity);
1746
1757
  let below_reverse_entries = kind === "long" ? entries.filter((u) => {
1747
- return u.entry < reverse_position.entry;
1758
+ return u.entry < (reverse_position.entry || focus_position.entry);
1748
1759
  }) : entries.filter((u) => {
1749
- return u.entry > reverse_position.entry;
1760
+ return u.entry > (reverse_position.entry || focus_position.entry);
1750
1761
  });
1751
1762
  const threshold = below_reverse_entries.at(-1);
1752
1763
  let adjusted_reverse_entries = entries.map((entry2) => {
@@ -1844,6 +1855,62 @@ class Strategy {
1844
1855
  }
1845
1856
  return result;
1846
1857
  }
1858
+ getPositionAfterTp(payload) {
1859
+ const { kind, include_fees = false } = payload;
1860
+ const focus_position = this.position[kind];
1861
+ const reverse_kind = kind == "long" ? "short" : "long";
1862
+ const reverse_position = this.position[reverse_kind];
1863
+ const focus_tp = this.tp(kind);
1864
+ const focus_pnl = this.pnl(kind);
1865
+ const fees = include_fees ? this.calculate_fee({
1866
+ price: focus_tp,
1867
+ quantity: focus_position.quantity
1868
+ }) * 2 : 0;
1869
+ const expected_loss = (focus_pnl - fees) * this.config.reduce_ratio;
1870
+ const actual_loss = Math.abs(focus_tp - reverse_position.entry) * reverse_position.quantity;
1871
+ const ratio = expected_loss / actual_loss;
1872
+ const loss_quantity = this.to_df(ratio * reverse_position.quantity);
1873
+ const remaining_quantity = this.to_df(reverse_position.quantity - loss_quantity);
1874
+ return {
1875
+ [kind]: {
1876
+ entry: focus_tp,
1877
+ quantity: remaining_quantity
1878
+ },
1879
+ [reverse_kind]: {
1880
+ entry: reverse_position.entry,
1881
+ quantity: remaining_quantity
1882
+ },
1883
+ pnl: {
1884
+ [kind]: focus_pnl,
1885
+ [reverse_kind]: -expected_loss
1886
+ },
1887
+ spread: this.to_f(Math.abs(focus_tp - reverse_position.entry) * remaining_quantity)
1888
+ };
1889
+ }
1890
+ getPositionAfterIteration(payload) {
1891
+ const { kind, iterations, with_fees = false } = payload;
1892
+ let _result = this.getPositionAfterTp({
1893
+ kind,
1894
+ include_fees: with_fees
1895
+ });
1896
+ const result = [_result];
1897
+ for (let i = 0;i < iterations - 1; i++) {
1898
+ const instance = new Strategy({
1899
+ long: _result.long,
1900
+ short: _result.short,
1901
+ config: {
1902
+ ...this.config,
1903
+ tp_percent: this.config.tp_percent + (i + 1) * 0.3
1904
+ }
1905
+ });
1906
+ _result = instance.getPositionAfterTp({
1907
+ kind,
1908
+ include_fees: with_fees
1909
+ });
1910
+ result.push(_result);
1911
+ }
1912
+ return result;
1913
+ }
1847
1914
  }
1848
1915
  export {
1849
1916
  to_f,
@@ -1874,6 +1941,7 @@ export {
1874
1941
  createGapPairs,
1875
1942
  createArray,
1876
1943
  computeTotalAverageForEachTrade,
1944
+ computeSellZones,
1877
1945
  buildConfig,
1878
1946
  buildAvg,
1879
1947
  buildAppConfig,