@gbozee/ultimate 0.0.2-45 → 0.0.2-47

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.
@@ -1,5 +1,78 @@
1
1
  // Generated by dts-bundle-generator v9.5.1
2
2
 
3
+ export declare function profitHelper(longPosition: any, shortPosition: any, config?: any, contract_size?: number, balance?: number): {
4
+ long: any;
5
+ short: any;
6
+ };
7
+ export declare function getParamForField(self: any, configs: any[], field: string, isGroup?: string): any | any[];
8
+ export declare function getTradeEntries(entry: number, min_size: number, kind: "long" | "short", size: number, spread?: number): {
9
+ entry: number;
10
+ size: number;
11
+ }[];
12
+ export declare function extractValue(_param: any, condition: boolean): any;
13
+ export declare function asCoins(symbol: string): string;
14
+ export declare const SpecialCoins: string[];
15
+ export declare function allCoins(symbols: string[]): string[];
16
+ export declare function formatPrice(value: number, opts?: {
17
+ locale?: string;
18
+ currency?: string;
19
+ }): string;
20
+ export declare function to_f(value: string | number, places?: string): number;
21
+ export declare function determine_stop_and_size(entry: number, pnl: number, take_profit: number, kind?: string): number;
22
+ export declare const range: (start: number, stop: number, step?: number) => number[];
23
+ export declare function determine_amount_to_sell(entry: number, quantity: number, sell_price: number, pnl: number, kind: "long" | "short", places?: string): number;
24
+ export declare function determine_position_size({ entry, stop, budget, percent, min_size, notional_value, as_coin, places, }: {
25
+ entry: number;
26
+ stop?: number;
27
+ budget?: number;
28
+ percent?: number;
29
+ notional_value?: number;
30
+ min_size?: number;
31
+ as_coin?: boolean;
32
+ places?: string;
33
+ }): number;
34
+ export declare function determine_remaining_entry({ risk, max_size, stop_loss, kind, position, }: {
35
+ risk: number;
36
+ max_size: number;
37
+ stop_loss: number;
38
+ kind: string;
39
+ position: {
40
+ quantity: number;
41
+ entry: number;
42
+ };
43
+ }): number;
44
+ export declare function determine_average_entry_and_size(orders: Array<{
45
+ price: number;
46
+ quantity: number;
47
+ }>, places?: string, price_places?: string): {
48
+ entry: number;
49
+ price: number;
50
+ quantity: number;
51
+ };
52
+ export declare const createArray: (start: number, stop: number, step: number) => number[];
53
+ export declare const groupBy: (xs: any[], key: string) => any;
54
+ export declare function fibonacci_analysis({ support, resistance, kind, trend, places, }: {
55
+ support: number;
56
+ resistance: number;
57
+ kind?: string;
58
+ trend?: string;
59
+ places?: string;
60
+ }): number[];
61
+ export declare const groupIntoPairs: (arr: any[], size: number) => any[][];
62
+ export declare const groupIntoPairsWithSumLessThan: (arr: any[], targetSum: number, key?: string, firstSize?: number) => any[][];
63
+ /**
64
+ * This function computes the cummulative entry and size for each trade
65
+ * @param trades The trades for which the cummulative entry and size will be computed
66
+ * @param config The current config
67
+ * @returns An array of trades with the cummulative entry and size
68
+ */
69
+ export declare const computeTotalAverageForEachTrade: (trades: any[], config: any) => any[];
70
+ export declare function getDecimalPlaces(numberString: string | number): number;
71
+ export declare function createGapPairs<T>(arr: T[], gap: number, item?: T): [
72
+ T,
73
+ T
74
+ ][];
75
+ export declare function logWithLineNumber(...args: any[]): void;
3
76
  export type SignalConfigType = {
4
77
  focus: number;
5
78
  budget: number;
@@ -149,15 +222,6 @@ export type GlobalConfig = {
149
222
  risk_reward: number;
150
223
  reverse_factor: number;
151
224
  };
152
- export declare function determine_average_entry_and_size(orders: Array<{
153
- price: number;
154
- quantity: number;
155
- }>, places?: string, price_places?: string): {
156
- entry: number;
157
- price: number;
158
- quantity: number;
159
- };
160
- export declare const createArray: (start: number, stop: number, step: number) => number[];
161
225
  export type AppConfig = {
162
226
  fee: number;
163
227
  risk_per_trade: number;
@@ -1,261 +1,5 @@
1
- // src/helpers/pnl.ts
2
- function determine_position_size(entry, stop, budget) {
3
- let stop_percent = Math.abs(entry - stop) / entry;
4
- let size = budget / stop_percent / entry;
5
- return size;
6
- }
7
- function determine_risk(entry, stop, quantity) {
8
- let stop_percent = Math.abs(entry - stop) / entry;
9
- let risk = quantity * stop_percent * entry;
10
- return risk;
11
- }
12
- function determine_close_price(entry, pnl, quantity, kind, single = false, leverage = 1) {
13
- const dollar_value = entry / leverage;
14
- const position = dollar_value * quantity;
15
- if (position) {
16
- let percent = pnl / position;
17
- let difference = position * percent / quantity;
18
- let result;
19
- if (kind === "long") {
20
- result = difference + entry;
21
- } else {
22
- result = entry - difference;
23
- }
24
- if (single) {
25
- return result;
26
- }
27
- return result;
28
- }
29
- return 0;
30
- }
31
- function determine_amount_to_sell(entry, quantity, sell_price, pnl, kind, places = "%.3f") {
32
- const _pnl = determine_pnl(entry, sell_price, quantity, kind);
33
- const ratio = pnl / to_f(Math.abs(_pnl), places);
34
- quantity = quantity * ratio;
35
- return to_f(quantity, places);
36
- }
37
- function determine_pnl(entry, close_price, quantity, kind, contract_size, places = "%.2f") {
38
- if (contract_size) {
39
- const direction = kind === "long" ? 1 : -1;
40
- return quantity * contract_size * direction * (1 / entry - 1 / close_price);
41
- }
42
- let difference = entry - close_price;
43
- if (kind === "long") {
44
- difference = close_price - entry;
45
- }
46
- return to_f(difference * quantity, places);
47
- }
48
- function position(entry, quantity, kind, leverage = 1) {
49
- const direction = { long: 1, short: -1 };
50
- return parseFloat((direction[kind] * quantity * (entry / leverage)).toFixed(3));
51
- }
52
- function to_f(value, places) {
53
- if (value) {
54
- let pp = parseInt(places.replace("%.", "").replace("f", ""));
55
- return parseFloat(value.toFixed(pp));
56
- }
57
- return value;
58
- }
59
- var value = {
60
- determine_risk,
61
- determine_position_size,
62
- determine_close_price,
63
- determine_pnl,
64
- position,
65
- determine_amount_to_sell,
66
- to_f
67
- };
68
- var pnl_default = value;
69
-
70
- // src/helpers/trade_utils.ts
71
- function to_f2(value2, places = "%.1f") {
72
- let v = typeof value2 === "string" ? parseFloat(value2) : value2;
73
- const formattedValue = places.replace("%.", "").replace("f", "");
74
- return parseFloat(v.toFixed(parseInt(formattedValue)));
75
- }
76
- function determine_position_size2({
77
- entry,
78
- stop,
79
- budget,
80
- percent,
81
- min_size,
82
- notional_value,
83
- as_coin = true,
84
- places = "%.3f"
85
- }) {
86
- let stop_percent = stop ? Math.abs(entry - stop) / entry : percent;
87
- if (stop_percent && budget) {
88
- let size = budget / stop_percent;
89
- let notion_value = size * entry;
90
- if (notional_value && notional_value > notion_value) {
91
- size = notional_value / entry;
92
- }
93
- if (as_coin) {
94
- size = size / entry;
95
- if (min_size && min_size === 1) {
96
- return to_f2(Math.round(size), places);
97
- }
98
- }
99
- return to_f2(size, places);
100
- }
101
- return;
102
- }
103
- function determine_average_entry_and_size(orders, places = "%.3f", price_places = "%.1f") {
104
- const sum_values = orders.reduce((sum, order) => sum + order.price * order.quantity, 0);
105
- const total_quantity = orders.reduce((sum, order) => sum + order.quantity, 0);
106
- const avg_price = total_quantity ? to_f2(sum_values / total_quantity, price_places) : 0;
107
- return {
108
- entry: avg_price,
109
- price: avg_price,
110
- quantity: to_f2(total_quantity, places)
111
- };
112
- }
113
- var createArray = (start, stop, step) => {
114
- const result = [];
115
- let current = start;
116
- while (current <= stop) {
117
- result.push(current);
118
- current += step;
119
- }
120
- return result;
121
- };
122
- var groupIntoPairsWithSumLessThan = (arr, targetSum, key = "quantity", firstSize = 0) => {
123
- if (firstSize) {
124
- const totalSize = arr.reduce((sum, order) => sum + order[key], 0);
125
- const remainingSize = totalSize - firstSize;
126
- let newSum = 0;
127
- let newArray = [];
128
- let lastIndex = 0;
129
- for (let i = 0;i < arr.length; i++) {
130
- if (newSum < remainingSize) {
131
- newSum += arr[i][key];
132
- newArray.push(arr[i]);
133
- lastIndex = i;
134
- }
135
- }
136
- const lastGroup = arr.slice(lastIndex + 1);
137
- const previousPair = groupInPairs(newArray, key, targetSum);
138
- if (lastGroup.length > 0) {
139
- previousPair.push(lastGroup);
140
- }
141
- return previousPair;
142
- }
143
- return groupInPairs(arr, key, targetSum);
144
- };
145
- function groupInPairs(_arr, key, targetSum) {
146
- const result = [];
147
- let currentSum = 0;
148
- let currentGroup = [];
149
- for (let i = 0;i < _arr.length; i++) {
150
- currentSum += _arr[i][key];
151
- currentGroup.push(_arr[i]);
152
- if (currentSum >= targetSum) {
153
- result.push(currentGroup);
154
- currentGroup = [];
155
- currentSum = 0;
156
- }
157
- }
158
- return result;
159
- }
160
- var computeTotalAverageForEachTrade = (trades, config) => {
161
- let _take_profit = config.take_profit;
162
- let kind = config.kind;
163
- let entryToUse = kind === "short" ? Math.min(config.entry, config.stop) : Math.max(config.entry, config.stop);
164
- let _currentEntry = config.currentEntry || entryToUse;
165
- let less = trades.filter((p) => kind === "long" ? p.entry <= _currentEntry : p.entry >= _currentEntry);
166
- let rrr = trades.map((r, i) => {
167
- let considered = [];
168
- if (kind === "long") {
169
- considered = trades.filter((p) => p.entry > _currentEntry);
170
- } else {
171
- considered = trades.filter((p) => p.entry < _currentEntry);
172
- }
173
- const x_pnl = 0;
174
- const remaining = less.filter((o) => {
175
- if (kind === "long") {
176
- return o.entry >= r.entry;
177
- }
178
- return o.entry <= r.entry;
179
- });
180
- if (remaining.length === 0) {
181
- return { ...r, pnl: x_pnl };
182
- }
183
- const start = kind === "long" ? Math.max(...remaining.map((o) => o.entry)) : Math.min(...remaining.map((o) => o.entry));
184
- considered = considered.map((o) => ({ ...o, entry: start }));
185
- considered = considered.concat(remaining);
186
- let avg_entry = determine_average_entry_and_size([
187
- ...considered.map((o) => ({
188
- price: o.entry,
189
- quantity: o.quantity
190
- })),
191
- {
192
- price: _currentEntry,
193
- quantity: config.currentQty || 0
194
- }
195
- ], config.decimal_places, config.price_places);
196
- let _pnl = r.pnl;
197
- let sell_price = r.sell_price;
198
- let entry_pnl = r.pnl;
199
- if (_take_profit) {
200
- _pnl = pnl_default.determine_pnl(avg_entry.price, _take_profit, avg_entry.quantity, kind);
201
- sell_price = _take_profit;
202
- entry_pnl = pnl_default.determine_pnl(r.entry, _take_profit, avg_entry.quantity, kind);
203
- }
204
- const loss = pnl_default.determine_pnl(avg_entry.price, r.stop, avg_entry.quantity, kind);
205
- let new_stop = r.new_stop;
206
- const entry_loss = pnl_default.determine_pnl(r.entry, new_stop, avg_entry.quantity, kind);
207
- let min_profit = 0;
208
- let min_entry_profit = 0;
209
- if (config.min_profit) {
210
- min_profit = pnl_default.determine_close_price(avg_entry.price, config.min_profit, avg_entry.quantity, kind);
211
- min_entry_profit = pnl_default.determine_close_price(r.entry, config.min_profit, avg_entry.quantity, kind);
212
- }
213
- let x_fee = r.fee;
214
- if (config.fee) {
215
- x_fee = config.fee * r.stop * avg_entry.quantity;
216
- }
217
- let tp_close = pnl_default.determine_close_price(r.entry, Math.abs(entry_loss) * (config.rr || 1) + x_fee, avg_entry.quantity, kind);
218
- return {
219
- ...r,
220
- x_fee: to_f2(x_fee, "%.2f"),
221
- avg_entry: avg_entry.price,
222
- avg_size: avg_entry.quantity,
223
- entry_pnl: to_f2(entry_pnl, "%.2f"),
224
- entry_loss: to_f2(entry_loss, "%.2f"),
225
- min_entry_pnl: to_f2(min_entry_profit, "%.2f"),
226
- pnl: _pnl,
227
- neg_pnl: to_f2(loss, "%.2f"),
228
- sell_price,
229
- close_p: to_f2(tp_close, "%.2f"),
230
- min_pnl: to_f2(min_profit, "%.2f"),
231
- new_stop
232
- };
233
- });
234
- return rrr;
235
- };
236
- function createGapPairs(arr, gap, item) {
237
- if (arr.length === 0) {
238
- return [];
239
- }
240
- const result = [];
241
- const firstElement = arr[0];
242
- for (let i = arr.length - 1;i >= 0; i--) {
243
- const current = arr[i];
244
- const gapIndex = i - gap;
245
- const pairedElement = gapIndex < 0 ? firstElement : arr[gapIndex];
246
- if (current !== pairedElement) {
247
- result.push([current, pairedElement]);
248
- }
249
- }
250
- if (item) {
251
- let r = result.find((o) => o[0] === item);
252
- return r ? [r] : [];
253
- }
254
- return result;
255
- }
256
-
257
1
  // src/helpers/trade_signal.ts
258
- function determine_close_price2({
2
+ function determine_close_price({
259
3
  entry,
260
4
  pnl,
261
5
  quantity,
@@ -263,16 +7,16 @@ function determine_close_price2({
263
7
  kind = "long"
264
8
  }) {
265
9
  const dollar_value = entry / leverage;
266
- const position2 = dollar_value * quantity;
267
- if (position2) {
268
- const percent = pnl / position2;
269
- const difference = position2 * percent / quantity;
10
+ const position = dollar_value * quantity;
11
+ if (position) {
12
+ const percent = pnl / position;
13
+ const difference = position * percent / quantity;
270
14
  const result = kind === "long" ? difference + entry : entry - difference;
271
15
  return result;
272
16
  }
273
17
  return 0;
274
18
  }
275
- function determine_pnl2(entry, close_price, quantity, kind = "long", contract_size) {
19
+ function determine_pnl(entry, close_price, quantity, kind = "long", contract_size) {
276
20
  if (contract_size) {
277
21
  const direction = kind === "long" ? 1 : -1;
278
22
  return quantity * contract_size * direction * (1 / entry - 1 / close_price);
@@ -291,7 +35,7 @@ function* _get_zones({
291
35
  let focus_low = last * Math.pow(1 + percent_change, -1);
292
36
  if (focus_high > current_price) {
293
37
  while (focus_high > current_price) {
294
- yield to_f2(last, places);
38
+ yield to_f(last, places);
295
39
  focus_high = last;
296
40
  last = focus_high * Math.pow(1 + percent_change, -1);
297
41
  focus_low = last * Math.pow(1 + percent_change, -1);
@@ -299,14 +43,14 @@ function* _get_zones({
299
43
  } else {
300
44
  if (focus_high <= current_price) {
301
45
  while (focus_high <= current_price) {
302
- yield to_f2(focus_high, places);
46
+ yield to_f(focus_high, places);
303
47
  focus_low = focus_high;
304
48
  last = focus_low * (1 + percent_change);
305
49
  focus_high = last * (1 + percent_change);
306
50
  }
307
51
  } else {
308
52
  while (focus_low <= current_price) {
309
- yield to_f2(focus_high, places);
53
+ yield to_f(focus_high, places);
310
54
  focus_low = focus_high;
311
55
  last = focus_low * (1 + percent_change);
312
56
  focus_high = last * (1 + percent_change);
@@ -570,7 +314,7 @@ class Signal {
570
314
  } else {
571
315
  i["risk_sell"] = Math.min(...potentials.slice(0, max_index));
572
316
  }
573
- i["pnl"] = this.to_df(determine_pnl2(i["entry"], i["risk_sell"], i["quantity"], kind));
317
+ i["pnl"] = this.to_df(determine_pnl(i["entry"], i["risk_sell"], i["quantity"], kind));
574
318
  }
575
319
  }
576
320
  }
@@ -634,13 +378,13 @@ class Signal {
634
378
  let remaining_zones = margin_zones.filter((x) => JSON.stringify(x) != JSON.stringify(margin_range));
635
379
  if (margin_range) {
636
380
  const difference = Math.abs(margin_range[0] - margin_range[1]);
637
- const spread = to_f2(difference / this.risk_reward, this.price_places);
381
+ const spread = to_f(difference / this.risk_reward, this.price_places);
638
382
  let entries;
639
383
  const percent_change = this.percent_change / this.risk_reward;
640
384
  if (kind === "long") {
641
- entries = Array.from({ length: Math.floor(this.risk_reward) + 1 }, (_, x) => to_f2(margin_range[1] - spread * x, this.price_places));
385
+ entries = Array.from({ length: Math.floor(this.risk_reward) + 1 }, (_, x) => to_f(margin_range[1] - spread * x, this.price_places));
642
386
  } else {
643
- entries = Array.from({ length: Math.floor(this.risk_reward) + 1 }, (_, x) => to_f2(margin_range[1] * Math.pow(1 + percent_change, x), this.price_places));
387
+ entries = Array.from({ length: Math.floor(this.risk_reward) + 1 }, (_, x) => to_f(margin_range[1] * Math.pow(1 + percent_change, x), this.price_places));
644
388
  }
645
389
  if (Math.min(...entries) < this.to_f(current_price) && this.to_f(current_price) < Math.max(...entries)) {
646
390
  return entries.sort((a, b) => a - b);
@@ -652,14 +396,14 @@ class Signal {
652
396
  if (new_range) {
653
397
  while (entries2.length < this.risk_reward + 1) {
654
398
  if (kind === "long") {
655
- let value2 = this.to_f(new_range[1] - spread * x);
656
- if (value2 <= current_price) {
657
- entries2.push(value2);
399
+ let value = this.to_f(new_range[1] - spread * x);
400
+ if (value <= current_price) {
401
+ entries2.push(value);
658
402
  }
659
403
  } else {
660
- let value2 = this.to_f(new_range[1] * Math.pow(1 + percent_change, x));
661
- if (value2 >= current_price) {
662
- entries2.push(value2);
404
+ let value = this.to_f(new_range[1] * Math.pow(1 + percent_change, x));
405
+ if (value >= current_price) {
406
+ entries2.push(value);
663
407
  }
664
408
  }
665
409
  x += 1;
@@ -673,14 +417,14 @@ class Signal {
673
417
  let x = 0;
674
418
  while (entries2.length < this.risk_reward + 1) {
675
419
  if (kind === "long") {
676
- let value2 = this.to_f(next_focus - spread * x);
677
- if (value2 <= this.to_f(current_price)) {
678
- entries2.push(value2);
420
+ let value = this.to_f(next_focus - spread * x);
421
+ if (value <= this.to_f(current_price)) {
422
+ entries2.push(value);
679
423
  }
680
424
  } else {
681
- let value2 = this.to_f(next_focus * Math.pow(1 + percent_change, x));
682
- if (value2 >= this.to_f(current_price)) {
683
- entries2.push(value2);
425
+ let value = this.to_f(next_focus * Math.pow(1 + percent_change, x));
426
+ if (value >= this.to_f(current_price)) {
427
+ entries2.push(value);
684
428
  }
685
429
  }
686
430
  x += 1;
@@ -691,8 +435,8 @@ class Signal {
691
435
  }
692
436
  return [];
693
437
  }
694
- to_f(value2, places) {
695
- return to_f2(value2, places || this.price_places);
438
+ to_f(value, places) {
439
+ return to_f(value, places || this.price_places);
696
440
  }
697
441
  get_margin_zones({
698
442
  current_price,
@@ -894,7 +638,7 @@ class Signal {
894
638
  }) {
895
639
  const considered = arr.map((x, i) => i).filter((i) => i > index);
896
640
  const with_quantity = considered.map((x) => {
897
- const q = determine_position_size2({
641
+ const q = determine_position_size({
898
642
  entry: arr[x],
899
643
  stop: arr[x - 1],
900
644
  budget: risk,
@@ -928,7 +672,7 @@ class Signal {
928
672
  const incurred_fees = fees.reduce((a, b) => a + b, 0) + previous_risks.reduce((a, b) => a + b, 0);
929
673
  if (index === 0) {
930
674
  }
931
- let quantity = determine_position_size2({
675
+ let quantity = determine_position_size({
932
676
  entry,
933
677
  stop,
934
678
  budget: risk,
@@ -940,7 +684,7 @@ class Signal {
940
684
  }
941
685
  if (this.increase_size) {
942
686
  quantity = quantity * multiplier;
943
- const new_risk = determine_pnl2(entry, stop, quantity, kind);
687
+ const new_risk = determine_pnl(entry, stop, quantity, kind);
944
688
  risk = Math.abs(new_risk);
945
689
  }
946
690
  const fee = this.to_df(this.fee * quantity * entry);
@@ -949,12 +693,12 @@ class Signal {
949
693
  if (this.minimum_pnl) {
950
694
  pnl = this.minimum_pnl + fee;
951
695
  }
952
- let sell_price = determine_close_price2({ entry, pnl, quantity, kind });
696
+ let sell_price = determine_close_price({ entry, pnl, quantity, kind });
953
697
  if (take_profit && !this.minimum_pnl) {
954
698
  sell_price = take_profit;
955
- pnl = this.to_df(determine_pnl2(entry, sell_price, quantity, kind));
699
+ pnl = this.to_df(determine_pnl(entry, sell_price, quantity, kind));
956
700
  pnl = pnl + fee;
957
- sell_price = determine_close_price2({ entry, pnl, quantity, kind });
701
+ sell_price = determine_close_price({ entry, pnl, quantity, kind });
958
702
  }
959
703
  let risk_sell = sell_price;
960
704
  return {
@@ -972,29 +716,455 @@ class Signal {
972
716
  };
973
717
  }
974
718
  to_df(currentPrice, places = "%.3f") {
975
- return to_f2(currentPrice, places);
719
+ return to_f(currentPrice, places);
976
720
  }
977
721
  }
978
722
 
979
- // src/helpers/shared.ts
980
- function buildConfig(app_config, {
981
- take_profit,
982
- entry,
983
- stop,
984
- raw_instance,
985
- risk,
986
- no_of_trades,
987
- min_profit = 0,
988
- risk_reward,
989
- kind,
990
- increase,
991
- gap,
992
- rr = 1,
993
- price_places = "%.1f",
994
- decimal_places = "%.3f"
995
- }) {
996
- let fee = app_config.fee / 100;
997
- let working_risk = risk || app_config.risk_per_trade;
723
+ // src/helpers/pnl.ts
724
+ function determine_position_size2(entry, stop, budget) {
725
+ let stop_percent = Math.abs(entry - stop) / entry;
726
+ let size = budget / stop_percent / entry;
727
+ return size;
728
+ }
729
+ function determine_risk(entry, stop, quantity) {
730
+ let stop_percent = Math.abs(entry - stop) / entry;
731
+ let risk = quantity * stop_percent * entry;
732
+ return risk;
733
+ }
734
+ function determine_close_price2(entry, pnl, quantity, kind, single = false, leverage = 1) {
735
+ const dollar_value = entry / leverage;
736
+ const position = dollar_value * quantity;
737
+ if (position) {
738
+ let percent = pnl / position;
739
+ let difference = position * percent / quantity;
740
+ let result;
741
+ if (kind === "long") {
742
+ result = difference + entry;
743
+ } else {
744
+ result = entry - difference;
745
+ }
746
+ if (single) {
747
+ return result;
748
+ }
749
+ return result;
750
+ }
751
+ return 0;
752
+ }
753
+ function determine_amount_to_sell(entry, quantity, sell_price, pnl, kind, places = "%.3f") {
754
+ const _pnl = determine_pnl2(entry, sell_price, quantity, kind);
755
+ const ratio = pnl / to_f2(Math.abs(_pnl), places);
756
+ quantity = quantity * ratio;
757
+ return to_f2(quantity, places);
758
+ }
759
+ function determine_pnl2(entry, close_price, quantity, kind, contract_size, places = "%.2f") {
760
+ if (contract_size) {
761
+ const direction = kind === "long" ? 1 : -1;
762
+ return quantity * contract_size * direction * (1 / entry - 1 / close_price);
763
+ }
764
+ let difference = entry - close_price;
765
+ if (kind === "long") {
766
+ difference = close_price - entry;
767
+ }
768
+ return to_f2(difference * quantity, places);
769
+ }
770
+ function position(entry, quantity, kind, leverage = 1) {
771
+ const direction = { long: 1, short: -1 };
772
+ return parseFloat((direction[kind] * quantity * (entry / leverage)).toFixed(3));
773
+ }
774
+ function to_f2(value, places) {
775
+ if (value) {
776
+ let pp = parseInt(places.replace("%.", "").replace("f", ""));
777
+ return parseFloat(value.toFixed(pp));
778
+ }
779
+ return value;
780
+ }
781
+ var value = {
782
+ determine_risk,
783
+ determine_position_size: determine_position_size2,
784
+ determine_close_price: determine_close_price2,
785
+ determine_pnl: determine_pnl2,
786
+ position,
787
+ determine_amount_to_sell,
788
+ to_f: to_f2
789
+ };
790
+ var pnl_default = value;
791
+
792
+ // src/helpers/trade_utils.ts
793
+ function profitHelper(longPosition, shortPosition, config, contract_size, balance = 0) {
794
+ let long = { takeProfit: 0, quantity: 0, pnl: 0 };
795
+ let short = { takeProfit: 0, quantity: 0, pnl: 0 };
796
+ if (longPosition) {
797
+ long = config?.getSize2(longPosition, contract_size, balance) || null;
798
+ }
799
+ if (shortPosition) {
800
+ short = config?.getSize2(shortPosition, contract_size, balance) || null;
801
+ }
802
+ return { long, short };
803
+ }
804
+ function getParamForField(self, configs, field, isGroup) {
805
+ if (isGroup === "group" && field === "checkbox") {
806
+ return configs.filter((o) => o.kind === field && o.group === true).map((o) => {
807
+ let _self = self;
808
+ let value2 = _self[o.name];
809
+ return { ...o, value: value2 };
810
+ });
811
+ }
812
+ let r = configs.find((o) => o.name == field);
813
+ if (r) {
814
+ let oo = self;
815
+ let tt = oo[r.name] || "";
816
+ r.value = tt;
817
+ }
818
+ return r;
819
+ }
820
+ function getTradeEntries(entry, min_size, kind, size, spread = 0) {
821
+ let result = [];
822
+ let index = 0;
823
+ let no_of_trades = size > min_size ? Math.round(size / min_size) : 1;
824
+ while (index < no_of_trades) {
825
+ if (kind === "long") {
826
+ result.push({ entry: entry - index * spread, size: min_size });
827
+ } else {
828
+ result.push({ entry: entry + index * spread, size: min_size });
829
+ }
830
+ index = index + 1;
831
+ }
832
+ return result;
833
+ }
834
+ function extractValue(_param, condition) {
835
+ let param;
836
+ if (condition) {
837
+ try {
838
+ let value2 = JSON.parse(_param || "[]");
839
+ param = value2.map((o) => parseFloat(o));
840
+ } catch (error) {
841
+ }
842
+ } else {
843
+ param = parseFloat(_param);
844
+ }
845
+ return param;
846
+ }
847
+ function asCoins(symbol) {
848
+ let _type = symbol.toLowerCase().includes("usdt") ? "usdt" : "coin";
849
+ if (symbol.toLowerCase() == "btcusdt") {
850
+ _type = "usdt";
851
+ }
852
+ let result = _type === "usdt" ? symbol.toLowerCase().includes("usdt") ? "USDT" : "BUSD" : symbol.toUpperCase().split("USD_")[0];
853
+ if (symbol.toLowerCase().includes("-")) {
854
+ result = result.split("-")[0];
855
+ }
856
+ if (symbol.toLowerCase() == "usdt-usd") {
857
+ }
858
+ let result2 = _type == "usdt" ? symbol.split(result)[0] : result;
859
+ if (result.includes("-")) {
860
+ result2 = result;
861
+ }
862
+ return result2;
863
+ }
864
+ var SpecialCoins = ["NGN", "USDT", "BUSD", "PAX", "USDC", "EUR"];
865
+ function allCoins(symbols) {
866
+ let r = symbols.map((o, i) => asCoins(o));
867
+ return [...new Set(r), ...SpecialCoins];
868
+ }
869
+ function formatPrice(value2, opts = {}) {
870
+ const { locale = "en-US", currency = "USD" } = opts;
871
+ const formatter = new Intl.NumberFormat(locale, {
872
+ currency,
873
+ style: "currency",
874
+ maximumFractionDigits: 2
875
+ });
876
+ return formatter.format(value2);
877
+ }
878
+ function to_f(value2, places = "%.1f") {
879
+ let v = typeof value2 === "string" ? parseFloat(value2) : value2;
880
+ const formattedValue = places.replace("%.", "").replace("f", "");
881
+ return parseFloat(v.toFixed(parseInt(formattedValue)));
882
+ }
883
+ function determine_stop_and_size(entry, pnl, take_profit, kind = "long") {
884
+ const difference = kind === "long" ? take_profit - entry : entry - take_profit;
885
+ const quantity = pnl / difference;
886
+ return Math.abs(quantity);
887
+ }
888
+ var range = (start, stop, step = 1) => Array.from({ length: (stop - start) / step + 1 }, (_, i) => start + i * step);
889
+ function determine_amount_to_sell2(entry, quantity, sell_price, pnl, kind, places = "%.3f") {
890
+ const _pnl = determine_pnl(entry, sell_price, quantity, kind);
891
+ const ratio = pnl / to_f(Math.abs(_pnl), places);
892
+ quantity = quantity * ratio;
893
+ return to_f(quantity, places);
894
+ }
895
+ function determine_position_size({
896
+ entry,
897
+ stop,
898
+ budget,
899
+ percent,
900
+ min_size,
901
+ notional_value,
902
+ as_coin = true,
903
+ places = "%.3f"
904
+ }) {
905
+ let stop_percent = stop ? Math.abs(entry - stop) / entry : percent;
906
+ if (stop_percent && budget) {
907
+ let size = budget / stop_percent;
908
+ let notion_value = size * entry;
909
+ if (notional_value && notional_value > notion_value) {
910
+ size = notional_value / entry;
911
+ }
912
+ if (as_coin) {
913
+ size = size / entry;
914
+ if (min_size && min_size === 1) {
915
+ return to_f(Math.round(size), places);
916
+ }
917
+ }
918
+ return to_f(size, places);
919
+ }
920
+ return;
921
+ }
922
+ function determine_remaining_entry({
923
+ risk,
924
+ max_size,
925
+ stop_loss,
926
+ kind,
927
+ position: position2
928
+ }) {
929
+ const avg_entry = determine_avg_entry_based_on_max_size({
930
+ risk,
931
+ max_size,
932
+ stop_loss,
933
+ kind
934
+ });
935
+ const result = avg_entry * max_size - position2.quantity * position2.entry;
936
+ return result / (max_size - position2.quantity);
937
+ }
938
+ function determine_avg_entry_based_on_max_size({
939
+ risk,
940
+ max_size,
941
+ stop_loss,
942
+ kind = "long"
943
+ }) {
944
+ const diff = max_size * stop_loss;
945
+ if (kind === "long") {
946
+ return (risk + diff) / max_size;
947
+ }
948
+ return (risk - diff) / max_size;
949
+ }
950
+ function determine_average_entry_and_size(orders, places = "%.3f", price_places = "%.1f") {
951
+ const sum_values = orders.reduce((sum, order) => sum + order.price * order.quantity, 0);
952
+ const total_quantity = orders.reduce((sum, order) => sum + order.quantity, 0);
953
+ const avg_price = total_quantity ? to_f(sum_values / total_quantity, price_places) : 0;
954
+ return {
955
+ entry: avg_price,
956
+ price: avg_price,
957
+ quantity: to_f(total_quantity, places)
958
+ };
959
+ }
960
+ var createArray = (start, stop, step) => {
961
+ const result = [];
962
+ let current = start;
963
+ while (current <= stop) {
964
+ result.push(current);
965
+ current += step;
966
+ }
967
+ return result;
968
+ };
969
+ var groupBy = (xs, key) => {
970
+ return xs.reduce((rv, x) => {
971
+ (rv[x[key]] = rv[x[key]] || []).push(x);
972
+ return rv;
973
+ }, {});
974
+ };
975
+ function fibonacci_analysis({
976
+ support,
977
+ resistance,
978
+ kind = "long",
979
+ trend = "long",
980
+ places = "%.1f"
981
+ }) {
982
+ const swing_high = trend === "long" ? resistance : support;
983
+ const swing_low = trend === "long" ? support : resistance;
984
+ const ranges = [0, 0.236, 0.382, 0.5, 0.618, 0.789, 1, 1.272, 1.414, 1.618];
985
+ const fib_calc = (p, h, l) => p * (h - l) + l;
986
+ const fib_values = ranges.map((x) => fib_calc(x, swing_high, swing_low)).map((x) => to_f(x, places));
987
+ if (kind === "short") {
988
+ return trend === "long" ? fib_values.reverse() : fib_values;
989
+ } else {
990
+ return trend === "short" ? fib_values.reverse() : fib_values;
991
+ }
992
+ return fib_values;
993
+ }
994
+ var groupIntoPairs = (arr, size) => {
995
+ const result = [];
996
+ for (let i = 0;i < arr.length; i += size) {
997
+ result.push(arr.slice(i, i + size));
998
+ }
999
+ return result;
1000
+ };
1001
+ var groupIntoPairsWithSumLessThan = (arr, targetSum, key = "quantity", firstSize = 0) => {
1002
+ if (firstSize) {
1003
+ const totalSize = arr.reduce((sum, order) => sum + order[key], 0);
1004
+ const remainingSize = totalSize - firstSize;
1005
+ let newSum = 0;
1006
+ let newArray = [];
1007
+ let lastIndex = 0;
1008
+ for (let i = 0;i < arr.length; i++) {
1009
+ if (newSum < remainingSize) {
1010
+ newSum += arr[i][key];
1011
+ newArray.push(arr[i]);
1012
+ lastIndex = i;
1013
+ }
1014
+ }
1015
+ const lastGroup = arr.slice(lastIndex + 1);
1016
+ const previousPair = groupInPairs(newArray, key, targetSum);
1017
+ if (lastGroup.length > 0) {
1018
+ previousPair.push(lastGroup);
1019
+ }
1020
+ return previousPair;
1021
+ }
1022
+ return groupInPairs(arr, key, targetSum);
1023
+ };
1024
+ function groupInPairs(_arr, key, targetSum) {
1025
+ const result = [];
1026
+ let currentSum = 0;
1027
+ let currentGroup = [];
1028
+ for (let i = 0;i < _arr.length; i++) {
1029
+ currentSum += _arr[i][key];
1030
+ currentGroup.push(_arr[i]);
1031
+ if (currentSum >= targetSum) {
1032
+ result.push(currentGroup);
1033
+ currentGroup = [];
1034
+ currentSum = 0;
1035
+ }
1036
+ }
1037
+ return result;
1038
+ }
1039
+ var computeTotalAverageForEachTrade = (trades, config) => {
1040
+ let _take_profit = config.take_profit;
1041
+ let kind = config.kind;
1042
+ let entryToUse = kind === "short" ? Math.min(config.entry, config.stop) : Math.max(config.entry, config.stop);
1043
+ let _currentEntry = config.currentEntry || entryToUse;
1044
+ let less = trades.filter((p) => kind === "long" ? p.entry <= _currentEntry : p.entry >= _currentEntry);
1045
+ let rrr = trades.map((r, i) => {
1046
+ let considered = [];
1047
+ if (kind === "long") {
1048
+ considered = trades.filter((p) => p.entry > _currentEntry);
1049
+ } else {
1050
+ considered = trades.filter((p) => p.entry < _currentEntry);
1051
+ }
1052
+ const x_pnl = 0;
1053
+ const remaining = less.filter((o) => {
1054
+ if (kind === "long") {
1055
+ return o.entry >= r.entry;
1056
+ }
1057
+ return o.entry <= r.entry;
1058
+ });
1059
+ if (remaining.length === 0) {
1060
+ return { ...r, pnl: x_pnl };
1061
+ }
1062
+ const start = kind === "long" ? Math.max(...remaining.map((o) => o.entry)) : Math.min(...remaining.map((o) => o.entry));
1063
+ considered = considered.map((o) => ({ ...o, entry: start }));
1064
+ considered = considered.concat(remaining);
1065
+ let avg_entry = determine_average_entry_and_size([
1066
+ ...considered.map((o) => ({
1067
+ price: o.entry,
1068
+ quantity: o.quantity
1069
+ })),
1070
+ {
1071
+ price: _currentEntry,
1072
+ quantity: config.currentQty || 0
1073
+ }
1074
+ ], config.decimal_places, config.price_places);
1075
+ let _pnl = r.pnl;
1076
+ let sell_price = r.sell_price;
1077
+ let entry_pnl = r.pnl;
1078
+ if (_take_profit) {
1079
+ _pnl = pnl_default.determine_pnl(avg_entry.price, _take_profit, avg_entry.quantity, kind);
1080
+ sell_price = _take_profit;
1081
+ entry_pnl = pnl_default.determine_pnl(r.entry, _take_profit, avg_entry.quantity, kind);
1082
+ }
1083
+ const loss = pnl_default.determine_pnl(avg_entry.price, r.stop, avg_entry.quantity, kind);
1084
+ let new_stop = r.new_stop;
1085
+ const entry_loss = pnl_default.determine_pnl(r.entry, new_stop, avg_entry.quantity, kind);
1086
+ let min_profit = 0;
1087
+ let min_entry_profit = 0;
1088
+ if (config.min_profit) {
1089
+ min_profit = pnl_default.determine_close_price(avg_entry.price, config.min_profit, avg_entry.quantity, kind);
1090
+ min_entry_profit = pnl_default.determine_close_price(r.entry, config.min_profit, avg_entry.quantity, kind);
1091
+ }
1092
+ let x_fee = r.fee;
1093
+ if (config.fee) {
1094
+ x_fee = config.fee * r.stop * avg_entry.quantity;
1095
+ }
1096
+ let tp_close = pnl_default.determine_close_price(r.entry, Math.abs(entry_loss) * (config.rr || 1) + x_fee, avg_entry.quantity, kind);
1097
+ return {
1098
+ ...r,
1099
+ x_fee: to_f(x_fee, "%.2f"),
1100
+ avg_entry: avg_entry.price,
1101
+ avg_size: avg_entry.quantity,
1102
+ entry_pnl: to_f(entry_pnl, "%.2f"),
1103
+ entry_loss: to_f(entry_loss, "%.2f"),
1104
+ min_entry_pnl: to_f(min_entry_profit, "%.2f"),
1105
+ pnl: _pnl,
1106
+ neg_pnl: to_f(loss, "%.2f"),
1107
+ sell_price,
1108
+ close_p: to_f(tp_close, "%.2f"),
1109
+ min_pnl: to_f(min_profit, "%.2f"),
1110
+ new_stop
1111
+ };
1112
+ });
1113
+ return rrr;
1114
+ };
1115
+ function getDecimalPlaces(numberString) {
1116
+ let parts = numberString.toString().split(".");
1117
+ if (parts.length == 2) {
1118
+ return parts[1].length;
1119
+ }
1120
+ return 0;
1121
+ }
1122
+ function createGapPairs(arr, gap, item) {
1123
+ if (arr.length === 0) {
1124
+ return [];
1125
+ }
1126
+ const result = [];
1127
+ const firstElement = arr[0];
1128
+ for (let i = arr.length - 1;i >= 0; i--) {
1129
+ const current = arr[i];
1130
+ const gapIndex = i - gap;
1131
+ const pairedElement = gapIndex < 0 ? firstElement : arr[gapIndex];
1132
+ if (current !== pairedElement) {
1133
+ result.push([current, pairedElement]);
1134
+ }
1135
+ }
1136
+ if (item) {
1137
+ let r = result.find((o) => o[0] === item);
1138
+ return r ? [r] : [];
1139
+ }
1140
+ return result;
1141
+ }
1142
+ function logWithLineNumber(...args) {
1143
+ const stack = new Error().stack;
1144
+ const lines = stack?.split(`
1145
+ `).slice(2).map((line) => line.trim());
1146
+ const lineNumber = lines?.[0]?.split(":").pop();
1147
+ console.log(`${lineNumber}:`, ...args);
1148
+ }
1149
+ // src/helpers/shared.ts
1150
+ function buildConfig(app_config, {
1151
+ take_profit,
1152
+ entry,
1153
+ stop,
1154
+ raw_instance,
1155
+ risk,
1156
+ no_of_trades,
1157
+ min_profit = 0,
1158
+ risk_reward,
1159
+ kind,
1160
+ increase,
1161
+ gap,
1162
+ rr = 1,
1163
+ price_places = "%.1f",
1164
+ decimal_places = "%.3f"
1165
+ }) {
1166
+ let fee = app_config.fee / 100;
1167
+ let working_risk = risk || app_config.risk_per_trade;
998
1168
  let trade_no = no_of_trades || app_config.risk_reward;
999
1169
  const config = {
1000
1170
  focus: app_config.focus,
@@ -1075,8 +1245,8 @@ function get_app_config_and_max_size(config, payload) {
1075
1245
  stop: payload.stop,
1076
1246
  risk_per_trade: config.risk,
1077
1247
  risk_reward: config.risk_reward || 199,
1078
- support: to_f2(config.support, config.price_places),
1079
- resistance: to_f2(config.resistance, config.price_places),
1248
+ support: to_f(config.support, config.price_places),
1249
+ resistance: to_f(config.resistance, config.price_places),
1080
1250
  focus: payload.entry,
1081
1251
  fee: 0,
1082
1252
  percent_change: config.stop_percent / 100,
@@ -1277,8 +1447,8 @@ function getOptimumStopAndRisk(app_config, params) {
1277
1447
  }
1278
1448
  }
1279
1449
  return {
1280
- optimal_stop: to_f2(optimal_stop, app_config.price_places),
1281
- optimal_risk: to_f2(final_risk, app_config.price_places),
1450
+ optimal_stop: to_f(optimal_stop, app_config.price_places),
1451
+ optimal_risk: to_f(final_risk, app_config.price_places),
1282
1452
  avg_size: final_result?.[0]?.avg_size || 0,
1283
1453
  avg_entry: final_result?.[0]?.avg_entry || 0,
1284
1454
  result: final_result,
@@ -1326,7 +1496,7 @@ function determine_amount_to_buy(payload) {
1326
1496
  existingOrders
1327
1497
  } = payload;
1328
1498
  const totalQuantity = orders.reduce((sum, order) => sum + (order.quantity || 0), 0);
1329
- let runningTotal = to_f2(totalQuantity, decimal_places);
1499
+ let runningTotal = to_f(totalQuantity, decimal_places);
1330
1500
  let sortedOrders = [...orders].sort((a, b) => (a.entry || 0) - (b.entry || 0));
1331
1501
  if (kind === "short") {
1332
1502
  sortedOrders.reverse();
@@ -1338,7 +1508,7 @@ function determine_amount_to_buy(payload) {
1338
1508
  cumulative_quantity: runningTotal
1339
1509
  });
1340
1510
  runningTotal -= order.quantity;
1341
- runningTotal = to_f2(runningTotal, decimal_places);
1511
+ runningTotal = to_f(runningTotal, decimal_places);
1342
1512
  }
1343
1513
  let filteredOrders = withCumulative.filter((order) => (order.cumulative_quantity || 0) > position2?.quantity).map((order) => ({
1344
1514
  ...order,
@@ -1350,15 +1520,37 @@ function determine_amount_to_buy(payload) {
1350
1520
  return filteredOrders;
1351
1521
  }
1352
1522
  export {
1523
+ to_f,
1353
1524
  sortedBuildConfig,
1525
+ range,
1526
+ profitHelper,
1527
+ logWithLineNumber,
1528
+ groupIntoPairsWithSumLessThan,
1529
+ groupIntoPairs,
1530
+ groupBy,
1354
1531
  get_app_config_and_max_size,
1532
+ getTradeEntries,
1533
+ getParamForField,
1355
1534
  getOptimumStopAndRisk,
1535
+ getDecimalPlaces,
1356
1536
  generate_config_params,
1537
+ formatPrice,
1538
+ fibonacci_analysis,
1539
+ extractValue,
1540
+ determine_stop_and_size,
1541
+ determine_remaining_entry,
1542
+ determine_position_size,
1357
1543
  determine_break_even_price,
1358
1544
  determine_average_entry_and_size,
1545
+ determine_amount_to_sell2 as determine_amount_to_sell,
1359
1546
  determine_amount_to_buy,
1547
+ createGapPairs,
1360
1548
  createArray,
1549
+ computeTotalAverageForEachTrade,
1361
1550
  buildConfig,
1362
1551
  buildAvg,
1363
- buildAppConfig
1552
+ buildAppConfig,
1553
+ asCoins,
1554
+ allCoins,
1555
+ SpecialCoins
1364
1556
  };
package/dist/index.js CHANGED
@@ -54806,8 +54806,8 @@ function build_reduce_config(payload) {
54806
54806
  owner: account.owner,
54807
54807
  exchange: account.exchange,
54808
54808
  not_reduce,
54809
- reduce_ratio_long: long_position?.reduce_ratio || 0.9,
54810
- reduce_ratio_short: short_position?.reduce_ratio || 0.9,
54809
+ reduce_ratio_long: long_position?.reduce_ratio || 0,
54810
+ reduce_ratio_short: short_position?.reduce_ratio || 0,
54811
54811
  use_full_long: long_position?.use_full || false,
54812
54812
  use_full_short: short_position?.use_full || false
54813
54813
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gbozee/ultimate",
3
3
  "type": "module",
4
- "version": "0.0.2-45",
4
+ "version": "0.0.2-47",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",