@gbozee/ultimate 0.0.2-94 → 0.0.2-97
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 +43 -0
- package/dist/index.cjs +178 -2
- package/dist/index.d.ts +115 -20
- package/dist/index.js +178 -2
- package/dist/mcp-server.cjs +177 -2
- package/dist/mcp-server.js +177 -2
- package/package.json +1 -1
package/dist/frontend-index.d.ts
CHANGED
|
@@ -398,6 +398,49 @@ export declare function getRiskReward(payload: {
|
|
|
398
398
|
risk: number;
|
|
399
399
|
global_config: GlobalConfig;
|
|
400
400
|
}): any;
|
|
401
|
+
export declare function computeProfitDetail(payload: {
|
|
402
|
+
focus_position: {
|
|
403
|
+
kind: "long" | "short";
|
|
404
|
+
entry: number;
|
|
405
|
+
quantity: number;
|
|
406
|
+
avg_qty: number;
|
|
407
|
+
avg_price: number;
|
|
408
|
+
};
|
|
409
|
+
strategy: {
|
|
410
|
+
reward_factor: number;
|
|
411
|
+
max_reward_factor: number;
|
|
412
|
+
risk: number;
|
|
413
|
+
};
|
|
414
|
+
reduce_position: {
|
|
415
|
+
kind: "long" | "short";
|
|
416
|
+
entry: number;
|
|
417
|
+
quantity: number;
|
|
418
|
+
avg_qty: number;
|
|
419
|
+
avg_price: number;
|
|
420
|
+
};
|
|
421
|
+
reverse_position: {
|
|
422
|
+
kind: "long" | "short";
|
|
423
|
+
avg_qty: number;
|
|
424
|
+
avg_price: number;
|
|
425
|
+
stop_loss: {
|
|
426
|
+
price: number;
|
|
427
|
+
quantity: number;
|
|
428
|
+
};
|
|
429
|
+
};
|
|
430
|
+
price_places?: string;
|
|
431
|
+
decimal_places?: string;
|
|
432
|
+
}): {
|
|
433
|
+
pnl: number;
|
|
434
|
+
loss: number;
|
|
435
|
+
original_pnl: number;
|
|
436
|
+
reward_factor: number;
|
|
437
|
+
profit_percent: number;
|
|
438
|
+
kind: "long" | "short";
|
|
439
|
+
sell_price: number;
|
|
440
|
+
quantity: number;
|
|
441
|
+
price_places: string;
|
|
442
|
+
decimal_places: string;
|
|
443
|
+
};
|
|
401
444
|
export type StrategyPosition = {
|
|
402
445
|
entry: number;
|
|
403
446
|
quantity: number;
|
package/dist/frontend-index.js
CHANGED
|
@@ -1761,6 +1761,48 @@ function getRiskReward(payload) {
|
|
|
1761
1761
|
});
|
|
1762
1762
|
return risk_reward;
|
|
1763
1763
|
}
|
|
1764
|
+
function computeProfitDetail(payload) {
|
|
1765
|
+
const {
|
|
1766
|
+
focus_position,
|
|
1767
|
+
strategy,
|
|
1768
|
+
price_places = "%.1f",
|
|
1769
|
+
reduce_position,
|
|
1770
|
+
decimal_places,
|
|
1771
|
+
reverse_position
|
|
1772
|
+
} = payload;
|
|
1773
|
+
let reward_factor = strategy.reward_factor;
|
|
1774
|
+
let risk = strategy.risk;
|
|
1775
|
+
if (strategy.max_reward_factor === 0) {
|
|
1776
|
+
reward_factor = strategy.reward_factor;
|
|
1777
|
+
}
|
|
1778
|
+
if (focus_position.avg_qty >= focus_position.quantity && strategy.max_reward_factor) {
|
|
1779
|
+
reward_factor = focus_position.quantity * strategy.max_reward_factor / focus_position.avg_qty;
|
|
1780
|
+
} else {
|
|
1781
|
+
reward_factor = strategy.reward_factor;
|
|
1782
|
+
}
|
|
1783
|
+
const full_pnl = reward_factor * risk;
|
|
1784
|
+
const profit_percent = to_f(full_pnl * 100 / (focus_position.avg_price * focus_position.avg_qty), "%.4f");
|
|
1785
|
+
const pnl = to_f(focus_position.entry * focus_position.quantity * profit_percent / 100, "%.2f");
|
|
1786
|
+
const diff = pnl / focus_position.quantity;
|
|
1787
|
+
const sell_price = to_f(focus_position.kind === "long" ? focus_position.entry + diff : focus_position.entry - diff, price_places);
|
|
1788
|
+
const loss = Math.abs(reduce_position.entry - sell_price) * reduce_position.quantity;
|
|
1789
|
+
const ratio = pnl / loss;
|
|
1790
|
+
const quantity = to_f(reduce_position.quantity * ratio, decimal_places);
|
|
1791
|
+
const expected_loss = Math.abs(reverse_position.avg_price - sell_price) * reverse_position.avg_qty;
|
|
1792
|
+
const new_pnl = to_f(pnl - expected_loss, "%.2f");
|
|
1793
|
+
return {
|
|
1794
|
+
pnl: new_pnl,
|
|
1795
|
+
loss: to_f(expected_loss, "%.2f"),
|
|
1796
|
+
original_pnl: pnl,
|
|
1797
|
+
reward_factor,
|
|
1798
|
+
profit_percent,
|
|
1799
|
+
kind: focus_position.kind,
|
|
1800
|
+
sell_price: to_f(sell_price, price_places),
|
|
1801
|
+
quantity,
|
|
1802
|
+
price_places,
|
|
1803
|
+
decimal_places
|
|
1804
|
+
};
|
|
1805
|
+
}
|
|
1764
1806
|
// src/helpers/strategy.ts
|
|
1765
1807
|
class Strategy {
|
|
1766
1808
|
position;
|
|
@@ -2196,6 +2238,7 @@ export {
|
|
|
2196
2238
|
computeTotalAverageForEachTrade,
|
|
2197
2239
|
computeSellZones,
|
|
2198
2240
|
computeRiskReward,
|
|
2241
|
+
computeProfitDetail,
|
|
2199
2242
|
buildConfig,
|
|
2200
2243
|
buildAvg,
|
|
2201
2244
|
buildAppConfig,
|
package/dist/index.cjs
CHANGED
|
@@ -41904,6 +41904,7 @@ __export(exports_src, {
|
|
|
41904
41904
|
database: () => exports_database,
|
|
41905
41905
|
createArray: () => createArray,
|
|
41906
41906
|
computeRiskReward: () => computeRiskReward,
|
|
41907
|
+
computeProfitDetail: () => computeProfitDetail,
|
|
41907
41908
|
buildConfig: () => buildConfig,
|
|
41908
41909
|
buildAvg: () => buildAvg,
|
|
41909
41910
|
buildAppConfig: () => buildAppConfig,
|
|
@@ -53840,6 +53841,48 @@ function getRiskReward(payload) {
|
|
|
53840
53841
|
});
|
|
53841
53842
|
return risk_reward;
|
|
53842
53843
|
}
|
|
53844
|
+
function computeProfitDetail(payload) {
|
|
53845
|
+
const {
|
|
53846
|
+
focus_position,
|
|
53847
|
+
strategy,
|
|
53848
|
+
price_places = "%.1f",
|
|
53849
|
+
reduce_position,
|
|
53850
|
+
decimal_places,
|
|
53851
|
+
reverse_position
|
|
53852
|
+
} = payload;
|
|
53853
|
+
let reward_factor = strategy.reward_factor;
|
|
53854
|
+
let risk = strategy.risk;
|
|
53855
|
+
if (strategy.max_reward_factor === 0) {
|
|
53856
|
+
reward_factor = strategy.reward_factor;
|
|
53857
|
+
}
|
|
53858
|
+
if (focus_position.avg_qty >= focus_position.quantity && strategy.max_reward_factor) {
|
|
53859
|
+
reward_factor = focus_position.quantity * strategy.max_reward_factor / focus_position.avg_qty;
|
|
53860
|
+
} else {
|
|
53861
|
+
reward_factor = strategy.reward_factor;
|
|
53862
|
+
}
|
|
53863
|
+
const full_pnl = reward_factor * risk;
|
|
53864
|
+
const profit_percent = to_f2(full_pnl * 100 / (focus_position.avg_price * focus_position.avg_qty), "%.4f");
|
|
53865
|
+
const pnl = to_f2(focus_position.entry * focus_position.quantity * profit_percent / 100, "%.2f");
|
|
53866
|
+
const diff = pnl / focus_position.quantity;
|
|
53867
|
+
const sell_price = to_f2(focus_position.kind === "long" ? focus_position.entry + diff : focus_position.entry - diff, price_places);
|
|
53868
|
+
const loss = Math.abs(reduce_position.entry - sell_price) * reduce_position.quantity;
|
|
53869
|
+
const ratio = pnl / loss;
|
|
53870
|
+
const quantity = to_f2(reduce_position.quantity * ratio, decimal_places);
|
|
53871
|
+
const expected_loss = Math.abs(reverse_position.avg_price - sell_price) * reverse_position.avg_qty;
|
|
53872
|
+
const new_pnl = to_f2(pnl - expected_loss, "%.2f");
|
|
53873
|
+
return {
|
|
53874
|
+
pnl: new_pnl,
|
|
53875
|
+
loss: to_f2(expected_loss, "%.2f"),
|
|
53876
|
+
original_pnl: pnl,
|
|
53877
|
+
reward_factor,
|
|
53878
|
+
profit_percent,
|
|
53879
|
+
kind: focus_position.kind,
|
|
53880
|
+
sell_price: to_f2(sell_price, price_places),
|
|
53881
|
+
quantity,
|
|
53882
|
+
price_places,
|
|
53883
|
+
decimal_places
|
|
53884
|
+
};
|
|
53885
|
+
}
|
|
53843
53886
|
|
|
53844
53887
|
// src/helpers/strategy.ts
|
|
53845
53888
|
class Strategy {
|
|
@@ -54246,6 +54289,54 @@ class Strategy {
|
|
|
54246
54289
|
|
|
54247
54290
|
// src/exchanges/binance.ts
|
|
54248
54291
|
var import_binance = __toESM(require_lib2());
|
|
54292
|
+
|
|
54293
|
+
// src/types/index.ts
|
|
54294
|
+
class BaseExchange {
|
|
54295
|
+
client;
|
|
54296
|
+
constructor(client) {
|
|
54297
|
+
this.client = client;
|
|
54298
|
+
}
|
|
54299
|
+
async customStopLoss(payload) {
|
|
54300
|
+
const {
|
|
54301
|
+
symbol,
|
|
54302
|
+
kind,
|
|
54303
|
+
stop: _stop,
|
|
54304
|
+
quantity,
|
|
54305
|
+
increase = false,
|
|
54306
|
+
price_places,
|
|
54307
|
+
decimal_places
|
|
54308
|
+
} = payload;
|
|
54309
|
+
const spread = 1.00005;
|
|
54310
|
+
const stop = kind === "long" ? _stop * spread ** -1 : _stop * spread;
|
|
54311
|
+
const order = [
|
|
54312
|
+
{
|
|
54313
|
+
kind,
|
|
54314
|
+
side: kind === "long" ? "sell" : "buy",
|
|
54315
|
+
price: stop,
|
|
54316
|
+
quantity,
|
|
54317
|
+
stop: _stop,
|
|
54318
|
+
is_market: false
|
|
54319
|
+
}
|
|
54320
|
+
];
|
|
54321
|
+
if (increase) {
|
|
54322
|
+
order.push({
|
|
54323
|
+
kind,
|
|
54324
|
+
price: stop,
|
|
54325
|
+
side: kind === "long" ? "buy" : "sell",
|
|
54326
|
+
quantity,
|
|
54327
|
+
is_market: false
|
|
54328
|
+
});
|
|
54329
|
+
}
|
|
54330
|
+
return this.rawCreateLimitPurchaseOrders({
|
|
54331
|
+
orders: order,
|
|
54332
|
+
symbol,
|
|
54333
|
+
price_places,
|
|
54334
|
+
decimal_places
|
|
54335
|
+
});
|
|
54336
|
+
}
|
|
54337
|
+
}
|
|
54338
|
+
|
|
54339
|
+
// src/exchanges/binance.ts
|
|
54249
54340
|
var CONSTANTS = {
|
|
54250
54341
|
SPOT_TO_FIAT: "MAIN_C2C",
|
|
54251
54342
|
SPOT_TO_USDT_FUTURE: "MAIN_UMFUTURE",
|
|
@@ -55016,12 +55107,13 @@ async function getAllOpenOrders(payload) {
|
|
|
55016
55107
|
return response;
|
|
55017
55108
|
}
|
|
55018
55109
|
|
|
55019
|
-
class BinanceExchange {
|
|
55110
|
+
class BinanceExchange extends BaseExchange {
|
|
55020
55111
|
client;
|
|
55021
55112
|
main_client;
|
|
55022
55113
|
getCredentials;
|
|
55023
55114
|
proxyAgent;
|
|
55024
55115
|
constructor(client, main_client) {
|
|
55116
|
+
super(client);
|
|
55025
55117
|
this.client = client;
|
|
55026
55118
|
this.main_client = main_client;
|
|
55027
55119
|
}
|
|
@@ -55333,6 +55425,10 @@ class BinanceExchange {
|
|
|
55333
55425
|
}
|
|
55334
55426
|
]);
|
|
55335
55427
|
}
|
|
55428
|
+
async rawCreateLimitPurchaseOrders(payload) {
|
|
55429
|
+
const { symbol, orders, price_places, decimal_places } = payload;
|
|
55430
|
+
return createLimitPurchaseOrders(this.client, symbol, price_places, decimal_places, orders);
|
|
55431
|
+
}
|
|
55336
55432
|
}
|
|
55337
55433
|
function getPricePlaces(target) {
|
|
55338
55434
|
const numStr = target.toString();
|
|
@@ -55830,10 +55926,11 @@ async function analyzeCharts2(params) {
|
|
|
55830
55926
|
return finalPairs;
|
|
55831
55927
|
}
|
|
55832
55928
|
|
|
55833
|
-
class BybitExchange {
|
|
55929
|
+
class BybitExchange extends BaseExchange {
|
|
55834
55930
|
client;
|
|
55835
55931
|
main_client;
|
|
55836
55932
|
constructor(client, main_client) {
|
|
55933
|
+
super(client);
|
|
55837
55934
|
this.client = client;
|
|
55838
55935
|
this.main_client = main_client;
|
|
55839
55936
|
}
|
|
@@ -56007,6 +56104,10 @@ class BybitExchange {
|
|
|
56007
56104
|
}
|
|
56008
56105
|
async placeMarketOrder(payload) {
|
|
56009
56106
|
}
|
|
56107
|
+
async rawCreateLimitPurchaseOrders(payload) {
|
|
56108
|
+
const { symbol, orders, price_places, decimal_places } = payload;
|
|
56109
|
+
return createLimitPurchaseOrders2(this.client, symbol, price_places, decimal_places, orders);
|
|
56110
|
+
}
|
|
56010
56111
|
}
|
|
56011
56112
|
|
|
56012
56113
|
// src/helpers/accounts.ts
|
|
@@ -58971,6 +59072,55 @@ class ExchangeAccount {
|
|
|
58971
59072
|
}
|
|
58972
59073
|
};
|
|
58973
59074
|
}
|
|
59075
|
+
async getSellPriceFromStrategy(payload) {
|
|
59076
|
+
const { symbol, reduce_position } = payload;
|
|
59077
|
+
const symbol_config = await this.recomputeSymbolConfig({
|
|
59078
|
+
symbol
|
|
59079
|
+
});
|
|
59080
|
+
const positions = await this.syncAccount({
|
|
59081
|
+
symbol,
|
|
59082
|
+
as_view: true
|
|
59083
|
+
});
|
|
59084
|
+
const focus_position = positions.find((k) => k.expand?.account_strategy);
|
|
59085
|
+
if (!focus_position) {
|
|
59086
|
+
return;
|
|
59087
|
+
}
|
|
59088
|
+
const reverse_kind = focus_position.kind === "long" ? "short" : "long";
|
|
59089
|
+
const reverse_position = positions.find((k) => k.kind === reverse_kind);
|
|
59090
|
+
const strategy = focus_position?.expand?.account_strategy;
|
|
59091
|
+
if (!strategy) {
|
|
59092
|
+
return;
|
|
59093
|
+
}
|
|
59094
|
+
return computeProfitDetail({
|
|
59095
|
+
focus_position: {
|
|
59096
|
+
kind: focus_position.kind,
|
|
59097
|
+
entry: focus_position.entry,
|
|
59098
|
+
quantity: focus_position.quantity,
|
|
59099
|
+
avg_price: focus_position.avg_price,
|
|
59100
|
+
avg_qty: focus_position.avg_qty
|
|
59101
|
+
},
|
|
59102
|
+
strategy: {
|
|
59103
|
+
reward_factor: strategy.reward_factor,
|
|
59104
|
+
risk: strategy.risk,
|
|
59105
|
+
max_reward_factor: strategy.max_reward_factor
|
|
59106
|
+
},
|
|
59107
|
+
reduce_position: {
|
|
59108
|
+
kind: reduce_position.kind,
|
|
59109
|
+
entry: reduce_position.entry,
|
|
59110
|
+
quantity: reduce_position.quantity,
|
|
59111
|
+
avg_price: reduce_position.avg_price,
|
|
59112
|
+
avg_qty: reduce_position.avg_qty
|
|
59113
|
+
},
|
|
59114
|
+
reverse_position: {
|
|
59115
|
+
kind: reverse_position.kind,
|
|
59116
|
+
avg_price: reverse_position.avg_price,
|
|
59117
|
+
avg_qty: reverse_position.avg_qty,
|
|
59118
|
+
stop_loss: reverse_position.stop_loss
|
|
59119
|
+
},
|
|
59120
|
+
price_places: symbol_config.price_places,
|
|
59121
|
+
decimal_places: symbol_config.decimal_places
|
|
59122
|
+
});
|
|
59123
|
+
}
|
|
58974
59124
|
}
|
|
58975
59125
|
function getExchangeKlass(exchange) {
|
|
58976
59126
|
const func = exchange === "binance" ? BinanceExchange : BybitExchange;
|
|
@@ -59303,6 +59453,32 @@ class App {
|
|
|
59303
59453
|
});
|
|
59304
59454
|
return result;
|
|
59305
59455
|
}
|
|
59456
|
+
async reduceExistingPosition(payload) {
|
|
59457
|
+
const { main_account, reduce_account, kind, place, increase } = payload;
|
|
59458
|
+
const main_exchange_account = await this.getExchangeAccount(main_account);
|
|
59459
|
+
const reduce_exchange_account = await this.getExchangeAccount(reduce_account);
|
|
59460
|
+
const reduce_position = await reduce_exchange_account.syncAccount({
|
|
59461
|
+
symbol: reduce_account.symbol,
|
|
59462
|
+
kind,
|
|
59463
|
+
as_view: true
|
|
59464
|
+
});
|
|
59465
|
+
const result = await main_exchange_account.getSellPriceFromStrategy({
|
|
59466
|
+
symbol: main_account.symbol,
|
|
59467
|
+
reduce_position
|
|
59468
|
+
});
|
|
59469
|
+
if (place) {
|
|
59470
|
+
return reduce_exchange_account.exchange.customStopLoss({
|
|
59471
|
+
symbol: reduce_account.symbol,
|
|
59472
|
+
kind: reduce_position.kind,
|
|
59473
|
+
stop: result.sell_price,
|
|
59474
|
+
quantity: result.quantity,
|
|
59475
|
+
price_places: result.price_places,
|
|
59476
|
+
decimal_places: result.decimal_places,
|
|
59477
|
+
increase
|
|
59478
|
+
});
|
|
59479
|
+
}
|
|
59480
|
+
return result;
|
|
59481
|
+
}
|
|
59306
59482
|
}
|
|
59307
59483
|
async function initApp(payload) {
|
|
59308
59484
|
const pb = await initPocketBaseClient(payload.db);
|
package/dist/index.d.ts
CHANGED
|
@@ -208,9 +208,26 @@ export interface Account {
|
|
|
208
208
|
short: any;
|
|
209
209
|
};
|
|
210
210
|
}
|
|
211
|
-
|
|
211
|
+
interface Order$1 {
|
|
212
|
+
order_id?: string;
|
|
213
|
+
symbol?: string;
|
|
214
|
+
price: number;
|
|
215
|
+
quantity: number;
|
|
216
|
+
kind: "long" | "short";
|
|
217
|
+
side: "buy" | "sell";
|
|
218
|
+
stop: number;
|
|
219
|
+
triggerPrice?: number;
|
|
220
|
+
}
|
|
221
|
+
declare abstract class BaseExchange {
|
|
212
222
|
client: any;
|
|
213
|
-
|
|
223
|
+
constructor(client: any);
|
|
224
|
+
abstract rawCreateLimitPurchaseOrders(payload: {
|
|
225
|
+
symbol: string;
|
|
226
|
+
orders: Order$1[];
|
|
227
|
+
price_places?: string;
|
|
228
|
+
decimal_places?: string;
|
|
229
|
+
}): Promise<any>;
|
|
230
|
+
abstract placeStopOrders(payload: {
|
|
214
231
|
symbol: string;
|
|
215
232
|
quantity: number;
|
|
216
233
|
kind: "long" | "short";
|
|
@@ -219,7 +236,7 @@ export interface BaseExchange {
|
|
|
219
236
|
decimal_places?: string;
|
|
220
237
|
place?: boolean;
|
|
221
238
|
}): Promise<any>;
|
|
222
|
-
bulkPlaceLimitOrders(payload: {
|
|
239
|
+
abstract bulkPlaceLimitOrders(payload: {
|
|
223
240
|
orders: any[];
|
|
224
241
|
kind: "long" | "short";
|
|
225
242
|
decimal_places?: string;
|
|
@@ -227,14 +244,14 @@ export interface BaseExchange {
|
|
|
227
244
|
symbol: string;
|
|
228
245
|
place?: boolean;
|
|
229
246
|
}): Promise<any>;
|
|
230
|
-
get_current_price(symbol: string): Promise<any>;
|
|
231
|
-
analyzeCharts(payload: {
|
|
247
|
+
abstract get_current_price(symbol: string): Promise<any>;
|
|
248
|
+
abstract analyzeCharts(payload: {
|
|
232
249
|
symbol: string;
|
|
233
250
|
chartType: any;
|
|
234
251
|
count: number;
|
|
235
252
|
raw?: boolean;
|
|
236
253
|
}): Promise<any>;
|
|
237
|
-
getExchangeAccountInfo(options: {
|
|
254
|
+
abstract getExchangeAccountInfo(options: {
|
|
238
255
|
price_places?: string;
|
|
239
256
|
decimal_places?: string;
|
|
240
257
|
account: {
|
|
@@ -243,11 +260,11 @@ export interface BaseExchange {
|
|
|
243
260
|
};
|
|
244
261
|
symbol: string;
|
|
245
262
|
}): Promise<any>;
|
|
246
|
-
cancelOrders(payload: {
|
|
263
|
+
abstract cancelOrders(payload: {
|
|
247
264
|
symbol: string;
|
|
248
265
|
orders: number[];
|
|
249
266
|
}): Promise<any>;
|
|
250
|
-
placeTpOrder(payload: {
|
|
267
|
+
abstract placeTpOrder(payload: {
|
|
251
268
|
symbol: string;
|
|
252
269
|
take_profit: number;
|
|
253
270
|
kind: "long" | "short";
|
|
@@ -256,7 +273,7 @@ export interface BaseExchange {
|
|
|
256
273
|
price_places?: string;
|
|
257
274
|
decimal_places?: string;
|
|
258
275
|
}): Promise<any>;
|
|
259
|
-
placeLimitOrder(payload: {
|
|
276
|
+
abstract placeLimitOrder(payload: {
|
|
260
277
|
symbol: string;
|
|
261
278
|
quantity: number;
|
|
262
279
|
kind: "long" | "short";
|
|
@@ -264,7 +281,7 @@ export interface BaseExchange {
|
|
|
264
281
|
price_places?: string;
|
|
265
282
|
decimal_places?: string;
|
|
266
283
|
}): Promise<any>;
|
|
267
|
-
placeStopOrder(payload: {
|
|
284
|
+
abstract placeStopOrder(payload: {
|
|
268
285
|
symbol: string;
|
|
269
286
|
stop: number;
|
|
270
287
|
quantity: number;
|
|
@@ -272,36 +289,36 @@ export interface BaseExchange {
|
|
|
272
289
|
price_places?: string;
|
|
273
290
|
decimal_places?: string;
|
|
274
291
|
}): Promise<any>;
|
|
275
|
-
setLeverage(payload: {
|
|
292
|
+
abstract setLeverage(payload: {
|
|
276
293
|
symbol: string;
|
|
277
294
|
leverage: number;
|
|
278
295
|
}): Promise<any>;
|
|
279
|
-
generateConfig(payload: {
|
|
296
|
+
abstract generateConfig(payload: {
|
|
280
297
|
symbol: string;
|
|
281
298
|
interval?: any;
|
|
282
299
|
limit?: number;
|
|
283
300
|
}): Promise<any>;
|
|
284
|
-
checkDelistedMovers(payload: {
|
|
301
|
+
abstract checkDelistedMovers(payload: {
|
|
285
302
|
movePercent: number;
|
|
286
303
|
include_delisted?: boolean;
|
|
287
304
|
}): Promise<any>;
|
|
288
|
-
closePosition(payload: {
|
|
305
|
+
abstract closePosition(payload: {
|
|
289
306
|
symbol: string;
|
|
290
307
|
kind: "long" | "short";
|
|
291
308
|
price_places?: string;
|
|
292
309
|
decimal_places?: string;
|
|
293
310
|
}): Promise<any>;
|
|
294
|
-
getAllOpenSymbols(): Promise<string[]>;
|
|
295
|
-
createLimitPurchaseOrders(payload: {
|
|
311
|
+
abstract getAllOpenSymbols(): Promise<string[]>;
|
|
312
|
+
abstract createLimitPurchaseOrders(payload: {
|
|
296
313
|
orders: any[];
|
|
297
314
|
kind: "long" | "short";
|
|
298
315
|
decimal_places?: string;
|
|
299
316
|
price_places?: string;
|
|
300
317
|
symbol: string;
|
|
301
318
|
}): Promise<any>;
|
|
302
|
-
getDelistedSpotSymbols(): Promise<any>;
|
|
303
|
-
getOpenPositions(): Promise<any>;
|
|
304
|
-
crossAccountTransfer(payload: {
|
|
319
|
+
abstract getDelistedSpotSymbols(): Promise<any>;
|
|
320
|
+
abstract getOpenPositions(): Promise<any>;
|
|
321
|
+
abstract crossAccountTransfer(payload: {
|
|
305
322
|
from: {
|
|
306
323
|
owner: string;
|
|
307
324
|
wallet: string;
|
|
@@ -313,13 +330,22 @@ export interface BaseExchange {
|
|
|
313
330
|
asset: string;
|
|
314
331
|
amount: number;
|
|
315
332
|
}): Promise<any>;
|
|
316
|
-
placeMarketOrder(payload: {
|
|
333
|
+
abstract placeMarketOrder(payload: {
|
|
317
334
|
symbol: string;
|
|
318
335
|
kind: "long" | "short";
|
|
319
336
|
quantity: number;
|
|
320
337
|
price_places?: string;
|
|
321
338
|
decimal_places?: string;
|
|
322
339
|
}): Promise<any>;
|
|
340
|
+
customStopLoss(payload: {
|
|
341
|
+
price_places: string;
|
|
342
|
+
decimal_places: string;
|
|
343
|
+
symbol: string;
|
|
344
|
+
kind: "long" | "short";
|
|
345
|
+
stop: number;
|
|
346
|
+
quantity: number;
|
|
347
|
+
increase?: boolean;
|
|
348
|
+
}): Promise<any>;
|
|
323
349
|
}
|
|
324
350
|
declare function initPocketBaseClient(proxy_credentials: {
|
|
325
351
|
host: string;
|
|
@@ -1029,6 +1055,49 @@ export declare function getRiskReward(payload: {
|
|
|
1029
1055
|
risk: number;
|
|
1030
1056
|
global_config: GlobalConfig;
|
|
1031
1057
|
}): any;
|
|
1058
|
+
export declare function computeProfitDetail(payload: {
|
|
1059
|
+
focus_position: {
|
|
1060
|
+
kind: "long" | "short";
|
|
1061
|
+
entry: number;
|
|
1062
|
+
quantity: number;
|
|
1063
|
+
avg_qty: number;
|
|
1064
|
+
avg_price: number;
|
|
1065
|
+
};
|
|
1066
|
+
strategy: {
|
|
1067
|
+
reward_factor: number;
|
|
1068
|
+
max_reward_factor: number;
|
|
1069
|
+
risk: number;
|
|
1070
|
+
};
|
|
1071
|
+
reduce_position: {
|
|
1072
|
+
kind: "long" | "short";
|
|
1073
|
+
entry: number;
|
|
1074
|
+
quantity: number;
|
|
1075
|
+
avg_qty: number;
|
|
1076
|
+
avg_price: number;
|
|
1077
|
+
};
|
|
1078
|
+
reverse_position: {
|
|
1079
|
+
kind: "long" | "short";
|
|
1080
|
+
avg_qty: number;
|
|
1081
|
+
avg_price: number;
|
|
1082
|
+
stop_loss: {
|
|
1083
|
+
price: number;
|
|
1084
|
+
quantity: number;
|
|
1085
|
+
};
|
|
1086
|
+
};
|
|
1087
|
+
price_places?: string;
|
|
1088
|
+
decimal_places?: string;
|
|
1089
|
+
}): {
|
|
1090
|
+
pnl: number;
|
|
1091
|
+
loss: number;
|
|
1092
|
+
original_pnl: number;
|
|
1093
|
+
reward_factor: number;
|
|
1094
|
+
profit_percent: number;
|
|
1095
|
+
kind: "long" | "short";
|
|
1096
|
+
sell_price: number;
|
|
1097
|
+
quantity: number;
|
|
1098
|
+
price_places: string;
|
|
1099
|
+
decimal_places: string;
|
|
1100
|
+
};
|
|
1032
1101
|
declare class ExchangePosition {
|
|
1033
1102
|
exchange: BaseExchange;
|
|
1034
1103
|
exchange_account: ExchangeAccount$1;
|
|
@@ -1787,6 +1856,21 @@ declare class ExchangeAccount$1 {
|
|
|
1787
1856
|
pnl: number;
|
|
1788
1857
|
};
|
|
1789
1858
|
}>;
|
|
1859
|
+
getSellPriceFromStrategy(payload: {
|
|
1860
|
+
symbol: string;
|
|
1861
|
+
reduce_position: PositionsView;
|
|
1862
|
+
}): Promise<{
|
|
1863
|
+
pnl: number;
|
|
1864
|
+
loss: number;
|
|
1865
|
+
original_pnl: number;
|
|
1866
|
+
reward_factor: number;
|
|
1867
|
+
profit_percent: number;
|
|
1868
|
+
kind: "long" | "short";
|
|
1869
|
+
sell_price: number;
|
|
1870
|
+
quantity: number;
|
|
1871
|
+
price_places: string;
|
|
1872
|
+
decimal_places: string;
|
|
1873
|
+
}>;
|
|
1790
1874
|
}
|
|
1791
1875
|
declare function getExchangeAccount(payload: {
|
|
1792
1876
|
account: ExchangeType;
|
|
@@ -2009,6 +2093,17 @@ declare class App {
|
|
|
2009
2093
|
pnl: number;
|
|
2010
2094
|
};
|
|
2011
2095
|
}>;
|
|
2096
|
+
reduceExistingPosition(payload: {
|
|
2097
|
+
main_account: ExchangeType & {
|
|
2098
|
+
symbol: string;
|
|
2099
|
+
};
|
|
2100
|
+
reduce_account: ExchangeType & {
|
|
2101
|
+
symbol: string;
|
|
2102
|
+
};
|
|
2103
|
+
kind: "long" | "short";
|
|
2104
|
+
place?: boolean;
|
|
2105
|
+
increase?: boolean;
|
|
2106
|
+
}): Promise<any>;
|
|
2012
2107
|
}
|
|
2013
2108
|
export declare function initApp(payload: {
|
|
2014
2109
|
db: {
|
package/dist/index.js
CHANGED
|
@@ -53795,6 +53795,48 @@ function getRiskReward(payload) {
|
|
|
53795
53795
|
});
|
|
53796
53796
|
return risk_reward;
|
|
53797
53797
|
}
|
|
53798
|
+
function computeProfitDetail(payload) {
|
|
53799
|
+
const {
|
|
53800
|
+
focus_position,
|
|
53801
|
+
strategy,
|
|
53802
|
+
price_places = "%.1f",
|
|
53803
|
+
reduce_position,
|
|
53804
|
+
decimal_places,
|
|
53805
|
+
reverse_position
|
|
53806
|
+
} = payload;
|
|
53807
|
+
let reward_factor = strategy.reward_factor;
|
|
53808
|
+
let risk = strategy.risk;
|
|
53809
|
+
if (strategy.max_reward_factor === 0) {
|
|
53810
|
+
reward_factor = strategy.reward_factor;
|
|
53811
|
+
}
|
|
53812
|
+
if (focus_position.avg_qty >= focus_position.quantity && strategy.max_reward_factor) {
|
|
53813
|
+
reward_factor = focus_position.quantity * strategy.max_reward_factor / focus_position.avg_qty;
|
|
53814
|
+
} else {
|
|
53815
|
+
reward_factor = strategy.reward_factor;
|
|
53816
|
+
}
|
|
53817
|
+
const full_pnl = reward_factor * risk;
|
|
53818
|
+
const profit_percent = to_f2(full_pnl * 100 / (focus_position.avg_price * focus_position.avg_qty), "%.4f");
|
|
53819
|
+
const pnl = to_f2(focus_position.entry * focus_position.quantity * profit_percent / 100, "%.2f");
|
|
53820
|
+
const diff = pnl / focus_position.quantity;
|
|
53821
|
+
const sell_price = to_f2(focus_position.kind === "long" ? focus_position.entry + diff : focus_position.entry - diff, price_places);
|
|
53822
|
+
const loss = Math.abs(reduce_position.entry - sell_price) * reduce_position.quantity;
|
|
53823
|
+
const ratio = pnl / loss;
|
|
53824
|
+
const quantity = to_f2(reduce_position.quantity * ratio, decimal_places);
|
|
53825
|
+
const expected_loss = Math.abs(reverse_position.avg_price - sell_price) * reverse_position.avg_qty;
|
|
53826
|
+
const new_pnl = to_f2(pnl - expected_loss, "%.2f");
|
|
53827
|
+
return {
|
|
53828
|
+
pnl: new_pnl,
|
|
53829
|
+
loss: to_f2(expected_loss, "%.2f"),
|
|
53830
|
+
original_pnl: pnl,
|
|
53831
|
+
reward_factor,
|
|
53832
|
+
profit_percent,
|
|
53833
|
+
kind: focus_position.kind,
|
|
53834
|
+
sell_price: to_f2(sell_price, price_places),
|
|
53835
|
+
quantity,
|
|
53836
|
+
price_places,
|
|
53837
|
+
decimal_places
|
|
53838
|
+
};
|
|
53839
|
+
}
|
|
53798
53840
|
|
|
53799
53841
|
// src/helpers/strategy.ts
|
|
53800
53842
|
class Strategy {
|
|
@@ -54201,6 +54243,54 @@ class Strategy {
|
|
|
54201
54243
|
|
|
54202
54244
|
// src/exchanges/binance.ts
|
|
54203
54245
|
var import_binance = __toESM(require_lib2(), 1);
|
|
54246
|
+
|
|
54247
|
+
// src/types/index.ts
|
|
54248
|
+
class BaseExchange {
|
|
54249
|
+
client;
|
|
54250
|
+
constructor(client) {
|
|
54251
|
+
this.client = client;
|
|
54252
|
+
}
|
|
54253
|
+
async customStopLoss(payload) {
|
|
54254
|
+
const {
|
|
54255
|
+
symbol,
|
|
54256
|
+
kind,
|
|
54257
|
+
stop: _stop,
|
|
54258
|
+
quantity,
|
|
54259
|
+
increase = false,
|
|
54260
|
+
price_places,
|
|
54261
|
+
decimal_places
|
|
54262
|
+
} = payload;
|
|
54263
|
+
const spread = 1.00005;
|
|
54264
|
+
const stop = kind === "long" ? _stop * spread ** -1 : _stop * spread;
|
|
54265
|
+
const order = [
|
|
54266
|
+
{
|
|
54267
|
+
kind,
|
|
54268
|
+
side: kind === "long" ? "sell" : "buy",
|
|
54269
|
+
price: stop,
|
|
54270
|
+
quantity,
|
|
54271
|
+
stop: _stop,
|
|
54272
|
+
is_market: false
|
|
54273
|
+
}
|
|
54274
|
+
];
|
|
54275
|
+
if (increase) {
|
|
54276
|
+
order.push({
|
|
54277
|
+
kind,
|
|
54278
|
+
price: stop,
|
|
54279
|
+
side: kind === "long" ? "buy" : "sell",
|
|
54280
|
+
quantity,
|
|
54281
|
+
is_market: false
|
|
54282
|
+
});
|
|
54283
|
+
}
|
|
54284
|
+
return this.rawCreateLimitPurchaseOrders({
|
|
54285
|
+
orders: order,
|
|
54286
|
+
symbol,
|
|
54287
|
+
price_places,
|
|
54288
|
+
decimal_places
|
|
54289
|
+
});
|
|
54290
|
+
}
|
|
54291
|
+
}
|
|
54292
|
+
|
|
54293
|
+
// src/exchanges/binance.ts
|
|
54204
54294
|
var CONSTANTS = {
|
|
54205
54295
|
SPOT_TO_FIAT: "MAIN_C2C",
|
|
54206
54296
|
SPOT_TO_USDT_FUTURE: "MAIN_UMFUTURE",
|
|
@@ -54971,12 +55061,13 @@ async function getAllOpenOrders(payload) {
|
|
|
54971
55061
|
return response;
|
|
54972
55062
|
}
|
|
54973
55063
|
|
|
54974
|
-
class BinanceExchange {
|
|
55064
|
+
class BinanceExchange extends BaseExchange {
|
|
54975
55065
|
client;
|
|
54976
55066
|
main_client;
|
|
54977
55067
|
getCredentials;
|
|
54978
55068
|
proxyAgent;
|
|
54979
55069
|
constructor(client, main_client) {
|
|
55070
|
+
super(client);
|
|
54980
55071
|
this.client = client;
|
|
54981
55072
|
this.main_client = main_client;
|
|
54982
55073
|
}
|
|
@@ -55288,6 +55379,10 @@ class BinanceExchange {
|
|
|
55288
55379
|
}
|
|
55289
55380
|
]);
|
|
55290
55381
|
}
|
|
55382
|
+
async rawCreateLimitPurchaseOrders(payload) {
|
|
55383
|
+
const { symbol, orders, price_places, decimal_places } = payload;
|
|
55384
|
+
return createLimitPurchaseOrders(this.client, symbol, price_places, decimal_places, orders);
|
|
55385
|
+
}
|
|
55291
55386
|
}
|
|
55292
55387
|
function getPricePlaces(target) {
|
|
55293
55388
|
const numStr = target.toString();
|
|
@@ -55785,10 +55880,11 @@ async function analyzeCharts2(params) {
|
|
|
55785
55880
|
return finalPairs;
|
|
55786
55881
|
}
|
|
55787
55882
|
|
|
55788
|
-
class BybitExchange {
|
|
55883
|
+
class BybitExchange extends BaseExchange {
|
|
55789
55884
|
client;
|
|
55790
55885
|
main_client;
|
|
55791
55886
|
constructor(client, main_client) {
|
|
55887
|
+
super(client);
|
|
55792
55888
|
this.client = client;
|
|
55793
55889
|
this.main_client = main_client;
|
|
55794
55890
|
}
|
|
@@ -55962,6 +56058,10 @@ class BybitExchange {
|
|
|
55962
56058
|
}
|
|
55963
56059
|
async placeMarketOrder(payload) {
|
|
55964
56060
|
}
|
|
56061
|
+
async rawCreateLimitPurchaseOrders(payload) {
|
|
56062
|
+
const { symbol, orders, price_places, decimal_places } = payload;
|
|
56063
|
+
return createLimitPurchaseOrders2(this.client, symbol, price_places, decimal_places, orders);
|
|
56064
|
+
}
|
|
55965
56065
|
}
|
|
55966
56066
|
|
|
55967
56067
|
// src/helpers/accounts.ts
|
|
@@ -58926,6 +59026,55 @@ class ExchangeAccount {
|
|
|
58926
59026
|
}
|
|
58927
59027
|
};
|
|
58928
59028
|
}
|
|
59029
|
+
async getSellPriceFromStrategy(payload) {
|
|
59030
|
+
const { symbol, reduce_position } = payload;
|
|
59031
|
+
const symbol_config = await this.recomputeSymbolConfig({
|
|
59032
|
+
symbol
|
|
59033
|
+
});
|
|
59034
|
+
const positions = await this.syncAccount({
|
|
59035
|
+
symbol,
|
|
59036
|
+
as_view: true
|
|
59037
|
+
});
|
|
59038
|
+
const focus_position = positions.find((k) => k.expand?.account_strategy);
|
|
59039
|
+
if (!focus_position) {
|
|
59040
|
+
return;
|
|
59041
|
+
}
|
|
59042
|
+
const reverse_kind = focus_position.kind === "long" ? "short" : "long";
|
|
59043
|
+
const reverse_position = positions.find((k) => k.kind === reverse_kind);
|
|
59044
|
+
const strategy = focus_position?.expand?.account_strategy;
|
|
59045
|
+
if (!strategy) {
|
|
59046
|
+
return;
|
|
59047
|
+
}
|
|
59048
|
+
return computeProfitDetail({
|
|
59049
|
+
focus_position: {
|
|
59050
|
+
kind: focus_position.kind,
|
|
59051
|
+
entry: focus_position.entry,
|
|
59052
|
+
quantity: focus_position.quantity,
|
|
59053
|
+
avg_price: focus_position.avg_price,
|
|
59054
|
+
avg_qty: focus_position.avg_qty
|
|
59055
|
+
},
|
|
59056
|
+
strategy: {
|
|
59057
|
+
reward_factor: strategy.reward_factor,
|
|
59058
|
+
risk: strategy.risk,
|
|
59059
|
+
max_reward_factor: strategy.max_reward_factor
|
|
59060
|
+
},
|
|
59061
|
+
reduce_position: {
|
|
59062
|
+
kind: reduce_position.kind,
|
|
59063
|
+
entry: reduce_position.entry,
|
|
59064
|
+
quantity: reduce_position.quantity,
|
|
59065
|
+
avg_price: reduce_position.avg_price,
|
|
59066
|
+
avg_qty: reduce_position.avg_qty
|
|
59067
|
+
},
|
|
59068
|
+
reverse_position: {
|
|
59069
|
+
kind: reverse_position.kind,
|
|
59070
|
+
avg_price: reverse_position.avg_price,
|
|
59071
|
+
avg_qty: reverse_position.avg_qty,
|
|
59072
|
+
stop_loss: reverse_position.stop_loss
|
|
59073
|
+
},
|
|
59074
|
+
price_places: symbol_config.price_places,
|
|
59075
|
+
decimal_places: symbol_config.decimal_places
|
|
59076
|
+
});
|
|
59077
|
+
}
|
|
58929
59078
|
}
|
|
58930
59079
|
function getExchangeKlass(exchange) {
|
|
58931
59080
|
const func = exchange === "binance" ? BinanceExchange : BybitExchange;
|
|
@@ -59258,6 +59407,32 @@ class App {
|
|
|
59258
59407
|
});
|
|
59259
59408
|
return result;
|
|
59260
59409
|
}
|
|
59410
|
+
async reduceExistingPosition(payload) {
|
|
59411
|
+
const { main_account, reduce_account, kind, place, increase } = payload;
|
|
59412
|
+
const main_exchange_account = await this.getExchangeAccount(main_account);
|
|
59413
|
+
const reduce_exchange_account = await this.getExchangeAccount(reduce_account);
|
|
59414
|
+
const reduce_position = await reduce_exchange_account.syncAccount({
|
|
59415
|
+
symbol: reduce_account.symbol,
|
|
59416
|
+
kind,
|
|
59417
|
+
as_view: true
|
|
59418
|
+
});
|
|
59419
|
+
const result = await main_exchange_account.getSellPriceFromStrategy({
|
|
59420
|
+
symbol: main_account.symbol,
|
|
59421
|
+
reduce_position
|
|
59422
|
+
});
|
|
59423
|
+
if (place) {
|
|
59424
|
+
return reduce_exchange_account.exchange.customStopLoss({
|
|
59425
|
+
symbol: reduce_account.symbol,
|
|
59426
|
+
kind: reduce_position.kind,
|
|
59427
|
+
stop: result.sell_price,
|
|
59428
|
+
quantity: result.quantity,
|
|
59429
|
+
price_places: result.price_places,
|
|
59430
|
+
decimal_places: result.decimal_places,
|
|
59431
|
+
increase
|
|
59432
|
+
});
|
|
59433
|
+
}
|
|
59434
|
+
return result;
|
|
59435
|
+
}
|
|
59261
59436
|
}
|
|
59262
59437
|
async function initApp(payload) {
|
|
59263
59438
|
const pb = await initPocketBaseClient(payload.db);
|
|
@@ -59364,6 +59539,7 @@ export {
|
|
|
59364
59539
|
exports_database as database,
|
|
59365
59540
|
createArray,
|
|
59366
59541
|
computeRiskReward,
|
|
59542
|
+
computeProfitDetail,
|
|
59367
59543
|
buildConfig,
|
|
59368
59544
|
buildAvg,
|
|
59369
59545
|
buildAppConfig,
|
package/dist/mcp-server.cjs
CHANGED
|
@@ -60531,6 +60531,48 @@ function getRiskReward(payload) {
|
|
|
60531
60531
|
});
|
|
60532
60532
|
return risk_reward;
|
|
60533
60533
|
}
|
|
60534
|
+
function computeProfitDetail(payload) {
|
|
60535
|
+
const {
|
|
60536
|
+
focus_position,
|
|
60537
|
+
strategy,
|
|
60538
|
+
price_places = "%.1f",
|
|
60539
|
+
reduce_position,
|
|
60540
|
+
decimal_places,
|
|
60541
|
+
reverse_position
|
|
60542
|
+
} = payload;
|
|
60543
|
+
let reward_factor = strategy.reward_factor;
|
|
60544
|
+
let risk = strategy.risk;
|
|
60545
|
+
if (strategy.max_reward_factor === 0) {
|
|
60546
|
+
reward_factor = strategy.reward_factor;
|
|
60547
|
+
}
|
|
60548
|
+
if (focus_position.avg_qty >= focus_position.quantity && strategy.max_reward_factor) {
|
|
60549
|
+
reward_factor = focus_position.quantity * strategy.max_reward_factor / focus_position.avg_qty;
|
|
60550
|
+
} else {
|
|
60551
|
+
reward_factor = strategy.reward_factor;
|
|
60552
|
+
}
|
|
60553
|
+
const full_pnl = reward_factor * risk;
|
|
60554
|
+
const profit_percent = to_f2(full_pnl * 100 / (focus_position.avg_price * focus_position.avg_qty), "%.4f");
|
|
60555
|
+
const pnl = to_f2(focus_position.entry * focus_position.quantity * profit_percent / 100, "%.2f");
|
|
60556
|
+
const diff = pnl / focus_position.quantity;
|
|
60557
|
+
const sell_price = to_f2(focus_position.kind === "long" ? focus_position.entry + diff : focus_position.entry - diff, price_places);
|
|
60558
|
+
const loss = Math.abs(reduce_position.entry - sell_price) * reduce_position.quantity;
|
|
60559
|
+
const ratio = pnl / loss;
|
|
60560
|
+
const quantity = to_f2(reduce_position.quantity * ratio, decimal_places);
|
|
60561
|
+
const expected_loss = Math.abs(reverse_position.avg_price - sell_price) * reverse_position.avg_qty;
|
|
60562
|
+
const new_pnl = to_f2(pnl - expected_loss, "%.2f");
|
|
60563
|
+
return {
|
|
60564
|
+
pnl: new_pnl,
|
|
60565
|
+
loss: to_f2(expected_loss, "%.2f"),
|
|
60566
|
+
original_pnl: pnl,
|
|
60567
|
+
reward_factor,
|
|
60568
|
+
profit_percent,
|
|
60569
|
+
kind: focus_position.kind,
|
|
60570
|
+
sell_price: to_f2(sell_price, price_places),
|
|
60571
|
+
quantity,
|
|
60572
|
+
price_places,
|
|
60573
|
+
decimal_places
|
|
60574
|
+
};
|
|
60575
|
+
}
|
|
60534
60576
|
|
|
60535
60577
|
// src/helpers/strategy.ts
|
|
60536
60578
|
class Strategy {
|
|
@@ -60937,6 +60979,54 @@ class Strategy {
|
|
|
60937
60979
|
|
|
60938
60980
|
// src/exchanges/binance.ts
|
|
60939
60981
|
var import_binance = __toESM(require_lib2());
|
|
60982
|
+
|
|
60983
|
+
// src/types/index.ts
|
|
60984
|
+
class BaseExchange {
|
|
60985
|
+
client;
|
|
60986
|
+
constructor(client) {
|
|
60987
|
+
this.client = client;
|
|
60988
|
+
}
|
|
60989
|
+
async customStopLoss(payload) {
|
|
60990
|
+
const {
|
|
60991
|
+
symbol,
|
|
60992
|
+
kind,
|
|
60993
|
+
stop: _stop,
|
|
60994
|
+
quantity,
|
|
60995
|
+
increase = false,
|
|
60996
|
+
price_places,
|
|
60997
|
+
decimal_places
|
|
60998
|
+
} = payload;
|
|
60999
|
+
const spread = 1.00005;
|
|
61000
|
+
const stop = kind === "long" ? _stop * spread ** -1 : _stop * spread;
|
|
61001
|
+
const order = [
|
|
61002
|
+
{
|
|
61003
|
+
kind,
|
|
61004
|
+
side: kind === "long" ? "sell" : "buy",
|
|
61005
|
+
price: stop,
|
|
61006
|
+
quantity,
|
|
61007
|
+
stop: _stop,
|
|
61008
|
+
is_market: false
|
|
61009
|
+
}
|
|
61010
|
+
];
|
|
61011
|
+
if (increase) {
|
|
61012
|
+
order.push({
|
|
61013
|
+
kind,
|
|
61014
|
+
price: stop,
|
|
61015
|
+
side: kind === "long" ? "buy" : "sell",
|
|
61016
|
+
quantity,
|
|
61017
|
+
is_market: false
|
|
61018
|
+
});
|
|
61019
|
+
}
|
|
61020
|
+
return this.rawCreateLimitPurchaseOrders({
|
|
61021
|
+
orders: order,
|
|
61022
|
+
symbol,
|
|
61023
|
+
price_places,
|
|
61024
|
+
decimal_places
|
|
61025
|
+
});
|
|
61026
|
+
}
|
|
61027
|
+
}
|
|
61028
|
+
|
|
61029
|
+
// src/exchanges/binance.ts
|
|
60940
61030
|
var CONSTANTS = {
|
|
60941
61031
|
SPOT_TO_FIAT: "MAIN_C2C",
|
|
60942
61032
|
SPOT_TO_USDT_FUTURE: "MAIN_UMFUTURE",
|
|
@@ -61707,12 +61797,13 @@ async function getAllOpenOrders(payload) {
|
|
|
61707
61797
|
return response;
|
|
61708
61798
|
}
|
|
61709
61799
|
|
|
61710
|
-
class BinanceExchange {
|
|
61800
|
+
class BinanceExchange extends BaseExchange {
|
|
61711
61801
|
client;
|
|
61712
61802
|
main_client;
|
|
61713
61803
|
getCredentials;
|
|
61714
61804
|
proxyAgent;
|
|
61715
61805
|
constructor(client, main_client) {
|
|
61806
|
+
super(client);
|
|
61716
61807
|
this.client = client;
|
|
61717
61808
|
this.main_client = main_client;
|
|
61718
61809
|
}
|
|
@@ -62024,6 +62115,10 @@ class BinanceExchange {
|
|
|
62024
62115
|
}
|
|
62025
62116
|
]);
|
|
62026
62117
|
}
|
|
62118
|
+
async rawCreateLimitPurchaseOrders(payload) {
|
|
62119
|
+
const { symbol, orders, price_places, decimal_places } = payload;
|
|
62120
|
+
return createLimitPurchaseOrders(this.client, symbol, price_places, decimal_places, orders);
|
|
62121
|
+
}
|
|
62027
62122
|
}
|
|
62028
62123
|
function getPricePlaces(target) {
|
|
62029
62124
|
const numStr = target.toString();
|
|
@@ -62521,10 +62616,11 @@ async function analyzeCharts2(params) {
|
|
|
62521
62616
|
return finalPairs;
|
|
62522
62617
|
}
|
|
62523
62618
|
|
|
62524
|
-
class BybitExchange {
|
|
62619
|
+
class BybitExchange extends BaseExchange {
|
|
62525
62620
|
client;
|
|
62526
62621
|
main_client;
|
|
62527
62622
|
constructor(client, main_client) {
|
|
62623
|
+
super(client);
|
|
62528
62624
|
this.client = client;
|
|
62529
62625
|
this.main_client = main_client;
|
|
62530
62626
|
}
|
|
@@ -62698,6 +62794,10 @@ class BybitExchange {
|
|
|
62698
62794
|
}
|
|
62699
62795
|
async placeMarketOrder(payload) {
|
|
62700
62796
|
}
|
|
62797
|
+
async rawCreateLimitPurchaseOrders(payload) {
|
|
62798
|
+
const { symbol, orders, price_places, decimal_places } = payload;
|
|
62799
|
+
return createLimitPurchaseOrders2(this.client, symbol, price_places, decimal_places, orders);
|
|
62800
|
+
}
|
|
62701
62801
|
}
|
|
62702
62802
|
|
|
62703
62803
|
// src/helpers/accounts.ts
|
|
@@ -65662,6 +65762,55 @@ class ExchangeAccount {
|
|
|
65662
65762
|
}
|
|
65663
65763
|
};
|
|
65664
65764
|
}
|
|
65765
|
+
async getSellPriceFromStrategy(payload) {
|
|
65766
|
+
const { symbol, reduce_position } = payload;
|
|
65767
|
+
const symbol_config = await this.recomputeSymbolConfig({
|
|
65768
|
+
symbol
|
|
65769
|
+
});
|
|
65770
|
+
const positions = await this.syncAccount({
|
|
65771
|
+
symbol,
|
|
65772
|
+
as_view: true
|
|
65773
|
+
});
|
|
65774
|
+
const focus_position = positions.find((k) => k.expand?.account_strategy);
|
|
65775
|
+
if (!focus_position) {
|
|
65776
|
+
return;
|
|
65777
|
+
}
|
|
65778
|
+
const reverse_kind = focus_position.kind === "long" ? "short" : "long";
|
|
65779
|
+
const reverse_position = positions.find((k) => k.kind === reverse_kind);
|
|
65780
|
+
const strategy = focus_position?.expand?.account_strategy;
|
|
65781
|
+
if (!strategy) {
|
|
65782
|
+
return;
|
|
65783
|
+
}
|
|
65784
|
+
return computeProfitDetail({
|
|
65785
|
+
focus_position: {
|
|
65786
|
+
kind: focus_position.kind,
|
|
65787
|
+
entry: focus_position.entry,
|
|
65788
|
+
quantity: focus_position.quantity,
|
|
65789
|
+
avg_price: focus_position.avg_price,
|
|
65790
|
+
avg_qty: focus_position.avg_qty
|
|
65791
|
+
},
|
|
65792
|
+
strategy: {
|
|
65793
|
+
reward_factor: strategy.reward_factor,
|
|
65794
|
+
risk: strategy.risk,
|
|
65795
|
+
max_reward_factor: strategy.max_reward_factor
|
|
65796
|
+
},
|
|
65797
|
+
reduce_position: {
|
|
65798
|
+
kind: reduce_position.kind,
|
|
65799
|
+
entry: reduce_position.entry,
|
|
65800
|
+
quantity: reduce_position.quantity,
|
|
65801
|
+
avg_price: reduce_position.avg_price,
|
|
65802
|
+
avg_qty: reduce_position.avg_qty
|
|
65803
|
+
},
|
|
65804
|
+
reverse_position: {
|
|
65805
|
+
kind: reverse_position.kind,
|
|
65806
|
+
avg_price: reverse_position.avg_price,
|
|
65807
|
+
avg_qty: reverse_position.avg_qty,
|
|
65808
|
+
stop_loss: reverse_position.stop_loss
|
|
65809
|
+
},
|
|
65810
|
+
price_places: symbol_config.price_places,
|
|
65811
|
+
decimal_places: symbol_config.decimal_places
|
|
65812
|
+
});
|
|
65813
|
+
}
|
|
65665
65814
|
}
|
|
65666
65815
|
function getExchangeKlass(exchange) {
|
|
65667
65816
|
const func = exchange === "binance" ? BinanceExchange : BybitExchange;
|
|
@@ -65994,6 +66143,32 @@ class App {
|
|
|
65994
66143
|
});
|
|
65995
66144
|
return result;
|
|
65996
66145
|
}
|
|
66146
|
+
async reduceExistingPosition(payload) {
|
|
66147
|
+
const { main_account, reduce_account, kind, place, increase } = payload;
|
|
66148
|
+
const main_exchange_account = await this.getExchangeAccount(main_account);
|
|
66149
|
+
const reduce_exchange_account = await this.getExchangeAccount(reduce_account);
|
|
66150
|
+
const reduce_position = await reduce_exchange_account.syncAccount({
|
|
66151
|
+
symbol: reduce_account.symbol,
|
|
66152
|
+
kind,
|
|
66153
|
+
as_view: true
|
|
66154
|
+
});
|
|
66155
|
+
const result = await main_exchange_account.getSellPriceFromStrategy({
|
|
66156
|
+
symbol: main_account.symbol,
|
|
66157
|
+
reduce_position
|
|
66158
|
+
});
|
|
66159
|
+
if (place) {
|
|
66160
|
+
return reduce_exchange_account.exchange.customStopLoss({
|
|
66161
|
+
symbol: reduce_account.symbol,
|
|
66162
|
+
kind: reduce_position.kind,
|
|
66163
|
+
stop: result.sell_price,
|
|
66164
|
+
quantity: result.quantity,
|
|
66165
|
+
price_places: result.price_places,
|
|
66166
|
+
decimal_places: result.decimal_places,
|
|
66167
|
+
increase
|
|
66168
|
+
});
|
|
66169
|
+
}
|
|
66170
|
+
return result;
|
|
66171
|
+
}
|
|
65997
66172
|
}
|
|
65998
66173
|
async function initApp(payload) {
|
|
65999
66174
|
const pb = await initPocketBaseClient(payload.db);
|
package/dist/mcp-server.js
CHANGED
|
@@ -60508,6 +60508,48 @@ function getRiskReward(payload) {
|
|
|
60508
60508
|
});
|
|
60509
60509
|
return risk_reward;
|
|
60510
60510
|
}
|
|
60511
|
+
function computeProfitDetail(payload) {
|
|
60512
|
+
const {
|
|
60513
|
+
focus_position,
|
|
60514
|
+
strategy,
|
|
60515
|
+
price_places = "%.1f",
|
|
60516
|
+
reduce_position,
|
|
60517
|
+
decimal_places,
|
|
60518
|
+
reverse_position
|
|
60519
|
+
} = payload;
|
|
60520
|
+
let reward_factor = strategy.reward_factor;
|
|
60521
|
+
let risk = strategy.risk;
|
|
60522
|
+
if (strategy.max_reward_factor === 0) {
|
|
60523
|
+
reward_factor = strategy.reward_factor;
|
|
60524
|
+
}
|
|
60525
|
+
if (focus_position.avg_qty >= focus_position.quantity && strategy.max_reward_factor) {
|
|
60526
|
+
reward_factor = focus_position.quantity * strategy.max_reward_factor / focus_position.avg_qty;
|
|
60527
|
+
} else {
|
|
60528
|
+
reward_factor = strategy.reward_factor;
|
|
60529
|
+
}
|
|
60530
|
+
const full_pnl = reward_factor * risk;
|
|
60531
|
+
const profit_percent = to_f2(full_pnl * 100 / (focus_position.avg_price * focus_position.avg_qty), "%.4f");
|
|
60532
|
+
const pnl = to_f2(focus_position.entry * focus_position.quantity * profit_percent / 100, "%.2f");
|
|
60533
|
+
const diff = pnl / focus_position.quantity;
|
|
60534
|
+
const sell_price = to_f2(focus_position.kind === "long" ? focus_position.entry + diff : focus_position.entry - diff, price_places);
|
|
60535
|
+
const loss = Math.abs(reduce_position.entry - sell_price) * reduce_position.quantity;
|
|
60536
|
+
const ratio = pnl / loss;
|
|
60537
|
+
const quantity = to_f2(reduce_position.quantity * ratio, decimal_places);
|
|
60538
|
+
const expected_loss = Math.abs(reverse_position.avg_price - sell_price) * reverse_position.avg_qty;
|
|
60539
|
+
const new_pnl = to_f2(pnl - expected_loss, "%.2f");
|
|
60540
|
+
return {
|
|
60541
|
+
pnl: new_pnl,
|
|
60542
|
+
loss: to_f2(expected_loss, "%.2f"),
|
|
60543
|
+
original_pnl: pnl,
|
|
60544
|
+
reward_factor,
|
|
60545
|
+
profit_percent,
|
|
60546
|
+
kind: focus_position.kind,
|
|
60547
|
+
sell_price: to_f2(sell_price, price_places),
|
|
60548
|
+
quantity,
|
|
60549
|
+
price_places,
|
|
60550
|
+
decimal_places
|
|
60551
|
+
};
|
|
60552
|
+
}
|
|
60511
60553
|
|
|
60512
60554
|
// src/helpers/strategy.ts
|
|
60513
60555
|
class Strategy {
|
|
@@ -60914,6 +60956,54 @@ class Strategy {
|
|
|
60914
60956
|
|
|
60915
60957
|
// src/exchanges/binance.ts
|
|
60916
60958
|
var import_binance = __toESM(require_lib2(), 1);
|
|
60959
|
+
|
|
60960
|
+
// src/types/index.ts
|
|
60961
|
+
class BaseExchange {
|
|
60962
|
+
client;
|
|
60963
|
+
constructor(client) {
|
|
60964
|
+
this.client = client;
|
|
60965
|
+
}
|
|
60966
|
+
async customStopLoss(payload) {
|
|
60967
|
+
const {
|
|
60968
|
+
symbol,
|
|
60969
|
+
kind,
|
|
60970
|
+
stop: _stop,
|
|
60971
|
+
quantity,
|
|
60972
|
+
increase = false,
|
|
60973
|
+
price_places,
|
|
60974
|
+
decimal_places
|
|
60975
|
+
} = payload;
|
|
60976
|
+
const spread = 1.00005;
|
|
60977
|
+
const stop = kind === "long" ? _stop * spread ** -1 : _stop * spread;
|
|
60978
|
+
const order = [
|
|
60979
|
+
{
|
|
60980
|
+
kind,
|
|
60981
|
+
side: kind === "long" ? "sell" : "buy",
|
|
60982
|
+
price: stop,
|
|
60983
|
+
quantity,
|
|
60984
|
+
stop: _stop,
|
|
60985
|
+
is_market: false
|
|
60986
|
+
}
|
|
60987
|
+
];
|
|
60988
|
+
if (increase) {
|
|
60989
|
+
order.push({
|
|
60990
|
+
kind,
|
|
60991
|
+
price: stop,
|
|
60992
|
+
side: kind === "long" ? "buy" : "sell",
|
|
60993
|
+
quantity,
|
|
60994
|
+
is_market: false
|
|
60995
|
+
});
|
|
60996
|
+
}
|
|
60997
|
+
return this.rawCreateLimitPurchaseOrders({
|
|
60998
|
+
orders: order,
|
|
60999
|
+
symbol,
|
|
61000
|
+
price_places,
|
|
61001
|
+
decimal_places
|
|
61002
|
+
});
|
|
61003
|
+
}
|
|
61004
|
+
}
|
|
61005
|
+
|
|
61006
|
+
// src/exchanges/binance.ts
|
|
60917
61007
|
var CONSTANTS = {
|
|
60918
61008
|
SPOT_TO_FIAT: "MAIN_C2C",
|
|
60919
61009
|
SPOT_TO_USDT_FUTURE: "MAIN_UMFUTURE",
|
|
@@ -61684,12 +61774,13 @@ async function getAllOpenOrders(payload) {
|
|
|
61684
61774
|
return response;
|
|
61685
61775
|
}
|
|
61686
61776
|
|
|
61687
|
-
class BinanceExchange {
|
|
61777
|
+
class BinanceExchange extends BaseExchange {
|
|
61688
61778
|
client;
|
|
61689
61779
|
main_client;
|
|
61690
61780
|
getCredentials;
|
|
61691
61781
|
proxyAgent;
|
|
61692
61782
|
constructor(client, main_client) {
|
|
61783
|
+
super(client);
|
|
61693
61784
|
this.client = client;
|
|
61694
61785
|
this.main_client = main_client;
|
|
61695
61786
|
}
|
|
@@ -62001,6 +62092,10 @@ class BinanceExchange {
|
|
|
62001
62092
|
}
|
|
62002
62093
|
]);
|
|
62003
62094
|
}
|
|
62095
|
+
async rawCreateLimitPurchaseOrders(payload) {
|
|
62096
|
+
const { symbol, orders, price_places, decimal_places } = payload;
|
|
62097
|
+
return createLimitPurchaseOrders(this.client, symbol, price_places, decimal_places, orders);
|
|
62098
|
+
}
|
|
62004
62099
|
}
|
|
62005
62100
|
function getPricePlaces(target) {
|
|
62006
62101
|
const numStr = target.toString();
|
|
@@ -62498,10 +62593,11 @@ async function analyzeCharts2(params) {
|
|
|
62498
62593
|
return finalPairs;
|
|
62499
62594
|
}
|
|
62500
62595
|
|
|
62501
|
-
class BybitExchange {
|
|
62596
|
+
class BybitExchange extends BaseExchange {
|
|
62502
62597
|
client;
|
|
62503
62598
|
main_client;
|
|
62504
62599
|
constructor(client, main_client) {
|
|
62600
|
+
super(client);
|
|
62505
62601
|
this.client = client;
|
|
62506
62602
|
this.main_client = main_client;
|
|
62507
62603
|
}
|
|
@@ -62675,6 +62771,10 @@ class BybitExchange {
|
|
|
62675
62771
|
}
|
|
62676
62772
|
async placeMarketOrder(payload) {
|
|
62677
62773
|
}
|
|
62774
|
+
async rawCreateLimitPurchaseOrders(payload) {
|
|
62775
|
+
const { symbol, orders, price_places, decimal_places } = payload;
|
|
62776
|
+
return createLimitPurchaseOrders2(this.client, symbol, price_places, decimal_places, orders);
|
|
62777
|
+
}
|
|
62678
62778
|
}
|
|
62679
62779
|
|
|
62680
62780
|
// src/helpers/accounts.ts
|
|
@@ -65639,6 +65739,55 @@ class ExchangeAccount {
|
|
|
65639
65739
|
}
|
|
65640
65740
|
};
|
|
65641
65741
|
}
|
|
65742
|
+
async getSellPriceFromStrategy(payload) {
|
|
65743
|
+
const { symbol, reduce_position } = payload;
|
|
65744
|
+
const symbol_config = await this.recomputeSymbolConfig({
|
|
65745
|
+
symbol
|
|
65746
|
+
});
|
|
65747
|
+
const positions = await this.syncAccount({
|
|
65748
|
+
symbol,
|
|
65749
|
+
as_view: true
|
|
65750
|
+
});
|
|
65751
|
+
const focus_position = positions.find((k) => k.expand?.account_strategy);
|
|
65752
|
+
if (!focus_position) {
|
|
65753
|
+
return;
|
|
65754
|
+
}
|
|
65755
|
+
const reverse_kind = focus_position.kind === "long" ? "short" : "long";
|
|
65756
|
+
const reverse_position = positions.find((k) => k.kind === reverse_kind);
|
|
65757
|
+
const strategy = focus_position?.expand?.account_strategy;
|
|
65758
|
+
if (!strategy) {
|
|
65759
|
+
return;
|
|
65760
|
+
}
|
|
65761
|
+
return computeProfitDetail({
|
|
65762
|
+
focus_position: {
|
|
65763
|
+
kind: focus_position.kind,
|
|
65764
|
+
entry: focus_position.entry,
|
|
65765
|
+
quantity: focus_position.quantity,
|
|
65766
|
+
avg_price: focus_position.avg_price,
|
|
65767
|
+
avg_qty: focus_position.avg_qty
|
|
65768
|
+
},
|
|
65769
|
+
strategy: {
|
|
65770
|
+
reward_factor: strategy.reward_factor,
|
|
65771
|
+
risk: strategy.risk,
|
|
65772
|
+
max_reward_factor: strategy.max_reward_factor
|
|
65773
|
+
},
|
|
65774
|
+
reduce_position: {
|
|
65775
|
+
kind: reduce_position.kind,
|
|
65776
|
+
entry: reduce_position.entry,
|
|
65777
|
+
quantity: reduce_position.quantity,
|
|
65778
|
+
avg_price: reduce_position.avg_price,
|
|
65779
|
+
avg_qty: reduce_position.avg_qty
|
|
65780
|
+
},
|
|
65781
|
+
reverse_position: {
|
|
65782
|
+
kind: reverse_position.kind,
|
|
65783
|
+
avg_price: reverse_position.avg_price,
|
|
65784
|
+
avg_qty: reverse_position.avg_qty,
|
|
65785
|
+
stop_loss: reverse_position.stop_loss
|
|
65786
|
+
},
|
|
65787
|
+
price_places: symbol_config.price_places,
|
|
65788
|
+
decimal_places: symbol_config.decimal_places
|
|
65789
|
+
});
|
|
65790
|
+
}
|
|
65642
65791
|
}
|
|
65643
65792
|
function getExchangeKlass(exchange) {
|
|
65644
65793
|
const func = exchange === "binance" ? BinanceExchange : BybitExchange;
|
|
@@ -65971,6 +66120,32 @@ class App {
|
|
|
65971
66120
|
});
|
|
65972
66121
|
return result;
|
|
65973
66122
|
}
|
|
66123
|
+
async reduceExistingPosition(payload) {
|
|
66124
|
+
const { main_account, reduce_account, kind, place, increase } = payload;
|
|
66125
|
+
const main_exchange_account = await this.getExchangeAccount(main_account);
|
|
66126
|
+
const reduce_exchange_account = await this.getExchangeAccount(reduce_account);
|
|
66127
|
+
const reduce_position = await reduce_exchange_account.syncAccount({
|
|
66128
|
+
symbol: reduce_account.symbol,
|
|
66129
|
+
kind,
|
|
66130
|
+
as_view: true
|
|
66131
|
+
});
|
|
66132
|
+
const result = await main_exchange_account.getSellPriceFromStrategy({
|
|
66133
|
+
symbol: main_account.symbol,
|
|
66134
|
+
reduce_position
|
|
66135
|
+
});
|
|
66136
|
+
if (place) {
|
|
66137
|
+
return reduce_exchange_account.exchange.customStopLoss({
|
|
66138
|
+
symbol: reduce_account.symbol,
|
|
66139
|
+
kind: reduce_position.kind,
|
|
66140
|
+
stop: result.sell_price,
|
|
66141
|
+
quantity: result.quantity,
|
|
66142
|
+
price_places: result.price_places,
|
|
66143
|
+
decimal_places: result.decimal_places,
|
|
66144
|
+
increase
|
|
66145
|
+
});
|
|
66146
|
+
}
|
|
66147
|
+
return result;
|
|
66148
|
+
}
|
|
65974
66149
|
}
|
|
65975
66150
|
async function initApp(payload) {
|
|
65976
66151
|
const pb = await initPocketBaseClient(payload.db);
|