@gbozee/ultimate 0.0.2-147 → 0.0.2-148

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.
@@ -143,6 +143,7 @@ export type SignalConfigType = {
143
143
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
144
144
  kelly_confidence_factor?: number;
145
145
  kelly_minimum_risk?: number;
146
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
146
147
  };
147
148
  declare class Signal {
148
149
  focus: number;
@@ -169,7 +170,8 @@ declare class Signal {
169
170
  kelly_prediction_model: "exponential" | "normal" | "uniform";
170
171
  kelly_confidence_factor: number;
171
172
  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);
173
+ kelly_func: "theoretical" | "position_based" | "theoretical_fixed";
174
+ 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, kelly_func, }: SignalConfigType);
173
175
  build_entry({ current_price, stop_loss, pnl, stop_percent, kind, risk, no_of_trades, take_profit, }: {
174
176
  take_profit?: number;
175
177
  no_of_trades?: number;
@@ -309,6 +311,7 @@ export type AppConfig = {
309
311
  kelly_confidence_factor?: number;
310
312
  kelly_minimum_risk?: number;
311
313
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
314
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
312
315
  };
313
316
  };
314
317
  export type ExtendConfigType = {
@@ -330,8 +333,9 @@ export type ExtendConfigType = {
330
333
  kelly_confidence_factor?: number;
331
334
  kelly_minimum_risk?: number;
332
335
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
336
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
333
337
  };
334
- export declare function buildConfig(app_config: AppConfig, { take_profit, entry, stop, raw_instance, risk, no_of_trades, min_profit, risk_reward, kind, increase, gap, rr, price_places, decimal_places, use_kelly, kelly_confidence_factor, kelly_minimum_risk, kelly_prediction_model, }: ExtendConfigType): any[] | Signal;
338
+ export declare function buildConfig(app_config: AppConfig, { take_profit, entry, stop, raw_instance, risk, no_of_trades, min_profit, risk_reward, kind, increase, gap, rr, price_places, decimal_places, use_kelly, kelly_confidence_factor, kelly_minimum_risk, kelly_prediction_model, kelly_func, }: ExtendConfigType): any[] | Signal;
335
339
  export declare function buildAvg({ _trades, kind, }: {
336
340
  _trades: any[];
337
341
  kind: "long" | "short";
@@ -345,6 +349,7 @@ export declare function get_app_config_and_max_size(config: GlobalConfig, payloa
345
349
  kelly_confidence_factor?: number;
346
350
  kelly_minimum_risk?: number;
347
351
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
352
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
348
353
  }): {
349
354
  app_config: AppConfig;
350
355
  max_size: any;
@@ -368,6 +373,7 @@ export declare function buildAppConfig(config: GlobalConfig, payload: {
368
373
  kelly_confidence_factor?: number;
369
374
  kelly_minimum_risk?: number;
370
375
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
376
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
371
377
  }): AppConfig;
372
378
  export declare function getOptimumStopAndRisk(app_config: AppConfig, params: {
373
379
  max_size: number;
@@ -845,6 +851,7 @@ export declare class Strategy {
845
851
  kelly_confidence_factor?: number;
846
852
  kelly_minimum_risk?: number;
847
853
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
854
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
848
855
  };
849
856
  };
850
857
  identifyGapConfig(payload: {
@@ -83,6 +83,101 @@ function calculateZoneVolatility(zone_prices) {
83
83
  const price_changes = zone_prices.slice(1).map((price, i) => Math.abs(price - zone_prices[i]) / zone_prices[i]);
84
84
  return price_changes.reduce((sum, change) => sum + change, 0) / price_changes.length;
85
85
  }
86
+ function calculateTheoreticalKellyFixed({
87
+ current_entry,
88
+ zone_prices,
89
+ kind = "long",
90
+ config = {}
91
+ }) {
92
+ const {
93
+ price_prediction_model = "uniform",
94
+ confidence_factor = 0.6,
95
+ volatility_adjustment = true
96
+ } = config;
97
+ const sorted_prices = zone_prices;
98
+ const current_index = sorted_prices.findIndex((price) => price === current_entry);
99
+ if (current_index === -1)
100
+ return 0.02;
101
+ let stop_loss;
102
+ let target_zones;
103
+ if (kind === "long") {
104
+ stop_loss = Math.min(...zone_prices);
105
+ target_zones = zone_prices.filter((price) => price > current_entry);
106
+ } else {
107
+ stop_loss = Math.max(...zone_prices);
108
+ target_zones = zone_prices.filter((price) => price < current_entry);
109
+ }
110
+ const risk_amount = Math.abs(current_entry - stop_loss);
111
+ const avg_reward = target_zones.length > 0 ? target_zones.reduce((sum, price) => sum + Math.abs(price - current_entry), 0) / target_zones.length : risk_amount;
112
+ const risk_reward_ratio = avg_reward / risk_amount;
113
+ let position_quality;
114
+ if (kind === "long") {
115
+ const distance_from_stop = current_entry - stop_loss;
116
+ const max_distance = Math.max(...zone_prices) - stop_loss;
117
+ position_quality = 1 - distance_from_stop / max_distance;
118
+ } else {
119
+ const distance_from_stop = stop_loss - current_entry;
120
+ const max_distance = stop_loss - Math.min(...zone_prices);
121
+ position_quality = 1 - distance_from_stop / max_distance;
122
+ }
123
+ let base_probability = 0.5;
124
+ switch (price_prediction_model) {
125
+ case "uniform":
126
+ base_probability = 0.5;
127
+ break;
128
+ case "normal":
129
+ base_probability = 0.3 + position_quality * 0.4;
130
+ break;
131
+ case "exponential":
132
+ base_probability = 0.2 + Math.pow(position_quality, 0.5) * 0.6;
133
+ break;
134
+ }
135
+ const win_probability = base_probability * confidence_factor + (1 - confidence_factor) * 0.5;
136
+ const odds_ratio = Math.max(risk_reward_ratio, 0.5);
137
+ const loss_probability = 1 - win_probability;
138
+ let kelly_fraction = (win_probability * odds_ratio - loss_probability) / odds_ratio;
139
+ if (volatility_adjustment) {
140
+ const zone_volatility = calculateZoneVolatility(sorted_prices);
141
+ const vol_adjustment = 1 / (1 + zone_volatility);
142
+ kelly_fraction *= vol_adjustment;
143
+ }
144
+ kelly_fraction = Math.max(0.005, Math.min(kelly_fraction, 0.5));
145
+ return to_f(kelly_fraction, "%.4f");
146
+ }
147
+ function calculatePositionBasedKelly({
148
+ current_entry,
149
+ zone_prices,
150
+ kind = "long",
151
+ config = {}
152
+ }) {
153
+ const {
154
+ price_prediction_model = "uniform",
155
+ confidence_factor: _confidence_factor = 0.6
156
+ } = config;
157
+ const current_index = zone_prices.findIndex((price) => price === current_entry);
158
+ if (current_index === -1)
159
+ return 0.02;
160
+ const total_zones = zone_prices.length;
161
+ const position_score = (total_zones - current_index) / total_zones;
162
+ let adjusted_score;
163
+ switch (price_prediction_model) {
164
+ case "uniform":
165
+ adjusted_score = 0.5;
166
+ break;
167
+ case "normal":
168
+ adjusted_score = 0.3 + position_score * 0.4;
169
+ break;
170
+ case "exponential":
171
+ adjusted_score = 0.2 + Math.pow(position_score, 0.3) * 0.6;
172
+ break;
173
+ default:
174
+ adjusted_score = 0.5;
175
+ }
176
+ const base_kelly = 0.02;
177
+ const max_kelly = 0.2;
178
+ const kelly_fraction = base_kelly + adjusted_score * (max_kelly - base_kelly);
179
+ return to_f(kelly_fraction, "%.4f");
180
+ }
86
181
 
87
182
  // src/helpers/trade_signal.ts
88
183
  function determine_close_price({
@@ -170,6 +265,7 @@ class Signal {
170
265
  kelly_prediction_model = "exponential";
171
266
  kelly_confidence_factor = 0.6;
172
267
  kelly_minimum_risk = 0.2;
268
+ kelly_func = "theoretical";
173
269
  constructor({
174
270
  focus,
175
271
  budget,
@@ -194,7 +290,8 @@ class Signal {
194
290
  use_kelly = false,
195
291
  kelly_prediction_model = "exponential",
196
292
  kelly_confidence_factor = 0.6,
197
- kelly_minimum_risk = 0.2
293
+ kelly_minimum_risk = 0.2,
294
+ kelly_func = "theoretical"
198
295
  }) {
199
296
  this.minimum_size = minimum_size;
200
297
  this.first_order_size = first_order_size;
@@ -220,6 +317,7 @@ class Signal {
220
317
  this.kelly_prediction_model = kelly_prediction_model;
221
318
  this.kelly_confidence_factor = kelly_confidence_factor;
222
319
  this.kelly_minimum_risk = kelly_minimum_risk;
320
+ this.kelly_func = kelly_func;
223
321
  }
224
322
  build_entry({
225
323
  current_price,
@@ -660,7 +758,8 @@ class Signal {
660
758
  const new_stop = kind === "long" ? this.support : stop_loss;
661
759
  let risk_to_use = risk_per_trade;
662
760
  if (this.use_kelly) {
663
- const theoretical_kelly = calculateTheoreticalKelly({
761
+ const func = this.kelly_func === "theoretical" ? calculateTheoreticalKelly : this.kelly_func === "position_based" ? calculatePositionBasedKelly : calculateTheoreticalKellyFixed;
762
+ const theoretical_kelly = func({
664
763
  current_entry: x,
665
764
  zone_prices: limit_orders,
666
765
  kind,
@@ -1342,7 +1441,8 @@ function buildConfig(app_config, {
1342
1441
  use_kelly = false,
1343
1442
  kelly_confidence_factor = 0.95,
1344
1443
  kelly_minimum_risk = 0.2,
1345
- kelly_prediction_model = "exponential"
1444
+ kelly_prediction_model = "exponential",
1445
+ kelly_func = "theoretical"
1346
1446
  }) {
1347
1447
  let fee = app_config.fee / 100;
1348
1448
  let working_risk = risk || app_config.risk_per_trade;
@@ -1370,7 +1470,8 @@ function buildConfig(app_config, {
1370
1470
  use_kelly: use_kelly || app_config.kelly?.use_kelly,
1371
1471
  kelly_confidence_factor: kelly_confidence_factor || app_config.kelly?.kelly_confidence_factor,
1372
1472
  kelly_minimum_risk: kelly_minimum_risk || app_config.kelly?.kelly_minimum_risk,
1373
- kelly_prediction_model: kelly_prediction_model || app_config.kelly?.kelly_prediction_model
1473
+ kelly_prediction_model: kelly_prediction_model || app_config.kelly?.kelly_prediction_model,
1474
+ kelly_func: kelly_func || app_config.kelly?.kelly_func
1374
1475
  };
1375
1476
  const instance = new Signal(config);
1376
1477
  if (raw_instance) {
@@ -1453,7 +1554,8 @@ function get_app_config_and_max_size(config, payload) {
1453
1554
  use_kelly: payload.use_kelly,
1454
1555
  kelly_confidence_factor: payload.kelly_confidence_factor,
1455
1556
  kelly_minimum_risk: payload.kelly_minimum_risk,
1456
- kelly_prediction_model: payload.kelly_prediction_model
1557
+ kelly_prediction_model: payload.kelly_prediction_model,
1558
+ kelly_func: payload.kelly_func
1457
1559
  });
1458
1560
  const max_size = initialResult[0]?.avg_size;
1459
1561
  const last_value = initialResult[0];
@@ -1490,7 +1592,8 @@ function buildAppConfig(config, payload) {
1490
1592
  use_kelly: payload.use_kelly,
1491
1593
  kelly_confidence_factor: payload.kelly_confidence_factor,
1492
1594
  kelly_minimum_risk: payload.kelly_minimum_risk,
1493
- kelly_prediction_model: payload.kelly_prediction_model
1595
+ kelly_prediction_model: payload.kelly_prediction_model,
1596
+ kelly_func: payload.kelly_func
1494
1597
  });
1495
1598
  app_config.max_size = max_size;
1496
1599
  app_config.entry = payload.entry || app_config.entry;
@@ -1501,7 +1604,8 @@ function buildAppConfig(config, payload) {
1501
1604
  use_kelly: payload.use_kelly,
1502
1605
  kelly_confidence_factor: payload.kelly_confidence_factor,
1503
1606
  kelly_minimum_risk: payload.kelly_minimum_risk,
1504
- kelly_prediction_model: payload.kelly_prediction_model
1607
+ kelly_prediction_model: payload.kelly_prediction_model,
1608
+ kelly_func: payload.kelly_func
1505
1609
  };
1506
1610
  return app_config;
1507
1611
  }
package/dist/index.cjs CHANGED
@@ -52955,6 +52955,101 @@ function calculateZoneVolatility(zone_prices) {
52955
52955
  const price_changes = zone_prices.slice(1).map((price, i2) => Math.abs(price - zone_prices[i2]) / zone_prices[i2]);
52956
52956
  return price_changes.reduce((sum, change) => sum + change, 0) / price_changes.length;
52957
52957
  }
52958
+ function calculateTheoreticalKellyFixed({
52959
+ current_entry,
52960
+ zone_prices,
52961
+ kind = "long",
52962
+ config: config2 = {}
52963
+ }) {
52964
+ const {
52965
+ price_prediction_model = "uniform",
52966
+ confidence_factor = 0.6,
52967
+ volatility_adjustment = true
52968
+ } = config2;
52969
+ const sorted_prices = zone_prices;
52970
+ const current_index = sorted_prices.findIndex((price) => price === current_entry);
52971
+ if (current_index === -1)
52972
+ return 0.02;
52973
+ let stop_loss;
52974
+ let target_zones;
52975
+ if (kind === "long") {
52976
+ stop_loss = Math.min(...zone_prices);
52977
+ target_zones = zone_prices.filter((price) => price > current_entry);
52978
+ } else {
52979
+ stop_loss = Math.max(...zone_prices);
52980
+ target_zones = zone_prices.filter((price) => price < current_entry);
52981
+ }
52982
+ const risk_amount = Math.abs(current_entry - stop_loss);
52983
+ const avg_reward = target_zones.length > 0 ? target_zones.reduce((sum, price) => sum + Math.abs(price - current_entry), 0) / target_zones.length : risk_amount;
52984
+ const risk_reward_ratio = avg_reward / risk_amount;
52985
+ let position_quality;
52986
+ if (kind === "long") {
52987
+ const distance_from_stop = current_entry - stop_loss;
52988
+ const max_distance = Math.max(...zone_prices) - stop_loss;
52989
+ position_quality = 1 - distance_from_stop / max_distance;
52990
+ } else {
52991
+ const distance_from_stop = stop_loss - current_entry;
52992
+ const max_distance = stop_loss - Math.min(...zone_prices);
52993
+ position_quality = 1 - distance_from_stop / max_distance;
52994
+ }
52995
+ let base_probability = 0.5;
52996
+ switch (price_prediction_model) {
52997
+ case "uniform":
52998
+ base_probability = 0.5;
52999
+ break;
53000
+ case "normal":
53001
+ base_probability = 0.3 + position_quality * 0.4;
53002
+ break;
53003
+ case "exponential":
53004
+ base_probability = 0.2 + Math.pow(position_quality, 0.5) * 0.6;
53005
+ break;
53006
+ }
53007
+ const win_probability = base_probability * confidence_factor + (1 - confidence_factor) * 0.5;
53008
+ const odds_ratio = Math.max(risk_reward_ratio, 0.5);
53009
+ const loss_probability = 1 - win_probability;
53010
+ let kelly_fraction = (win_probability * odds_ratio - loss_probability) / odds_ratio;
53011
+ if (volatility_adjustment) {
53012
+ const zone_volatility = calculateZoneVolatility(sorted_prices);
53013
+ const vol_adjustment = 1 / (1 + zone_volatility);
53014
+ kelly_fraction *= vol_adjustment;
53015
+ }
53016
+ kelly_fraction = Math.max(0.005, Math.min(kelly_fraction, 0.5));
53017
+ return to_f2(kelly_fraction, "%.4f");
53018
+ }
53019
+ function calculatePositionBasedKelly({
53020
+ current_entry,
53021
+ zone_prices,
53022
+ kind = "long",
53023
+ config: config2 = {}
53024
+ }) {
53025
+ const {
53026
+ price_prediction_model = "uniform",
53027
+ confidence_factor: _confidence_factor = 0.6
53028
+ } = config2;
53029
+ const current_index = zone_prices.findIndex((price) => price === current_entry);
53030
+ if (current_index === -1)
53031
+ return 0.02;
53032
+ const total_zones = zone_prices.length;
53033
+ const position_score = (total_zones - current_index) / total_zones;
53034
+ let adjusted_score;
53035
+ switch (price_prediction_model) {
53036
+ case "uniform":
53037
+ adjusted_score = 0.5;
53038
+ break;
53039
+ case "normal":
53040
+ adjusted_score = 0.3 + position_score * 0.4;
53041
+ break;
53042
+ case "exponential":
53043
+ adjusted_score = 0.2 + Math.pow(position_score, 0.3) * 0.6;
53044
+ break;
53045
+ default:
53046
+ adjusted_score = 0.5;
53047
+ }
53048
+ const base_kelly = 0.02;
53049
+ const max_kelly = 0.2;
53050
+ const kelly_fraction = base_kelly + adjusted_score * (max_kelly - base_kelly);
53051
+ return to_f2(kelly_fraction, "%.4f");
53052
+ }
52958
53053
 
52959
53054
  // src/helpers/trade_signal.ts
52960
53055
  function determine_close_price2({
@@ -53042,6 +53137,7 @@ class Signal {
53042
53137
  kelly_prediction_model = "exponential";
53043
53138
  kelly_confidence_factor = 0.6;
53044
53139
  kelly_minimum_risk = 0.2;
53140
+ kelly_func = "theoretical";
53045
53141
  constructor({
53046
53142
  focus,
53047
53143
  budget,
@@ -53066,7 +53162,8 @@ class Signal {
53066
53162
  use_kelly = false,
53067
53163
  kelly_prediction_model = "exponential",
53068
53164
  kelly_confidence_factor = 0.6,
53069
- kelly_minimum_risk = 0.2
53165
+ kelly_minimum_risk = 0.2,
53166
+ kelly_func = "theoretical"
53070
53167
  }) {
53071
53168
  this.minimum_size = minimum_size;
53072
53169
  this.first_order_size = first_order_size;
@@ -53092,6 +53189,7 @@ class Signal {
53092
53189
  this.kelly_prediction_model = kelly_prediction_model;
53093
53190
  this.kelly_confidence_factor = kelly_confidence_factor;
53094
53191
  this.kelly_minimum_risk = kelly_minimum_risk;
53192
+ this.kelly_func = kelly_func;
53095
53193
  }
53096
53194
  build_entry({
53097
53195
  current_price,
@@ -53532,7 +53630,8 @@ class Signal {
53532
53630
  const new_stop = kind === "long" ? this.support : stop_loss;
53533
53631
  let risk_to_use = risk_per_trade;
53534
53632
  if (this.use_kelly) {
53535
- const theoretical_kelly = calculateTheoreticalKelly({
53633
+ const func = this.kelly_func === "theoretical" ? calculateTheoreticalKelly : this.kelly_func === "position_based" ? calculatePositionBasedKelly : calculateTheoreticalKellyFixed;
53634
+ const theoretical_kelly = func({
53536
53635
  current_entry: x,
53537
53636
  zone_prices: limit_orders,
53538
53637
  kind,
@@ -53740,7 +53839,8 @@ function buildConfig(app_config, {
53740
53839
  use_kelly = false,
53741
53840
  kelly_confidence_factor = 0.95,
53742
53841
  kelly_minimum_risk = 0.2,
53743
- kelly_prediction_model = "exponential"
53842
+ kelly_prediction_model = "exponential",
53843
+ kelly_func = "theoretical"
53744
53844
  }) {
53745
53845
  let fee = app_config.fee / 100;
53746
53846
  let working_risk = risk || app_config.risk_per_trade;
@@ -53768,7 +53868,8 @@ function buildConfig(app_config, {
53768
53868
  use_kelly: use_kelly || app_config.kelly?.use_kelly,
53769
53869
  kelly_confidence_factor: kelly_confidence_factor || app_config.kelly?.kelly_confidence_factor,
53770
53870
  kelly_minimum_risk: kelly_minimum_risk || app_config.kelly?.kelly_minimum_risk,
53771
- kelly_prediction_model: kelly_prediction_model || app_config.kelly?.kelly_prediction_model
53871
+ kelly_prediction_model: kelly_prediction_model || app_config.kelly?.kelly_prediction_model,
53872
+ kelly_func: kelly_func || app_config.kelly?.kelly_func
53772
53873
  };
53773
53874
  const instance = new Signal(config2);
53774
53875
  if (raw_instance) {
@@ -53851,7 +53952,8 @@ function get_app_config_and_max_size(config2, payload) {
53851
53952
  use_kelly: payload.use_kelly,
53852
53953
  kelly_confidence_factor: payload.kelly_confidence_factor,
53853
53954
  kelly_minimum_risk: payload.kelly_minimum_risk,
53854
- kelly_prediction_model: payload.kelly_prediction_model
53955
+ kelly_prediction_model: payload.kelly_prediction_model,
53956
+ kelly_func: payload.kelly_func
53855
53957
  });
53856
53958
  const max_size = initialResult[0]?.avg_size;
53857
53959
  const last_value = initialResult[0];
@@ -53888,7 +53990,8 @@ function buildAppConfig(config2, payload) {
53888
53990
  use_kelly: payload.use_kelly,
53889
53991
  kelly_confidence_factor: payload.kelly_confidence_factor,
53890
53992
  kelly_minimum_risk: payload.kelly_minimum_risk,
53891
- kelly_prediction_model: payload.kelly_prediction_model
53993
+ kelly_prediction_model: payload.kelly_prediction_model,
53994
+ kelly_func: payload.kelly_func
53892
53995
  });
53893
53996
  app_config.max_size = max_size;
53894
53997
  app_config.entry = payload.entry || app_config.entry;
@@ -53899,7 +54002,8 @@ function buildAppConfig(config2, payload) {
53899
54002
  use_kelly: payload.use_kelly,
53900
54003
  kelly_confidence_factor: payload.kelly_confidence_factor,
53901
54004
  kelly_minimum_risk: payload.kelly_minimum_risk,
53902
- kelly_prediction_model: payload.kelly_prediction_model
54005
+ kelly_prediction_model: payload.kelly_prediction_model,
54006
+ kelly_func: payload.kelly_func
53903
54007
  };
53904
54008
  return app_config;
53905
54009
  }
@@ -58286,6 +58390,7 @@ class ExchangeAccount {
58286
58390
  kelly_confidence_factor: config2.kelly?.kelly_confidence_factor,
58287
58391
  kelly_minimum_risk: config2.kelly?.kelly_minimum_risk,
58288
58392
  kelly_prediction_model: config2.kelly?.kelly_prediction_model,
58393
+ kelly_func: config2.kelly?.kelly_func,
58289
58394
  ...override
58290
58395
  });
58291
58396
  return app_config;
package/dist/index.d.ts CHANGED
@@ -1027,6 +1027,7 @@ export declare class Strategy {
1027
1027
  kelly_confidence_factor?: number;
1028
1028
  kelly_minimum_risk?: number;
1029
1029
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
1030
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
1030
1031
  };
1031
1032
  };
1032
1033
  identifyGapConfig(payload: {
@@ -1145,6 +1146,7 @@ export type SignalConfigType = {
1145
1146
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
1146
1147
  kelly_confidence_factor?: number;
1147
1148
  kelly_minimum_risk?: number;
1149
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
1148
1150
  };
1149
1151
  declare class Signal {
1150
1152
  focus: number;
@@ -1171,7 +1173,8 @@ declare class Signal {
1171
1173
  kelly_prediction_model: "exponential" | "normal" | "uniform";
1172
1174
  kelly_confidence_factor: number;
1173
1175
  kelly_minimum_risk: number;
1174
- 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);
1176
+ kelly_func: "theoretical" | "position_based" | "theoretical_fixed";
1177
+ 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, kelly_func, }: SignalConfigType);
1175
1178
  build_entry({ current_price, stop_loss, pnl, stop_percent, kind, risk, no_of_trades, take_profit, }: {
1176
1179
  take_profit?: number;
1177
1180
  no_of_trades?: number;
@@ -1299,6 +1302,7 @@ export type AppConfig = {
1299
1302
  kelly_confidence_factor?: number;
1300
1303
  kelly_minimum_risk?: number;
1301
1304
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
1305
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
1302
1306
  };
1303
1307
  };
1304
1308
  export type ExtendConfigType = {
@@ -1320,8 +1324,9 @@ export type ExtendConfigType = {
1320
1324
  kelly_confidence_factor?: number;
1321
1325
  kelly_minimum_risk?: number;
1322
1326
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
1327
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
1323
1328
  };
1324
- export declare function buildConfig(app_config: AppConfig, { take_profit, entry, stop, raw_instance, risk, no_of_trades, min_profit, risk_reward, kind, increase, gap, rr, price_places, decimal_places, use_kelly, kelly_confidence_factor, kelly_minimum_risk, kelly_prediction_model, }: ExtendConfigType): any[] | Signal;
1329
+ export declare function buildConfig(app_config: AppConfig, { take_profit, entry, stop, raw_instance, risk, no_of_trades, min_profit, risk_reward, kind, increase, gap, rr, price_places, decimal_places, use_kelly, kelly_confidence_factor, kelly_minimum_risk, kelly_prediction_model, kelly_func, }: ExtendConfigType): any[] | Signal;
1325
1330
  export declare function buildAvg({ _trades, kind, }: {
1326
1331
  _trades: any[];
1327
1332
  kind: "long" | "short";
@@ -1335,6 +1340,7 @@ export declare function get_app_config_and_max_size(config: GlobalConfig, payloa
1335
1340
  kelly_confidence_factor?: number;
1336
1341
  kelly_minimum_risk?: number;
1337
1342
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
1343
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
1338
1344
  }): {
1339
1345
  app_config: AppConfig;
1340
1346
  max_size: any;
@@ -1358,6 +1364,7 @@ export declare function buildAppConfig(config: GlobalConfig, payload: {
1358
1364
  kelly_confidence_factor?: number;
1359
1365
  kelly_minimum_risk?: number;
1360
1366
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
1367
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
1361
1368
  }): AppConfig;
1362
1369
  export declare function getOptimumStopAndRisk(app_config: AppConfig, params: {
1363
1370
  max_size: number;
@@ -1896,6 +1903,7 @@ declare class ExchangeAccount$1 {
1896
1903
  kelly_confidence_factor?: number;
1897
1904
  kelly_minimum_risk?: number;
1898
1905
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
1906
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
1899
1907
  }): Promise<AppConfig>;
1900
1908
  tradeConfig(payload: {
1901
1909
  symbol: string;
@@ -2249,6 +2257,7 @@ declare class ExchangeAccount$1 {
2249
2257
  kelly_confidence_factor?: number;
2250
2258
  kelly_minimum_risk?: number;
2251
2259
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
2260
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
2252
2261
  };
2253
2262
  }>;
2254
2263
  runSimulation(payload: {
@@ -2435,6 +2444,7 @@ declare class ExchangeAccount$1 {
2435
2444
  kelly_confidence_factor?: number;
2436
2445
  kelly_minimum_risk?: number;
2437
2446
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
2447
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
2438
2448
  };
2439
2449
  };
2440
2450
  last_value: any;
@@ -2708,6 +2718,7 @@ declare class App {
2708
2718
  kelly_confidence_factor?: number;
2709
2719
  kelly_minimum_risk?: number;
2710
2720
  kelly_prediction_model?: "exponential" | "normal" | "uniform";
2721
+ kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
2711
2722
  };
2712
2723
  };
2713
2724
  last_value: any;
package/dist/index.js CHANGED
@@ -52903,6 +52903,101 @@ function calculateZoneVolatility(zone_prices) {
52903
52903
  const price_changes = zone_prices.slice(1).map((price, i2) => Math.abs(price - zone_prices[i2]) / zone_prices[i2]);
52904
52904
  return price_changes.reduce((sum, change) => sum + change, 0) / price_changes.length;
52905
52905
  }
52906
+ function calculateTheoreticalKellyFixed({
52907
+ current_entry,
52908
+ zone_prices,
52909
+ kind = "long",
52910
+ config: config2 = {}
52911
+ }) {
52912
+ const {
52913
+ price_prediction_model = "uniform",
52914
+ confidence_factor = 0.6,
52915
+ volatility_adjustment = true
52916
+ } = config2;
52917
+ const sorted_prices = zone_prices;
52918
+ const current_index = sorted_prices.findIndex((price) => price === current_entry);
52919
+ if (current_index === -1)
52920
+ return 0.02;
52921
+ let stop_loss;
52922
+ let target_zones;
52923
+ if (kind === "long") {
52924
+ stop_loss = Math.min(...zone_prices);
52925
+ target_zones = zone_prices.filter((price) => price > current_entry);
52926
+ } else {
52927
+ stop_loss = Math.max(...zone_prices);
52928
+ target_zones = zone_prices.filter((price) => price < current_entry);
52929
+ }
52930
+ const risk_amount = Math.abs(current_entry - stop_loss);
52931
+ const avg_reward = target_zones.length > 0 ? target_zones.reduce((sum, price) => sum + Math.abs(price - current_entry), 0) / target_zones.length : risk_amount;
52932
+ const risk_reward_ratio = avg_reward / risk_amount;
52933
+ let position_quality;
52934
+ if (kind === "long") {
52935
+ const distance_from_stop = current_entry - stop_loss;
52936
+ const max_distance = Math.max(...zone_prices) - stop_loss;
52937
+ position_quality = 1 - distance_from_stop / max_distance;
52938
+ } else {
52939
+ const distance_from_stop = stop_loss - current_entry;
52940
+ const max_distance = stop_loss - Math.min(...zone_prices);
52941
+ position_quality = 1 - distance_from_stop / max_distance;
52942
+ }
52943
+ let base_probability = 0.5;
52944
+ switch (price_prediction_model) {
52945
+ case "uniform":
52946
+ base_probability = 0.5;
52947
+ break;
52948
+ case "normal":
52949
+ base_probability = 0.3 + position_quality * 0.4;
52950
+ break;
52951
+ case "exponential":
52952
+ base_probability = 0.2 + Math.pow(position_quality, 0.5) * 0.6;
52953
+ break;
52954
+ }
52955
+ const win_probability = base_probability * confidence_factor + (1 - confidence_factor) * 0.5;
52956
+ const odds_ratio = Math.max(risk_reward_ratio, 0.5);
52957
+ const loss_probability = 1 - win_probability;
52958
+ let kelly_fraction = (win_probability * odds_ratio - loss_probability) / odds_ratio;
52959
+ if (volatility_adjustment) {
52960
+ const zone_volatility = calculateZoneVolatility(sorted_prices);
52961
+ const vol_adjustment = 1 / (1 + zone_volatility);
52962
+ kelly_fraction *= vol_adjustment;
52963
+ }
52964
+ kelly_fraction = Math.max(0.005, Math.min(kelly_fraction, 0.5));
52965
+ return to_f2(kelly_fraction, "%.4f");
52966
+ }
52967
+ function calculatePositionBasedKelly({
52968
+ current_entry,
52969
+ zone_prices,
52970
+ kind = "long",
52971
+ config: config2 = {}
52972
+ }) {
52973
+ const {
52974
+ price_prediction_model = "uniform",
52975
+ confidence_factor: _confidence_factor = 0.6
52976
+ } = config2;
52977
+ const current_index = zone_prices.findIndex((price) => price === current_entry);
52978
+ if (current_index === -1)
52979
+ return 0.02;
52980
+ const total_zones = zone_prices.length;
52981
+ const position_score = (total_zones - current_index) / total_zones;
52982
+ let adjusted_score;
52983
+ switch (price_prediction_model) {
52984
+ case "uniform":
52985
+ adjusted_score = 0.5;
52986
+ break;
52987
+ case "normal":
52988
+ adjusted_score = 0.3 + position_score * 0.4;
52989
+ break;
52990
+ case "exponential":
52991
+ adjusted_score = 0.2 + Math.pow(position_score, 0.3) * 0.6;
52992
+ break;
52993
+ default:
52994
+ adjusted_score = 0.5;
52995
+ }
52996
+ const base_kelly = 0.02;
52997
+ const max_kelly = 0.2;
52998
+ const kelly_fraction = base_kelly + adjusted_score * (max_kelly - base_kelly);
52999
+ return to_f2(kelly_fraction, "%.4f");
53000
+ }
52906
53001
 
52907
53002
  // src/helpers/trade_signal.ts
52908
53003
  function determine_close_price2({
@@ -52990,6 +53085,7 @@ class Signal {
52990
53085
  kelly_prediction_model = "exponential";
52991
53086
  kelly_confidence_factor = 0.6;
52992
53087
  kelly_minimum_risk = 0.2;
53088
+ kelly_func = "theoretical";
52993
53089
  constructor({
52994
53090
  focus,
52995
53091
  budget,
@@ -53014,7 +53110,8 @@ class Signal {
53014
53110
  use_kelly = false,
53015
53111
  kelly_prediction_model = "exponential",
53016
53112
  kelly_confidence_factor = 0.6,
53017
- kelly_minimum_risk = 0.2
53113
+ kelly_minimum_risk = 0.2,
53114
+ kelly_func = "theoretical"
53018
53115
  }) {
53019
53116
  this.minimum_size = minimum_size;
53020
53117
  this.first_order_size = first_order_size;
@@ -53040,6 +53137,7 @@ class Signal {
53040
53137
  this.kelly_prediction_model = kelly_prediction_model;
53041
53138
  this.kelly_confidence_factor = kelly_confidence_factor;
53042
53139
  this.kelly_minimum_risk = kelly_minimum_risk;
53140
+ this.kelly_func = kelly_func;
53043
53141
  }
53044
53142
  build_entry({
53045
53143
  current_price,
@@ -53480,7 +53578,8 @@ class Signal {
53480
53578
  const new_stop = kind === "long" ? this.support : stop_loss;
53481
53579
  let risk_to_use = risk_per_trade;
53482
53580
  if (this.use_kelly) {
53483
- const theoretical_kelly = calculateTheoreticalKelly({
53581
+ const func = this.kelly_func === "theoretical" ? calculateTheoreticalKelly : this.kelly_func === "position_based" ? calculatePositionBasedKelly : calculateTheoreticalKellyFixed;
53582
+ const theoretical_kelly = func({
53484
53583
  current_entry: x,
53485
53584
  zone_prices: limit_orders,
53486
53585
  kind,
@@ -53688,7 +53787,8 @@ function buildConfig(app_config, {
53688
53787
  use_kelly = false,
53689
53788
  kelly_confidence_factor = 0.95,
53690
53789
  kelly_minimum_risk = 0.2,
53691
- kelly_prediction_model = "exponential"
53790
+ kelly_prediction_model = "exponential",
53791
+ kelly_func = "theoretical"
53692
53792
  }) {
53693
53793
  let fee = app_config.fee / 100;
53694
53794
  let working_risk = risk || app_config.risk_per_trade;
@@ -53716,7 +53816,8 @@ function buildConfig(app_config, {
53716
53816
  use_kelly: use_kelly || app_config.kelly?.use_kelly,
53717
53817
  kelly_confidence_factor: kelly_confidence_factor || app_config.kelly?.kelly_confidence_factor,
53718
53818
  kelly_minimum_risk: kelly_minimum_risk || app_config.kelly?.kelly_minimum_risk,
53719
- kelly_prediction_model: kelly_prediction_model || app_config.kelly?.kelly_prediction_model
53819
+ kelly_prediction_model: kelly_prediction_model || app_config.kelly?.kelly_prediction_model,
53820
+ kelly_func: kelly_func || app_config.kelly?.kelly_func
53720
53821
  };
53721
53822
  const instance = new Signal(config2);
53722
53823
  if (raw_instance) {
@@ -53799,7 +53900,8 @@ function get_app_config_and_max_size(config2, payload) {
53799
53900
  use_kelly: payload.use_kelly,
53800
53901
  kelly_confidence_factor: payload.kelly_confidence_factor,
53801
53902
  kelly_minimum_risk: payload.kelly_minimum_risk,
53802
- kelly_prediction_model: payload.kelly_prediction_model
53903
+ kelly_prediction_model: payload.kelly_prediction_model,
53904
+ kelly_func: payload.kelly_func
53803
53905
  });
53804
53906
  const max_size = initialResult[0]?.avg_size;
53805
53907
  const last_value = initialResult[0];
@@ -53836,7 +53938,8 @@ function buildAppConfig(config2, payload) {
53836
53938
  use_kelly: payload.use_kelly,
53837
53939
  kelly_confidence_factor: payload.kelly_confidence_factor,
53838
53940
  kelly_minimum_risk: payload.kelly_minimum_risk,
53839
- kelly_prediction_model: payload.kelly_prediction_model
53941
+ kelly_prediction_model: payload.kelly_prediction_model,
53942
+ kelly_func: payload.kelly_func
53840
53943
  });
53841
53944
  app_config.max_size = max_size;
53842
53945
  app_config.entry = payload.entry || app_config.entry;
@@ -53847,7 +53950,8 @@ function buildAppConfig(config2, payload) {
53847
53950
  use_kelly: payload.use_kelly,
53848
53951
  kelly_confidence_factor: payload.kelly_confidence_factor,
53849
53952
  kelly_minimum_risk: payload.kelly_minimum_risk,
53850
- kelly_prediction_model: payload.kelly_prediction_model
53953
+ kelly_prediction_model: payload.kelly_prediction_model,
53954
+ kelly_func: payload.kelly_func
53851
53955
  };
53852
53956
  return app_config;
53853
53957
  }
@@ -58234,6 +58338,7 @@ class ExchangeAccount {
58234
58338
  kelly_confidence_factor: config2.kelly?.kelly_confidence_factor,
58235
58339
  kelly_minimum_risk: config2.kelly?.kelly_minimum_risk,
58236
58340
  kelly_prediction_model: config2.kelly?.kelly_prediction_model,
58341
+ kelly_func: config2.kelly?.kelly_func,
58237
58342
  ...override
58238
58343
  });
58239
58344
  return app_config;
@@ -59650,6 +59650,101 @@ function calculateZoneVolatility(zone_prices) {
59650
59650
  const price_changes = zone_prices.slice(1).map((price, i2) => Math.abs(price - zone_prices[i2]) / zone_prices[i2]);
59651
59651
  return price_changes.reduce((sum, change) => sum + change, 0) / price_changes.length;
59652
59652
  }
59653
+ function calculateTheoreticalKellyFixed({
59654
+ current_entry,
59655
+ zone_prices,
59656
+ kind = "long",
59657
+ config: config2 = {}
59658
+ }) {
59659
+ const {
59660
+ price_prediction_model = "uniform",
59661
+ confidence_factor = 0.6,
59662
+ volatility_adjustment = true
59663
+ } = config2;
59664
+ const sorted_prices = zone_prices;
59665
+ const current_index = sorted_prices.findIndex((price) => price === current_entry);
59666
+ if (current_index === -1)
59667
+ return 0.02;
59668
+ let stop_loss;
59669
+ let target_zones;
59670
+ if (kind === "long") {
59671
+ stop_loss = Math.min(...zone_prices);
59672
+ target_zones = zone_prices.filter((price) => price > current_entry);
59673
+ } else {
59674
+ stop_loss = Math.max(...zone_prices);
59675
+ target_zones = zone_prices.filter((price) => price < current_entry);
59676
+ }
59677
+ const risk_amount = Math.abs(current_entry - stop_loss);
59678
+ const avg_reward = target_zones.length > 0 ? target_zones.reduce((sum, price) => sum + Math.abs(price - current_entry), 0) / target_zones.length : risk_amount;
59679
+ const risk_reward_ratio = avg_reward / risk_amount;
59680
+ let position_quality;
59681
+ if (kind === "long") {
59682
+ const distance_from_stop = current_entry - stop_loss;
59683
+ const max_distance = Math.max(...zone_prices) - stop_loss;
59684
+ position_quality = 1 - distance_from_stop / max_distance;
59685
+ } else {
59686
+ const distance_from_stop = stop_loss - current_entry;
59687
+ const max_distance = stop_loss - Math.min(...zone_prices);
59688
+ position_quality = 1 - distance_from_stop / max_distance;
59689
+ }
59690
+ let base_probability = 0.5;
59691
+ switch (price_prediction_model) {
59692
+ case "uniform":
59693
+ base_probability = 0.5;
59694
+ break;
59695
+ case "normal":
59696
+ base_probability = 0.3 + position_quality * 0.4;
59697
+ break;
59698
+ case "exponential":
59699
+ base_probability = 0.2 + Math.pow(position_quality, 0.5) * 0.6;
59700
+ break;
59701
+ }
59702
+ const win_probability = base_probability * confidence_factor + (1 - confidence_factor) * 0.5;
59703
+ const odds_ratio = Math.max(risk_reward_ratio, 0.5);
59704
+ const loss_probability = 1 - win_probability;
59705
+ let kelly_fraction = (win_probability * odds_ratio - loss_probability) / odds_ratio;
59706
+ if (volatility_adjustment) {
59707
+ const zone_volatility = calculateZoneVolatility(sorted_prices);
59708
+ const vol_adjustment = 1 / (1 + zone_volatility);
59709
+ kelly_fraction *= vol_adjustment;
59710
+ }
59711
+ kelly_fraction = Math.max(0.005, Math.min(kelly_fraction, 0.5));
59712
+ return to_f2(kelly_fraction, "%.4f");
59713
+ }
59714
+ function calculatePositionBasedKelly({
59715
+ current_entry,
59716
+ zone_prices,
59717
+ kind = "long",
59718
+ config: config2 = {}
59719
+ }) {
59720
+ const {
59721
+ price_prediction_model = "uniform",
59722
+ confidence_factor: _confidence_factor = 0.6
59723
+ } = config2;
59724
+ const current_index = zone_prices.findIndex((price) => price === current_entry);
59725
+ if (current_index === -1)
59726
+ return 0.02;
59727
+ const total_zones = zone_prices.length;
59728
+ const position_score = (total_zones - current_index) / total_zones;
59729
+ let adjusted_score;
59730
+ switch (price_prediction_model) {
59731
+ case "uniform":
59732
+ adjusted_score = 0.5;
59733
+ break;
59734
+ case "normal":
59735
+ adjusted_score = 0.3 + position_score * 0.4;
59736
+ break;
59737
+ case "exponential":
59738
+ adjusted_score = 0.2 + Math.pow(position_score, 0.3) * 0.6;
59739
+ break;
59740
+ default:
59741
+ adjusted_score = 0.5;
59742
+ }
59743
+ const base_kelly = 0.02;
59744
+ const max_kelly = 0.2;
59745
+ const kelly_fraction = base_kelly + adjusted_score * (max_kelly - base_kelly);
59746
+ return to_f2(kelly_fraction, "%.4f");
59747
+ }
59653
59748
 
59654
59749
  // src/helpers/trade_signal.ts
59655
59750
  function determine_close_price2({
@@ -59737,6 +59832,7 @@ class Signal {
59737
59832
  kelly_prediction_model = "exponential";
59738
59833
  kelly_confidence_factor = 0.6;
59739
59834
  kelly_minimum_risk = 0.2;
59835
+ kelly_func = "theoretical";
59740
59836
  constructor({
59741
59837
  focus,
59742
59838
  budget,
@@ -59761,7 +59857,8 @@ class Signal {
59761
59857
  use_kelly = false,
59762
59858
  kelly_prediction_model = "exponential",
59763
59859
  kelly_confidence_factor = 0.6,
59764
- kelly_minimum_risk = 0.2
59860
+ kelly_minimum_risk = 0.2,
59861
+ kelly_func = "theoretical"
59765
59862
  }) {
59766
59863
  this.minimum_size = minimum_size;
59767
59864
  this.first_order_size = first_order_size;
@@ -59787,6 +59884,7 @@ class Signal {
59787
59884
  this.kelly_prediction_model = kelly_prediction_model;
59788
59885
  this.kelly_confidence_factor = kelly_confidence_factor;
59789
59886
  this.kelly_minimum_risk = kelly_minimum_risk;
59887
+ this.kelly_func = kelly_func;
59790
59888
  }
59791
59889
  build_entry({
59792
59890
  current_price,
@@ -60227,7 +60325,8 @@ class Signal {
60227
60325
  const new_stop = kind === "long" ? this.support : stop_loss;
60228
60326
  let risk_to_use = risk_per_trade;
60229
60327
  if (this.use_kelly) {
60230
- const theoretical_kelly = calculateTheoreticalKelly({
60328
+ const func = this.kelly_func === "theoretical" ? calculateTheoreticalKelly : this.kelly_func === "position_based" ? calculatePositionBasedKelly : calculateTheoreticalKellyFixed;
60329
+ const theoretical_kelly = func({
60231
60330
  current_entry: x,
60232
60331
  zone_prices: limit_orders,
60233
60332
  kind,
@@ -60435,7 +60534,8 @@ function buildConfig(app_config, {
60435
60534
  use_kelly = false,
60436
60535
  kelly_confidence_factor = 0.95,
60437
60536
  kelly_minimum_risk = 0.2,
60438
- kelly_prediction_model = "exponential"
60537
+ kelly_prediction_model = "exponential",
60538
+ kelly_func = "theoretical"
60439
60539
  }) {
60440
60540
  let fee = app_config.fee / 100;
60441
60541
  let working_risk = risk || app_config.risk_per_trade;
@@ -60463,7 +60563,8 @@ function buildConfig(app_config, {
60463
60563
  use_kelly: use_kelly || app_config.kelly?.use_kelly,
60464
60564
  kelly_confidence_factor: kelly_confidence_factor || app_config.kelly?.kelly_confidence_factor,
60465
60565
  kelly_minimum_risk: kelly_minimum_risk || app_config.kelly?.kelly_minimum_risk,
60466
- kelly_prediction_model: kelly_prediction_model || app_config.kelly?.kelly_prediction_model
60566
+ kelly_prediction_model: kelly_prediction_model || app_config.kelly?.kelly_prediction_model,
60567
+ kelly_func: kelly_func || app_config.kelly?.kelly_func
60467
60568
  };
60468
60569
  const instance = new Signal(config2);
60469
60570
  if (raw_instance) {
@@ -60533,7 +60634,8 @@ function get_app_config_and_max_size(config2, payload) {
60533
60634
  use_kelly: payload.use_kelly,
60534
60635
  kelly_confidence_factor: payload.kelly_confidence_factor,
60535
60636
  kelly_minimum_risk: payload.kelly_minimum_risk,
60536
- kelly_prediction_model: payload.kelly_prediction_model
60637
+ kelly_prediction_model: payload.kelly_prediction_model,
60638
+ kelly_func: payload.kelly_func
60537
60639
  });
60538
60640
  const max_size = initialResult[0]?.avg_size;
60539
60641
  const last_value = initialResult[0];
@@ -60570,7 +60672,8 @@ function buildAppConfig(config2, payload) {
60570
60672
  use_kelly: payload.use_kelly,
60571
60673
  kelly_confidence_factor: payload.kelly_confidence_factor,
60572
60674
  kelly_minimum_risk: payload.kelly_minimum_risk,
60573
- kelly_prediction_model: payload.kelly_prediction_model
60675
+ kelly_prediction_model: payload.kelly_prediction_model,
60676
+ kelly_func: payload.kelly_func
60574
60677
  });
60575
60678
  app_config.max_size = max_size;
60576
60679
  app_config.entry = payload.entry || app_config.entry;
@@ -60581,7 +60684,8 @@ function buildAppConfig(config2, payload) {
60581
60684
  use_kelly: payload.use_kelly,
60582
60685
  kelly_confidence_factor: payload.kelly_confidence_factor,
60583
60686
  kelly_minimum_risk: payload.kelly_minimum_risk,
60584
- kelly_prediction_model: payload.kelly_prediction_model
60687
+ kelly_prediction_model: payload.kelly_prediction_model,
60688
+ kelly_func: payload.kelly_func
60585
60689
  };
60586
60690
  return app_config;
60587
60691
  }
@@ -64962,6 +65066,7 @@ class ExchangeAccount {
64962
65066
  kelly_confidence_factor: config2.kelly?.kelly_confidence_factor,
64963
65067
  kelly_minimum_risk: config2.kelly?.kelly_minimum_risk,
64964
65068
  kelly_prediction_model: config2.kelly?.kelly_prediction_model,
65069
+ kelly_func: config2.kelly?.kelly_func,
64965
65070
  ...override
64966
65071
  });
64967
65072
  return app_config;
@@ -59627,6 +59627,101 @@ function calculateZoneVolatility(zone_prices) {
59627
59627
  const price_changes = zone_prices.slice(1).map((price, i2) => Math.abs(price - zone_prices[i2]) / zone_prices[i2]);
59628
59628
  return price_changes.reduce((sum, change) => sum + change, 0) / price_changes.length;
59629
59629
  }
59630
+ function calculateTheoreticalKellyFixed({
59631
+ current_entry,
59632
+ zone_prices,
59633
+ kind = "long",
59634
+ config: config2 = {}
59635
+ }) {
59636
+ const {
59637
+ price_prediction_model = "uniform",
59638
+ confidence_factor = 0.6,
59639
+ volatility_adjustment = true
59640
+ } = config2;
59641
+ const sorted_prices = zone_prices;
59642
+ const current_index = sorted_prices.findIndex((price) => price === current_entry);
59643
+ if (current_index === -1)
59644
+ return 0.02;
59645
+ let stop_loss;
59646
+ let target_zones;
59647
+ if (kind === "long") {
59648
+ stop_loss = Math.min(...zone_prices);
59649
+ target_zones = zone_prices.filter((price) => price > current_entry);
59650
+ } else {
59651
+ stop_loss = Math.max(...zone_prices);
59652
+ target_zones = zone_prices.filter((price) => price < current_entry);
59653
+ }
59654
+ const risk_amount = Math.abs(current_entry - stop_loss);
59655
+ const avg_reward = target_zones.length > 0 ? target_zones.reduce((sum, price) => sum + Math.abs(price - current_entry), 0) / target_zones.length : risk_amount;
59656
+ const risk_reward_ratio = avg_reward / risk_amount;
59657
+ let position_quality;
59658
+ if (kind === "long") {
59659
+ const distance_from_stop = current_entry - stop_loss;
59660
+ const max_distance = Math.max(...zone_prices) - stop_loss;
59661
+ position_quality = 1 - distance_from_stop / max_distance;
59662
+ } else {
59663
+ const distance_from_stop = stop_loss - current_entry;
59664
+ const max_distance = stop_loss - Math.min(...zone_prices);
59665
+ position_quality = 1 - distance_from_stop / max_distance;
59666
+ }
59667
+ let base_probability = 0.5;
59668
+ switch (price_prediction_model) {
59669
+ case "uniform":
59670
+ base_probability = 0.5;
59671
+ break;
59672
+ case "normal":
59673
+ base_probability = 0.3 + position_quality * 0.4;
59674
+ break;
59675
+ case "exponential":
59676
+ base_probability = 0.2 + Math.pow(position_quality, 0.5) * 0.6;
59677
+ break;
59678
+ }
59679
+ const win_probability = base_probability * confidence_factor + (1 - confidence_factor) * 0.5;
59680
+ const odds_ratio = Math.max(risk_reward_ratio, 0.5);
59681
+ const loss_probability = 1 - win_probability;
59682
+ let kelly_fraction = (win_probability * odds_ratio - loss_probability) / odds_ratio;
59683
+ if (volatility_adjustment) {
59684
+ const zone_volatility = calculateZoneVolatility(sorted_prices);
59685
+ const vol_adjustment = 1 / (1 + zone_volatility);
59686
+ kelly_fraction *= vol_adjustment;
59687
+ }
59688
+ kelly_fraction = Math.max(0.005, Math.min(kelly_fraction, 0.5));
59689
+ return to_f2(kelly_fraction, "%.4f");
59690
+ }
59691
+ function calculatePositionBasedKelly({
59692
+ current_entry,
59693
+ zone_prices,
59694
+ kind = "long",
59695
+ config: config2 = {}
59696
+ }) {
59697
+ const {
59698
+ price_prediction_model = "uniform",
59699
+ confidence_factor: _confidence_factor = 0.6
59700
+ } = config2;
59701
+ const current_index = zone_prices.findIndex((price) => price === current_entry);
59702
+ if (current_index === -1)
59703
+ return 0.02;
59704
+ const total_zones = zone_prices.length;
59705
+ const position_score = (total_zones - current_index) / total_zones;
59706
+ let adjusted_score;
59707
+ switch (price_prediction_model) {
59708
+ case "uniform":
59709
+ adjusted_score = 0.5;
59710
+ break;
59711
+ case "normal":
59712
+ adjusted_score = 0.3 + position_score * 0.4;
59713
+ break;
59714
+ case "exponential":
59715
+ adjusted_score = 0.2 + Math.pow(position_score, 0.3) * 0.6;
59716
+ break;
59717
+ default:
59718
+ adjusted_score = 0.5;
59719
+ }
59720
+ const base_kelly = 0.02;
59721
+ const max_kelly = 0.2;
59722
+ const kelly_fraction = base_kelly + adjusted_score * (max_kelly - base_kelly);
59723
+ return to_f2(kelly_fraction, "%.4f");
59724
+ }
59630
59725
 
59631
59726
  // src/helpers/trade_signal.ts
59632
59727
  function determine_close_price2({
@@ -59714,6 +59809,7 @@ class Signal {
59714
59809
  kelly_prediction_model = "exponential";
59715
59810
  kelly_confidence_factor = 0.6;
59716
59811
  kelly_minimum_risk = 0.2;
59812
+ kelly_func = "theoretical";
59717
59813
  constructor({
59718
59814
  focus,
59719
59815
  budget,
@@ -59738,7 +59834,8 @@ class Signal {
59738
59834
  use_kelly = false,
59739
59835
  kelly_prediction_model = "exponential",
59740
59836
  kelly_confidence_factor = 0.6,
59741
- kelly_minimum_risk = 0.2
59837
+ kelly_minimum_risk = 0.2,
59838
+ kelly_func = "theoretical"
59742
59839
  }) {
59743
59840
  this.minimum_size = minimum_size;
59744
59841
  this.first_order_size = first_order_size;
@@ -59764,6 +59861,7 @@ class Signal {
59764
59861
  this.kelly_prediction_model = kelly_prediction_model;
59765
59862
  this.kelly_confidence_factor = kelly_confidence_factor;
59766
59863
  this.kelly_minimum_risk = kelly_minimum_risk;
59864
+ this.kelly_func = kelly_func;
59767
59865
  }
59768
59866
  build_entry({
59769
59867
  current_price,
@@ -60204,7 +60302,8 @@ class Signal {
60204
60302
  const new_stop = kind === "long" ? this.support : stop_loss;
60205
60303
  let risk_to_use = risk_per_trade;
60206
60304
  if (this.use_kelly) {
60207
- const theoretical_kelly = calculateTheoreticalKelly({
60305
+ const func = this.kelly_func === "theoretical" ? calculateTheoreticalKelly : this.kelly_func === "position_based" ? calculatePositionBasedKelly : calculateTheoreticalKellyFixed;
60306
+ const theoretical_kelly = func({
60208
60307
  current_entry: x,
60209
60308
  zone_prices: limit_orders,
60210
60309
  kind,
@@ -60412,7 +60511,8 @@ function buildConfig(app_config, {
60412
60511
  use_kelly = false,
60413
60512
  kelly_confidence_factor = 0.95,
60414
60513
  kelly_minimum_risk = 0.2,
60415
- kelly_prediction_model = "exponential"
60514
+ kelly_prediction_model = "exponential",
60515
+ kelly_func = "theoretical"
60416
60516
  }) {
60417
60517
  let fee = app_config.fee / 100;
60418
60518
  let working_risk = risk || app_config.risk_per_trade;
@@ -60440,7 +60540,8 @@ function buildConfig(app_config, {
60440
60540
  use_kelly: use_kelly || app_config.kelly?.use_kelly,
60441
60541
  kelly_confidence_factor: kelly_confidence_factor || app_config.kelly?.kelly_confidence_factor,
60442
60542
  kelly_minimum_risk: kelly_minimum_risk || app_config.kelly?.kelly_minimum_risk,
60443
- kelly_prediction_model: kelly_prediction_model || app_config.kelly?.kelly_prediction_model
60543
+ kelly_prediction_model: kelly_prediction_model || app_config.kelly?.kelly_prediction_model,
60544
+ kelly_func: kelly_func || app_config.kelly?.kelly_func
60444
60545
  };
60445
60546
  const instance = new Signal(config2);
60446
60547
  if (raw_instance) {
@@ -60510,7 +60611,8 @@ function get_app_config_and_max_size(config2, payload) {
60510
60611
  use_kelly: payload.use_kelly,
60511
60612
  kelly_confidence_factor: payload.kelly_confidence_factor,
60512
60613
  kelly_minimum_risk: payload.kelly_minimum_risk,
60513
- kelly_prediction_model: payload.kelly_prediction_model
60614
+ kelly_prediction_model: payload.kelly_prediction_model,
60615
+ kelly_func: payload.kelly_func
60514
60616
  });
60515
60617
  const max_size = initialResult[0]?.avg_size;
60516
60618
  const last_value = initialResult[0];
@@ -60547,7 +60649,8 @@ function buildAppConfig(config2, payload) {
60547
60649
  use_kelly: payload.use_kelly,
60548
60650
  kelly_confidence_factor: payload.kelly_confidence_factor,
60549
60651
  kelly_minimum_risk: payload.kelly_minimum_risk,
60550
- kelly_prediction_model: payload.kelly_prediction_model
60652
+ kelly_prediction_model: payload.kelly_prediction_model,
60653
+ kelly_func: payload.kelly_func
60551
60654
  });
60552
60655
  app_config.max_size = max_size;
60553
60656
  app_config.entry = payload.entry || app_config.entry;
@@ -60558,7 +60661,8 @@ function buildAppConfig(config2, payload) {
60558
60661
  use_kelly: payload.use_kelly,
60559
60662
  kelly_confidence_factor: payload.kelly_confidence_factor,
60560
60663
  kelly_minimum_risk: payload.kelly_minimum_risk,
60561
- kelly_prediction_model: payload.kelly_prediction_model
60664
+ kelly_prediction_model: payload.kelly_prediction_model,
60665
+ kelly_func: payload.kelly_func
60562
60666
  };
60563
60667
  return app_config;
60564
60668
  }
@@ -64939,6 +65043,7 @@ class ExchangeAccount {
64939
65043
  kelly_confidence_factor: config2.kelly?.kelly_confidence_factor,
64940
65044
  kelly_minimum_risk: config2.kelly?.kelly_minimum_risk,
64941
65045
  kelly_prediction_model: config2.kelly?.kelly_prediction_model,
65046
+ kelly_func: config2.kelly?.kelly_func,
64942
65047
  ...override
64943
65048
  });
64944
65049
  return app_config;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gbozee/ultimate",
3
3
  "type": "module",
4
- "version": "0.0.2-147",
4
+ "version": "0.0.2-148",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",