@gbozee/ultimate 0.0.2-146 → 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.
- package/dist/frontend-index.d.ts +9 -2
- package/dist/frontend-index.js +114 -10
- package/dist/index.cjs +118 -12
- package/dist/index.d.ts +14 -2
- package/dist/index.js +118 -12
- package/dist/mcp-server.cjs +118 -12
- package/dist/mcp-server.js +118 -12
- package/package.json +1 -1
package/dist/frontend-index.d.ts
CHANGED
|
@@ -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
|
-
|
|
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: {
|
package/dist/frontend-index.js
CHANGED
|
@@ -10,12 +10,12 @@ function calculateTheoreticalKelly({
|
|
|
10
10
|
confidence_factor = 0.6,
|
|
11
11
|
volatility_adjustment = true
|
|
12
12
|
} = config;
|
|
13
|
-
const sorted_prices =
|
|
13
|
+
const sorted_prices = zone_prices;
|
|
14
14
|
const current_index = sorted_prices.findIndex((price) => price === current_entry);
|
|
15
15
|
if (current_index === -1)
|
|
16
16
|
return 0.02;
|
|
17
|
-
const win_zones = kind === "long" ? sorted_prices.
|
|
18
|
-
const lose_zones = kind === "long" ? sorted_prices.
|
|
17
|
+
const win_zones = kind === "long" ? sorted_prices.filter((price) => price > current_entry) : sorted_prices.filter((price) => price < current_entry);
|
|
18
|
+
const lose_zones = kind === "long" ? sorted_prices.filter((price) => price < current_entry) : sorted_prices.filter((price) => price > current_entry);
|
|
19
19
|
const { win_probability, avg_win_ratio, avg_loss_ratio } = calculateZoneProbabilities({
|
|
20
20
|
current_entry,
|
|
21
21
|
win_zones,
|
|
@@ -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
|
|
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
|
@@ -52882,12 +52882,12 @@ function calculateTheoreticalKelly({
|
|
|
52882
52882
|
confidence_factor = 0.6,
|
|
52883
52883
|
volatility_adjustment = true
|
|
52884
52884
|
} = config2;
|
|
52885
|
-
const sorted_prices =
|
|
52885
|
+
const sorted_prices = zone_prices;
|
|
52886
52886
|
const current_index = sorted_prices.findIndex((price) => price === current_entry);
|
|
52887
52887
|
if (current_index === -1)
|
|
52888
52888
|
return 0.02;
|
|
52889
|
-
const win_zones = kind === "long" ? sorted_prices.
|
|
52890
|
-
const lose_zones = kind === "long" ? sorted_prices.
|
|
52889
|
+
const win_zones = kind === "long" ? sorted_prices.filter((price) => price > current_entry) : sorted_prices.filter((price) => price < current_entry);
|
|
52890
|
+
const lose_zones = kind === "long" ? sorted_prices.filter((price) => price < current_entry) : sorted_prices.filter((price) => price > current_entry);
|
|
52891
52891
|
const { win_probability, avg_win_ratio, avg_loss_ratio } = calculateZoneProbabilities({
|
|
52892
52892
|
current_entry,
|
|
52893
52893
|
win_zones,
|
|
@@ -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
|
|
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
|
}
|
|
@@ -58271,7 +58375,7 @@ class ExchangeAccount {
|
|
|
58271
58375
|
return app_config;
|
|
58272
58376
|
}
|
|
58273
58377
|
async tradeConfig(payload) {
|
|
58274
|
-
const { symbol, kind } = payload;
|
|
58378
|
+
const { symbol, kind, override = {} } = payload;
|
|
58275
58379
|
const config2 = await this.getPositionConfig({
|
|
58276
58380
|
symbol,
|
|
58277
58381
|
kind
|
|
@@ -58285,7 +58389,9 @@ class ExchangeAccount {
|
|
|
58285
58389
|
use_kelly: config2.kelly?.use_kelly,
|
|
58286
58390
|
kelly_confidence_factor: config2.kelly?.kelly_confidence_factor,
|
|
58287
58391
|
kelly_minimum_risk: config2.kelly?.kelly_minimum_risk,
|
|
58288
|
-
kelly_prediction_model: config2.kelly?.kelly_prediction_model
|
|
58392
|
+
kelly_prediction_model: config2.kelly?.kelly_prediction_model,
|
|
58393
|
+
kelly_func: config2.kelly?.kelly_func,
|
|
58394
|
+
...override
|
|
58289
58395
|
});
|
|
58290
58396
|
return app_config;
|
|
58291
58397
|
}
|
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
|
-
|
|
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,10 +1903,12 @@ 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;
|
|
1902
1910
|
kind: "long" | "short";
|
|
1911
|
+
override?: any;
|
|
1903
1912
|
}): Promise<AppConfig>;
|
|
1904
1913
|
justInTimeProfit(payload: {
|
|
1905
1914
|
symbol: string;
|
|
@@ -2248,6 +2257,7 @@ declare class ExchangeAccount$1 {
|
|
|
2248
2257
|
kelly_confidence_factor?: number;
|
|
2249
2258
|
kelly_minimum_risk?: number;
|
|
2250
2259
|
kelly_prediction_model?: "exponential" | "normal" | "uniform";
|
|
2260
|
+
kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
|
|
2251
2261
|
};
|
|
2252
2262
|
}>;
|
|
2253
2263
|
runSimulation(payload: {
|
|
@@ -2434,6 +2444,7 @@ declare class ExchangeAccount$1 {
|
|
|
2434
2444
|
kelly_confidence_factor?: number;
|
|
2435
2445
|
kelly_minimum_risk?: number;
|
|
2436
2446
|
kelly_prediction_model?: "exponential" | "normal" | "uniform";
|
|
2447
|
+
kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
|
|
2437
2448
|
};
|
|
2438
2449
|
};
|
|
2439
2450
|
last_value: any;
|
|
@@ -2707,6 +2718,7 @@ declare class App {
|
|
|
2707
2718
|
kelly_confidence_factor?: number;
|
|
2708
2719
|
kelly_minimum_risk?: number;
|
|
2709
2720
|
kelly_prediction_model?: "exponential" | "normal" | "uniform";
|
|
2721
|
+
kelly_func?: "theoretical" | "position_based" | "theoretical_fixed";
|
|
2710
2722
|
};
|
|
2711
2723
|
};
|
|
2712
2724
|
last_value: any;
|
package/dist/index.js
CHANGED
|
@@ -52830,12 +52830,12 @@ function calculateTheoreticalKelly({
|
|
|
52830
52830
|
confidence_factor = 0.6,
|
|
52831
52831
|
volatility_adjustment = true
|
|
52832
52832
|
} = config2;
|
|
52833
|
-
const sorted_prices =
|
|
52833
|
+
const sorted_prices = zone_prices;
|
|
52834
52834
|
const current_index = sorted_prices.findIndex((price) => price === current_entry);
|
|
52835
52835
|
if (current_index === -1)
|
|
52836
52836
|
return 0.02;
|
|
52837
|
-
const win_zones = kind === "long" ? sorted_prices.
|
|
52838
|
-
const lose_zones = kind === "long" ? sorted_prices.
|
|
52837
|
+
const win_zones = kind === "long" ? sorted_prices.filter((price) => price > current_entry) : sorted_prices.filter((price) => price < current_entry);
|
|
52838
|
+
const lose_zones = kind === "long" ? sorted_prices.filter((price) => price < current_entry) : sorted_prices.filter((price) => price > current_entry);
|
|
52839
52839
|
const { win_probability, avg_win_ratio, avg_loss_ratio } = calculateZoneProbabilities({
|
|
52840
52840
|
current_entry,
|
|
52841
52841
|
win_zones,
|
|
@@ -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
|
|
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
|
}
|
|
@@ -58219,7 +58323,7 @@ class ExchangeAccount {
|
|
|
58219
58323
|
return app_config;
|
|
58220
58324
|
}
|
|
58221
58325
|
async tradeConfig(payload) {
|
|
58222
|
-
const { symbol, kind } = payload;
|
|
58326
|
+
const { symbol, kind, override = {} } = payload;
|
|
58223
58327
|
const config2 = await this.getPositionConfig({
|
|
58224
58328
|
symbol,
|
|
58225
58329
|
kind
|
|
@@ -58233,7 +58337,9 @@ class ExchangeAccount {
|
|
|
58233
58337
|
use_kelly: config2.kelly?.use_kelly,
|
|
58234
58338
|
kelly_confidence_factor: config2.kelly?.kelly_confidence_factor,
|
|
58235
58339
|
kelly_minimum_risk: config2.kelly?.kelly_minimum_risk,
|
|
58236
|
-
kelly_prediction_model: config2.kelly?.kelly_prediction_model
|
|
58340
|
+
kelly_prediction_model: config2.kelly?.kelly_prediction_model,
|
|
58341
|
+
kelly_func: config2.kelly?.kelly_func,
|
|
58342
|
+
...override
|
|
58237
58343
|
});
|
|
58238
58344
|
return app_config;
|
|
58239
58345
|
}
|
package/dist/mcp-server.cjs
CHANGED
|
@@ -59577,12 +59577,12 @@ function calculateTheoreticalKelly({
|
|
|
59577
59577
|
confidence_factor = 0.6,
|
|
59578
59578
|
volatility_adjustment = true
|
|
59579
59579
|
} = config2;
|
|
59580
|
-
const sorted_prices =
|
|
59580
|
+
const sorted_prices = zone_prices;
|
|
59581
59581
|
const current_index = sorted_prices.findIndex((price) => price === current_entry);
|
|
59582
59582
|
if (current_index === -1)
|
|
59583
59583
|
return 0.02;
|
|
59584
|
-
const win_zones = kind === "long" ? sorted_prices.
|
|
59585
|
-
const lose_zones = kind === "long" ? sorted_prices.
|
|
59584
|
+
const win_zones = kind === "long" ? sorted_prices.filter((price) => price > current_entry) : sorted_prices.filter((price) => price < current_entry);
|
|
59585
|
+
const lose_zones = kind === "long" ? sorted_prices.filter((price) => price < current_entry) : sorted_prices.filter((price) => price > current_entry);
|
|
59586
59586
|
const { win_probability, avg_win_ratio, avg_loss_ratio } = calculateZoneProbabilities({
|
|
59587
59587
|
current_entry,
|
|
59588
59588
|
win_zones,
|
|
@@ -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
|
|
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
|
}
|
|
@@ -64947,7 +65051,7 @@ class ExchangeAccount {
|
|
|
64947
65051
|
return app_config;
|
|
64948
65052
|
}
|
|
64949
65053
|
async tradeConfig(payload) {
|
|
64950
|
-
const { symbol, kind } = payload;
|
|
65054
|
+
const { symbol, kind, override = {} } = payload;
|
|
64951
65055
|
const config2 = await this.getPositionConfig({
|
|
64952
65056
|
symbol,
|
|
64953
65057
|
kind
|
|
@@ -64961,7 +65065,9 @@ class ExchangeAccount {
|
|
|
64961
65065
|
use_kelly: config2.kelly?.use_kelly,
|
|
64962
65066
|
kelly_confidence_factor: config2.kelly?.kelly_confidence_factor,
|
|
64963
65067
|
kelly_minimum_risk: config2.kelly?.kelly_minimum_risk,
|
|
64964
|
-
kelly_prediction_model: config2.kelly?.kelly_prediction_model
|
|
65068
|
+
kelly_prediction_model: config2.kelly?.kelly_prediction_model,
|
|
65069
|
+
kelly_func: config2.kelly?.kelly_func,
|
|
65070
|
+
...override
|
|
64965
65071
|
});
|
|
64966
65072
|
return app_config;
|
|
64967
65073
|
}
|
package/dist/mcp-server.js
CHANGED
|
@@ -59554,12 +59554,12 @@ function calculateTheoreticalKelly({
|
|
|
59554
59554
|
confidence_factor = 0.6,
|
|
59555
59555
|
volatility_adjustment = true
|
|
59556
59556
|
} = config2;
|
|
59557
|
-
const sorted_prices =
|
|
59557
|
+
const sorted_prices = zone_prices;
|
|
59558
59558
|
const current_index = sorted_prices.findIndex((price) => price === current_entry);
|
|
59559
59559
|
if (current_index === -1)
|
|
59560
59560
|
return 0.02;
|
|
59561
|
-
const win_zones = kind === "long" ? sorted_prices.
|
|
59562
|
-
const lose_zones = kind === "long" ? sorted_prices.
|
|
59561
|
+
const win_zones = kind === "long" ? sorted_prices.filter((price) => price > current_entry) : sorted_prices.filter((price) => price < current_entry);
|
|
59562
|
+
const lose_zones = kind === "long" ? sorted_prices.filter((price) => price < current_entry) : sorted_prices.filter((price) => price > current_entry);
|
|
59563
59563
|
const { win_probability, avg_win_ratio, avg_loss_ratio } = calculateZoneProbabilities({
|
|
59564
59564
|
current_entry,
|
|
59565
59565
|
win_zones,
|
|
@@ -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
|
|
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
|
}
|
|
@@ -64924,7 +65028,7 @@ class ExchangeAccount {
|
|
|
64924
65028
|
return app_config;
|
|
64925
65029
|
}
|
|
64926
65030
|
async tradeConfig(payload) {
|
|
64927
|
-
const { symbol, kind } = payload;
|
|
65031
|
+
const { symbol, kind, override = {} } = payload;
|
|
64928
65032
|
const config2 = await this.getPositionConfig({
|
|
64929
65033
|
symbol,
|
|
64930
65034
|
kind
|
|
@@ -64938,7 +65042,9 @@ class ExchangeAccount {
|
|
|
64938
65042
|
use_kelly: config2.kelly?.use_kelly,
|
|
64939
65043
|
kelly_confidence_factor: config2.kelly?.kelly_confidence_factor,
|
|
64940
65044
|
kelly_minimum_risk: config2.kelly?.kelly_minimum_risk,
|
|
64941
|
-
kelly_prediction_model: config2.kelly?.kelly_prediction_model
|
|
65045
|
+
kelly_prediction_model: config2.kelly?.kelly_prediction_model,
|
|
65046
|
+
kelly_func: config2.kelly?.kelly_func,
|
|
65047
|
+
...override
|
|
64942
65048
|
});
|
|
64943
65049
|
return app_config;
|
|
64944
65050
|
}
|