@gbozee/ultimate 0.0.2-57 → 0.0.2-58

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.
@@ -372,6 +372,7 @@ export type Config = {
372
372
  fee_percent?: number;
373
373
  budget: number;
374
374
  risk_reward: number;
375
+ reduce_ratio: number;
375
376
  global_config: GlobalConfig;
376
377
  };
377
378
  export declare class Strategy {
@@ -389,7 +390,7 @@ export declare class Strategy {
389
390
  get decimal_places(): string;
390
391
  to_f(price: number): number;
391
392
  to_df(quantity: number): number;
392
- pnl(kind: "long" | "short"): number;
393
+ pnl(kind: "long" | "short", _position?: StrategyPosition): number;
393
394
  tp(kind: "long" | "short"): number;
394
395
  calculate_fee(position: {
395
396
  price: number;
@@ -419,6 +420,41 @@ export declare class Strategy {
419
420
  first_entry: any;
420
421
  threshold: any;
421
422
  }[];
423
+ getPositionAfterTp(payload: {
424
+ kind: "long" | "short";
425
+ include_fees?: boolean;
426
+ }): {
427
+ [x: string]: number | {
428
+ entry: number;
429
+ quantity: number;
430
+ } | {
431
+ [x: string]: number;
432
+ entry?: undefined;
433
+ quantity?: undefined;
434
+ };
435
+ pnl: {
436
+ [x: string]: number;
437
+ };
438
+ spread: number;
439
+ };
440
+ getPositionAfterIteration(payload: {
441
+ kind: "long" | "short";
442
+ iterations: number;
443
+ with_fees?: boolean;
444
+ }): {
445
+ [x: string]: number | {
446
+ entry: number;
447
+ quantity: number;
448
+ } | {
449
+ [x: string]: number;
450
+ entry?: undefined;
451
+ quantity?: undefined;
452
+ };
453
+ pnl: {
454
+ [x: string]: number;
455
+ };
456
+ spread: number;
457
+ }[];
422
458
  }
423
459
 
424
460
  export {};
@@ -1663,8 +1663,8 @@ class Strategy {
1663
1663
  to_df(quantity) {
1664
1664
  return to_f(quantity, this.decimal_places);
1665
1665
  }
1666
- pnl(kind) {
1667
- const position2 = this.position[kind];
1666
+ pnl(kind, _position) {
1667
+ const position2 = _position || this.position[kind];
1668
1668
  const { entry, quantity } = position2;
1669
1669
  const notional = entry * quantity;
1670
1670
  let tp_percent = this.config.tp_percent;
@@ -1675,10 +1675,14 @@ class Strategy {
1675
1675
  return this.to_f(profit);
1676
1676
  }
1677
1677
  tp(kind) {
1678
- const position2 = this.position[kind];
1678
+ let position2 = this.position[kind];
1679
+ if (position2.quantity == 0) {
1680
+ const reverse_kind = kind == "long" ? "short" : "long";
1681
+ position2 = this.position[reverse_kind];
1682
+ }
1679
1683
  const { entry, quantity } = position2;
1680
- const profit = this.pnl(kind);
1681
- const diff = profit / quantity;
1684
+ const profit = this.pnl(kind, position2);
1685
+ const diff = profit / (quantity || 1);
1682
1686
  return this.to_f(kind == "long" ? entry + diff : entry - diff);
1683
1687
  }
1684
1688
  calculate_fee(position2) {
@@ -1744,9 +1748,9 @@ class Strategy {
1744
1748
  ]), rest.decimal_places, rest.price_places);
1745
1749
  const focus_loss = this.to_f((avg.price - second_payload.stop) * avg.quantity);
1746
1750
  let below_reverse_entries = kind === "long" ? entries.filter((u) => {
1747
- return u.entry < reverse_position.entry;
1751
+ return u.entry < (reverse_position.entry || focus_position.entry);
1748
1752
  }) : entries.filter((u) => {
1749
- return u.entry > reverse_position.entry;
1753
+ return u.entry > (reverse_position.entry || focus_position.entry);
1750
1754
  });
1751
1755
  const threshold = below_reverse_entries.at(-1);
1752
1756
  let adjusted_reverse_entries = entries.map((entry2) => {
@@ -1844,6 +1848,62 @@ class Strategy {
1844
1848
  }
1845
1849
  return result;
1846
1850
  }
1851
+ getPositionAfterTp(payload) {
1852
+ const { kind, include_fees = false } = payload;
1853
+ const focus_position = this.position[kind];
1854
+ const reverse_kind = kind == "long" ? "short" : "long";
1855
+ const reverse_position = this.position[reverse_kind];
1856
+ const focus_tp = this.tp(kind);
1857
+ const focus_pnl = this.pnl(kind);
1858
+ const fees = include_fees ? this.calculate_fee({
1859
+ price: focus_tp,
1860
+ quantity: focus_position.quantity
1861
+ }) * 2 : 0;
1862
+ const expected_loss = (focus_pnl - fees) * this.config.reduce_ratio;
1863
+ const actual_loss = Math.abs(focus_tp - reverse_position.entry) * reverse_position.quantity;
1864
+ const ratio = expected_loss / actual_loss;
1865
+ const loss_quantity = this.to_df(ratio * reverse_position.quantity);
1866
+ const remaining_quantity = this.to_df(reverse_position.quantity - loss_quantity);
1867
+ return {
1868
+ [kind]: {
1869
+ entry: focus_tp,
1870
+ quantity: remaining_quantity
1871
+ },
1872
+ [reverse_kind]: {
1873
+ entry: reverse_position.entry,
1874
+ quantity: remaining_quantity
1875
+ },
1876
+ pnl: {
1877
+ [kind]: focus_pnl,
1878
+ [reverse_kind]: -expected_loss
1879
+ },
1880
+ spread: this.to_f(Math.abs(focus_tp - reverse_position.entry) * remaining_quantity)
1881
+ };
1882
+ }
1883
+ getPositionAfterIteration(payload) {
1884
+ const { kind, iterations, with_fees = false } = payload;
1885
+ let _result = this.getPositionAfterTp({
1886
+ kind,
1887
+ include_fees: with_fees
1888
+ });
1889
+ const result = [_result];
1890
+ for (let i = 0;i < iterations - 1; i++) {
1891
+ const instance = new Strategy({
1892
+ long: _result.long,
1893
+ short: _result.short,
1894
+ config: {
1895
+ ...this.config,
1896
+ tp_percent: this.config.tp_percent + (i + 1) * 0.3
1897
+ }
1898
+ });
1899
+ _result = instance.getPositionAfterTp({
1900
+ kind,
1901
+ include_fees: with_fees
1902
+ });
1903
+ result.push(_result);
1904
+ }
1905
+ return result;
1906
+ }
1847
1907
  }
1848
1908
  export {
1849
1909
  to_f,