@gbozee/ultimate 0.0.2-144 → 0.0.2-145

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.
@@ -139,6 +139,10 @@ export type SignalConfigType = {
139
139
  first_order_size?: number;
140
140
  gap?: number;
141
141
  max_size?: number;
142
+ use_kelly?: boolean;
143
+ kelly_prediction_model?: "exponential" | "normal" | "uniform";
144
+ kelly_confidence_factor?: number;
145
+ kelly_minimum_risk?: number;
142
146
  };
143
147
  declare class Signal {
144
148
  focus: number;
@@ -161,7 +165,11 @@ declare class Signal {
161
165
  first_order_size: number;
162
166
  gap: number;
163
167
  max_size: number;
164
- constructor({ focus, budget, percent_change, price_places, decimal_places, zone_risk, fee, support, risk_reward, resistance, risk_per_trade, increase_size, additional_increase, minimum_pnl, take_profit, increase_position, minimum_size, first_order_size, gap, max_size, }: SignalConfigType);
168
+ use_kelly: boolean;
169
+ kelly_prediction_model: "exponential" | "normal" | "uniform";
170
+ kelly_confidence_factor: number;
171
+ kelly_minimum_risk: number;
172
+ constructor({ focus, budget, percent_change, price_places, decimal_places, zone_risk, fee, support, risk_reward, resistance, risk_per_trade, increase_size, additional_increase, minimum_pnl, take_profit, increase_position, minimum_size, first_order_size, gap, max_size, use_kelly, kelly_prediction_model, kelly_confidence_factor, kelly_minimum_risk, }: SignalConfigType);
165
173
  build_entry({ current_price, stop_loss, pnl, stop_percent, kind, risk, no_of_trades, take_profit, }: {
166
174
  take_profit?: number;
167
175
  no_of_trades?: number;
@@ -296,6 +304,7 @@ export type AppConfig = {
296
304
  last_value?: any;
297
305
  entries?: any[];
298
306
  max_quantity?: number;
307
+ use_kelly?: boolean;
299
308
  };
300
309
  export type ExtendConfigType = {
301
310
  take_profit?: number;
@@ -814,6 +823,7 @@ export declare class Strategy {
814
823
  rr?: number;
815
824
  max_size?: number;
816
825
  max_quantity?: number;
826
+ use_kelly?: boolean;
817
827
  };
818
828
  identifyGapConfig(payload: {
819
829
  factor?: number;
@@ -1,3 +1,89 @@
1
+ // src/helpers/optimizations.ts
2
+ function calculateTheoreticalKelly({
3
+ current_entry,
4
+ zone_prices,
5
+ kind = "long",
6
+ config = {}
7
+ }) {
8
+ const {
9
+ price_prediction_model = "uniform",
10
+ confidence_factor = 0.6,
11
+ volatility_adjustment = true
12
+ } = config;
13
+ const sorted_prices = kind === "long" ? zone_prices : zone_prices.reverse();
14
+ const current_index = sorted_prices.findIndex((price) => price === current_entry);
15
+ if (current_index === -1)
16
+ return 0.02;
17
+ const win_zones = kind === "long" ? sorted_prices.slice(current_index + 1) : sorted_prices.slice(0, current_index);
18
+ const lose_zones = kind === "long" ? sorted_prices.slice(0, current_index) : sorted_prices.slice(current_index + 1);
19
+ const { win_probability, avg_win_ratio, avg_loss_ratio } = calculateZoneProbabilities({
20
+ current_entry,
21
+ win_zones,
22
+ lose_zones,
23
+ price_prediction_model,
24
+ confidence_factor,
25
+ kind
26
+ });
27
+ const odds_ratio = avg_win_ratio / avg_loss_ratio;
28
+ const loss_probability = 1 - win_probability;
29
+ let kelly_fraction = (win_probability * odds_ratio - loss_probability) / odds_ratio;
30
+ if (volatility_adjustment) {
31
+ const zone_volatility = calculateZoneVolatility(sorted_prices);
32
+ const vol_adjustment = 1 / (1 + zone_volatility);
33
+ kelly_fraction *= vol_adjustment;
34
+ }
35
+ kelly_fraction = Math.max(0.005, Math.min(kelly_fraction, 0.5));
36
+ return to_f(kelly_fraction, "%.4f");
37
+ }
38
+ function calculateZoneProbabilities({
39
+ current_entry,
40
+ win_zones,
41
+ lose_zones,
42
+ price_prediction_model,
43
+ confidence_factor,
44
+ kind
45
+ }) {
46
+ if (win_zones.length === 0 && lose_zones.length === 0) {
47
+ return { win_probability: 0.5, avg_win_ratio: 0.02, avg_loss_ratio: 0.02 };
48
+ }
49
+ let win_probability;
50
+ switch (price_prediction_model) {
51
+ case "uniform":
52
+ win_probability = win_zones.length / (win_zones.length + lose_zones.length);
53
+ break;
54
+ case "normal":
55
+ const win_weight = win_zones.reduce((sum, _, idx) => sum + 1 / (idx + 1), 0);
56
+ const lose_weight = lose_zones.reduce((sum, _, idx) => sum + 1 / (idx + 1), 0);
57
+ win_probability = win_weight / (win_weight + lose_weight);
58
+ break;
59
+ case "exponential":
60
+ const exp_win_weight = win_zones.reduce((sum, _, idx) => sum + Math.exp(-idx * 0.5), 0);
61
+ const exp_lose_weight = lose_zones.reduce((sum, _, idx) => sum + Math.exp(-idx * 0.5), 0);
62
+ win_probability = exp_win_weight / (exp_win_weight + exp_lose_weight);
63
+ break;
64
+ default:
65
+ win_probability = 0.5;
66
+ }
67
+ win_probability = win_probability * confidence_factor + (1 - confidence_factor) * 0.5;
68
+ const avg_win_ratio = win_zones.length > 0 ? win_zones.reduce((sum, price) => {
69
+ return sum + Math.abs(price - current_entry) / current_entry;
70
+ }, 0) / win_zones.length : 0.02;
71
+ const avg_loss_ratio = lose_zones.length > 0 ? lose_zones.reduce((sum, price) => {
72
+ return sum + Math.abs(price - current_entry) / current_entry;
73
+ }, 0) / lose_zones.length : 0.02;
74
+ return {
75
+ win_probability: Math.max(0.1, Math.min(0.9, win_probability)),
76
+ avg_win_ratio: Math.max(0.005, avg_win_ratio),
77
+ avg_loss_ratio: Math.max(0.005, avg_loss_ratio)
78
+ };
79
+ }
80
+ function calculateZoneVolatility(zone_prices) {
81
+ if (zone_prices.length < 2)
82
+ return 0;
83
+ const price_changes = zone_prices.slice(1).map((price, i) => Math.abs(price - zone_prices[i]) / zone_prices[i]);
84
+ return price_changes.reduce((sum, change) => sum + change, 0) / price_changes.length;
85
+ }
86
+
1
87
  // src/helpers/trade_signal.ts
2
88
  function determine_close_price({
3
89
  entry,
@@ -80,6 +166,10 @@ class Signal {
80
166
  first_order_size;
81
167
  gap = 10;
82
168
  max_size = 0;
169
+ use_kelly = false;
170
+ kelly_prediction_model = "exponential";
171
+ kelly_confidence_factor = 0.6;
172
+ kelly_minimum_risk = 0.2;
83
173
  constructor({
84
174
  focus,
85
175
  budget,
@@ -100,7 +190,11 @@ class Signal {
100
190
  minimum_size = 0,
101
191
  first_order_size = 0,
102
192
  gap = 10,
103
- max_size = 0
193
+ max_size = 0,
194
+ use_kelly = false,
195
+ kelly_prediction_model = "exponential",
196
+ kelly_confidence_factor = 0.6,
197
+ kelly_minimum_risk = 0.2
104
198
  }) {
105
199
  this.minimum_size = minimum_size;
106
200
  this.first_order_size = first_order_size;
@@ -122,6 +216,10 @@ class Signal {
122
216
  this.increase_position = increase_position;
123
217
  this.gap = gap;
124
218
  this.max_size = max_size;
219
+ this.use_kelly = use_kelly;
220
+ this.kelly_prediction_model = kelly_prediction_model;
221
+ this.kelly_confidence_factor = kelly_confidence_factor;
222
+ this.kelly_minimum_risk = kelly_minimum_risk;
125
223
  }
126
224
  build_entry({
127
225
  current_price,
@@ -560,10 +658,25 @@ class Signal {
560
658
  }
561
659
  const defaultStopLoss = i === 0 ? stop_loss : _base;
562
660
  const new_stop = kind === "long" ? this.support : stop_loss;
661
+ let risk_to_use = risk_per_trade;
662
+ if (this.use_kelly) {
663
+ const theoretical_kelly = calculateTheoreticalKelly({
664
+ current_entry: x,
665
+ zone_prices: limit_orders,
666
+ kind,
667
+ config: {
668
+ price_prediction_model: this.kelly_prediction_model,
669
+ confidence_factor: this.kelly_confidence_factor,
670
+ volatility_adjustment: true
671
+ }
672
+ });
673
+ risk_to_use = theoretical_kelly * risk_per_trade / this.kelly_minimum_risk;
674
+ console.log({ risk_per_trade, theoretical_kelly });
675
+ }
563
676
  const y = this.build_trade_dict({
564
677
  entry: x,
565
678
  stop: (this.increase_position ? new_stop : defaultStopLoss) || defaultStopLoss,
566
- risk: risk_per_trade,
679
+ risk: risk_to_use,
567
680
  arr: limit_orders,
568
681
  index: i,
569
682
  new_fees: total_incurred_market_fees,
@@ -1249,7 +1362,8 @@ function buildConfig(app_config, {
1249
1362
  kind: app_config.kind,
1250
1363
  gap,
1251
1364
  min_profit: min_profit || app_config.min_profit,
1252
- rr: rr || 1
1365
+ rr: rr || 1,
1366
+ use_kelly: app_config.use_kelly
1253
1367
  };
1254
1368
  const instance = new Signal(config);
1255
1369
  if (raw_instance) {
@@ -1261,6 +1375,7 @@ function buildConfig(app_config, {
1261
1375
  const condition = (kind === "long" ? entry > app_config.support : entry >= app_config.support) && stop >= app_config.support * 0.999;
1262
1376
  if (kind === "short") {
1263
1377
  }
1378
+ console.log({ entry, stop, condition, working_risk, config });
1264
1379
  const result = entry === stop ? [] : condition ? instance.build_entry({
1265
1380
  current_price: entry,
1266
1381
  stop_loss: stop,
package/dist/index.cjs CHANGED
@@ -52870,6 +52870,92 @@ function createGapPairs(arr, gap, item) {
52870
52870
  return result;
52871
52871
  }
52872
52872
 
52873
+ // src/helpers/optimizations.ts
52874
+ function calculateTheoreticalKelly({
52875
+ current_entry,
52876
+ zone_prices,
52877
+ kind = "long",
52878
+ config: config2 = {}
52879
+ }) {
52880
+ const {
52881
+ price_prediction_model = "uniform",
52882
+ confidence_factor = 0.6,
52883
+ volatility_adjustment = true
52884
+ } = config2;
52885
+ const sorted_prices = kind === "long" ? zone_prices : zone_prices.reverse();
52886
+ const current_index = sorted_prices.findIndex((price) => price === current_entry);
52887
+ if (current_index === -1)
52888
+ return 0.02;
52889
+ const win_zones = kind === "long" ? sorted_prices.slice(current_index + 1) : sorted_prices.slice(0, current_index);
52890
+ const lose_zones = kind === "long" ? sorted_prices.slice(0, current_index) : sorted_prices.slice(current_index + 1);
52891
+ const { win_probability, avg_win_ratio, avg_loss_ratio } = calculateZoneProbabilities({
52892
+ current_entry,
52893
+ win_zones,
52894
+ lose_zones,
52895
+ price_prediction_model,
52896
+ confidence_factor,
52897
+ kind
52898
+ });
52899
+ const odds_ratio = avg_win_ratio / avg_loss_ratio;
52900
+ const loss_probability = 1 - win_probability;
52901
+ let kelly_fraction = (win_probability * odds_ratio - loss_probability) / odds_ratio;
52902
+ if (volatility_adjustment) {
52903
+ const zone_volatility = calculateZoneVolatility(sorted_prices);
52904
+ const vol_adjustment = 1 / (1 + zone_volatility);
52905
+ kelly_fraction *= vol_adjustment;
52906
+ }
52907
+ kelly_fraction = Math.max(0.005, Math.min(kelly_fraction, 0.5));
52908
+ return to_f2(kelly_fraction, "%.4f");
52909
+ }
52910
+ function calculateZoneProbabilities({
52911
+ current_entry,
52912
+ win_zones,
52913
+ lose_zones,
52914
+ price_prediction_model,
52915
+ confidence_factor,
52916
+ kind
52917
+ }) {
52918
+ if (win_zones.length === 0 && lose_zones.length === 0) {
52919
+ return { win_probability: 0.5, avg_win_ratio: 0.02, avg_loss_ratio: 0.02 };
52920
+ }
52921
+ let win_probability;
52922
+ switch (price_prediction_model) {
52923
+ case "uniform":
52924
+ win_probability = win_zones.length / (win_zones.length + lose_zones.length);
52925
+ break;
52926
+ case "normal":
52927
+ const win_weight = win_zones.reduce((sum, _, idx) => sum + 1 / (idx + 1), 0);
52928
+ const lose_weight = lose_zones.reduce((sum, _, idx) => sum + 1 / (idx + 1), 0);
52929
+ win_probability = win_weight / (win_weight + lose_weight);
52930
+ break;
52931
+ case "exponential":
52932
+ const exp_win_weight = win_zones.reduce((sum, _, idx) => sum + Math.exp(-idx * 0.5), 0);
52933
+ const exp_lose_weight = lose_zones.reduce((sum, _, idx) => sum + Math.exp(-idx * 0.5), 0);
52934
+ win_probability = exp_win_weight / (exp_win_weight + exp_lose_weight);
52935
+ break;
52936
+ default:
52937
+ win_probability = 0.5;
52938
+ }
52939
+ win_probability = win_probability * confidence_factor + (1 - confidence_factor) * 0.5;
52940
+ const avg_win_ratio = win_zones.length > 0 ? win_zones.reduce((sum, price) => {
52941
+ return sum + Math.abs(price - current_entry) / current_entry;
52942
+ }, 0) / win_zones.length : 0.02;
52943
+ const avg_loss_ratio = lose_zones.length > 0 ? lose_zones.reduce((sum, price) => {
52944
+ return sum + Math.abs(price - current_entry) / current_entry;
52945
+ }, 0) / lose_zones.length : 0.02;
52946
+ return {
52947
+ win_probability: Math.max(0.1, Math.min(0.9, win_probability)),
52948
+ avg_win_ratio: Math.max(0.005, avg_win_ratio),
52949
+ avg_loss_ratio: Math.max(0.005, avg_loss_ratio)
52950
+ };
52951
+ }
52952
+ function calculateZoneVolatility(zone_prices) {
52953
+ if (zone_prices.length < 2)
52954
+ return 0;
52955
+ const price_changes = zone_prices.slice(1).map((price, i2) => Math.abs(price - zone_prices[i2]) / zone_prices[i2]);
52956
+ return price_changes.reduce((sum, change) => sum + change, 0) / price_changes.length;
52957
+ }
52958
+
52873
52959
  // src/helpers/trade_signal.ts
52874
52960
  function determine_close_price2({
52875
52961
  entry,
@@ -52952,6 +53038,10 @@ class Signal {
52952
53038
  first_order_size;
52953
53039
  gap = 10;
52954
53040
  max_size = 0;
53041
+ use_kelly = false;
53042
+ kelly_prediction_model = "exponential";
53043
+ kelly_confidence_factor = 0.6;
53044
+ kelly_minimum_risk = 0.2;
52955
53045
  constructor({
52956
53046
  focus,
52957
53047
  budget,
@@ -52972,7 +53062,11 @@ class Signal {
52972
53062
  minimum_size = 0,
52973
53063
  first_order_size = 0,
52974
53064
  gap = 10,
52975
- max_size = 0
53065
+ max_size = 0,
53066
+ use_kelly = false,
53067
+ kelly_prediction_model = "exponential",
53068
+ kelly_confidence_factor = 0.6,
53069
+ kelly_minimum_risk = 0.2
52976
53070
  }) {
52977
53071
  this.minimum_size = minimum_size;
52978
53072
  this.first_order_size = first_order_size;
@@ -52994,6 +53088,10 @@ class Signal {
52994
53088
  this.increase_position = increase_position;
52995
53089
  this.gap = gap;
52996
53090
  this.max_size = max_size;
53091
+ this.use_kelly = use_kelly;
53092
+ this.kelly_prediction_model = kelly_prediction_model;
53093
+ this.kelly_confidence_factor = kelly_confidence_factor;
53094
+ this.kelly_minimum_risk = kelly_minimum_risk;
52997
53095
  }
52998
53096
  build_entry({
52999
53097
  current_price,
@@ -53432,10 +53530,25 @@ class Signal {
53432
53530
  }
53433
53531
  const defaultStopLoss = i2 === 0 ? stop_loss : _base;
53434
53532
  const new_stop = kind === "long" ? this.support : stop_loss;
53533
+ let risk_to_use = risk_per_trade;
53534
+ if (this.use_kelly) {
53535
+ const theoretical_kelly = calculateTheoreticalKelly({
53536
+ current_entry: x,
53537
+ zone_prices: limit_orders,
53538
+ kind,
53539
+ config: {
53540
+ price_prediction_model: this.kelly_prediction_model,
53541
+ confidence_factor: this.kelly_confidence_factor,
53542
+ volatility_adjustment: true
53543
+ }
53544
+ });
53545
+ risk_to_use = theoretical_kelly * risk_per_trade / this.kelly_minimum_risk;
53546
+ console.log({ risk_per_trade, theoretical_kelly });
53547
+ }
53435
53548
  const y = this.build_trade_dict({
53436
53549
  entry: x,
53437
53550
  stop: (this.increase_position ? new_stop : defaultStopLoss) || defaultStopLoss,
53438
- risk: risk_per_trade,
53551
+ risk: risk_to_use,
53439
53552
  arr: limit_orders,
53440
53553
  index: i2,
53441
53554
  new_fees: total_incurred_market_fees,
@@ -53647,7 +53760,8 @@ function buildConfig(app_config, {
53647
53760
  kind: app_config.kind,
53648
53761
  gap,
53649
53762
  min_profit: min_profit || app_config.min_profit,
53650
- rr: rr || 1
53763
+ rr: rr || 1,
53764
+ use_kelly: app_config.use_kelly
53651
53765
  };
53652
53766
  const instance = new Signal(config2);
53653
53767
  if (raw_instance) {
@@ -53659,6 +53773,7 @@ function buildConfig(app_config, {
53659
53773
  const condition = (kind === "long" ? entry > app_config.support : entry >= app_config.support) && stop >= app_config.support * 0.999;
53660
53774
  if (kind === "short") {
53661
53775
  }
53776
+ console.log({ entry, stop, condition, working_risk, config: config2 });
53662
53777
  const result = entry === stop ? [] : condition ? instance.build_entry({
53663
53778
  current_price: entry,
53664
53779
  stop_loss: stop,
@@ -58935,15 +59050,25 @@ class ExchangeAccount {
58935
59050
  }
58936
59051
  }
58937
59052
  async increasePositionAtStop(payload) {
58938
- const { symbol, kind, place = false } = payload;
59053
+ const { symbol, kind, place = false, increase = true } = payload;
58939
59054
  const position2 = await this.syncAccount({
58940
59055
  symbol,
58941
59056
  kind,
58942
59057
  as_view: true
58943
59058
  });
58944
59059
  console.log(position2);
58945
- if (position2 && position2.stop_loss) {
58946
- const { price, quantity } = position2.stop_loss;
59060
+ let price_params = {
59061
+ price: payload.price,
59062
+ quantity: payload.quantity
59063
+ };
59064
+ if (!payload.price && position2 && position2.stop_loss) {
59065
+ price_params.price = position2.stop_loss.price;
59066
+ }
59067
+ if (!payload.quantity && position2 && position2.stop_loss) {
59068
+ price_params.quantity = position2.stop_loss.quantity;
59069
+ }
59070
+ if (price_params.price && price_params.quantity) {
59071
+ const { price, quantity } = price_params;
58947
59072
  const symbol_config = await this.recomputeSymbolConfig({
58948
59073
  symbol
58949
59074
  });
@@ -58963,7 +59088,7 @@ class ExchangeAccount {
58963
59088
  quantity,
58964
59089
  price_places,
58965
59090
  decimal_places,
58966
- increase: true,
59091
+ increase,
58967
59092
  place
58968
59093
  });
58969
59094
  }
package/dist/index.d.ts CHANGED
@@ -1016,6 +1016,7 @@ export declare class Strategy {
1016
1016
  rr?: number;
1017
1017
  max_size?: number;
1018
1018
  max_quantity?: number;
1019
+ use_kelly?: boolean;
1019
1020
  };
1020
1021
  identifyGapConfig(payload: {
1021
1022
  factor?: number;
@@ -1129,6 +1130,10 @@ export type SignalConfigType = {
1129
1130
  first_order_size?: number;
1130
1131
  gap?: number;
1131
1132
  max_size?: number;
1133
+ use_kelly?: boolean;
1134
+ kelly_prediction_model?: "exponential" | "normal" | "uniform";
1135
+ kelly_confidence_factor?: number;
1136
+ kelly_minimum_risk?: number;
1132
1137
  };
1133
1138
  declare class Signal {
1134
1139
  focus: number;
@@ -1151,7 +1156,11 @@ declare class Signal {
1151
1156
  first_order_size: number;
1152
1157
  gap: number;
1153
1158
  max_size: number;
1154
- constructor({ focus, budget, percent_change, price_places, decimal_places, zone_risk, fee, support, risk_reward, resistance, risk_per_trade, increase_size, additional_increase, minimum_pnl, take_profit, increase_position, minimum_size, first_order_size, gap, max_size, }: SignalConfigType);
1159
+ use_kelly: boolean;
1160
+ kelly_prediction_model: "exponential" | "normal" | "uniform";
1161
+ kelly_confidence_factor: number;
1162
+ kelly_minimum_risk: number;
1163
+ constructor({ focus, budget, percent_change, price_places, decimal_places, zone_risk, fee, support, risk_reward, resistance, risk_per_trade, increase_size, additional_increase, minimum_pnl, take_profit, increase_position, minimum_size, first_order_size, gap, max_size, use_kelly, kelly_prediction_model, kelly_confidence_factor, kelly_minimum_risk, }: SignalConfigType);
1155
1164
  build_entry({ current_price, stop_loss, pnl, stop_percent, kind, risk, no_of_trades, take_profit, }: {
1156
1165
  take_profit?: number;
1157
1166
  no_of_trades?: number;
@@ -1274,6 +1283,7 @@ export type AppConfig = {
1274
1283
  last_value?: any;
1275
1284
  entries?: any[];
1276
1285
  max_quantity?: number;
1286
+ use_kelly?: boolean;
1277
1287
  };
1278
1288
  export type ExtendConfigType = {
1279
1289
  take_profit?: number;
@@ -2072,6 +2082,9 @@ declare class ExchangeAccount$1 {
2072
2082
  symbol: string;
2073
2083
  kind: "long" | "short";
2074
2084
  place?: boolean;
2085
+ price?: number;
2086
+ quantity?: number;
2087
+ increase?: boolean;
2075
2088
  }): Promise<any>;
2076
2089
  triggerTradeFromConfig(payload: {
2077
2090
  symbol: string;
@@ -2198,6 +2211,7 @@ declare class ExchangeAccount$1 {
2198
2211
  rr?: number;
2199
2212
  max_size?: number;
2200
2213
  max_quantity?: number;
2214
+ use_kelly?: boolean;
2201
2215
  }>;
2202
2216
  runSimulation(payload: {
2203
2217
  symbol: string;
@@ -2378,6 +2392,7 @@ declare class ExchangeAccount$1 {
2378
2392
  rr?: number;
2379
2393
  max_size?: number;
2380
2394
  max_quantity?: number;
2395
+ use_kelly?: boolean;
2381
2396
  };
2382
2397
  last_value: any;
2383
2398
  config: {
@@ -2645,6 +2660,7 @@ declare class App {
2645
2660
  rr?: number;
2646
2661
  max_size?: number;
2647
2662
  max_quantity?: number;
2663
+ use_kelly?: boolean;
2648
2664
  };
2649
2665
  last_value: any;
2650
2666
  config: {
package/dist/index.js CHANGED
@@ -52818,6 +52818,92 @@ function createGapPairs(arr, gap, item) {
52818
52818
  return result;
52819
52819
  }
52820
52820
 
52821
+ // src/helpers/optimizations.ts
52822
+ function calculateTheoreticalKelly({
52823
+ current_entry,
52824
+ zone_prices,
52825
+ kind = "long",
52826
+ config: config2 = {}
52827
+ }) {
52828
+ const {
52829
+ price_prediction_model = "uniform",
52830
+ confidence_factor = 0.6,
52831
+ volatility_adjustment = true
52832
+ } = config2;
52833
+ const sorted_prices = kind === "long" ? zone_prices : zone_prices.reverse();
52834
+ const current_index = sorted_prices.findIndex((price) => price === current_entry);
52835
+ if (current_index === -1)
52836
+ return 0.02;
52837
+ const win_zones = kind === "long" ? sorted_prices.slice(current_index + 1) : sorted_prices.slice(0, current_index);
52838
+ const lose_zones = kind === "long" ? sorted_prices.slice(0, current_index) : sorted_prices.slice(current_index + 1);
52839
+ const { win_probability, avg_win_ratio, avg_loss_ratio } = calculateZoneProbabilities({
52840
+ current_entry,
52841
+ win_zones,
52842
+ lose_zones,
52843
+ price_prediction_model,
52844
+ confidence_factor,
52845
+ kind
52846
+ });
52847
+ const odds_ratio = avg_win_ratio / avg_loss_ratio;
52848
+ const loss_probability = 1 - win_probability;
52849
+ let kelly_fraction = (win_probability * odds_ratio - loss_probability) / odds_ratio;
52850
+ if (volatility_adjustment) {
52851
+ const zone_volatility = calculateZoneVolatility(sorted_prices);
52852
+ const vol_adjustment = 1 / (1 + zone_volatility);
52853
+ kelly_fraction *= vol_adjustment;
52854
+ }
52855
+ kelly_fraction = Math.max(0.005, Math.min(kelly_fraction, 0.5));
52856
+ return to_f2(kelly_fraction, "%.4f");
52857
+ }
52858
+ function calculateZoneProbabilities({
52859
+ current_entry,
52860
+ win_zones,
52861
+ lose_zones,
52862
+ price_prediction_model,
52863
+ confidence_factor,
52864
+ kind
52865
+ }) {
52866
+ if (win_zones.length === 0 && lose_zones.length === 0) {
52867
+ return { win_probability: 0.5, avg_win_ratio: 0.02, avg_loss_ratio: 0.02 };
52868
+ }
52869
+ let win_probability;
52870
+ switch (price_prediction_model) {
52871
+ case "uniform":
52872
+ win_probability = win_zones.length / (win_zones.length + lose_zones.length);
52873
+ break;
52874
+ case "normal":
52875
+ const win_weight = win_zones.reduce((sum, _, idx) => sum + 1 / (idx + 1), 0);
52876
+ const lose_weight = lose_zones.reduce((sum, _, idx) => sum + 1 / (idx + 1), 0);
52877
+ win_probability = win_weight / (win_weight + lose_weight);
52878
+ break;
52879
+ case "exponential":
52880
+ const exp_win_weight = win_zones.reduce((sum, _, idx) => sum + Math.exp(-idx * 0.5), 0);
52881
+ const exp_lose_weight = lose_zones.reduce((sum, _, idx) => sum + Math.exp(-idx * 0.5), 0);
52882
+ win_probability = exp_win_weight / (exp_win_weight + exp_lose_weight);
52883
+ break;
52884
+ default:
52885
+ win_probability = 0.5;
52886
+ }
52887
+ win_probability = win_probability * confidence_factor + (1 - confidence_factor) * 0.5;
52888
+ const avg_win_ratio = win_zones.length > 0 ? win_zones.reduce((sum, price) => {
52889
+ return sum + Math.abs(price - current_entry) / current_entry;
52890
+ }, 0) / win_zones.length : 0.02;
52891
+ const avg_loss_ratio = lose_zones.length > 0 ? lose_zones.reduce((sum, price) => {
52892
+ return sum + Math.abs(price - current_entry) / current_entry;
52893
+ }, 0) / lose_zones.length : 0.02;
52894
+ return {
52895
+ win_probability: Math.max(0.1, Math.min(0.9, win_probability)),
52896
+ avg_win_ratio: Math.max(0.005, avg_win_ratio),
52897
+ avg_loss_ratio: Math.max(0.005, avg_loss_ratio)
52898
+ };
52899
+ }
52900
+ function calculateZoneVolatility(zone_prices) {
52901
+ if (zone_prices.length < 2)
52902
+ return 0;
52903
+ const price_changes = zone_prices.slice(1).map((price, i2) => Math.abs(price - zone_prices[i2]) / zone_prices[i2]);
52904
+ return price_changes.reduce((sum, change) => sum + change, 0) / price_changes.length;
52905
+ }
52906
+
52821
52907
  // src/helpers/trade_signal.ts
52822
52908
  function determine_close_price2({
52823
52909
  entry,
@@ -52900,6 +52986,10 @@ class Signal {
52900
52986
  first_order_size;
52901
52987
  gap = 10;
52902
52988
  max_size = 0;
52989
+ use_kelly = false;
52990
+ kelly_prediction_model = "exponential";
52991
+ kelly_confidence_factor = 0.6;
52992
+ kelly_minimum_risk = 0.2;
52903
52993
  constructor({
52904
52994
  focus,
52905
52995
  budget,
@@ -52920,7 +53010,11 @@ class Signal {
52920
53010
  minimum_size = 0,
52921
53011
  first_order_size = 0,
52922
53012
  gap = 10,
52923
- max_size = 0
53013
+ max_size = 0,
53014
+ use_kelly = false,
53015
+ kelly_prediction_model = "exponential",
53016
+ kelly_confidence_factor = 0.6,
53017
+ kelly_minimum_risk = 0.2
52924
53018
  }) {
52925
53019
  this.minimum_size = minimum_size;
52926
53020
  this.first_order_size = first_order_size;
@@ -52942,6 +53036,10 @@ class Signal {
52942
53036
  this.increase_position = increase_position;
52943
53037
  this.gap = gap;
52944
53038
  this.max_size = max_size;
53039
+ this.use_kelly = use_kelly;
53040
+ this.kelly_prediction_model = kelly_prediction_model;
53041
+ this.kelly_confidence_factor = kelly_confidence_factor;
53042
+ this.kelly_minimum_risk = kelly_minimum_risk;
52945
53043
  }
52946
53044
  build_entry({
52947
53045
  current_price,
@@ -53380,10 +53478,25 @@ class Signal {
53380
53478
  }
53381
53479
  const defaultStopLoss = i2 === 0 ? stop_loss : _base;
53382
53480
  const new_stop = kind === "long" ? this.support : stop_loss;
53481
+ let risk_to_use = risk_per_trade;
53482
+ if (this.use_kelly) {
53483
+ const theoretical_kelly = calculateTheoreticalKelly({
53484
+ current_entry: x,
53485
+ zone_prices: limit_orders,
53486
+ kind,
53487
+ config: {
53488
+ price_prediction_model: this.kelly_prediction_model,
53489
+ confidence_factor: this.kelly_confidence_factor,
53490
+ volatility_adjustment: true
53491
+ }
53492
+ });
53493
+ risk_to_use = theoretical_kelly * risk_per_trade / this.kelly_minimum_risk;
53494
+ console.log({ risk_per_trade, theoretical_kelly });
53495
+ }
53383
53496
  const y = this.build_trade_dict({
53384
53497
  entry: x,
53385
53498
  stop: (this.increase_position ? new_stop : defaultStopLoss) || defaultStopLoss,
53386
- risk: risk_per_trade,
53499
+ risk: risk_to_use,
53387
53500
  arr: limit_orders,
53388
53501
  index: i2,
53389
53502
  new_fees: total_incurred_market_fees,
@@ -53595,7 +53708,8 @@ function buildConfig(app_config, {
53595
53708
  kind: app_config.kind,
53596
53709
  gap,
53597
53710
  min_profit: min_profit || app_config.min_profit,
53598
- rr: rr || 1
53711
+ rr: rr || 1,
53712
+ use_kelly: app_config.use_kelly
53599
53713
  };
53600
53714
  const instance = new Signal(config2);
53601
53715
  if (raw_instance) {
@@ -53607,6 +53721,7 @@ function buildConfig(app_config, {
53607
53721
  const condition = (kind === "long" ? entry > app_config.support : entry >= app_config.support) && stop >= app_config.support * 0.999;
53608
53722
  if (kind === "short") {
53609
53723
  }
53724
+ console.log({ entry, stop, condition, working_risk, config: config2 });
53610
53725
  const result = entry === stop ? [] : condition ? instance.build_entry({
53611
53726
  current_price: entry,
53612
53727
  stop_loss: stop,
@@ -58883,15 +58998,25 @@ class ExchangeAccount {
58883
58998
  }
58884
58999
  }
58885
59000
  async increasePositionAtStop(payload) {
58886
- const { symbol, kind, place = false } = payload;
59001
+ const { symbol, kind, place = false, increase = true } = payload;
58887
59002
  const position2 = await this.syncAccount({
58888
59003
  symbol,
58889
59004
  kind,
58890
59005
  as_view: true
58891
59006
  });
58892
59007
  console.log(position2);
58893
- if (position2 && position2.stop_loss) {
58894
- const { price, quantity } = position2.stop_loss;
59008
+ let price_params = {
59009
+ price: payload.price,
59010
+ quantity: payload.quantity
59011
+ };
59012
+ if (!payload.price && position2 && position2.stop_loss) {
59013
+ price_params.price = position2.stop_loss.price;
59014
+ }
59015
+ if (!payload.quantity && position2 && position2.stop_loss) {
59016
+ price_params.quantity = position2.stop_loss.quantity;
59017
+ }
59018
+ if (price_params.price && price_params.quantity) {
59019
+ const { price, quantity } = price_params;
58895
59020
  const symbol_config = await this.recomputeSymbolConfig({
58896
59021
  symbol
58897
59022
  });
@@ -58911,7 +59036,7 @@ class ExchangeAccount {
58911
59036
  quantity,
58912
59037
  price_places,
58913
59038
  decimal_places,
58914
- increase: true,
59039
+ increase,
58915
59040
  place
58916
59041
  });
58917
59042
  }
@@ -59565,6 +59565,92 @@ function createGapPairs(arr, gap, item) {
59565
59565
  return result;
59566
59566
  }
59567
59567
 
59568
+ // src/helpers/optimizations.ts
59569
+ function calculateTheoreticalKelly({
59570
+ current_entry,
59571
+ zone_prices,
59572
+ kind = "long",
59573
+ config: config2 = {}
59574
+ }) {
59575
+ const {
59576
+ price_prediction_model = "uniform",
59577
+ confidence_factor = 0.6,
59578
+ volatility_adjustment = true
59579
+ } = config2;
59580
+ const sorted_prices = kind === "long" ? zone_prices : zone_prices.reverse();
59581
+ const current_index = sorted_prices.findIndex((price) => price === current_entry);
59582
+ if (current_index === -1)
59583
+ return 0.02;
59584
+ const win_zones = kind === "long" ? sorted_prices.slice(current_index + 1) : sorted_prices.slice(0, current_index);
59585
+ const lose_zones = kind === "long" ? sorted_prices.slice(0, current_index) : sorted_prices.slice(current_index + 1);
59586
+ const { win_probability, avg_win_ratio, avg_loss_ratio } = calculateZoneProbabilities({
59587
+ current_entry,
59588
+ win_zones,
59589
+ lose_zones,
59590
+ price_prediction_model,
59591
+ confidence_factor,
59592
+ kind
59593
+ });
59594
+ const odds_ratio = avg_win_ratio / avg_loss_ratio;
59595
+ const loss_probability = 1 - win_probability;
59596
+ let kelly_fraction = (win_probability * odds_ratio - loss_probability) / odds_ratio;
59597
+ if (volatility_adjustment) {
59598
+ const zone_volatility = calculateZoneVolatility(sorted_prices);
59599
+ const vol_adjustment = 1 / (1 + zone_volatility);
59600
+ kelly_fraction *= vol_adjustment;
59601
+ }
59602
+ kelly_fraction = Math.max(0.005, Math.min(kelly_fraction, 0.5));
59603
+ return to_f2(kelly_fraction, "%.4f");
59604
+ }
59605
+ function calculateZoneProbabilities({
59606
+ current_entry,
59607
+ win_zones,
59608
+ lose_zones,
59609
+ price_prediction_model,
59610
+ confidence_factor,
59611
+ kind
59612
+ }) {
59613
+ if (win_zones.length === 0 && lose_zones.length === 0) {
59614
+ return { win_probability: 0.5, avg_win_ratio: 0.02, avg_loss_ratio: 0.02 };
59615
+ }
59616
+ let win_probability;
59617
+ switch (price_prediction_model) {
59618
+ case "uniform":
59619
+ win_probability = win_zones.length / (win_zones.length + lose_zones.length);
59620
+ break;
59621
+ case "normal":
59622
+ const win_weight = win_zones.reduce((sum, _, idx) => sum + 1 / (idx + 1), 0);
59623
+ const lose_weight = lose_zones.reduce((sum, _, idx) => sum + 1 / (idx + 1), 0);
59624
+ win_probability = win_weight / (win_weight + lose_weight);
59625
+ break;
59626
+ case "exponential":
59627
+ const exp_win_weight = win_zones.reduce((sum, _, idx) => sum + Math.exp(-idx * 0.5), 0);
59628
+ const exp_lose_weight = lose_zones.reduce((sum, _, idx) => sum + Math.exp(-idx * 0.5), 0);
59629
+ win_probability = exp_win_weight / (exp_win_weight + exp_lose_weight);
59630
+ break;
59631
+ default:
59632
+ win_probability = 0.5;
59633
+ }
59634
+ win_probability = win_probability * confidence_factor + (1 - confidence_factor) * 0.5;
59635
+ const avg_win_ratio = win_zones.length > 0 ? win_zones.reduce((sum, price) => {
59636
+ return sum + Math.abs(price - current_entry) / current_entry;
59637
+ }, 0) / win_zones.length : 0.02;
59638
+ const avg_loss_ratio = lose_zones.length > 0 ? lose_zones.reduce((sum, price) => {
59639
+ return sum + Math.abs(price - current_entry) / current_entry;
59640
+ }, 0) / lose_zones.length : 0.02;
59641
+ return {
59642
+ win_probability: Math.max(0.1, Math.min(0.9, win_probability)),
59643
+ avg_win_ratio: Math.max(0.005, avg_win_ratio),
59644
+ avg_loss_ratio: Math.max(0.005, avg_loss_ratio)
59645
+ };
59646
+ }
59647
+ function calculateZoneVolatility(zone_prices) {
59648
+ if (zone_prices.length < 2)
59649
+ return 0;
59650
+ const price_changes = zone_prices.slice(1).map((price, i2) => Math.abs(price - zone_prices[i2]) / zone_prices[i2]);
59651
+ return price_changes.reduce((sum, change) => sum + change, 0) / price_changes.length;
59652
+ }
59653
+
59568
59654
  // src/helpers/trade_signal.ts
59569
59655
  function determine_close_price2({
59570
59656
  entry,
@@ -59647,6 +59733,10 @@ class Signal {
59647
59733
  first_order_size;
59648
59734
  gap = 10;
59649
59735
  max_size = 0;
59736
+ use_kelly = false;
59737
+ kelly_prediction_model = "exponential";
59738
+ kelly_confidence_factor = 0.6;
59739
+ kelly_minimum_risk = 0.2;
59650
59740
  constructor({
59651
59741
  focus,
59652
59742
  budget,
@@ -59667,7 +59757,11 @@ class Signal {
59667
59757
  minimum_size = 0,
59668
59758
  first_order_size = 0,
59669
59759
  gap = 10,
59670
- max_size = 0
59760
+ max_size = 0,
59761
+ use_kelly = false,
59762
+ kelly_prediction_model = "exponential",
59763
+ kelly_confidence_factor = 0.6,
59764
+ kelly_minimum_risk = 0.2
59671
59765
  }) {
59672
59766
  this.minimum_size = minimum_size;
59673
59767
  this.first_order_size = first_order_size;
@@ -59689,6 +59783,10 @@ class Signal {
59689
59783
  this.increase_position = increase_position;
59690
59784
  this.gap = gap;
59691
59785
  this.max_size = max_size;
59786
+ this.use_kelly = use_kelly;
59787
+ this.kelly_prediction_model = kelly_prediction_model;
59788
+ this.kelly_confidence_factor = kelly_confidence_factor;
59789
+ this.kelly_minimum_risk = kelly_minimum_risk;
59692
59790
  }
59693
59791
  build_entry({
59694
59792
  current_price,
@@ -60127,10 +60225,25 @@ class Signal {
60127
60225
  }
60128
60226
  const defaultStopLoss = i2 === 0 ? stop_loss : _base;
60129
60227
  const new_stop = kind === "long" ? this.support : stop_loss;
60228
+ let risk_to_use = risk_per_trade;
60229
+ if (this.use_kelly) {
60230
+ const theoretical_kelly = calculateTheoreticalKelly({
60231
+ current_entry: x,
60232
+ zone_prices: limit_orders,
60233
+ kind,
60234
+ config: {
60235
+ price_prediction_model: this.kelly_prediction_model,
60236
+ confidence_factor: this.kelly_confidence_factor,
60237
+ volatility_adjustment: true
60238
+ }
60239
+ });
60240
+ risk_to_use = theoretical_kelly * risk_per_trade / this.kelly_minimum_risk;
60241
+ console.log({ risk_per_trade, theoretical_kelly });
60242
+ }
60130
60243
  const y = this.build_trade_dict({
60131
60244
  entry: x,
60132
60245
  stop: (this.increase_position ? new_stop : defaultStopLoss) || defaultStopLoss,
60133
- risk: risk_per_trade,
60246
+ risk: risk_to_use,
60134
60247
  arr: limit_orders,
60135
60248
  index: i2,
60136
60249
  new_fees: total_incurred_market_fees,
@@ -60342,7 +60455,8 @@ function buildConfig(app_config, {
60342
60455
  kind: app_config.kind,
60343
60456
  gap,
60344
60457
  min_profit: min_profit || app_config.min_profit,
60345
- rr: rr || 1
60458
+ rr: rr || 1,
60459
+ use_kelly: app_config.use_kelly
60346
60460
  };
60347
60461
  const instance = new Signal(config2);
60348
60462
  if (raw_instance) {
@@ -60354,6 +60468,7 @@ function buildConfig(app_config, {
60354
60468
  const condition = (kind === "long" ? entry > app_config.support : entry >= app_config.support) && stop >= app_config.support * 0.999;
60355
60469
  if (kind === "short") {
60356
60470
  }
60471
+ console.log({ entry, stop, condition, working_risk, config: config2 });
60357
60472
  const result = entry === stop ? [] : condition ? instance.build_entry({
60358
60473
  current_price: entry,
60359
60474
  stop_loss: stop,
@@ -65611,15 +65726,25 @@ class ExchangeAccount {
65611
65726
  }
65612
65727
  }
65613
65728
  async increasePositionAtStop(payload) {
65614
- const { symbol, kind, place = false } = payload;
65729
+ const { symbol, kind, place = false, increase = true } = payload;
65615
65730
  const position2 = await this.syncAccount({
65616
65731
  symbol,
65617
65732
  kind,
65618
65733
  as_view: true
65619
65734
  });
65620
65735
  console.log(position2);
65621
- if (position2 && position2.stop_loss) {
65622
- const { price, quantity } = position2.stop_loss;
65736
+ let price_params = {
65737
+ price: payload.price,
65738
+ quantity: payload.quantity
65739
+ };
65740
+ if (!payload.price && position2 && position2.stop_loss) {
65741
+ price_params.price = position2.stop_loss.price;
65742
+ }
65743
+ if (!payload.quantity && position2 && position2.stop_loss) {
65744
+ price_params.quantity = position2.stop_loss.quantity;
65745
+ }
65746
+ if (price_params.price && price_params.quantity) {
65747
+ const { price, quantity } = price_params;
65623
65748
  const symbol_config = await this.recomputeSymbolConfig({
65624
65749
  symbol
65625
65750
  });
@@ -65639,7 +65764,7 @@ class ExchangeAccount {
65639
65764
  quantity,
65640
65765
  price_places,
65641
65766
  decimal_places,
65642
- increase: true,
65767
+ increase,
65643
65768
  place
65644
65769
  });
65645
65770
  }
@@ -59542,6 +59542,92 @@ function createGapPairs(arr, gap, item) {
59542
59542
  return result;
59543
59543
  }
59544
59544
 
59545
+ // src/helpers/optimizations.ts
59546
+ function calculateTheoreticalKelly({
59547
+ current_entry,
59548
+ zone_prices,
59549
+ kind = "long",
59550
+ config: config2 = {}
59551
+ }) {
59552
+ const {
59553
+ price_prediction_model = "uniform",
59554
+ confidence_factor = 0.6,
59555
+ volatility_adjustment = true
59556
+ } = config2;
59557
+ const sorted_prices = kind === "long" ? zone_prices : zone_prices.reverse();
59558
+ const current_index = sorted_prices.findIndex((price) => price === current_entry);
59559
+ if (current_index === -1)
59560
+ return 0.02;
59561
+ const win_zones = kind === "long" ? sorted_prices.slice(current_index + 1) : sorted_prices.slice(0, current_index);
59562
+ const lose_zones = kind === "long" ? sorted_prices.slice(0, current_index) : sorted_prices.slice(current_index + 1);
59563
+ const { win_probability, avg_win_ratio, avg_loss_ratio } = calculateZoneProbabilities({
59564
+ current_entry,
59565
+ win_zones,
59566
+ lose_zones,
59567
+ price_prediction_model,
59568
+ confidence_factor,
59569
+ kind
59570
+ });
59571
+ const odds_ratio = avg_win_ratio / avg_loss_ratio;
59572
+ const loss_probability = 1 - win_probability;
59573
+ let kelly_fraction = (win_probability * odds_ratio - loss_probability) / odds_ratio;
59574
+ if (volatility_adjustment) {
59575
+ const zone_volatility = calculateZoneVolatility(sorted_prices);
59576
+ const vol_adjustment = 1 / (1 + zone_volatility);
59577
+ kelly_fraction *= vol_adjustment;
59578
+ }
59579
+ kelly_fraction = Math.max(0.005, Math.min(kelly_fraction, 0.5));
59580
+ return to_f2(kelly_fraction, "%.4f");
59581
+ }
59582
+ function calculateZoneProbabilities({
59583
+ current_entry,
59584
+ win_zones,
59585
+ lose_zones,
59586
+ price_prediction_model,
59587
+ confidence_factor,
59588
+ kind
59589
+ }) {
59590
+ if (win_zones.length === 0 && lose_zones.length === 0) {
59591
+ return { win_probability: 0.5, avg_win_ratio: 0.02, avg_loss_ratio: 0.02 };
59592
+ }
59593
+ let win_probability;
59594
+ switch (price_prediction_model) {
59595
+ case "uniform":
59596
+ win_probability = win_zones.length / (win_zones.length + lose_zones.length);
59597
+ break;
59598
+ case "normal":
59599
+ const win_weight = win_zones.reduce((sum, _, idx) => sum + 1 / (idx + 1), 0);
59600
+ const lose_weight = lose_zones.reduce((sum, _, idx) => sum + 1 / (idx + 1), 0);
59601
+ win_probability = win_weight / (win_weight + lose_weight);
59602
+ break;
59603
+ case "exponential":
59604
+ const exp_win_weight = win_zones.reduce((sum, _, idx) => sum + Math.exp(-idx * 0.5), 0);
59605
+ const exp_lose_weight = lose_zones.reduce((sum, _, idx) => sum + Math.exp(-idx * 0.5), 0);
59606
+ win_probability = exp_win_weight / (exp_win_weight + exp_lose_weight);
59607
+ break;
59608
+ default:
59609
+ win_probability = 0.5;
59610
+ }
59611
+ win_probability = win_probability * confidence_factor + (1 - confidence_factor) * 0.5;
59612
+ const avg_win_ratio = win_zones.length > 0 ? win_zones.reduce((sum, price) => {
59613
+ return sum + Math.abs(price - current_entry) / current_entry;
59614
+ }, 0) / win_zones.length : 0.02;
59615
+ const avg_loss_ratio = lose_zones.length > 0 ? lose_zones.reduce((sum, price) => {
59616
+ return sum + Math.abs(price - current_entry) / current_entry;
59617
+ }, 0) / lose_zones.length : 0.02;
59618
+ return {
59619
+ win_probability: Math.max(0.1, Math.min(0.9, win_probability)),
59620
+ avg_win_ratio: Math.max(0.005, avg_win_ratio),
59621
+ avg_loss_ratio: Math.max(0.005, avg_loss_ratio)
59622
+ };
59623
+ }
59624
+ function calculateZoneVolatility(zone_prices) {
59625
+ if (zone_prices.length < 2)
59626
+ return 0;
59627
+ const price_changes = zone_prices.slice(1).map((price, i2) => Math.abs(price - zone_prices[i2]) / zone_prices[i2]);
59628
+ return price_changes.reduce((sum, change) => sum + change, 0) / price_changes.length;
59629
+ }
59630
+
59545
59631
  // src/helpers/trade_signal.ts
59546
59632
  function determine_close_price2({
59547
59633
  entry,
@@ -59624,6 +59710,10 @@ class Signal {
59624
59710
  first_order_size;
59625
59711
  gap = 10;
59626
59712
  max_size = 0;
59713
+ use_kelly = false;
59714
+ kelly_prediction_model = "exponential";
59715
+ kelly_confidence_factor = 0.6;
59716
+ kelly_minimum_risk = 0.2;
59627
59717
  constructor({
59628
59718
  focus,
59629
59719
  budget,
@@ -59644,7 +59734,11 @@ class Signal {
59644
59734
  minimum_size = 0,
59645
59735
  first_order_size = 0,
59646
59736
  gap = 10,
59647
- max_size = 0
59737
+ max_size = 0,
59738
+ use_kelly = false,
59739
+ kelly_prediction_model = "exponential",
59740
+ kelly_confidence_factor = 0.6,
59741
+ kelly_minimum_risk = 0.2
59648
59742
  }) {
59649
59743
  this.minimum_size = minimum_size;
59650
59744
  this.first_order_size = first_order_size;
@@ -59666,6 +59760,10 @@ class Signal {
59666
59760
  this.increase_position = increase_position;
59667
59761
  this.gap = gap;
59668
59762
  this.max_size = max_size;
59763
+ this.use_kelly = use_kelly;
59764
+ this.kelly_prediction_model = kelly_prediction_model;
59765
+ this.kelly_confidence_factor = kelly_confidence_factor;
59766
+ this.kelly_minimum_risk = kelly_minimum_risk;
59669
59767
  }
59670
59768
  build_entry({
59671
59769
  current_price,
@@ -60104,10 +60202,25 @@ class Signal {
60104
60202
  }
60105
60203
  const defaultStopLoss = i2 === 0 ? stop_loss : _base;
60106
60204
  const new_stop = kind === "long" ? this.support : stop_loss;
60205
+ let risk_to_use = risk_per_trade;
60206
+ if (this.use_kelly) {
60207
+ const theoretical_kelly = calculateTheoreticalKelly({
60208
+ current_entry: x,
60209
+ zone_prices: limit_orders,
60210
+ kind,
60211
+ config: {
60212
+ price_prediction_model: this.kelly_prediction_model,
60213
+ confidence_factor: this.kelly_confidence_factor,
60214
+ volatility_adjustment: true
60215
+ }
60216
+ });
60217
+ risk_to_use = theoretical_kelly * risk_per_trade / this.kelly_minimum_risk;
60218
+ console.log({ risk_per_trade, theoretical_kelly });
60219
+ }
60107
60220
  const y = this.build_trade_dict({
60108
60221
  entry: x,
60109
60222
  stop: (this.increase_position ? new_stop : defaultStopLoss) || defaultStopLoss,
60110
- risk: risk_per_trade,
60223
+ risk: risk_to_use,
60111
60224
  arr: limit_orders,
60112
60225
  index: i2,
60113
60226
  new_fees: total_incurred_market_fees,
@@ -60319,7 +60432,8 @@ function buildConfig(app_config, {
60319
60432
  kind: app_config.kind,
60320
60433
  gap,
60321
60434
  min_profit: min_profit || app_config.min_profit,
60322
- rr: rr || 1
60435
+ rr: rr || 1,
60436
+ use_kelly: app_config.use_kelly
60323
60437
  };
60324
60438
  const instance = new Signal(config2);
60325
60439
  if (raw_instance) {
@@ -60331,6 +60445,7 @@ function buildConfig(app_config, {
60331
60445
  const condition = (kind === "long" ? entry > app_config.support : entry >= app_config.support) && stop >= app_config.support * 0.999;
60332
60446
  if (kind === "short") {
60333
60447
  }
60448
+ console.log({ entry, stop, condition, working_risk, config: config2 });
60334
60449
  const result = entry === stop ? [] : condition ? instance.build_entry({
60335
60450
  current_price: entry,
60336
60451
  stop_loss: stop,
@@ -65588,15 +65703,25 @@ class ExchangeAccount {
65588
65703
  }
65589
65704
  }
65590
65705
  async increasePositionAtStop(payload) {
65591
- const { symbol, kind, place = false } = payload;
65706
+ const { symbol, kind, place = false, increase = true } = payload;
65592
65707
  const position2 = await this.syncAccount({
65593
65708
  symbol,
65594
65709
  kind,
65595
65710
  as_view: true
65596
65711
  });
65597
65712
  console.log(position2);
65598
- if (position2 && position2.stop_loss) {
65599
- const { price, quantity } = position2.stop_loss;
65713
+ let price_params = {
65714
+ price: payload.price,
65715
+ quantity: payload.quantity
65716
+ };
65717
+ if (!payload.price && position2 && position2.stop_loss) {
65718
+ price_params.price = position2.stop_loss.price;
65719
+ }
65720
+ if (!payload.quantity && position2 && position2.stop_loss) {
65721
+ price_params.quantity = position2.stop_loss.quantity;
65722
+ }
65723
+ if (price_params.price && price_params.quantity) {
65724
+ const { price, quantity } = price_params;
65600
65725
  const symbol_config = await this.recomputeSymbolConfig({
65601
65726
  symbol
65602
65727
  });
@@ -65616,7 +65741,7 @@ class ExchangeAccount {
65616
65741
  quantity,
65617
65742
  price_places,
65618
65743
  decimal_places,
65619
- increase: true,
65744
+ increase,
65620
65745
  place
65621
65746
  });
65622
65747
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gbozee/ultimate",
3
3
  "type": "module",
4
- "version": "0.0.2-144",
4
+ "version": "0.0.2-145",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",