@gbozee/ultimate 0.0.2-100 → 0.0.2-102
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 +43 -0
- package/dist/frontend-index.js +107 -3
- package/dist/index.cjs +127 -15
- package/dist/index.d.ts +43 -0
- package/dist/index.js +127 -15
- package/dist/mcp-server.cjs +127 -15
- package/dist/mcp-server.js +127 -15
- package/package.json +1 -1
package/dist/frontend-index.d.ts
CHANGED
|
@@ -450,6 +450,8 @@ export declare function generateGapTp(payload: {
|
|
|
450
450
|
entry: number;
|
|
451
451
|
quantity: number;
|
|
452
452
|
};
|
|
453
|
+
risk?: number;
|
|
454
|
+
kind?: "long" | "short";
|
|
453
455
|
factor?: number;
|
|
454
456
|
sell_factor?: number;
|
|
455
457
|
price_places?: string;
|
|
@@ -671,6 +673,8 @@ export declare class Strategy {
|
|
|
671
673
|
identifyGapConfig(payload: {
|
|
672
674
|
factor?: number;
|
|
673
675
|
sell_factor?: number;
|
|
676
|
+
kind?: "long" | "short";
|
|
677
|
+
risk?: number;
|
|
674
678
|
}): {
|
|
675
679
|
profit_percent: {
|
|
676
680
|
long: number;
|
|
@@ -716,6 +720,45 @@ export declare class Strategy {
|
|
|
716
720
|
price_places: string;
|
|
717
721
|
decimal_places: string;
|
|
718
722
|
};
|
|
723
|
+
simulateGapReduction(payload: {
|
|
724
|
+
iterations?: number;
|
|
725
|
+
factor?: number;
|
|
726
|
+
direction: "long" | "short";
|
|
727
|
+
kind?: "long" | "short";
|
|
728
|
+
risk?: number;
|
|
729
|
+
sell_factor?: number;
|
|
730
|
+
}): {
|
|
731
|
+
results: {
|
|
732
|
+
profit_percent: {
|
|
733
|
+
long: number;
|
|
734
|
+
short: number;
|
|
735
|
+
};
|
|
736
|
+
risk: {
|
|
737
|
+
short: number;
|
|
738
|
+
long: number;
|
|
739
|
+
};
|
|
740
|
+
take_profit: {
|
|
741
|
+
long: number;
|
|
742
|
+
short: number;
|
|
743
|
+
};
|
|
744
|
+
sell_quantity: {
|
|
745
|
+
short: number;
|
|
746
|
+
long: number;
|
|
747
|
+
};
|
|
748
|
+
gap_loss: number;
|
|
749
|
+
position: {
|
|
750
|
+
long: {
|
|
751
|
+
entry: number;
|
|
752
|
+
quantity: number;
|
|
753
|
+
};
|
|
754
|
+
short: {
|
|
755
|
+
entry: number;
|
|
756
|
+
quantity: number;
|
|
757
|
+
};
|
|
758
|
+
};
|
|
759
|
+
}[];
|
|
760
|
+
quantity: number;
|
|
761
|
+
};
|
|
719
762
|
}
|
|
720
763
|
|
|
721
764
|
export {};
|
package/dist/frontend-index.js
CHANGED
|
@@ -1809,11 +1809,26 @@ function generateGapTp(payload) {
|
|
|
1809
1809
|
const {
|
|
1810
1810
|
long,
|
|
1811
1811
|
short,
|
|
1812
|
-
factor =
|
|
1812
|
+
factor: factor_value = 0,
|
|
1813
|
+
risk: desired_risk,
|
|
1813
1814
|
sell_factor = 1,
|
|
1815
|
+
kind,
|
|
1814
1816
|
price_places = "%.1f",
|
|
1815
1817
|
decimal_places = "%.3f"
|
|
1816
1818
|
} = payload;
|
|
1819
|
+
if (!factor_value && !desired_risk) {
|
|
1820
|
+
throw new Error("Either factor or risk must be provided");
|
|
1821
|
+
}
|
|
1822
|
+
if (desired_risk && !kind) {
|
|
1823
|
+
throw new Error("Kind must be provided when risk is provided");
|
|
1824
|
+
}
|
|
1825
|
+
let factor = factor_value || calculate_factor({
|
|
1826
|
+
long,
|
|
1827
|
+
short,
|
|
1828
|
+
risk: desired_risk,
|
|
1829
|
+
kind,
|
|
1830
|
+
sell_factor
|
|
1831
|
+
});
|
|
1817
1832
|
const gap = Math.abs(long.entry - short.entry);
|
|
1818
1833
|
const max_quantity = Math.max(long.quantity, short.quantity);
|
|
1819
1834
|
const gapLoss = gap * max_quantity;
|
|
@@ -1826,7 +1841,7 @@ function generateGapTp(payload) {
|
|
|
1826
1841
|
const actualShortReduce = to_f(shortToReduce * sell_factor, "%.1f");
|
|
1827
1842
|
const actualLongReduce = to_f(longToReduce * sell_factor, "%.1f");
|
|
1828
1843
|
const short_quantity_to_sell = determine_amount_to_sell2(short.entry, short.quantity, longTp, actualShortReduce, "short", decimal_places);
|
|
1829
|
-
const long_quantity_to_sell = determine_amount_to_sell2(long.entry, long.quantity, shortTp,
|
|
1844
|
+
const long_quantity_to_sell = determine_amount_to_sell2(long.entry, long.quantity, shortTp, actualLongReduce, "long", decimal_places);
|
|
1830
1845
|
const risk_amount_short = to_f(shortToReduce - actualShortReduce, "%.2f");
|
|
1831
1846
|
const risk_amount_long = to_f(longToReduce - actualLongReduce, "%.2f");
|
|
1832
1847
|
const profit_percent_long = to_f(shortToReduce * 100 / (long.entry * long.quantity), "%.4f");
|
|
@@ -1860,6 +1875,32 @@ function generateGapTp(payload) {
|
|
|
1860
1875
|
gap_loss: to_f(gapLoss, "%.2f")
|
|
1861
1876
|
};
|
|
1862
1877
|
}
|
|
1878
|
+
function calculate_factor(payload) {
|
|
1879
|
+
const {
|
|
1880
|
+
long,
|
|
1881
|
+
short,
|
|
1882
|
+
risk: desired_risk,
|
|
1883
|
+
kind,
|
|
1884
|
+
sell_factor,
|
|
1885
|
+
places = "%.4f"
|
|
1886
|
+
} = payload;
|
|
1887
|
+
const gap = Math.abs(long.entry - short.entry);
|
|
1888
|
+
const max_quantity = Math.max(long.quantity, short.quantity);
|
|
1889
|
+
const gapLoss = gap * max_quantity;
|
|
1890
|
+
let calculated_factor;
|
|
1891
|
+
const long_notional = long.entry * long.quantity;
|
|
1892
|
+
const short_notional = short.entry * short.quantity;
|
|
1893
|
+
const target_to_reduce = desired_risk / (1 - sell_factor);
|
|
1894
|
+
if (kind === "short") {
|
|
1895
|
+
const calculate_longPercent = target_to_reduce / long_notional;
|
|
1896
|
+
calculated_factor = calculate_longPercent * short_notional / gapLoss;
|
|
1897
|
+
} else {
|
|
1898
|
+
const calculated_shortPercent = target_to_reduce / (short_notional - target_to_reduce);
|
|
1899
|
+
calculated_factor = calculated_shortPercent * long_notional / gapLoss;
|
|
1900
|
+
}
|
|
1901
|
+
calculated_factor = to_f(calculated_factor, places);
|
|
1902
|
+
return calculated_factor;
|
|
1903
|
+
}
|
|
1863
1904
|
// src/helpers/strategy.ts
|
|
1864
1905
|
class Strategy {
|
|
1865
1906
|
position;
|
|
@@ -2262,12 +2303,14 @@ class Strategy {
|
|
|
2262
2303
|
return { ...app_config, avg, loss: -expected_loss, profit_percent };
|
|
2263
2304
|
}
|
|
2264
2305
|
identifyGapConfig(payload) {
|
|
2265
|
-
const { factor = 1,
|
|
2306
|
+
const { factor, sell_factor = 1, kind, risk } = payload;
|
|
2266
2307
|
return generateGapTp({
|
|
2267
2308
|
long: this.position.long,
|
|
2268
2309
|
short: this.position.short,
|
|
2269
2310
|
factor,
|
|
2270
2311
|
sell_factor,
|
|
2312
|
+
kind,
|
|
2313
|
+
risk,
|
|
2271
2314
|
decimal_places: this.config.global_config.decimal_places,
|
|
2272
2315
|
price_places: this.config.global_config.price_places
|
|
2273
2316
|
});
|
|
@@ -2291,6 +2334,67 @@ class Strategy {
|
|
|
2291
2334
|
});
|
|
2292
2335
|
return result;
|
|
2293
2336
|
}
|
|
2337
|
+
simulateGapReduction(payload) {
|
|
2338
|
+
const {
|
|
2339
|
+
factor,
|
|
2340
|
+
direction,
|
|
2341
|
+
sell_factor = 1,
|
|
2342
|
+
iterations = 10,
|
|
2343
|
+
risk: desired_risk,
|
|
2344
|
+
kind
|
|
2345
|
+
} = payload;
|
|
2346
|
+
const results = [];
|
|
2347
|
+
let params = {
|
|
2348
|
+
long: this.position.long,
|
|
2349
|
+
short: this.position.short,
|
|
2350
|
+
config: this.config
|
|
2351
|
+
};
|
|
2352
|
+
for (let i = 0;i < iterations; i++) {
|
|
2353
|
+
const instance = new Strategy(params);
|
|
2354
|
+
const { profit_percent, risk, take_profit, sell_quantity, gap_loss } = instance.identifyGapConfig({
|
|
2355
|
+
factor,
|
|
2356
|
+
sell_factor,
|
|
2357
|
+
kind,
|
|
2358
|
+
risk: desired_risk
|
|
2359
|
+
});
|
|
2360
|
+
const to_add = {
|
|
2361
|
+
profit_percent,
|
|
2362
|
+
risk,
|
|
2363
|
+
take_profit,
|
|
2364
|
+
sell_quantity,
|
|
2365
|
+
gap_loss,
|
|
2366
|
+
position: {
|
|
2367
|
+
long: {
|
|
2368
|
+
entry: this.to_f(params.long.entry),
|
|
2369
|
+
quantity: this.to_df(params.long.quantity)
|
|
2370
|
+
},
|
|
2371
|
+
short: {
|
|
2372
|
+
entry: this.to_f(params.short.entry),
|
|
2373
|
+
quantity: this.to_df(params.short.quantity)
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
};
|
|
2377
|
+
results.push(to_add);
|
|
2378
|
+
const sell_kind = direction == "long" ? "short" : "long";
|
|
2379
|
+
const remaining = this.to_df(params[sell_kind].quantity - sell_quantity[sell_kind]);
|
|
2380
|
+
if (remaining <= 0) {
|
|
2381
|
+
break;
|
|
2382
|
+
}
|
|
2383
|
+
params[sell_kind].quantity = remaining;
|
|
2384
|
+
params[direction] = {
|
|
2385
|
+
entry: take_profit[direction],
|
|
2386
|
+
quantity: remaining
|
|
2387
|
+
};
|
|
2388
|
+
}
|
|
2389
|
+
const last_gap_loss = results.at(-1)?.gap_loss;
|
|
2390
|
+
const last_tp = results.at(-1)?.take_profit[direction];
|
|
2391
|
+
const entry = this.position[direction].entry;
|
|
2392
|
+
const quantity = this.to_df(Math.abs(last_tp - entry) / last_gap_loss);
|
|
2393
|
+
return {
|
|
2394
|
+
results,
|
|
2395
|
+
quantity
|
|
2396
|
+
};
|
|
2397
|
+
}
|
|
2294
2398
|
}
|
|
2295
2399
|
export {
|
|
2296
2400
|
to_f,
|
package/dist/index.cjs
CHANGED
|
@@ -53820,11 +53820,26 @@ function generateGapTp(payload) {
|
|
|
53820
53820
|
const {
|
|
53821
53821
|
long,
|
|
53822
53822
|
short,
|
|
53823
|
-
factor =
|
|
53823
|
+
factor: factor_value = 0,
|
|
53824
|
+
risk: desired_risk,
|
|
53824
53825
|
sell_factor = 1,
|
|
53826
|
+
kind,
|
|
53825
53827
|
price_places = "%.1f",
|
|
53826
53828
|
decimal_places = "%.3f"
|
|
53827
53829
|
} = payload;
|
|
53830
|
+
if (!factor_value && !desired_risk) {
|
|
53831
|
+
throw new Error("Either factor or risk must be provided");
|
|
53832
|
+
}
|
|
53833
|
+
if (desired_risk && !kind) {
|
|
53834
|
+
throw new Error("Kind must be provided when risk is provided");
|
|
53835
|
+
}
|
|
53836
|
+
let factor = factor_value || calculate_factor({
|
|
53837
|
+
long,
|
|
53838
|
+
short,
|
|
53839
|
+
risk: desired_risk,
|
|
53840
|
+
kind,
|
|
53841
|
+
sell_factor
|
|
53842
|
+
});
|
|
53828
53843
|
const gap = Math.abs(long.entry - short.entry);
|
|
53829
53844
|
const max_quantity = Math.max(long.quantity, short.quantity);
|
|
53830
53845
|
const gapLoss = gap * max_quantity;
|
|
@@ -53837,7 +53852,7 @@ function generateGapTp(payload) {
|
|
|
53837
53852
|
const actualShortReduce = to_f2(shortToReduce * sell_factor, "%.1f");
|
|
53838
53853
|
const actualLongReduce = to_f2(longToReduce * sell_factor, "%.1f");
|
|
53839
53854
|
const short_quantity_to_sell = determine_amount_to_sell2(short.entry, short.quantity, longTp, actualShortReduce, "short", decimal_places);
|
|
53840
|
-
const long_quantity_to_sell = determine_amount_to_sell2(long.entry, long.quantity, shortTp,
|
|
53855
|
+
const long_quantity_to_sell = determine_amount_to_sell2(long.entry, long.quantity, shortTp, actualLongReduce, "long", decimal_places);
|
|
53841
53856
|
const risk_amount_short = to_f2(shortToReduce - actualShortReduce, "%.2f");
|
|
53842
53857
|
const risk_amount_long = to_f2(longToReduce - actualLongReduce, "%.2f");
|
|
53843
53858
|
const profit_percent_long = to_f2(shortToReduce * 100 / (long.entry * long.quantity), "%.4f");
|
|
@@ -53871,6 +53886,32 @@ function generateGapTp(payload) {
|
|
|
53871
53886
|
gap_loss: to_f2(gapLoss, "%.2f")
|
|
53872
53887
|
};
|
|
53873
53888
|
}
|
|
53889
|
+
function calculate_factor(payload) {
|
|
53890
|
+
const {
|
|
53891
|
+
long,
|
|
53892
|
+
short,
|
|
53893
|
+
risk: desired_risk,
|
|
53894
|
+
kind,
|
|
53895
|
+
sell_factor,
|
|
53896
|
+
places = "%.4f"
|
|
53897
|
+
} = payload;
|
|
53898
|
+
const gap = Math.abs(long.entry - short.entry);
|
|
53899
|
+
const max_quantity = Math.max(long.quantity, short.quantity);
|
|
53900
|
+
const gapLoss = gap * max_quantity;
|
|
53901
|
+
let calculated_factor;
|
|
53902
|
+
const long_notional = long.entry * long.quantity;
|
|
53903
|
+
const short_notional = short.entry * short.quantity;
|
|
53904
|
+
const target_to_reduce = desired_risk / (1 - sell_factor);
|
|
53905
|
+
if (kind === "short") {
|
|
53906
|
+
const calculate_longPercent = target_to_reduce / long_notional;
|
|
53907
|
+
calculated_factor = calculate_longPercent * short_notional / gapLoss;
|
|
53908
|
+
} else {
|
|
53909
|
+
const calculated_shortPercent = target_to_reduce / (short_notional - target_to_reduce);
|
|
53910
|
+
calculated_factor = calculated_shortPercent * long_notional / gapLoss;
|
|
53911
|
+
}
|
|
53912
|
+
calculated_factor = to_f2(calculated_factor, places);
|
|
53913
|
+
return calculated_factor;
|
|
53914
|
+
}
|
|
53874
53915
|
|
|
53875
53916
|
// src/helpers/strategy.ts
|
|
53876
53917
|
class Strategy {
|
|
@@ -54274,12 +54315,14 @@ class Strategy {
|
|
|
54274
54315
|
return { ...app_config, avg, loss: -expected_loss, profit_percent };
|
|
54275
54316
|
}
|
|
54276
54317
|
identifyGapConfig(payload) {
|
|
54277
|
-
const { factor = 1,
|
|
54318
|
+
const { factor, sell_factor = 1, kind, risk } = payload;
|
|
54278
54319
|
return generateGapTp({
|
|
54279
54320
|
long: this.position.long,
|
|
54280
54321
|
short: this.position.short,
|
|
54281
54322
|
factor,
|
|
54282
54323
|
sell_factor,
|
|
54324
|
+
kind,
|
|
54325
|
+
risk,
|
|
54283
54326
|
decimal_places: this.config.global_config.decimal_places,
|
|
54284
54327
|
price_places: this.config.global_config.price_places
|
|
54285
54328
|
});
|
|
@@ -54303,6 +54346,67 @@ class Strategy {
|
|
|
54303
54346
|
});
|
|
54304
54347
|
return result;
|
|
54305
54348
|
}
|
|
54349
|
+
simulateGapReduction(payload) {
|
|
54350
|
+
const {
|
|
54351
|
+
factor,
|
|
54352
|
+
direction,
|
|
54353
|
+
sell_factor = 1,
|
|
54354
|
+
iterations = 10,
|
|
54355
|
+
risk: desired_risk,
|
|
54356
|
+
kind
|
|
54357
|
+
} = payload;
|
|
54358
|
+
const results = [];
|
|
54359
|
+
let params = {
|
|
54360
|
+
long: this.position.long,
|
|
54361
|
+
short: this.position.short,
|
|
54362
|
+
config: this.config
|
|
54363
|
+
};
|
|
54364
|
+
for (let i2 = 0;i2 < iterations; i2++) {
|
|
54365
|
+
const instance = new Strategy(params);
|
|
54366
|
+
const { profit_percent, risk, take_profit, sell_quantity, gap_loss } = instance.identifyGapConfig({
|
|
54367
|
+
factor,
|
|
54368
|
+
sell_factor,
|
|
54369
|
+
kind,
|
|
54370
|
+
risk: desired_risk
|
|
54371
|
+
});
|
|
54372
|
+
const to_add = {
|
|
54373
|
+
profit_percent,
|
|
54374
|
+
risk,
|
|
54375
|
+
take_profit,
|
|
54376
|
+
sell_quantity,
|
|
54377
|
+
gap_loss,
|
|
54378
|
+
position: {
|
|
54379
|
+
long: {
|
|
54380
|
+
entry: this.to_f(params.long.entry),
|
|
54381
|
+
quantity: this.to_df(params.long.quantity)
|
|
54382
|
+
},
|
|
54383
|
+
short: {
|
|
54384
|
+
entry: this.to_f(params.short.entry),
|
|
54385
|
+
quantity: this.to_df(params.short.quantity)
|
|
54386
|
+
}
|
|
54387
|
+
}
|
|
54388
|
+
};
|
|
54389
|
+
results.push(to_add);
|
|
54390
|
+
const sell_kind = direction == "long" ? "short" : "long";
|
|
54391
|
+
const remaining = this.to_df(params[sell_kind].quantity - sell_quantity[sell_kind]);
|
|
54392
|
+
if (remaining <= 0) {
|
|
54393
|
+
break;
|
|
54394
|
+
}
|
|
54395
|
+
params[sell_kind].quantity = remaining;
|
|
54396
|
+
params[direction] = {
|
|
54397
|
+
entry: take_profit[direction],
|
|
54398
|
+
quantity: remaining
|
|
54399
|
+
};
|
|
54400
|
+
}
|
|
54401
|
+
const last_gap_loss = results.at(-1)?.gap_loss;
|
|
54402
|
+
const last_tp = results.at(-1)?.take_profit[direction];
|
|
54403
|
+
const entry = this.position[direction].entry;
|
|
54404
|
+
const quantity = this.to_df(Math.abs(last_tp - entry) / last_gap_loss);
|
|
54405
|
+
return {
|
|
54406
|
+
results,
|
|
54407
|
+
quantity
|
|
54408
|
+
};
|
|
54409
|
+
}
|
|
54306
54410
|
}
|
|
54307
54411
|
|
|
54308
54412
|
// src/exchanges/binance.ts
|
|
@@ -58199,19 +58303,24 @@ class ExchangeAccount {
|
|
|
58199
58303
|
kind,
|
|
58200
58304
|
raw: true
|
|
58201
58305
|
});
|
|
58202
|
-
|
|
58203
|
-
|
|
58204
|
-
|
|
58205
|
-
|
|
58206
|
-
|
|
58207
|
-
|
|
58208
|
-
|
|
58209
|
-
|
|
58210
|
-
|
|
58211
|
-
|
|
58212
|
-
|
|
58306
|
+
try {
|
|
58307
|
+
const result = strategy.generateOppositeTrades({
|
|
58308
|
+
kind,
|
|
58309
|
+
avg_entry: strategy.position[kind].avg_price
|
|
58310
|
+
});
|
|
58311
|
+
if (place && result?.kind) {
|
|
58312
|
+
const _symbol = place_symbol || symbol;
|
|
58313
|
+
await this.placeOppositeTradeAction({
|
|
58314
|
+
symbol: _symbol,
|
|
58315
|
+
kind: result.kind,
|
|
58316
|
+
data: result
|
|
58317
|
+
});
|
|
58318
|
+
}
|
|
58319
|
+
return result;
|
|
58320
|
+
} catch (error) {
|
|
58321
|
+
console.log("Error in buildOppositeTrades", error);
|
|
58322
|
+
return null;
|
|
58213
58323
|
}
|
|
58214
|
-
return result;
|
|
58215
58324
|
}
|
|
58216
58325
|
async runSimulation(payload) {
|
|
58217
58326
|
const { symbol, kind, iterations = 2, raw = false } = payload;
|
|
@@ -59056,6 +59165,9 @@ class ExchangeAccount {
|
|
|
59056
59165
|
symbol,
|
|
59057
59166
|
kind
|
|
59058
59167
|
});
|
|
59168
|
+
if (!reverse_action) {
|
|
59169
|
+
return;
|
|
59170
|
+
}
|
|
59059
59171
|
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
59060
59172
|
await this.getPositionConfig({
|
|
59061
59173
|
symbol,
|
package/dist/index.d.ts
CHANGED
|
@@ -760,6 +760,8 @@ export declare class Strategy {
|
|
|
760
760
|
identifyGapConfig(payload: {
|
|
761
761
|
factor?: number;
|
|
762
762
|
sell_factor?: number;
|
|
763
|
+
kind?: "long" | "short";
|
|
764
|
+
risk?: number;
|
|
763
765
|
}): {
|
|
764
766
|
profit_percent: {
|
|
765
767
|
long: number;
|
|
@@ -805,6 +807,45 @@ export declare class Strategy {
|
|
|
805
807
|
price_places: string;
|
|
806
808
|
decimal_places: string;
|
|
807
809
|
};
|
|
810
|
+
simulateGapReduction(payload: {
|
|
811
|
+
iterations?: number;
|
|
812
|
+
factor?: number;
|
|
813
|
+
direction: "long" | "short";
|
|
814
|
+
kind?: "long" | "short";
|
|
815
|
+
risk?: number;
|
|
816
|
+
sell_factor?: number;
|
|
817
|
+
}): {
|
|
818
|
+
results: {
|
|
819
|
+
profit_percent: {
|
|
820
|
+
long: number;
|
|
821
|
+
short: number;
|
|
822
|
+
};
|
|
823
|
+
risk: {
|
|
824
|
+
short: number;
|
|
825
|
+
long: number;
|
|
826
|
+
};
|
|
827
|
+
take_profit: {
|
|
828
|
+
long: number;
|
|
829
|
+
short: number;
|
|
830
|
+
};
|
|
831
|
+
sell_quantity: {
|
|
832
|
+
short: number;
|
|
833
|
+
long: number;
|
|
834
|
+
};
|
|
835
|
+
gap_loss: number;
|
|
836
|
+
position: {
|
|
837
|
+
long: {
|
|
838
|
+
entry: number;
|
|
839
|
+
quantity: number;
|
|
840
|
+
};
|
|
841
|
+
short: {
|
|
842
|
+
entry: number;
|
|
843
|
+
quantity: number;
|
|
844
|
+
};
|
|
845
|
+
};
|
|
846
|
+
}[];
|
|
847
|
+
quantity: number;
|
|
848
|
+
};
|
|
808
849
|
}
|
|
809
850
|
export type SignalConfigType = {
|
|
810
851
|
focus: number;
|
|
@@ -1166,6 +1207,8 @@ export declare function generateGapTp(payload: {
|
|
|
1166
1207
|
entry: number;
|
|
1167
1208
|
quantity: number;
|
|
1168
1209
|
};
|
|
1210
|
+
risk?: number;
|
|
1211
|
+
kind?: "long" | "short";
|
|
1169
1212
|
factor?: number;
|
|
1170
1213
|
sell_factor?: number;
|
|
1171
1214
|
price_places?: string;
|
package/dist/index.js
CHANGED
|
@@ -53769,11 +53769,26 @@ function generateGapTp(payload) {
|
|
|
53769
53769
|
const {
|
|
53770
53770
|
long,
|
|
53771
53771
|
short,
|
|
53772
|
-
factor =
|
|
53772
|
+
factor: factor_value = 0,
|
|
53773
|
+
risk: desired_risk,
|
|
53773
53774
|
sell_factor = 1,
|
|
53775
|
+
kind,
|
|
53774
53776
|
price_places = "%.1f",
|
|
53775
53777
|
decimal_places = "%.3f"
|
|
53776
53778
|
} = payload;
|
|
53779
|
+
if (!factor_value && !desired_risk) {
|
|
53780
|
+
throw new Error("Either factor or risk must be provided");
|
|
53781
|
+
}
|
|
53782
|
+
if (desired_risk && !kind) {
|
|
53783
|
+
throw new Error("Kind must be provided when risk is provided");
|
|
53784
|
+
}
|
|
53785
|
+
let factor = factor_value || calculate_factor({
|
|
53786
|
+
long,
|
|
53787
|
+
short,
|
|
53788
|
+
risk: desired_risk,
|
|
53789
|
+
kind,
|
|
53790
|
+
sell_factor
|
|
53791
|
+
});
|
|
53777
53792
|
const gap = Math.abs(long.entry - short.entry);
|
|
53778
53793
|
const max_quantity = Math.max(long.quantity, short.quantity);
|
|
53779
53794
|
const gapLoss = gap * max_quantity;
|
|
@@ -53786,7 +53801,7 @@ function generateGapTp(payload) {
|
|
|
53786
53801
|
const actualShortReduce = to_f2(shortToReduce * sell_factor, "%.1f");
|
|
53787
53802
|
const actualLongReduce = to_f2(longToReduce * sell_factor, "%.1f");
|
|
53788
53803
|
const short_quantity_to_sell = determine_amount_to_sell2(short.entry, short.quantity, longTp, actualShortReduce, "short", decimal_places);
|
|
53789
|
-
const long_quantity_to_sell = determine_amount_to_sell2(long.entry, long.quantity, shortTp,
|
|
53804
|
+
const long_quantity_to_sell = determine_amount_to_sell2(long.entry, long.quantity, shortTp, actualLongReduce, "long", decimal_places);
|
|
53790
53805
|
const risk_amount_short = to_f2(shortToReduce - actualShortReduce, "%.2f");
|
|
53791
53806
|
const risk_amount_long = to_f2(longToReduce - actualLongReduce, "%.2f");
|
|
53792
53807
|
const profit_percent_long = to_f2(shortToReduce * 100 / (long.entry * long.quantity), "%.4f");
|
|
@@ -53820,6 +53835,32 @@ function generateGapTp(payload) {
|
|
|
53820
53835
|
gap_loss: to_f2(gapLoss, "%.2f")
|
|
53821
53836
|
};
|
|
53822
53837
|
}
|
|
53838
|
+
function calculate_factor(payload) {
|
|
53839
|
+
const {
|
|
53840
|
+
long,
|
|
53841
|
+
short,
|
|
53842
|
+
risk: desired_risk,
|
|
53843
|
+
kind,
|
|
53844
|
+
sell_factor,
|
|
53845
|
+
places = "%.4f"
|
|
53846
|
+
} = payload;
|
|
53847
|
+
const gap = Math.abs(long.entry - short.entry);
|
|
53848
|
+
const max_quantity = Math.max(long.quantity, short.quantity);
|
|
53849
|
+
const gapLoss = gap * max_quantity;
|
|
53850
|
+
let calculated_factor;
|
|
53851
|
+
const long_notional = long.entry * long.quantity;
|
|
53852
|
+
const short_notional = short.entry * short.quantity;
|
|
53853
|
+
const target_to_reduce = desired_risk / (1 - sell_factor);
|
|
53854
|
+
if (kind === "short") {
|
|
53855
|
+
const calculate_longPercent = target_to_reduce / long_notional;
|
|
53856
|
+
calculated_factor = calculate_longPercent * short_notional / gapLoss;
|
|
53857
|
+
} else {
|
|
53858
|
+
const calculated_shortPercent = target_to_reduce / (short_notional - target_to_reduce);
|
|
53859
|
+
calculated_factor = calculated_shortPercent * long_notional / gapLoss;
|
|
53860
|
+
}
|
|
53861
|
+
calculated_factor = to_f2(calculated_factor, places);
|
|
53862
|
+
return calculated_factor;
|
|
53863
|
+
}
|
|
53823
53864
|
|
|
53824
53865
|
// src/helpers/strategy.ts
|
|
53825
53866
|
class Strategy {
|
|
@@ -54223,12 +54264,14 @@ class Strategy {
|
|
|
54223
54264
|
return { ...app_config, avg, loss: -expected_loss, profit_percent };
|
|
54224
54265
|
}
|
|
54225
54266
|
identifyGapConfig(payload) {
|
|
54226
|
-
const { factor = 1,
|
|
54267
|
+
const { factor, sell_factor = 1, kind, risk } = payload;
|
|
54227
54268
|
return generateGapTp({
|
|
54228
54269
|
long: this.position.long,
|
|
54229
54270
|
short: this.position.short,
|
|
54230
54271
|
factor,
|
|
54231
54272
|
sell_factor,
|
|
54273
|
+
kind,
|
|
54274
|
+
risk,
|
|
54232
54275
|
decimal_places: this.config.global_config.decimal_places,
|
|
54233
54276
|
price_places: this.config.global_config.price_places
|
|
54234
54277
|
});
|
|
@@ -54252,6 +54295,67 @@ class Strategy {
|
|
|
54252
54295
|
});
|
|
54253
54296
|
return result;
|
|
54254
54297
|
}
|
|
54298
|
+
simulateGapReduction(payload) {
|
|
54299
|
+
const {
|
|
54300
|
+
factor,
|
|
54301
|
+
direction,
|
|
54302
|
+
sell_factor = 1,
|
|
54303
|
+
iterations = 10,
|
|
54304
|
+
risk: desired_risk,
|
|
54305
|
+
kind
|
|
54306
|
+
} = payload;
|
|
54307
|
+
const results = [];
|
|
54308
|
+
let params = {
|
|
54309
|
+
long: this.position.long,
|
|
54310
|
+
short: this.position.short,
|
|
54311
|
+
config: this.config
|
|
54312
|
+
};
|
|
54313
|
+
for (let i2 = 0;i2 < iterations; i2++) {
|
|
54314
|
+
const instance = new Strategy(params);
|
|
54315
|
+
const { profit_percent, risk, take_profit, sell_quantity, gap_loss } = instance.identifyGapConfig({
|
|
54316
|
+
factor,
|
|
54317
|
+
sell_factor,
|
|
54318
|
+
kind,
|
|
54319
|
+
risk: desired_risk
|
|
54320
|
+
});
|
|
54321
|
+
const to_add = {
|
|
54322
|
+
profit_percent,
|
|
54323
|
+
risk,
|
|
54324
|
+
take_profit,
|
|
54325
|
+
sell_quantity,
|
|
54326
|
+
gap_loss,
|
|
54327
|
+
position: {
|
|
54328
|
+
long: {
|
|
54329
|
+
entry: this.to_f(params.long.entry),
|
|
54330
|
+
quantity: this.to_df(params.long.quantity)
|
|
54331
|
+
},
|
|
54332
|
+
short: {
|
|
54333
|
+
entry: this.to_f(params.short.entry),
|
|
54334
|
+
quantity: this.to_df(params.short.quantity)
|
|
54335
|
+
}
|
|
54336
|
+
}
|
|
54337
|
+
};
|
|
54338
|
+
results.push(to_add);
|
|
54339
|
+
const sell_kind = direction == "long" ? "short" : "long";
|
|
54340
|
+
const remaining = this.to_df(params[sell_kind].quantity - sell_quantity[sell_kind]);
|
|
54341
|
+
if (remaining <= 0) {
|
|
54342
|
+
break;
|
|
54343
|
+
}
|
|
54344
|
+
params[sell_kind].quantity = remaining;
|
|
54345
|
+
params[direction] = {
|
|
54346
|
+
entry: take_profit[direction],
|
|
54347
|
+
quantity: remaining
|
|
54348
|
+
};
|
|
54349
|
+
}
|
|
54350
|
+
const last_gap_loss = results.at(-1)?.gap_loss;
|
|
54351
|
+
const last_tp = results.at(-1)?.take_profit[direction];
|
|
54352
|
+
const entry = this.position[direction].entry;
|
|
54353
|
+
const quantity = this.to_df(Math.abs(last_tp - entry) / last_gap_loss);
|
|
54354
|
+
return {
|
|
54355
|
+
results,
|
|
54356
|
+
quantity
|
|
54357
|
+
};
|
|
54358
|
+
}
|
|
54255
54359
|
}
|
|
54256
54360
|
|
|
54257
54361
|
// src/exchanges/binance.ts
|
|
@@ -58148,19 +58252,24 @@ class ExchangeAccount {
|
|
|
58148
58252
|
kind,
|
|
58149
58253
|
raw: true
|
|
58150
58254
|
});
|
|
58151
|
-
|
|
58152
|
-
|
|
58153
|
-
|
|
58154
|
-
|
|
58155
|
-
|
|
58156
|
-
|
|
58157
|
-
|
|
58158
|
-
|
|
58159
|
-
|
|
58160
|
-
|
|
58161
|
-
|
|
58255
|
+
try {
|
|
58256
|
+
const result = strategy.generateOppositeTrades({
|
|
58257
|
+
kind,
|
|
58258
|
+
avg_entry: strategy.position[kind].avg_price
|
|
58259
|
+
});
|
|
58260
|
+
if (place && result?.kind) {
|
|
58261
|
+
const _symbol = place_symbol || symbol;
|
|
58262
|
+
await this.placeOppositeTradeAction({
|
|
58263
|
+
symbol: _symbol,
|
|
58264
|
+
kind: result.kind,
|
|
58265
|
+
data: result
|
|
58266
|
+
});
|
|
58267
|
+
}
|
|
58268
|
+
return result;
|
|
58269
|
+
} catch (error) {
|
|
58270
|
+
console.log("Error in buildOppositeTrades", error);
|
|
58271
|
+
return null;
|
|
58162
58272
|
}
|
|
58163
|
-
return result;
|
|
58164
58273
|
}
|
|
58165
58274
|
async runSimulation(payload) {
|
|
58166
58275
|
const { symbol, kind, iterations = 2, raw = false } = payload;
|
|
@@ -59005,6 +59114,9 @@ class ExchangeAccount {
|
|
|
59005
59114
|
symbol,
|
|
59006
59115
|
kind
|
|
59007
59116
|
});
|
|
59117
|
+
if (!reverse_action) {
|
|
59118
|
+
return;
|
|
59119
|
+
}
|
|
59008
59120
|
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
59009
59121
|
await this.getPositionConfig({
|
|
59010
59122
|
symbol,
|
package/dist/mcp-server.cjs
CHANGED
|
@@ -60507,11 +60507,26 @@ function generateGapTp(payload) {
|
|
|
60507
60507
|
const {
|
|
60508
60508
|
long,
|
|
60509
60509
|
short,
|
|
60510
|
-
factor =
|
|
60510
|
+
factor: factor_value = 0,
|
|
60511
|
+
risk: desired_risk,
|
|
60511
60512
|
sell_factor = 1,
|
|
60513
|
+
kind,
|
|
60512
60514
|
price_places = "%.1f",
|
|
60513
60515
|
decimal_places = "%.3f"
|
|
60514
60516
|
} = payload;
|
|
60517
|
+
if (!factor_value && !desired_risk) {
|
|
60518
|
+
throw new Error("Either factor or risk must be provided");
|
|
60519
|
+
}
|
|
60520
|
+
if (desired_risk && !kind) {
|
|
60521
|
+
throw new Error("Kind must be provided when risk is provided");
|
|
60522
|
+
}
|
|
60523
|
+
let factor = factor_value || calculate_factor({
|
|
60524
|
+
long,
|
|
60525
|
+
short,
|
|
60526
|
+
risk: desired_risk,
|
|
60527
|
+
kind,
|
|
60528
|
+
sell_factor
|
|
60529
|
+
});
|
|
60515
60530
|
const gap = Math.abs(long.entry - short.entry);
|
|
60516
60531
|
const max_quantity = Math.max(long.quantity, short.quantity);
|
|
60517
60532
|
const gapLoss = gap * max_quantity;
|
|
@@ -60524,7 +60539,7 @@ function generateGapTp(payload) {
|
|
|
60524
60539
|
const actualShortReduce = to_f2(shortToReduce * sell_factor, "%.1f");
|
|
60525
60540
|
const actualLongReduce = to_f2(longToReduce * sell_factor, "%.1f");
|
|
60526
60541
|
const short_quantity_to_sell = determine_amount_to_sell2(short.entry, short.quantity, longTp, actualShortReduce, "short", decimal_places);
|
|
60527
|
-
const long_quantity_to_sell = determine_amount_to_sell2(long.entry, long.quantity, shortTp,
|
|
60542
|
+
const long_quantity_to_sell = determine_amount_to_sell2(long.entry, long.quantity, shortTp, actualLongReduce, "long", decimal_places);
|
|
60528
60543
|
const risk_amount_short = to_f2(shortToReduce - actualShortReduce, "%.2f");
|
|
60529
60544
|
const risk_amount_long = to_f2(longToReduce - actualLongReduce, "%.2f");
|
|
60530
60545
|
const profit_percent_long = to_f2(shortToReduce * 100 / (long.entry * long.quantity), "%.4f");
|
|
@@ -60558,6 +60573,32 @@ function generateGapTp(payload) {
|
|
|
60558
60573
|
gap_loss: to_f2(gapLoss, "%.2f")
|
|
60559
60574
|
};
|
|
60560
60575
|
}
|
|
60576
|
+
function calculate_factor(payload) {
|
|
60577
|
+
const {
|
|
60578
|
+
long,
|
|
60579
|
+
short,
|
|
60580
|
+
risk: desired_risk,
|
|
60581
|
+
kind,
|
|
60582
|
+
sell_factor,
|
|
60583
|
+
places = "%.4f"
|
|
60584
|
+
} = payload;
|
|
60585
|
+
const gap = Math.abs(long.entry - short.entry);
|
|
60586
|
+
const max_quantity = Math.max(long.quantity, short.quantity);
|
|
60587
|
+
const gapLoss = gap * max_quantity;
|
|
60588
|
+
let calculated_factor;
|
|
60589
|
+
const long_notional = long.entry * long.quantity;
|
|
60590
|
+
const short_notional = short.entry * short.quantity;
|
|
60591
|
+
const target_to_reduce = desired_risk / (1 - sell_factor);
|
|
60592
|
+
if (kind === "short") {
|
|
60593
|
+
const calculate_longPercent = target_to_reduce / long_notional;
|
|
60594
|
+
calculated_factor = calculate_longPercent * short_notional / gapLoss;
|
|
60595
|
+
} else {
|
|
60596
|
+
const calculated_shortPercent = target_to_reduce / (short_notional - target_to_reduce);
|
|
60597
|
+
calculated_factor = calculated_shortPercent * long_notional / gapLoss;
|
|
60598
|
+
}
|
|
60599
|
+
calculated_factor = to_f2(calculated_factor, places);
|
|
60600
|
+
return calculated_factor;
|
|
60601
|
+
}
|
|
60561
60602
|
|
|
60562
60603
|
// src/helpers/strategy.ts
|
|
60563
60604
|
class Strategy {
|
|
@@ -60961,12 +61002,14 @@ class Strategy {
|
|
|
60961
61002
|
return { ...app_config, avg, loss: -expected_loss, profit_percent };
|
|
60962
61003
|
}
|
|
60963
61004
|
identifyGapConfig(payload) {
|
|
60964
|
-
const { factor = 1,
|
|
61005
|
+
const { factor, sell_factor = 1, kind, risk } = payload;
|
|
60965
61006
|
return generateGapTp({
|
|
60966
61007
|
long: this.position.long,
|
|
60967
61008
|
short: this.position.short,
|
|
60968
61009
|
factor,
|
|
60969
61010
|
sell_factor,
|
|
61011
|
+
kind,
|
|
61012
|
+
risk,
|
|
60970
61013
|
decimal_places: this.config.global_config.decimal_places,
|
|
60971
61014
|
price_places: this.config.global_config.price_places
|
|
60972
61015
|
});
|
|
@@ -60990,6 +61033,67 @@ class Strategy {
|
|
|
60990
61033
|
});
|
|
60991
61034
|
return result;
|
|
60992
61035
|
}
|
|
61036
|
+
simulateGapReduction(payload) {
|
|
61037
|
+
const {
|
|
61038
|
+
factor,
|
|
61039
|
+
direction,
|
|
61040
|
+
sell_factor = 1,
|
|
61041
|
+
iterations = 10,
|
|
61042
|
+
risk: desired_risk,
|
|
61043
|
+
kind
|
|
61044
|
+
} = payload;
|
|
61045
|
+
const results = [];
|
|
61046
|
+
let params = {
|
|
61047
|
+
long: this.position.long,
|
|
61048
|
+
short: this.position.short,
|
|
61049
|
+
config: this.config
|
|
61050
|
+
};
|
|
61051
|
+
for (let i2 = 0;i2 < iterations; i2++) {
|
|
61052
|
+
const instance = new Strategy(params);
|
|
61053
|
+
const { profit_percent, risk, take_profit, sell_quantity, gap_loss } = instance.identifyGapConfig({
|
|
61054
|
+
factor,
|
|
61055
|
+
sell_factor,
|
|
61056
|
+
kind,
|
|
61057
|
+
risk: desired_risk
|
|
61058
|
+
});
|
|
61059
|
+
const to_add = {
|
|
61060
|
+
profit_percent,
|
|
61061
|
+
risk,
|
|
61062
|
+
take_profit,
|
|
61063
|
+
sell_quantity,
|
|
61064
|
+
gap_loss,
|
|
61065
|
+
position: {
|
|
61066
|
+
long: {
|
|
61067
|
+
entry: this.to_f(params.long.entry),
|
|
61068
|
+
quantity: this.to_df(params.long.quantity)
|
|
61069
|
+
},
|
|
61070
|
+
short: {
|
|
61071
|
+
entry: this.to_f(params.short.entry),
|
|
61072
|
+
quantity: this.to_df(params.short.quantity)
|
|
61073
|
+
}
|
|
61074
|
+
}
|
|
61075
|
+
};
|
|
61076
|
+
results.push(to_add);
|
|
61077
|
+
const sell_kind = direction == "long" ? "short" : "long";
|
|
61078
|
+
const remaining = this.to_df(params[sell_kind].quantity - sell_quantity[sell_kind]);
|
|
61079
|
+
if (remaining <= 0) {
|
|
61080
|
+
break;
|
|
61081
|
+
}
|
|
61082
|
+
params[sell_kind].quantity = remaining;
|
|
61083
|
+
params[direction] = {
|
|
61084
|
+
entry: take_profit[direction],
|
|
61085
|
+
quantity: remaining
|
|
61086
|
+
};
|
|
61087
|
+
}
|
|
61088
|
+
const last_gap_loss = results.at(-1)?.gap_loss;
|
|
61089
|
+
const last_tp = results.at(-1)?.take_profit[direction];
|
|
61090
|
+
const entry = this.position[direction].entry;
|
|
61091
|
+
const quantity = this.to_df(Math.abs(last_tp - entry) / last_gap_loss);
|
|
61092
|
+
return {
|
|
61093
|
+
results,
|
|
61094
|
+
quantity
|
|
61095
|
+
};
|
|
61096
|
+
}
|
|
60993
61097
|
}
|
|
60994
61098
|
|
|
60995
61099
|
// src/exchanges/binance.ts
|
|
@@ -64886,19 +64990,24 @@ class ExchangeAccount {
|
|
|
64886
64990
|
kind,
|
|
64887
64991
|
raw: true
|
|
64888
64992
|
});
|
|
64889
|
-
|
|
64890
|
-
|
|
64891
|
-
|
|
64892
|
-
|
|
64893
|
-
|
|
64894
|
-
|
|
64895
|
-
|
|
64896
|
-
|
|
64897
|
-
|
|
64898
|
-
|
|
64899
|
-
|
|
64993
|
+
try {
|
|
64994
|
+
const result = strategy.generateOppositeTrades({
|
|
64995
|
+
kind,
|
|
64996
|
+
avg_entry: strategy.position[kind].avg_price
|
|
64997
|
+
});
|
|
64998
|
+
if (place && result?.kind) {
|
|
64999
|
+
const _symbol = place_symbol || symbol;
|
|
65000
|
+
await this.placeOppositeTradeAction({
|
|
65001
|
+
symbol: _symbol,
|
|
65002
|
+
kind: result.kind,
|
|
65003
|
+
data: result
|
|
65004
|
+
});
|
|
65005
|
+
}
|
|
65006
|
+
return result;
|
|
65007
|
+
} catch (error) {
|
|
65008
|
+
console.log("Error in buildOppositeTrades", error);
|
|
65009
|
+
return null;
|
|
64900
65010
|
}
|
|
64901
|
-
return result;
|
|
64902
65011
|
}
|
|
64903
65012
|
async runSimulation(payload) {
|
|
64904
65013
|
const { symbol, kind, iterations = 2, raw = false } = payload;
|
|
@@ -65743,6 +65852,9 @@ class ExchangeAccount {
|
|
|
65743
65852
|
symbol,
|
|
65744
65853
|
kind
|
|
65745
65854
|
});
|
|
65855
|
+
if (!reverse_action) {
|
|
65856
|
+
return;
|
|
65857
|
+
}
|
|
65746
65858
|
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
65747
65859
|
await this.getPositionConfig({
|
|
65748
65860
|
symbol,
|
package/dist/mcp-server.js
CHANGED
|
@@ -60480,11 +60480,26 @@ function generateGapTp(payload) {
|
|
|
60480
60480
|
const {
|
|
60481
60481
|
long,
|
|
60482
60482
|
short,
|
|
60483
|
-
factor =
|
|
60483
|
+
factor: factor_value = 0,
|
|
60484
|
+
risk: desired_risk,
|
|
60484
60485
|
sell_factor = 1,
|
|
60486
|
+
kind,
|
|
60485
60487
|
price_places = "%.1f",
|
|
60486
60488
|
decimal_places = "%.3f"
|
|
60487
60489
|
} = payload;
|
|
60490
|
+
if (!factor_value && !desired_risk) {
|
|
60491
|
+
throw new Error("Either factor or risk must be provided");
|
|
60492
|
+
}
|
|
60493
|
+
if (desired_risk && !kind) {
|
|
60494
|
+
throw new Error("Kind must be provided when risk is provided");
|
|
60495
|
+
}
|
|
60496
|
+
let factor = factor_value || calculate_factor({
|
|
60497
|
+
long,
|
|
60498
|
+
short,
|
|
60499
|
+
risk: desired_risk,
|
|
60500
|
+
kind,
|
|
60501
|
+
sell_factor
|
|
60502
|
+
});
|
|
60488
60503
|
const gap = Math.abs(long.entry - short.entry);
|
|
60489
60504
|
const max_quantity = Math.max(long.quantity, short.quantity);
|
|
60490
60505
|
const gapLoss = gap * max_quantity;
|
|
@@ -60497,7 +60512,7 @@ function generateGapTp(payload) {
|
|
|
60497
60512
|
const actualShortReduce = to_f2(shortToReduce * sell_factor, "%.1f");
|
|
60498
60513
|
const actualLongReduce = to_f2(longToReduce * sell_factor, "%.1f");
|
|
60499
60514
|
const short_quantity_to_sell = determine_amount_to_sell2(short.entry, short.quantity, longTp, actualShortReduce, "short", decimal_places);
|
|
60500
|
-
const long_quantity_to_sell = determine_amount_to_sell2(long.entry, long.quantity, shortTp,
|
|
60515
|
+
const long_quantity_to_sell = determine_amount_to_sell2(long.entry, long.quantity, shortTp, actualLongReduce, "long", decimal_places);
|
|
60501
60516
|
const risk_amount_short = to_f2(shortToReduce - actualShortReduce, "%.2f");
|
|
60502
60517
|
const risk_amount_long = to_f2(longToReduce - actualLongReduce, "%.2f");
|
|
60503
60518
|
const profit_percent_long = to_f2(shortToReduce * 100 / (long.entry * long.quantity), "%.4f");
|
|
@@ -60531,6 +60546,32 @@ function generateGapTp(payload) {
|
|
|
60531
60546
|
gap_loss: to_f2(gapLoss, "%.2f")
|
|
60532
60547
|
};
|
|
60533
60548
|
}
|
|
60549
|
+
function calculate_factor(payload) {
|
|
60550
|
+
const {
|
|
60551
|
+
long,
|
|
60552
|
+
short,
|
|
60553
|
+
risk: desired_risk,
|
|
60554
|
+
kind,
|
|
60555
|
+
sell_factor,
|
|
60556
|
+
places = "%.4f"
|
|
60557
|
+
} = payload;
|
|
60558
|
+
const gap = Math.abs(long.entry - short.entry);
|
|
60559
|
+
const max_quantity = Math.max(long.quantity, short.quantity);
|
|
60560
|
+
const gapLoss = gap * max_quantity;
|
|
60561
|
+
let calculated_factor;
|
|
60562
|
+
const long_notional = long.entry * long.quantity;
|
|
60563
|
+
const short_notional = short.entry * short.quantity;
|
|
60564
|
+
const target_to_reduce = desired_risk / (1 - sell_factor);
|
|
60565
|
+
if (kind === "short") {
|
|
60566
|
+
const calculate_longPercent = target_to_reduce / long_notional;
|
|
60567
|
+
calculated_factor = calculate_longPercent * short_notional / gapLoss;
|
|
60568
|
+
} else {
|
|
60569
|
+
const calculated_shortPercent = target_to_reduce / (short_notional - target_to_reduce);
|
|
60570
|
+
calculated_factor = calculated_shortPercent * long_notional / gapLoss;
|
|
60571
|
+
}
|
|
60572
|
+
calculated_factor = to_f2(calculated_factor, places);
|
|
60573
|
+
return calculated_factor;
|
|
60574
|
+
}
|
|
60534
60575
|
|
|
60535
60576
|
// src/helpers/strategy.ts
|
|
60536
60577
|
class Strategy {
|
|
@@ -60934,12 +60975,14 @@ class Strategy {
|
|
|
60934
60975
|
return { ...app_config, avg, loss: -expected_loss, profit_percent };
|
|
60935
60976
|
}
|
|
60936
60977
|
identifyGapConfig(payload) {
|
|
60937
|
-
const { factor = 1,
|
|
60978
|
+
const { factor, sell_factor = 1, kind, risk } = payload;
|
|
60938
60979
|
return generateGapTp({
|
|
60939
60980
|
long: this.position.long,
|
|
60940
60981
|
short: this.position.short,
|
|
60941
60982
|
factor,
|
|
60942
60983
|
sell_factor,
|
|
60984
|
+
kind,
|
|
60985
|
+
risk,
|
|
60943
60986
|
decimal_places: this.config.global_config.decimal_places,
|
|
60944
60987
|
price_places: this.config.global_config.price_places
|
|
60945
60988
|
});
|
|
@@ -60963,6 +61006,67 @@ class Strategy {
|
|
|
60963
61006
|
});
|
|
60964
61007
|
return result;
|
|
60965
61008
|
}
|
|
61009
|
+
simulateGapReduction(payload) {
|
|
61010
|
+
const {
|
|
61011
|
+
factor,
|
|
61012
|
+
direction,
|
|
61013
|
+
sell_factor = 1,
|
|
61014
|
+
iterations = 10,
|
|
61015
|
+
risk: desired_risk,
|
|
61016
|
+
kind
|
|
61017
|
+
} = payload;
|
|
61018
|
+
const results = [];
|
|
61019
|
+
let params = {
|
|
61020
|
+
long: this.position.long,
|
|
61021
|
+
short: this.position.short,
|
|
61022
|
+
config: this.config
|
|
61023
|
+
};
|
|
61024
|
+
for (let i2 = 0;i2 < iterations; i2++) {
|
|
61025
|
+
const instance = new Strategy(params);
|
|
61026
|
+
const { profit_percent, risk, take_profit, sell_quantity, gap_loss } = instance.identifyGapConfig({
|
|
61027
|
+
factor,
|
|
61028
|
+
sell_factor,
|
|
61029
|
+
kind,
|
|
61030
|
+
risk: desired_risk
|
|
61031
|
+
});
|
|
61032
|
+
const to_add = {
|
|
61033
|
+
profit_percent,
|
|
61034
|
+
risk,
|
|
61035
|
+
take_profit,
|
|
61036
|
+
sell_quantity,
|
|
61037
|
+
gap_loss,
|
|
61038
|
+
position: {
|
|
61039
|
+
long: {
|
|
61040
|
+
entry: this.to_f(params.long.entry),
|
|
61041
|
+
quantity: this.to_df(params.long.quantity)
|
|
61042
|
+
},
|
|
61043
|
+
short: {
|
|
61044
|
+
entry: this.to_f(params.short.entry),
|
|
61045
|
+
quantity: this.to_df(params.short.quantity)
|
|
61046
|
+
}
|
|
61047
|
+
}
|
|
61048
|
+
};
|
|
61049
|
+
results.push(to_add);
|
|
61050
|
+
const sell_kind = direction == "long" ? "short" : "long";
|
|
61051
|
+
const remaining = this.to_df(params[sell_kind].quantity - sell_quantity[sell_kind]);
|
|
61052
|
+
if (remaining <= 0) {
|
|
61053
|
+
break;
|
|
61054
|
+
}
|
|
61055
|
+
params[sell_kind].quantity = remaining;
|
|
61056
|
+
params[direction] = {
|
|
61057
|
+
entry: take_profit[direction],
|
|
61058
|
+
quantity: remaining
|
|
61059
|
+
};
|
|
61060
|
+
}
|
|
61061
|
+
const last_gap_loss = results.at(-1)?.gap_loss;
|
|
61062
|
+
const last_tp = results.at(-1)?.take_profit[direction];
|
|
61063
|
+
const entry = this.position[direction].entry;
|
|
61064
|
+
const quantity = this.to_df(Math.abs(last_tp - entry) / last_gap_loss);
|
|
61065
|
+
return {
|
|
61066
|
+
results,
|
|
61067
|
+
quantity
|
|
61068
|
+
};
|
|
61069
|
+
}
|
|
60966
61070
|
}
|
|
60967
61071
|
|
|
60968
61072
|
// src/exchanges/binance.ts
|
|
@@ -64859,19 +64963,24 @@ class ExchangeAccount {
|
|
|
64859
64963
|
kind,
|
|
64860
64964
|
raw: true
|
|
64861
64965
|
});
|
|
64862
|
-
|
|
64863
|
-
|
|
64864
|
-
|
|
64865
|
-
|
|
64866
|
-
|
|
64867
|
-
|
|
64868
|
-
|
|
64869
|
-
|
|
64870
|
-
|
|
64871
|
-
|
|
64872
|
-
|
|
64966
|
+
try {
|
|
64967
|
+
const result = strategy.generateOppositeTrades({
|
|
64968
|
+
kind,
|
|
64969
|
+
avg_entry: strategy.position[kind].avg_price
|
|
64970
|
+
});
|
|
64971
|
+
if (place && result?.kind) {
|
|
64972
|
+
const _symbol = place_symbol || symbol;
|
|
64973
|
+
await this.placeOppositeTradeAction({
|
|
64974
|
+
symbol: _symbol,
|
|
64975
|
+
kind: result.kind,
|
|
64976
|
+
data: result
|
|
64977
|
+
});
|
|
64978
|
+
}
|
|
64979
|
+
return result;
|
|
64980
|
+
} catch (error) {
|
|
64981
|
+
console.log("Error in buildOppositeTrades", error);
|
|
64982
|
+
return null;
|
|
64873
64983
|
}
|
|
64874
|
-
return result;
|
|
64875
64984
|
}
|
|
64876
64985
|
async runSimulation(payload) {
|
|
64877
64986
|
const { symbol, kind, iterations = 2, raw = false } = payload;
|
|
@@ -65716,6 +65825,9 @@ class ExchangeAccount {
|
|
|
65716
65825
|
symbol,
|
|
65717
65826
|
kind
|
|
65718
65827
|
});
|
|
65828
|
+
if (!reverse_action) {
|
|
65829
|
+
return;
|
|
65830
|
+
}
|
|
65719
65831
|
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
65720
65832
|
await this.getPositionConfig({
|
|
65721
65833
|
symbol,
|