@gbozee/ultimate 0.0.2-144 → 0.0.2-146
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.
- package/dist/frontend-index.d.ts +34 -2
- package/dist/frontend-index.js +142 -6
- package/dist/index.cjs +161 -11
- package/dist/index.d.ts +65 -2
- package/dist/index.js +161 -11
- package/dist/mcp-server.cjs +161 -11
- package/dist/mcp-server.js +161 -11
- package/package.json +1 -1
package/dist/frontend-index.d.ts
CHANGED
|
@@ -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
|
-
|
|
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,12 @@ export type AppConfig = {
|
|
|
296
304
|
last_value?: any;
|
|
297
305
|
entries?: any[];
|
|
298
306
|
max_quantity?: number;
|
|
307
|
+
kelly?: {
|
|
308
|
+
use_kelly?: boolean;
|
|
309
|
+
kelly_confidence_factor?: number;
|
|
310
|
+
kelly_minimum_risk?: number;
|
|
311
|
+
kelly_prediction_model?: "exponential" | "normal" | "uniform";
|
|
312
|
+
};
|
|
299
313
|
};
|
|
300
314
|
export type ExtendConfigType = {
|
|
301
315
|
take_profit?: number;
|
|
@@ -312,8 +326,12 @@ export type ExtendConfigType = {
|
|
|
312
326
|
kind?: "long" | "short";
|
|
313
327
|
gap?: number;
|
|
314
328
|
rr?: number;
|
|
329
|
+
use_kelly?: boolean;
|
|
330
|
+
kelly_confidence_factor?: number;
|
|
331
|
+
kelly_minimum_risk?: number;
|
|
332
|
+
kelly_prediction_model?: "exponential" | "normal" | "uniform";
|
|
315
333
|
};
|
|
316
|
-
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, }: ExtendConfigType): any[] | Signal;
|
|
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;
|
|
317
335
|
export declare function buildAvg({ _trades, kind, }: {
|
|
318
336
|
_trades: any[];
|
|
319
337
|
kind: "long" | "short";
|
|
@@ -323,6 +341,10 @@ export declare function get_app_config_and_max_size(config: GlobalConfig, payloa
|
|
|
323
341
|
entry: number;
|
|
324
342
|
stop: number;
|
|
325
343
|
kind: "long" | "short";
|
|
344
|
+
use_kelly?: boolean;
|
|
345
|
+
kelly_confidence_factor?: number;
|
|
346
|
+
kelly_minimum_risk?: number;
|
|
347
|
+
kelly_prediction_model?: "exponential" | "normal" | "uniform";
|
|
326
348
|
}): {
|
|
327
349
|
app_config: AppConfig;
|
|
328
350
|
max_size: any;
|
|
@@ -342,6 +364,10 @@ export declare function buildAppConfig(config: GlobalConfig, payload: {
|
|
|
342
364
|
risk: number;
|
|
343
365
|
symbol: string;
|
|
344
366
|
profit?: number;
|
|
367
|
+
use_kelly?: boolean;
|
|
368
|
+
kelly_confidence_factor?: number;
|
|
369
|
+
kelly_minimum_risk?: number;
|
|
370
|
+
kelly_prediction_model?: "exponential" | "normal" | "uniform";
|
|
345
371
|
}): AppConfig;
|
|
346
372
|
export declare function getOptimumStopAndRisk(app_config: AppConfig, params: {
|
|
347
373
|
max_size: number;
|
|
@@ -814,6 +840,12 @@ export declare class Strategy {
|
|
|
814
840
|
rr?: number;
|
|
815
841
|
max_size?: number;
|
|
816
842
|
max_quantity?: number;
|
|
843
|
+
kelly?: {
|
|
844
|
+
use_kelly?: boolean;
|
|
845
|
+
kelly_confidence_factor?: number;
|
|
846
|
+
kelly_minimum_risk?: number;
|
|
847
|
+
kelly_prediction_model?: "exponential" | "normal" | "uniform";
|
|
848
|
+
};
|
|
817
849
|
};
|
|
818
850
|
identifyGapConfig(payload: {
|
|
819
851
|
factor?: number;
|
package/dist/frontend-index.js
CHANGED
|
@@ -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:
|
|
679
|
+
risk: risk_to_use,
|
|
567
680
|
arr: limit_orders,
|
|
568
681
|
index: i,
|
|
569
682
|
new_fees: total_incurred_market_fees,
|
|
@@ -1225,7 +1338,11 @@ function buildConfig(app_config, {
|
|
|
1225
1338
|
gap,
|
|
1226
1339
|
rr = 1,
|
|
1227
1340
|
price_places = "%.1f",
|
|
1228
|
-
decimal_places = "%.3f"
|
|
1341
|
+
decimal_places = "%.3f",
|
|
1342
|
+
use_kelly = false,
|
|
1343
|
+
kelly_confidence_factor = 0.95,
|
|
1344
|
+
kelly_minimum_risk = 0.2,
|
|
1345
|
+
kelly_prediction_model = "exponential"
|
|
1229
1346
|
}) {
|
|
1230
1347
|
let fee = app_config.fee / 100;
|
|
1231
1348
|
let working_risk = risk || app_config.risk_per_trade;
|
|
@@ -1249,7 +1366,11 @@ function buildConfig(app_config, {
|
|
|
1249
1366
|
kind: app_config.kind,
|
|
1250
1367
|
gap,
|
|
1251
1368
|
min_profit: min_profit || app_config.min_profit,
|
|
1252
|
-
rr: rr || 1
|
|
1369
|
+
rr: rr || 1,
|
|
1370
|
+
use_kelly: use_kelly || app_config.kelly?.use_kelly,
|
|
1371
|
+
kelly_confidence_factor: kelly_confidence_factor || app_config.kelly?.kelly_confidence_factor,
|
|
1372
|
+
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
|
|
1253
1374
|
};
|
|
1254
1375
|
const instance = new Signal(config);
|
|
1255
1376
|
if (raw_instance) {
|
|
@@ -1261,6 +1382,7 @@ function buildConfig(app_config, {
|
|
|
1261
1382
|
const condition = (kind === "long" ? entry > app_config.support : entry >= app_config.support) && stop >= app_config.support * 0.999;
|
|
1262
1383
|
if (kind === "short") {
|
|
1263
1384
|
}
|
|
1385
|
+
console.log({ entry, stop, condition, working_risk, config });
|
|
1264
1386
|
const result = entry === stop ? [] : condition ? instance.build_entry({
|
|
1265
1387
|
current_price: entry,
|
|
1266
1388
|
stop_loss: stop,
|
|
@@ -1327,7 +1449,11 @@ function get_app_config_and_max_size(config, payload) {
|
|
|
1327
1449
|
increase: true,
|
|
1328
1450
|
gap: app_config.gap,
|
|
1329
1451
|
price_places: app_config.price_places,
|
|
1330
|
-
decimal_places: app_config.decimal_places
|
|
1452
|
+
decimal_places: app_config.decimal_places,
|
|
1453
|
+
use_kelly: payload.use_kelly,
|
|
1454
|
+
kelly_confidence_factor: payload.kelly_confidence_factor,
|
|
1455
|
+
kelly_minimum_risk: payload.kelly_minimum_risk,
|
|
1456
|
+
kelly_prediction_model: payload.kelly_prediction_model
|
|
1331
1457
|
});
|
|
1332
1458
|
const max_size = initialResult[0]?.avg_size;
|
|
1333
1459
|
const last_value = initialResult[0];
|
|
@@ -1360,13 +1486,23 @@ function buildAppConfig(config, payload) {
|
|
|
1360
1486
|
}, {
|
|
1361
1487
|
entry: payload.entry,
|
|
1362
1488
|
stop: payload.stop,
|
|
1363
|
-
kind: payload.entry > payload.stop ? "long" : "short"
|
|
1489
|
+
kind: payload.entry > payload.stop ? "long" : "short",
|
|
1490
|
+
use_kelly: payload.use_kelly,
|
|
1491
|
+
kelly_confidence_factor: payload.kelly_confidence_factor,
|
|
1492
|
+
kelly_minimum_risk: payload.kelly_minimum_risk,
|
|
1493
|
+
kelly_prediction_model: payload.kelly_prediction_model
|
|
1364
1494
|
});
|
|
1365
1495
|
app_config.max_size = max_size;
|
|
1366
1496
|
app_config.entry = payload.entry || app_config.entry;
|
|
1367
1497
|
app_config.stop = payload.stop || app_config.stop;
|
|
1368
1498
|
app_config.last_value = last_value;
|
|
1369
1499
|
app_config.entries = entries;
|
|
1500
|
+
app_config.kelly = {
|
|
1501
|
+
use_kelly: payload.use_kelly,
|
|
1502
|
+
kelly_confidence_factor: payload.kelly_confidence_factor,
|
|
1503
|
+
kelly_minimum_risk: payload.kelly_minimum_risk,
|
|
1504
|
+
kelly_prediction_model: payload.kelly_prediction_model
|
|
1505
|
+
};
|
|
1370
1506
|
return app_config;
|
|
1371
1507
|
}
|
|
1372
1508
|
function getOptimumStopAndRisk(app_config, params) {
|
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:
|
|
53551
|
+
risk: risk_to_use,
|
|
53439
53552
|
arr: limit_orders,
|
|
53440
53553
|
index: i2,
|
|
53441
53554
|
new_fees: total_incurred_market_fees,
|
|
@@ -53623,7 +53736,11 @@ function buildConfig(app_config, {
|
|
|
53623
53736
|
gap,
|
|
53624
53737
|
rr = 1,
|
|
53625
53738
|
price_places = "%.1f",
|
|
53626
|
-
decimal_places = "%.3f"
|
|
53739
|
+
decimal_places = "%.3f",
|
|
53740
|
+
use_kelly = false,
|
|
53741
|
+
kelly_confidence_factor = 0.95,
|
|
53742
|
+
kelly_minimum_risk = 0.2,
|
|
53743
|
+
kelly_prediction_model = "exponential"
|
|
53627
53744
|
}) {
|
|
53628
53745
|
let fee = app_config.fee / 100;
|
|
53629
53746
|
let working_risk = risk || app_config.risk_per_trade;
|
|
@@ -53647,7 +53764,11 @@ function buildConfig(app_config, {
|
|
|
53647
53764
|
kind: app_config.kind,
|
|
53648
53765
|
gap,
|
|
53649
53766
|
min_profit: min_profit || app_config.min_profit,
|
|
53650
|
-
rr: rr || 1
|
|
53767
|
+
rr: rr || 1,
|
|
53768
|
+
use_kelly: use_kelly || app_config.kelly?.use_kelly,
|
|
53769
|
+
kelly_confidence_factor: kelly_confidence_factor || app_config.kelly?.kelly_confidence_factor,
|
|
53770
|
+
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
|
|
53651
53772
|
};
|
|
53652
53773
|
const instance = new Signal(config2);
|
|
53653
53774
|
if (raw_instance) {
|
|
@@ -53659,6 +53780,7 @@ function buildConfig(app_config, {
|
|
|
53659
53780
|
const condition = (kind === "long" ? entry > app_config.support : entry >= app_config.support) && stop >= app_config.support * 0.999;
|
|
53660
53781
|
if (kind === "short") {
|
|
53661
53782
|
}
|
|
53783
|
+
console.log({ entry, stop, condition, working_risk, config: config2 });
|
|
53662
53784
|
const result = entry === stop ? [] : condition ? instance.build_entry({
|
|
53663
53785
|
current_price: entry,
|
|
53664
53786
|
stop_loss: stop,
|
|
@@ -53725,7 +53847,11 @@ function get_app_config_and_max_size(config2, payload) {
|
|
|
53725
53847
|
increase: true,
|
|
53726
53848
|
gap: app_config.gap,
|
|
53727
53849
|
price_places: app_config.price_places,
|
|
53728
|
-
decimal_places: app_config.decimal_places
|
|
53850
|
+
decimal_places: app_config.decimal_places,
|
|
53851
|
+
use_kelly: payload.use_kelly,
|
|
53852
|
+
kelly_confidence_factor: payload.kelly_confidence_factor,
|
|
53853
|
+
kelly_minimum_risk: payload.kelly_minimum_risk,
|
|
53854
|
+
kelly_prediction_model: payload.kelly_prediction_model
|
|
53729
53855
|
});
|
|
53730
53856
|
const max_size = initialResult[0]?.avg_size;
|
|
53731
53857
|
const last_value = initialResult[0];
|
|
@@ -53758,13 +53884,23 @@ function buildAppConfig(config2, payload) {
|
|
|
53758
53884
|
}, {
|
|
53759
53885
|
entry: payload.entry,
|
|
53760
53886
|
stop: payload.stop,
|
|
53761
|
-
kind: payload.entry > payload.stop ? "long" : "short"
|
|
53887
|
+
kind: payload.entry > payload.stop ? "long" : "short",
|
|
53888
|
+
use_kelly: payload.use_kelly,
|
|
53889
|
+
kelly_confidence_factor: payload.kelly_confidence_factor,
|
|
53890
|
+
kelly_minimum_risk: payload.kelly_minimum_risk,
|
|
53891
|
+
kelly_prediction_model: payload.kelly_prediction_model
|
|
53762
53892
|
});
|
|
53763
53893
|
app_config.max_size = max_size;
|
|
53764
53894
|
app_config.entry = payload.entry || app_config.entry;
|
|
53765
53895
|
app_config.stop = payload.stop || app_config.stop;
|
|
53766
53896
|
app_config.last_value = last_value;
|
|
53767
53897
|
app_config.entries = entries;
|
|
53898
|
+
app_config.kelly = {
|
|
53899
|
+
use_kelly: payload.use_kelly,
|
|
53900
|
+
kelly_confidence_factor: payload.kelly_confidence_factor,
|
|
53901
|
+
kelly_minimum_risk: payload.kelly_minimum_risk,
|
|
53902
|
+
kelly_prediction_model: payload.kelly_prediction_model
|
|
53903
|
+
};
|
|
53768
53904
|
return app_config;
|
|
53769
53905
|
}
|
|
53770
53906
|
function getOptimumStopAndRisk(app_config, params) {
|
|
@@ -58145,7 +58281,11 @@ class ExchangeAccount {
|
|
|
58145
58281
|
stop: config2.stop,
|
|
58146
58282
|
risk_reward: config2.risk_reward,
|
|
58147
58283
|
risk: config2.risk,
|
|
58148
|
-
symbol
|
|
58284
|
+
symbol,
|
|
58285
|
+
use_kelly: config2.kelly?.use_kelly,
|
|
58286
|
+
kelly_confidence_factor: config2.kelly?.kelly_confidence_factor,
|
|
58287
|
+
kelly_minimum_risk: config2.kelly?.kelly_minimum_risk,
|
|
58288
|
+
kelly_prediction_model: config2.kelly?.kelly_prediction_model
|
|
58149
58289
|
});
|
|
58150
58290
|
return app_config;
|
|
58151
58291
|
}
|
|
@@ -58935,15 +59075,25 @@ class ExchangeAccount {
|
|
|
58935
59075
|
}
|
|
58936
59076
|
}
|
|
58937
59077
|
async increasePositionAtStop(payload) {
|
|
58938
|
-
const { symbol, kind, place = false } = payload;
|
|
59078
|
+
const { symbol, kind, place = false, increase = true } = payload;
|
|
58939
59079
|
const position2 = await this.syncAccount({
|
|
58940
59080
|
symbol,
|
|
58941
59081
|
kind,
|
|
58942
59082
|
as_view: true
|
|
58943
59083
|
});
|
|
58944
59084
|
console.log(position2);
|
|
58945
|
-
|
|
58946
|
-
|
|
59085
|
+
let price_params = {
|
|
59086
|
+
price: payload.price,
|
|
59087
|
+
quantity: payload.quantity
|
|
59088
|
+
};
|
|
59089
|
+
if (!payload.price && position2 && position2.stop_loss) {
|
|
59090
|
+
price_params.price = position2.stop_loss.price;
|
|
59091
|
+
}
|
|
59092
|
+
if (!payload.quantity && position2 && position2.stop_loss) {
|
|
59093
|
+
price_params.quantity = position2.stop_loss.quantity;
|
|
59094
|
+
}
|
|
59095
|
+
if (price_params.price && price_params.quantity) {
|
|
59096
|
+
const { price, quantity } = price_params;
|
|
58947
59097
|
const symbol_config = await this.recomputeSymbolConfig({
|
|
58948
59098
|
symbol
|
|
58949
59099
|
});
|
|
@@ -58963,7 +59113,7 @@ class ExchangeAccount {
|
|
|
58963
59113
|
quantity,
|
|
58964
59114
|
price_places,
|
|
58965
59115
|
decimal_places,
|
|
58966
|
-
increase
|
|
59116
|
+
increase,
|
|
58967
59117
|
place
|
|
58968
59118
|
});
|
|
58969
59119
|
}
|