@gbozee/ultimate 0.0.2-19 → 0.0.2-21
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/index.d.ts +249 -78
- package/dist/index.js +1496 -391
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -32115,6 +32115,18 @@ class AppDatabase {
|
|
|
32115
32115
|
constructor(pb) {
|
|
32116
32116
|
this.pb = pb;
|
|
32117
32117
|
}
|
|
32118
|
+
async getAllSymbolsFromPositions(options) {
|
|
32119
|
+
const { no_position = false, kind = "long", custom_filter } = options || {};
|
|
32120
|
+
let filter = custom_filter || (no_position ? `quantity = 0` : undefined);
|
|
32121
|
+
if (kind && filter && !custom_filter) {
|
|
32122
|
+
filter = `${filter} && kind = "${kind}"`;
|
|
32123
|
+
}
|
|
32124
|
+
const positions = await this.pb.collection("positions").getFullList({
|
|
32125
|
+
fields: `symbol`,
|
|
32126
|
+
filter
|
|
32127
|
+
});
|
|
32128
|
+
return Array.from(new Set(positions.map((p) => p.symbol)));
|
|
32129
|
+
}
|
|
32118
32130
|
async createOrUpdateLiveExchangeInstance(payload) {
|
|
32119
32131
|
const result = await this.getLiveExchangeInstance(payload);
|
|
32120
32132
|
if (result) {
|
|
@@ -32157,18 +32169,21 @@ class AppDatabase {
|
|
|
32157
32169
|
async getAccounts() {
|
|
32158
32170
|
return await this.pb.collection("exchange_accounts").getFullList();
|
|
32159
32171
|
}
|
|
32160
|
-
async getAllSymbolConfigs(
|
|
32172
|
+
async getAllSymbolConfigs(payload) {
|
|
32173
|
+
const { with_positions = false, custom_filter } = payload || {
|
|
32174
|
+
with_positions: false
|
|
32175
|
+
};
|
|
32176
|
+
let filter = custom_filter || undefined;
|
|
32161
32177
|
if (with_positions) {
|
|
32162
32178
|
const positions = await this.pb.collection("positions").getFullList({
|
|
32163
32179
|
fields: `symbol`
|
|
32164
32180
|
});
|
|
32165
32181
|
const symbol_set = new Set(positions.map((p) => p.symbol));
|
|
32166
|
-
|
|
32167
|
-
return await this.pb.collection("symbol_configs").getFullList({
|
|
32168
|
-
filter
|
|
32169
|
-
});
|
|
32182
|
+
filter = Array.from(symbol_set).map((s2) => `symbol:lower="${s2.toLowerCase()}"`).join(" || ");
|
|
32170
32183
|
}
|
|
32171
|
-
return await this.pb.collection("symbol_configs").getFullList(
|
|
32184
|
+
return await this.pb.collection("symbol_configs").getFullList({
|
|
32185
|
+
filter
|
|
32186
|
+
});
|
|
32172
32187
|
}
|
|
32173
32188
|
async get_exchange_db_instance(account) {
|
|
32174
32189
|
const result = await this.pb.collection("exchange_accounts").getFirstListItem(`owner="${account.owner}" && exchange="${account.exchange}"`, {
|
|
@@ -32176,9 +32191,9 @@ class AppDatabase {
|
|
|
32176
32191
|
});
|
|
32177
32192
|
return result;
|
|
32178
32193
|
}
|
|
32179
|
-
async getPositions(
|
|
32180
|
-
const { symbol, as_view = false } = options;
|
|
32181
|
-
|
|
32194
|
+
async getPositions(options) {
|
|
32195
|
+
const { symbol, as_view = false, account, custom_filter } = options;
|
|
32196
|
+
let default_params = as_view ? {
|
|
32182
32197
|
table: "positions_view",
|
|
32183
32198
|
params: {
|
|
32184
32199
|
filter: `symbol:lower="${symbol.toLowerCase()}" && account:lower="${account.owner.toLowerCase()} ${account.exchange.toLowerCase()}"`,
|
|
@@ -32191,6 +32206,9 @@ class AppDatabase {
|
|
|
32191
32206
|
expand: "account,config"
|
|
32192
32207
|
}
|
|
32193
32208
|
};
|
|
32209
|
+
if (custom_filter) {
|
|
32210
|
+
default_params.params.filter = custom_filter;
|
|
32211
|
+
}
|
|
32194
32212
|
return await this.pb.collection(default_params.table).getFullList(default_params.params);
|
|
32195
32213
|
}
|
|
32196
32214
|
async _createOrUpdatePosition(db_position, params) {
|
|
@@ -32208,7 +32226,8 @@ class AppDatabase {
|
|
|
32208
32226
|
}
|
|
32209
32227
|
async createOrUpdatePositions(account, options) {
|
|
32210
32228
|
const { symbol, long_position, usd_balance, short_position } = options;
|
|
32211
|
-
const db_positions = await this.getPositions(
|
|
32229
|
+
const db_positions = await this.getPositions({
|
|
32230
|
+
account,
|
|
32212
32231
|
symbol
|
|
32213
32232
|
});
|
|
32214
32233
|
const exchange_db_instance = await this.get_exchange_db_instance(account);
|
|
@@ -32236,7 +32255,13 @@ class AppDatabase {
|
|
|
32236
32255
|
return await this.pb.collection("positions").update(position.id, payload);
|
|
32237
32256
|
}
|
|
32238
32257
|
async getSymbolConfigFromDB(symbol) {
|
|
32239
|
-
|
|
32258
|
+
const item = await this.pb.collection("symbol_configs").getFullList({
|
|
32259
|
+
filter: `symbol:lower="${symbol.toLowerCase()}"`
|
|
32260
|
+
});
|
|
32261
|
+
if (item.length > 0) {
|
|
32262
|
+
return item[0];
|
|
32263
|
+
}
|
|
32264
|
+
return null;
|
|
32240
32265
|
}
|
|
32241
32266
|
async getRunningInstanceFromDB(account, symbol, options) {
|
|
32242
32267
|
const { delay = 60 * 1000 } = options || {
|
|
@@ -32385,31 +32410,74 @@ class AppDatabase {
|
|
|
32385
32410
|
return { success: false, error: error.message };
|
|
32386
32411
|
}
|
|
32387
32412
|
}
|
|
32413
|
+
async getMoverExchangeInstances() {
|
|
32414
|
+
const result = await this.pb.collection("exchange_accounts").getFullList({
|
|
32415
|
+
filter: `totalRisk > 0 && movePercent > 0 && profit_percent > 0 && risk_reward > 0 && max_non_essential > 0`
|
|
32416
|
+
});
|
|
32417
|
+
return result;
|
|
32418
|
+
}
|
|
32419
|
+
async updateScheduledTrade(id, payload) {
|
|
32420
|
+
return await this.pb.collection("scheduled_trades").update(id, payload);
|
|
32421
|
+
}
|
|
32388
32422
|
async createOrUpdatePositionConfig(db_position, payload) {
|
|
32389
32423
|
let config = null;
|
|
32390
32424
|
if (db_position.config) {
|
|
32391
|
-
|
|
32425
|
+
const obj = {
|
|
32392
32426
|
entry: payload.entry,
|
|
32393
32427
|
stop: payload.stop,
|
|
32394
32428
|
risk_reward: payload.risk_reward,
|
|
32395
32429
|
risk: payload.risk
|
|
32396
|
-
}
|
|
32430
|
+
};
|
|
32431
|
+
if (payload.profit_percent !== undefined) {
|
|
32432
|
+
obj.profit_percent = payload.profit_percent;
|
|
32433
|
+
}
|
|
32434
|
+
if (payload.place_tp !== undefined) {
|
|
32435
|
+
obj.place_tp = payload.place_tp;
|
|
32436
|
+
}
|
|
32437
|
+
if (payload.profit !== undefined) {
|
|
32438
|
+
obj.profit = payload.profit;
|
|
32439
|
+
}
|
|
32440
|
+
return await this.pb.collection("scheduled_trades").update(db_position.config, obj);
|
|
32397
32441
|
} else {
|
|
32398
|
-
|
|
32399
|
-
|
|
32400
|
-
|
|
32401
|
-
|
|
32402
|
-
kind: payload.entry > payload.stop ? "long" : "short",
|
|
32403
|
-
entry: payload.entry,
|
|
32404
|
-
stop: payload.stop,
|
|
32405
|
-
risk_reward: payload.risk_reward,
|
|
32406
|
-
risk: payload.risk,
|
|
32407
|
-
profit_percent: payload.profit_percent,
|
|
32408
|
-
place_tp: true
|
|
32442
|
+
const kind = payload.entry > payload.stop ? "long" : "short";
|
|
32443
|
+
const account = db_position.expand?.account;
|
|
32444
|
+
const configs = await this.pb.collection("scheduled_trades").getFullList({
|
|
32445
|
+
filter: `symbol:lower="${db_position.symbol.toLowerCase()}" && kind="${kind}" && account.owner:lower="${account.owner.toLowerCase()}" && account.exchange:lower="${account.exchange.toLowerCase()}"`
|
|
32409
32446
|
});
|
|
32447
|
+
if (configs.length > 0) {
|
|
32448
|
+
config = configs[0];
|
|
32449
|
+
await this.pb.collection("scheduled_trades").update(config.id, {
|
|
32450
|
+
entry: payload.entry,
|
|
32451
|
+
stop: payload.stop,
|
|
32452
|
+
risk_reward: payload.risk_reward,
|
|
32453
|
+
risk: payload.risk,
|
|
32454
|
+
profit_percent: payload.profit_percent,
|
|
32455
|
+
place_tp: payload.place_tp !== undefined ? payload.place_tp : true,
|
|
32456
|
+
profit: payload.profit !== undefined ? payload.profit : config.profit
|
|
32457
|
+
});
|
|
32458
|
+
for (const _config of configs) {
|
|
32459
|
+
if (_config.id !== config.id) {
|
|
32460
|
+
await this.pb.collection("scheduled_trades").delete(_config.id);
|
|
32461
|
+
}
|
|
32462
|
+
}
|
|
32463
|
+
} else {
|
|
32464
|
+
config = await this.pb.collection("scheduled_trades").create({
|
|
32465
|
+
symbol: db_position.symbol,
|
|
32466
|
+
account: db_position.account,
|
|
32467
|
+
profit: payload.profit || payload.risk,
|
|
32468
|
+
kind,
|
|
32469
|
+
entry: payload.entry,
|
|
32470
|
+
stop: payload.stop,
|
|
32471
|
+
risk_reward: payload.risk_reward,
|
|
32472
|
+
risk: payload.risk,
|
|
32473
|
+
profit_percent: payload.profit_percent,
|
|
32474
|
+
place_tp: payload.place_tp !== undefined ? payload.place_tp : true
|
|
32475
|
+
});
|
|
32476
|
+
}
|
|
32410
32477
|
await this.pb.collection("positions").update(db_position.id, {
|
|
32411
32478
|
config: config?.id
|
|
32412
32479
|
});
|
|
32480
|
+
return config;
|
|
32413
32481
|
}
|
|
32414
32482
|
}
|
|
32415
32483
|
async getPositionConfig(payload) {
|
|
@@ -32458,7 +32526,7 @@ class AppDatabase {
|
|
|
32458
32526
|
moved_to_winding: []
|
|
32459
32527
|
};
|
|
32460
32528
|
}
|
|
32461
|
-
const { new_markets, totalRisk } = options;
|
|
32529
|
+
const { new_markets, totalRisk, max_count: _max_count } = options;
|
|
32462
32530
|
const newMarketSymbols = new Set(new_markets.map((m) => m.symbol));
|
|
32463
32531
|
console.log(`Processing ${new_markets.length} new top movers with total risk ${totalRisk}`);
|
|
32464
32532
|
let currentBullish = [];
|
|
@@ -32649,6 +32717,12 @@ class AppDatabase {
|
|
|
32649
32717
|
});
|
|
32650
32718
|
return result;
|
|
32651
32719
|
}
|
|
32720
|
+
async hasExistingOrders(symbol) {
|
|
32721
|
+
const result = await this.pb.collection("orders").getFullList({
|
|
32722
|
+
filter: `symbol:lower="${symbol.toLowerCase()}"`
|
|
32723
|
+
});
|
|
32724
|
+
return result;
|
|
32725
|
+
}
|
|
32652
32726
|
async removeSymbolFromUnwindingMarkets(symbol) {
|
|
32653
32727
|
const result = await this.pb.collection("winding_down_markets").getFullList({
|
|
32654
32728
|
filter: `symbol:lower="${symbol.toLowerCase()}"`
|
|
@@ -33192,6 +33266,10 @@ class Signal {
|
|
|
33192
33266
|
limit_orders = trade_zones.slice(1).filter((x) => x >= this.to_f(current_price));
|
|
33193
33267
|
market_orders = trade_zones.slice(1).filter((x) => x < this.to_f(current_price));
|
|
33194
33268
|
}
|
|
33269
|
+
if (market_orders.length === 1) {
|
|
33270
|
+
limit_orders = limit_orders.concat(market_orders);
|
|
33271
|
+
market_orders = [];
|
|
33272
|
+
}
|
|
33195
33273
|
const increase_position = Boolean(this.support) && this.increase_position;
|
|
33196
33274
|
const market_trades = limit_orders.length > 0 ? market_orders.map((x, i2) => {
|
|
33197
33275
|
const defaultStopLoss = i2 === 0 ? limit_orders[limit_orders.length - 1] : market_orders[i2 - 1];
|
|
@@ -33338,6 +33416,8 @@ class Signal {
|
|
|
33338
33416
|
});
|
|
33339
33417
|
const multiplier = start - index;
|
|
33340
33418
|
const incurred_fees = fees.reduce((a, b) => a + b, 0) + previous_risks.reduce((a, b) => a + b, 0);
|
|
33419
|
+
if (index === 0) {
|
|
33420
|
+
}
|
|
33341
33421
|
let quantity = determine_position_size({
|
|
33342
33422
|
entry,
|
|
33343
33423
|
stop,
|
|
@@ -33819,7 +33899,11 @@ async function placeTpOrder(client, payload) {
|
|
|
33819
33899
|
price: payload.tp,
|
|
33820
33900
|
quantity: _quantity
|
|
33821
33901
|
};
|
|
33822
|
-
|
|
33902
|
+
const rr = await createLimitPurchaseOrders(client, symbol, price_places, decimal_places, [order]);
|
|
33903
|
+
if (payload.kind == "long") {
|
|
33904
|
+
console.log("rr", { rr, price_places, decimal_places });
|
|
33905
|
+
}
|
|
33906
|
+
return rr;
|
|
33823
33907
|
}
|
|
33824
33908
|
return { error: "No quantity" };
|
|
33825
33909
|
}
|
|
@@ -33935,17 +34019,21 @@ async function allWalletBalances(client) {
|
|
|
33935
34019
|
balance: to_f(x.balance, "%.8f")
|
|
33936
34020
|
}));
|
|
33937
34021
|
}
|
|
33938
|
-
function buildPosition(position2, orders) {
|
|
34022
|
+
function buildPosition(position2, orders, options) {
|
|
34023
|
+
const { price_places = "%.1f", decimal_places = "%.3f" } = options;
|
|
33939
34024
|
const entry = position2.entryPrice;
|
|
33940
|
-
|
|
34025
|
+
let quantity = Math.abs(position2.positionAmt);
|
|
33941
34026
|
const kind = position2.kind;
|
|
34027
|
+
if (Number.isNaN(quantity)) {
|
|
34028
|
+
quantity = 0;
|
|
34029
|
+
}
|
|
33942
34030
|
const limitOrders = orders.filter((x) => x.kind === kind && !x.isStop).filter((o) => {
|
|
33943
34031
|
return kind === "long" ? o.side === "buy" : o.side === "sell";
|
|
33944
34032
|
});
|
|
33945
34033
|
const avg = determine_average_entry_and_size([
|
|
33946
34034
|
{ price: entry, quantity },
|
|
33947
34035
|
...limitOrders.map((o) => ({ price: o.price, quantity: o.qty }))
|
|
33948
|
-
],
|
|
34036
|
+
], decimal_places, price_places);
|
|
33949
34037
|
const stopOrders = orders.filter((x) => x.kind === kind && x.isStop)[0];
|
|
33950
34038
|
const tpOrders = orders.filter((x) => x.kind === kind && !x.isStop).filter((x) => x.kind === "long" ? x.side === "sell" : x.side === "buy")[0];
|
|
33951
34039
|
const avg_entry = avg.entry;
|
|
@@ -33980,7 +34068,7 @@ var emptyPosition = {
|
|
|
33980
34068
|
tp_quantity: 0,
|
|
33981
34069
|
stop_quantity: 0
|
|
33982
34070
|
};
|
|
33983
|
-
async function fetchBinanceAccount(client, json) {
|
|
34071
|
+
async function fetchBinanceAccount(client, json, options) {
|
|
33984
34072
|
const [position2, balance, orders, current_price, all_balances] = await Promise.all([
|
|
33985
34073
|
getPositionInfo(client, json.symbol),
|
|
33986
34074
|
getWalletBalance(client, json.symbol.toLowerCase().endsWith("usdt") ? "USDT" : "USDC"),
|
|
@@ -33995,19 +34083,19 @@ async function fetchBinanceAccount(client, json) {
|
|
|
33995
34083
|
const long_position = buildPosition(position2.long || {
|
|
33996
34084
|
...emptyPosition,
|
|
33997
34085
|
kind: "long"
|
|
33998
|
-
}, orders);
|
|
34086
|
+
}, orders, options);
|
|
33999
34087
|
const short_position = buildPosition(position2.short || {
|
|
34000
34088
|
...emptyPosition,
|
|
34001
34089
|
kind: "short"
|
|
34002
|
-
}, orders);
|
|
34090
|
+
}, orders, options);
|
|
34003
34091
|
const result = {
|
|
34004
34092
|
id: `${json.owner}-${json.symbol}-binance`,
|
|
34005
34093
|
owner: json.owner,
|
|
34006
34094
|
config: {
|
|
34007
34095
|
symbol: json.symbol,
|
|
34008
34096
|
id: 0,
|
|
34009
|
-
price_places:
|
|
34010
|
-
decimal_places:
|
|
34097
|
+
price_places: options.price_places,
|
|
34098
|
+
decimal_places: options.decimal_places,
|
|
34011
34099
|
trades: {}
|
|
34012
34100
|
},
|
|
34013
34101
|
exchange: "binance",
|
|
@@ -34103,10 +34191,10 @@ async function analyzeCharts(params) {
|
|
|
34103
34191
|
return finalPairs;
|
|
34104
34192
|
}
|
|
34105
34193
|
async function getWeeklyKlines(payload) {
|
|
34106
|
-
const { client, symbol, limit = 20 } = payload;
|
|
34194
|
+
const { client, symbol, limit = 20, interval = "1w" } = payload;
|
|
34107
34195
|
const requestParams = {
|
|
34108
34196
|
symbol: symbol.toUpperCase(),
|
|
34109
|
-
interval
|
|
34197
|
+
interval
|
|
34110
34198
|
};
|
|
34111
34199
|
if (limit) {
|
|
34112
34200
|
requestParams.limit = limit;
|
|
@@ -34163,11 +34251,18 @@ async function getActiveSymbols(payload) {
|
|
|
34163
34251
|
const response = await client.getExchangeInfo();
|
|
34164
34252
|
return response.symbols;
|
|
34165
34253
|
}
|
|
34254
|
+
async function getAllOpenOrders(payload) {
|
|
34255
|
+
const { client } = payload;
|
|
34256
|
+
const response = await client.getAllOpenOrders();
|
|
34257
|
+
return response;
|
|
34258
|
+
}
|
|
34166
34259
|
|
|
34167
34260
|
class BinanceExchange {
|
|
34168
34261
|
client;
|
|
34169
|
-
|
|
34262
|
+
main_client;
|
|
34263
|
+
constructor(client, main_client) {
|
|
34170
34264
|
this.client = client;
|
|
34265
|
+
this.main_client = main_client;
|
|
34171
34266
|
}
|
|
34172
34267
|
async placeStopOrders(payload) {
|
|
34173
34268
|
if (payload.place) {
|
|
@@ -34184,6 +34279,22 @@ class BinanceExchange {
|
|
|
34184
34279
|
});
|
|
34185
34280
|
}
|
|
34186
34281
|
}
|
|
34282
|
+
async createLimitPurchaseOrders(payload) {
|
|
34283
|
+
const {
|
|
34284
|
+
orders,
|
|
34285
|
+
kind,
|
|
34286
|
+
decimal_places = "%.3f",
|
|
34287
|
+
price_places = "%.1f",
|
|
34288
|
+
symbol
|
|
34289
|
+
} = payload;
|
|
34290
|
+
const _orders = orders.map((order) => ({
|
|
34291
|
+
...order,
|
|
34292
|
+
price: order.entry,
|
|
34293
|
+
kind,
|
|
34294
|
+
side: kind.toLowerCase() === "long" ? "buy" : "sell"
|
|
34295
|
+
}));
|
|
34296
|
+
return await createLimitPurchaseOrders(this.client, symbol, price_places, decimal_places, _orders);
|
|
34297
|
+
}
|
|
34187
34298
|
async bulkPlaceLimitOrders(payload) {
|
|
34188
34299
|
const {
|
|
34189
34300
|
orders,
|
|
@@ -34242,10 +34353,19 @@ class BinanceExchange {
|
|
|
34242
34353
|
raw: payload.raw || false
|
|
34243
34354
|
});
|
|
34244
34355
|
}
|
|
34245
|
-
async getExchangeAccountInfo(
|
|
34356
|
+
async getExchangeAccountInfo(options) {
|
|
34357
|
+
const {
|
|
34358
|
+
price_places = "%.1f",
|
|
34359
|
+
decimal_places = "%.3f",
|
|
34360
|
+
account,
|
|
34361
|
+
symbol
|
|
34362
|
+
} = options;
|
|
34246
34363
|
return await fetchBinanceAccount(this.client, {
|
|
34247
34364
|
owner: account.owner,
|
|
34248
34365
|
symbol
|
|
34366
|
+
}, {
|
|
34367
|
+
price_places,
|
|
34368
|
+
decimal_places
|
|
34249
34369
|
});
|
|
34250
34370
|
}
|
|
34251
34371
|
async cancelOrders(payload) {
|
|
@@ -34304,20 +34424,25 @@ class BinanceExchange {
|
|
|
34304
34424
|
}
|
|
34305
34425
|
maxLeverage = Math.max(...brackets.brackets.map((b) => b.initialLeverage));
|
|
34306
34426
|
}
|
|
34307
|
-
|
|
34308
|
-
|
|
34309
|
-
|
|
34310
|
-
|
|
34427
|
+
try {
|
|
34428
|
+
await this.client.setLeverage({
|
|
34429
|
+
symbol: payload.symbol,
|
|
34430
|
+
leverage: payload.leverage || maxLeverage
|
|
34431
|
+
});
|
|
34432
|
+
} catch (error) {
|
|
34433
|
+
console.log("error", error);
|
|
34434
|
+
}
|
|
34311
34435
|
return maxLeverage;
|
|
34312
34436
|
}
|
|
34313
34437
|
async generateConfig(payload) {
|
|
34314
34438
|
const symbols = await getActiveSymbols({ client: this.client });
|
|
34315
34439
|
console.log("symbols", symbols);
|
|
34316
|
-
const { symbol, limit = 5 } = payload;
|
|
34440
|
+
const { symbol, limit = 5, interval = "1w" } = payload;
|
|
34317
34441
|
const klines = await getWeeklyKlines({
|
|
34318
34442
|
client: this.client,
|
|
34319
34443
|
symbol,
|
|
34320
|
-
limit
|
|
34444
|
+
limit,
|
|
34445
|
+
interval
|
|
34321
34446
|
});
|
|
34322
34447
|
const { support, resistance } = calculateSupportResistance(klines);
|
|
34323
34448
|
const target = symbols.find((s2) => s2.symbol === symbol);
|
|
@@ -34328,14 +34453,19 @@ class BinanceExchange {
|
|
|
34328
34453
|
if (f.filterType === "MIN_NOTIONAL")
|
|
34329
34454
|
minNotional = parseFloat(f.notional);
|
|
34330
34455
|
});
|
|
34456
|
+
if (["BTCUSDT", "BTCUSDC"].includes(symbol)) {
|
|
34457
|
+
minNotional = 105;
|
|
34458
|
+
}
|
|
34459
|
+
const isBTC = ["BTCUSDT", "BTCUSDC"].includes(symbol);
|
|
34331
34460
|
const currentPrice = await getCurrentPrice(this.client, symbol);
|
|
34332
|
-
const price_places = `%.${getPricePlaces(currentPrice)}f`;
|
|
34461
|
+
const price_places = isBTC ? "%.1f" : `%.${getPricePlaces(currentPrice)}f`;
|
|
34333
34462
|
const decimal_places = `%.${target.quantityPrecision}f`;
|
|
34463
|
+
const min_size = to_f((minNotional || 0) / support, decimal_places);
|
|
34334
34464
|
const configObj = {
|
|
34335
34465
|
support,
|
|
34336
34466
|
resistance,
|
|
34337
34467
|
minNotional,
|
|
34338
|
-
min_size:
|
|
34468
|
+
min_size: isBTC ? 0.002 : min_size,
|
|
34339
34469
|
price_places,
|
|
34340
34470
|
decimal_places,
|
|
34341
34471
|
leverage: await this.setLeverage({ symbol }),
|
|
@@ -34353,18 +34483,49 @@ class BinanceExchange {
|
|
|
34353
34483
|
const delisted = movers.map((x) => x.symbol).filter((symbol) => !activeSymbols.includes(symbol));
|
|
34354
34484
|
const validMovers = movers.filter((m) => !delisted.includes(m.symbol)).filter((m) => activeSymbols.includes(m.symbol));
|
|
34355
34485
|
const activeMovers = [];
|
|
34356
|
-
|
|
34357
|
-
|
|
34486
|
+
const isActivePromises = validMovers.map(async (m) => {
|
|
34487
|
+
return await isSymbolActive({
|
|
34358
34488
|
client: this.client,
|
|
34359
34489
|
symbol: m.symbol
|
|
34360
34490
|
});
|
|
34361
|
-
|
|
34362
|
-
|
|
34491
|
+
});
|
|
34492
|
+
const isActiveResults = await Promise.all(isActivePromises);
|
|
34493
|
+
for (let i2 = 0;i2 < validMovers.length; i2++) {
|
|
34494
|
+
if (isActiveResults[i2]) {
|
|
34495
|
+
activeMovers.push(validMovers[i2]);
|
|
34363
34496
|
}
|
|
34364
34497
|
}
|
|
34365
34498
|
console.log(`Top movers:`, movers);
|
|
34366
34499
|
console.log(`Delisted movers:`, delisted);
|
|
34367
|
-
|
|
34500
|
+
const toBeDelisted = await this.getDelistedSpotSymbols();
|
|
34501
|
+
const _movers = activeMovers.filter((m) => !toBeDelisted.includes(m.symbol));
|
|
34502
|
+
return { movers: _movers, delisted };
|
|
34503
|
+
}
|
|
34504
|
+
async closePosition(payload) {
|
|
34505
|
+
const { symbol, kind, price_places, decimal_places } = payload;
|
|
34506
|
+
const currentPrice = await this.get_current_price(symbol);
|
|
34507
|
+
return this.placeTpOrder({
|
|
34508
|
+
price_places,
|
|
34509
|
+
decimal_places,
|
|
34510
|
+
symbol,
|
|
34511
|
+
take_profit: currentPrice,
|
|
34512
|
+
kind
|
|
34513
|
+
});
|
|
34514
|
+
}
|
|
34515
|
+
async getAllOpenSymbols() {
|
|
34516
|
+
const response = await getAllOpenOrders({ client: this.client });
|
|
34517
|
+
return Array.from(new Set(response.map((x) => x.symbol)));
|
|
34518
|
+
}
|
|
34519
|
+
async getDelistedSpotSymbols() {
|
|
34520
|
+
if (this.main_client) {
|
|
34521
|
+
const client = this.main_client;
|
|
34522
|
+
const response = await client.getDelistSchedule();
|
|
34523
|
+
if (response.length > 0) {
|
|
34524
|
+
return response[0].symbols;
|
|
34525
|
+
}
|
|
34526
|
+
return [];
|
|
34527
|
+
}
|
|
34528
|
+
return [];
|
|
34368
34529
|
}
|
|
34369
34530
|
}
|
|
34370
34531
|
function getPricePlaces(target) {
|
|
@@ -34681,7 +34842,8 @@ async function allWalletBalances2(client) {
|
|
|
34681
34842
|
balance: to_f(x.walletBalance, "%.8f")
|
|
34682
34843
|
}));
|
|
34683
34844
|
}
|
|
34684
|
-
function buildPosition2(position2, orders) {
|
|
34845
|
+
function buildPosition2(position2, orders, options) {
|
|
34846
|
+
const { price_places = "%.1f", decimal_places = "%.3f" } = options;
|
|
34685
34847
|
const entry = parseFloat(position2.avgPrice || "0");
|
|
34686
34848
|
const quantity = parseFloat(position2.size || "0");
|
|
34687
34849
|
const kind = position2.positionIdx === 1 ? "long" : "short";
|
|
@@ -34691,7 +34853,7 @@ function buildPosition2(position2, orders) {
|
|
|
34691
34853
|
const avg = determine_average_entry_and_size([
|
|
34692
34854
|
{ price: entry, quantity },
|
|
34693
34855
|
...limitOrders.map((o) => ({ price: o.price, quantity: o.qty }))
|
|
34694
|
-
],
|
|
34856
|
+
], decimal_places, price_places);
|
|
34695
34857
|
const stopOrders = orders.filter((x) => x.kind === kind && x.isStop)[0];
|
|
34696
34858
|
const tpOrders = orders.filter((x) => x.kind === kind && !x.isStop).filter((x) => x.kind === "long" ? x.side === "sell" : x.side === "buy")[0];
|
|
34697
34859
|
const avg_entry = avg.entry;
|
|
@@ -34726,7 +34888,8 @@ var emptyPosition2 = {
|
|
|
34726
34888
|
tp_quantity: 0,
|
|
34727
34889
|
stop_quantity: 0
|
|
34728
34890
|
};
|
|
34729
|
-
async function fetchBybitAccount(client, json) {
|
|
34891
|
+
async function fetchBybitAccount(client, json, options) {
|
|
34892
|
+
const { price_places = "%.1f", decimal_places = "%.3f" } = options;
|
|
34730
34893
|
const [position2, balance, orders, current_price, all_balances] = await Promise.all([
|
|
34731
34894
|
getPositionInfo2(client, json.symbol),
|
|
34732
34895
|
getWalletBalance2(client, "USDT"),
|
|
@@ -34744,8 +34907,8 @@ async function fetchBybitAccount(client, json) {
|
|
|
34744
34907
|
config: {
|
|
34745
34908
|
symbol: json.symbol,
|
|
34746
34909
|
id: 0,
|
|
34747
|
-
price_places
|
|
34748
|
-
decimal_places
|
|
34910
|
+
price_places,
|
|
34911
|
+
decimal_places,
|
|
34749
34912
|
trades: {}
|
|
34750
34913
|
},
|
|
34751
34914
|
exchange: "bybit",
|
|
@@ -34758,12 +34921,18 @@ async function fetchBybitAccount(client, json) {
|
|
|
34758
34921
|
...emptyPosition2,
|
|
34759
34922
|
positionIdx: 1,
|
|
34760
34923
|
kind: "long"
|
|
34761
|
-
}, orders
|
|
34924
|
+
}, orders, {
|
|
34925
|
+
price_places,
|
|
34926
|
+
decimal_places
|
|
34927
|
+
}),
|
|
34762
34928
|
short_position: buildPosition2(position2.short || {
|
|
34763
34929
|
...emptyPosition2,
|
|
34764
34930
|
positionIdx: 2,
|
|
34765
34931
|
kind: "short"
|
|
34766
|
-
}, orders
|
|
34932
|
+
}, orders, {
|
|
34933
|
+
price_places,
|
|
34934
|
+
decimal_places
|
|
34935
|
+
}),
|
|
34767
34936
|
current_price,
|
|
34768
34937
|
orders: limitOrders,
|
|
34769
34938
|
entries: [],
|
|
@@ -34856,8 +35025,10 @@ async function analyzeCharts2(params) {
|
|
|
34856
35025
|
|
|
34857
35026
|
class BybitExchange {
|
|
34858
35027
|
client;
|
|
34859
|
-
|
|
35028
|
+
main_client;
|
|
35029
|
+
constructor(client, main_client) {
|
|
34860
35030
|
this.client = client;
|
|
35031
|
+
this.main_client = main_client;
|
|
34861
35032
|
}
|
|
34862
35033
|
async placeStopOrders(payload) {
|
|
34863
35034
|
if (payload.place) {
|
|
@@ -34932,10 +35103,19 @@ class BybitExchange {
|
|
|
34932
35103
|
raw: payload.raw || false
|
|
34933
35104
|
});
|
|
34934
35105
|
}
|
|
34935
|
-
async getExchangeAccountInfo(
|
|
35106
|
+
async getExchangeAccountInfo(options) {
|
|
35107
|
+
const {
|
|
35108
|
+
price_places = "%.1f",
|
|
35109
|
+
decimal_places = "%.3f",
|
|
35110
|
+
account,
|
|
35111
|
+
symbol
|
|
35112
|
+
} = options;
|
|
34936
35113
|
return await fetchBybitAccount(this.client, {
|
|
34937
35114
|
owner: account.owner,
|
|
34938
35115
|
symbol
|
|
35116
|
+
}, {
|
|
35117
|
+
price_places,
|
|
35118
|
+
decimal_places
|
|
34939
35119
|
});
|
|
34940
35120
|
}
|
|
34941
35121
|
async cancelOrders(payload) {
|
|
@@ -34990,6 +35170,29 @@ class BybitExchange {
|
|
|
34990
35170
|
}
|
|
34991
35171
|
async checkDelistedMovers(payload) {
|
|
34992
35172
|
}
|
|
35173
|
+
async closePosition(payload) {
|
|
35174
|
+
}
|
|
35175
|
+
async getAllOpenSymbols() {
|
|
35176
|
+
return [];
|
|
35177
|
+
}
|
|
35178
|
+
async createLimitPurchaseOrders(payload) {
|
|
35179
|
+
const {
|
|
35180
|
+
orders,
|
|
35181
|
+
kind,
|
|
35182
|
+
decimal_places = "%.3f",
|
|
35183
|
+
price_places = "%.1f",
|
|
35184
|
+
symbol
|
|
35185
|
+
} = payload;
|
|
35186
|
+
return await createLimitPurchaseOrders2(this.client, symbol, price_places, decimal_places, orders.map((order) => ({
|
|
35187
|
+
...order,
|
|
35188
|
+
price: order.entry,
|
|
35189
|
+
kind,
|
|
35190
|
+
side: kind.toLowerCase() === "long" ? "buy" : "sell"
|
|
35191
|
+
})));
|
|
35192
|
+
}
|
|
35193
|
+
async getDelistedSpotSymbols() {
|
|
35194
|
+
return [];
|
|
35195
|
+
}
|
|
34993
35196
|
}
|
|
34994
35197
|
|
|
34995
35198
|
// src/helpers/accounts.ts
|
|
@@ -35145,12 +35348,12 @@ function calculateHedge(kind, active_account, targetPnl = 100, ratio = 0.9, use_
|
|
|
35145
35348
|
return {
|
|
35146
35349
|
[kind]: {
|
|
35147
35350
|
price: to_f(takeProfitPrice, active_account.price_places),
|
|
35148
|
-
quantity: to_f(position2.quantity, active_account.decimal_places),
|
|
35351
|
+
quantity: to_f(position2.quantity || 0, active_account.decimal_places),
|
|
35149
35352
|
type: "TAKE_PROFIT"
|
|
35150
35353
|
},
|
|
35151
35354
|
[oppositeKind]: {
|
|
35152
35355
|
stop_price: to_f(stopLossPrice, active_account.price_places),
|
|
35153
|
-
quantity: to_f(stopLossQuantity, active_account.decimal_places),
|
|
35356
|
+
quantity: to_f(stopLossQuantity || 0, active_account.decimal_places),
|
|
35154
35357
|
type: "STOP_LOSS"
|
|
35155
35358
|
}
|
|
35156
35359
|
};
|
|
@@ -35219,7 +35422,9 @@ function processPosition(codeNode, input, kind) {
|
|
|
35219
35422
|
owner: active_account.owner,
|
|
35220
35423
|
risk: codeNode.profit || 150,
|
|
35221
35424
|
increase: codeNode.increase,
|
|
35222
|
-
not_reduce: codeNode.not_reduce
|
|
35425
|
+
not_reduce: codeNode.not_reduce,
|
|
35426
|
+
price_places: active_account.price_places,
|
|
35427
|
+
decimal_places: active_account.decimal_places
|
|
35223
35428
|
};
|
|
35224
35429
|
}
|
|
35225
35430
|
async function reduceMajorPositionCalculation(input, exchange_instance) {
|
|
@@ -35242,11 +35447,13 @@ async function reduceMajorPositionCalculation(input, exchange_instance) {
|
|
|
35242
35447
|
});
|
|
35243
35448
|
if (conditionsCheck) {
|
|
35244
35449
|
const async_tp = async () => {
|
|
35245
|
-
if (input.stop) {
|
|
35450
|
+
if (input.stop && input.stop !== Infinity) {
|
|
35246
35451
|
await exchange_instance.placeTpOrder({
|
|
35247
35452
|
symbol: input.position.symbol,
|
|
35248
35453
|
kind: input.kind,
|
|
35249
|
-
take_profit: input.stop
|
|
35454
|
+
take_profit: input.stop,
|
|
35455
|
+
price_places: input.price_places,
|
|
35456
|
+
decimal_places: input.decimal_places
|
|
35250
35457
|
});
|
|
35251
35458
|
}
|
|
35252
35459
|
};
|
|
@@ -35256,7 +35463,9 @@ async function reduceMajorPositionCalculation(input, exchange_instance) {
|
|
|
35256
35463
|
symbol: input.position.symbol,
|
|
35257
35464
|
kind: input.to_place.kind,
|
|
35258
35465
|
price: input.to_place.stop_price,
|
|
35259
|
-
quantity: input.to_place.quantity
|
|
35466
|
+
quantity: input.to_place.quantity,
|
|
35467
|
+
price_places: input.price_places,
|
|
35468
|
+
decimal_places: input.decimal_places
|
|
35260
35469
|
}).then((r2) => {
|
|
35261
35470
|
console.log("placeNewOrderData", r2);
|
|
35262
35471
|
});
|
|
@@ -35264,12 +35473,14 @@ async function reduceMajorPositionCalculation(input, exchange_instance) {
|
|
|
35264
35473
|
};
|
|
35265
35474
|
let placeNewOrderData = null;
|
|
35266
35475
|
const async_place_stop = async () => {
|
|
35267
|
-
if (!input.not_reduce && input.to_place.stop_price) {
|
|
35476
|
+
if (!input.not_reduce && input.to_place.stop_price && input.to_place.quantity) {
|
|
35268
35477
|
await exchange_instance.placeStopOrder({
|
|
35269
35478
|
symbol: input.position.symbol,
|
|
35270
35479
|
kind: input.to_place.kind,
|
|
35271
35480
|
stop: input.to_place.stop_price,
|
|
35272
|
-
quantity: Math.abs(input.to_place.quantity)
|
|
35481
|
+
quantity: Math.abs(input.to_place.quantity),
|
|
35482
|
+
price_places: input.price_places,
|
|
35483
|
+
decimal_places: input.decimal_places
|
|
35273
35484
|
});
|
|
35274
35485
|
}
|
|
35275
35486
|
};
|
|
@@ -35385,6 +35596,7 @@ function buildConfig(app_config, {
|
|
|
35385
35596
|
if (kind === "short") {
|
|
35386
35597
|
console.log("condition", condition, entry === stop);
|
|
35387
35598
|
}
|
|
35599
|
+
console.log({ entry, support: app_config.support, stop });
|
|
35388
35600
|
const result = entry === stop ? [] : condition ? instance.build_entry({
|
|
35389
35601
|
current_price: entry,
|
|
35390
35602
|
stop_loss: stop,
|
|
@@ -35418,8 +35630,8 @@ function get_app_config_and_max_size(config, payload) {
|
|
|
35418
35630
|
stop: payload.stop,
|
|
35419
35631
|
risk_per_trade: config.risk,
|
|
35420
35632
|
risk_reward: config.risk_reward || 199,
|
|
35421
|
-
support: config.support,
|
|
35422
|
-
resistance: config.resistance,
|
|
35633
|
+
support: to_f(config.support, config.price_places),
|
|
35634
|
+
resistance: to_f(config.resistance, config.price_places),
|
|
35423
35635
|
focus: payload.entry,
|
|
35424
35636
|
fee: 0,
|
|
35425
35637
|
percent_change: config.stop_percent / 100,
|
|
@@ -35443,13 +35655,23 @@ function get_app_config_and_max_size(config, payload) {
|
|
|
35443
35655
|
decimal_places: app_config.decimal_places
|
|
35444
35656
|
});
|
|
35445
35657
|
const max_size = initialResult[0]?.avg_size;
|
|
35658
|
+
const last_value = initialResult[0];
|
|
35659
|
+
const entries = initialResult.map((x) => ({
|
|
35660
|
+
entry: x.entry,
|
|
35661
|
+
avg_entry: x.avg_entry,
|
|
35662
|
+
avg_size: x.avg_size,
|
|
35663
|
+
neg_pnl: x.neg_pnl,
|
|
35664
|
+
quantity: x.quantity
|
|
35665
|
+
}));
|
|
35446
35666
|
return {
|
|
35447
35667
|
app_config,
|
|
35448
|
-
max_size
|
|
35668
|
+
max_size,
|
|
35669
|
+
last_value,
|
|
35670
|
+
entries
|
|
35449
35671
|
};
|
|
35450
35672
|
}
|
|
35451
35673
|
function buildAppConfig(config, payload) {
|
|
35452
|
-
const { app_config, max_size } = get_app_config_and_max_size({
|
|
35674
|
+
const { app_config, max_size, last_value, entries } = get_app_config_and_max_size({
|
|
35453
35675
|
...config,
|
|
35454
35676
|
risk: payload.risk,
|
|
35455
35677
|
profit: payload.profit || 500,
|
|
@@ -35468,6 +35690,8 @@ function buildAppConfig(config, payload) {
|
|
|
35468
35690
|
app_config.max_size = max_size;
|
|
35469
35691
|
app_config.entry = payload.entry || app_config.entry;
|
|
35470
35692
|
app_config.stop = payload.stop || app_config.stop;
|
|
35693
|
+
app_config.last_value = last_value;
|
|
35694
|
+
app_config.entries = entries;
|
|
35471
35695
|
return app_config;
|
|
35472
35696
|
}
|
|
35473
35697
|
function getOptimumStopAndRisk(app_config, params) {
|
|
@@ -35641,24 +35865,35 @@ function generate_config_params(app_config, payload) {
|
|
|
35641
35865
|
class ExchangeAccount {
|
|
35642
35866
|
instance;
|
|
35643
35867
|
exchange;
|
|
35868
|
+
main_exchange;
|
|
35644
35869
|
app_db;
|
|
35645
35870
|
constructor(payload, options) {
|
|
35646
35871
|
this.instance = payload;
|
|
35647
35872
|
this.exchange = options.exchange;
|
|
35648
35873
|
this.app_db = options.app_db;
|
|
35874
|
+
this.main_exchange = options.main_exchange;
|
|
35649
35875
|
}
|
|
35650
35876
|
async getLiveExchangeInstance(payload) {
|
|
35877
|
+
const symbol_config = await this.recomputeSymbolConfig({
|
|
35878
|
+
symbol: payload.symbol,
|
|
35879
|
+
refresh: payload.refresh_symbol_config
|
|
35880
|
+
});
|
|
35651
35881
|
const result = await this.app_db.getLiveExchangeInstance({
|
|
35652
35882
|
account: this.instance,
|
|
35653
35883
|
symbol: payload.symbol
|
|
35654
35884
|
});
|
|
35655
35885
|
if (payload.refresh || !result) {
|
|
35656
|
-
const data = await this.exchange.getExchangeAccountInfo(
|
|
35657
|
-
|
|
35658
|
-
|
|
35886
|
+
const data = await this.exchange.getExchangeAccountInfo({
|
|
35887
|
+
account: this.instance,
|
|
35888
|
+
symbol: payload.symbol,
|
|
35889
|
+
price_places: symbol_config?.price_places,
|
|
35890
|
+
decimal_places: symbol_config?.decimal_places
|
|
35891
|
+
});
|
|
35892
|
+
if (symbol_config?.price_places) {
|
|
35893
|
+
data.config.price_places = symbol_config.price_places;
|
|
35659
35894
|
}
|
|
35660
|
-
if (
|
|
35661
|
-
data.config.decimal_places =
|
|
35895
|
+
if (symbol_config?.decimal_places) {
|
|
35896
|
+
data.config.decimal_places = symbol_config.decimal_places;
|
|
35662
35897
|
}
|
|
35663
35898
|
return await this.app_db.createOrUpdateLiveExchangeInstance({
|
|
35664
35899
|
account: this.instance,
|
|
@@ -35668,11 +35903,15 @@ class ExchangeAccount {
|
|
|
35668
35903
|
}
|
|
35669
35904
|
return result;
|
|
35670
35905
|
}
|
|
35671
|
-
async getActiveAccount(
|
|
35672
|
-
const
|
|
35673
|
-
const
|
|
35906
|
+
async getActiveAccount(payload) {
|
|
35907
|
+
const { symbol, full = false, refresh = false } = payload;
|
|
35908
|
+
const symbol_config = await this.recomputeSymbolConfig({
|
|
35674
35909
|
symbol
|
|
35675
35910
|
});
|
|
35911
|
+
const live_exchange_instance = await this.getLiveExchangeInstance({
|
|
35912
|
+
symbol,
|
|
35913
|
+
refresh
|
|
35914
|
+
});
|
|
35676
35915
|
const raw_active_account = live_exchange_instance.data;
|
|
35677
35916
|
const _all = get_active_accounts({
|
|
35678
35917
|
active_account: raw_active_account,
|
|
@@ -35684,9 +35923,10 @@ class ExchangeAccount {
|
|
|
35684
35923
|
return _all.active_account;
|
|
35685
35924
|
}
|
|
35686
35925
|
async syncAccount(options) {
|
|
35687
|
-
const { symbol, update = false } = options;
|
|
35926
|
+
const { symbol, update = false, live_refresh = false } = options;
|
|
35688
35927
|
if (!update) {
|
|
35689
|
-
const db_positions2 = await this.app_db.getPositions(
|
|
35928
|
+
const db_positions2 = await this.app_db.getPositions({
|
|
35929
|
+
account: this.instance,
|
|
35690
35930
|
symbol: options.symbol,
|
|
35691
35931
|
as_view: options.as_view
|
|
35692
35932
|
});
|
|
@@ -35696,7 +35936,10 @@ class ExchangeAccount {
|
|
|
35696
35936
|
}
|
|
35697
35937
|
return db_positions2;
|
|
35698
35938
|
}
|
|
35699
|
-
const active_account = await this.getActiveAccount(
|
|
35939
|
+
const active_account = await this.getActiveAccount({
|
|
35940
|
+
refresh: live_refresh,
|
|
35941
|
+
symbol
|
|
35942
|
+
});
|
|
35700
35943
|
if (options.leverage) {
|
|
35701
35944
|
await this.exchange.setLeverage({ symbol, leverage: options.leverage });
|
|
35702
35945
|
}
|
|
@@ -35723,7 +35966,9 @@ class ExchangeAccount {
|
|
|
35723
35966
|
});
|
|
35724
35967
|
return db_orders;
|
|
35725
35968
|
}
|
|
35726
|
-
const active_account = await this.getActiveAccount(
|
|
35969
|
+
const active_account = await this.getActiveAccount({
|
|
35970
|
+
symbol
|
|
35971
|
+
});
|
|
35727
35972
|
const orders = kind === "long" ? active_account.orders.long.entries : active_account.orders.short.entries;
|
|
35728
35973
|
const stop_orders = kind === "long" ? active_account.orders.long.stop_orders : active_account.orders.short.stop_orders;
|
|
35729
35974
|
const tp_orders = kind === "long" ? active_account.orders.long.tp_orders : active_account.orders.short.tp_orders;
|
|
@@ -35851,7 +36096,8 @@ class ExchangeAccount {
|
|
|
35851
36096
|
final_stop: solution.stop,
|
|
35852
36097
|
kind: app_config.kind,
|
|
35853
36098
|
quantity: trades[0]?.avg_size,
|
|
35854
|
-
is_limit: true
|
|
36099
|
+
is_limit: true,
|
|
36100
|
+
neg_pnl: trades[0]?.neg_pnl
|
|
35855
36101
|
};
|
|
35856
36102
|
if (place) {
|
|
35857
36103
|
let arr = [
|
|
@@ -35886,6 +36132,59 @@ class ExchangeAccount {
|
|
|
35886
36132
|
trades
|
|
35887
36133
|
};
|
|
35888
36134
|
}
|
|
36135
|
+
async determineAmountToBuy(payload) {
|
|
36136
|
+
const {
|
|
36137
|
+
orders,
|
|
36138
|
+
kind,
|
|
36139
|
+
decimal_places = "%.3f",
|
|
36140
|
+
symbol
|
|
36141
|
+
} = payload;
|
|
36142
|
+
const totalQuantity = orders.reduce((sum, order) => sum + (order.quantity || 0), 0);
|
|
36143
|
+
let runningTotal = to_f(totalQuantity, decimal_places);
|
|
36144
|
+
let sortedOrders = [...orders].sort((a, b) => (a.entry || 0) - (b.entry || 0));
|
|
36145
|
+
if (kind === "short") {
|
|
36146
|
+
sortedOrders.reverse();
|
|
36147
|
+
}
|
|
36148
|
+
const withCumulative = [];
|
|
36149
|
+
for (const order of sortedOrders) {
|
|
36150
|
+
withCumulative.push({
|
|
36151
|
+
...order,
|
|
36152
|
+
cumulative_quantity: runningTotal
|
|
36153
|
+
});
|
|
36154
|
+
runningTotal -= order.quantity;
|
|
36155
|
+
runningTotal = to_f(runningTotal, decimal_places);
|
|
36156
|
+
}
|
|
36157
|
+
const position2 = await this.syncAccount({
|
|
36158
|
+
symbol,
|
|
36159
|
+
kind,
|
|
36160
|
+
live_refresh: true,
|
|
36161
|
+
update: true
|
|
36162
|
+
});
|
|
36163
|
+
let existingOrders = await this.syncOrders({
|
|
36164
|
+
symbol,
|
|
36165
|
+
kind,
|
|
36166
|
+
update: true
|
|
36167
|
+
});
|
|
36168
|
+
let filteredOrders = withCumulative.filter((order) => (order.cumulative_quantity || 0) > position2?.quantity).map((order) => ({
|
|
36169
|
+
...order,
|
|
36170
|
+
price: order.entry,
|
|
36171
|
+
kind,
|
|
36172
|
+
side: kind.toLowerCase() === "long" ? "buy" : "sell"
|
|
36173
|
+
}));
|
|
36174
|
+
filteredOrders = filteredOrders.filter((k) => !existingOrders.map((j) => j.price).includes(k.price));
|
|
36175
|
+
const side = kind.toLowerCase() === "long" ? "buy" : "sell";
|
|
36176
|
+
const shouldCancel = existingOrders.filter((k) => !orders.map((j) => j.entry).includes(k.price) && k.side === side).map((u) => u.price);
|
|
36177
|
+
if (shouldCancel.length > 0) {
|
|
36178
|
+
const pp = kind === "long" ? Math.max(...shouldCancel) : Math.min(...shouldCancel);
|
|
36179
|
+
const cancel_orders = await this.cancelOrders({
|
|
36180
|
+
symbol,
|
|
36181
|
+
kind,
|
|
36182
|
+
price: pp
|
|
36183
|
+
});
|
|
36184
|
+
console.log("cancel_orders", cancel_orders);
|
|
36185
|
+
}
|
|
36186
|
+
return filteredOrders;
|
|
36187
|
+
}
|
|
35889
36188
|
async placeSharedOrder(action, payload) {
|
|
35890
36189
|
const app_config = await this.buildAppConfig({
|
|
35891
36190
|
entry: payload.entry,
|
|
@@ -35906,6 +36205,29 @@ class ExchangeAccount {
|
|
|
35906
36205
|
min_size: app_config.min_size,
|
|
35907
36206
|
symbol: payload.symbol
|
|
35908
36207
|
}, false);
|
|
36208
|
+
if (payload.raw) {
|
|
36209
|
+
let actual_orders_to_buy = await this.determineAmountToBuy({
|
|
36210
|
+
orders: trades,
|
|
36211
|
+
kind: app_config.kind,
|
|
36212
|
+
decimal_places: app_config.decimal_places,
|
|
36213
|
+
price_places: app_config.price_places,
|
|
36214
|
+
symbol: payload.symbol,
|
|
36215
|
+
place: payload.place
|
|
36216
|
+
});
|
|
36217
|
+
if (action === "place_limit_orders" && payload.place) {
|
|
36218
|
+
return await this.exchange.createLimitPurchaseOrders({
|
|
36219
|
+
orders: actual_orders_to_buy.map((x) => ({
|
|
36220
|
+
entry: x.entry,
|
|
36221
|
+
quantity: x.quantity
|
|
36222
|
+
})),
|
|
36223
|
+
kind: app_config.kind,
|
|
36224
|
+
decimal_places: app_config.decimal_places,
|
|
36225
|
+
price_places: app_config.price_places,
|
|
36226
|
+
symbol: payload.symbol
|
|
36227
|
+
});
|
|
36228
|
+
}
|
|
36229
|
+
return actual_orders_to_buy;
|
|
36230
|
+
}
|
|
35909
36231
|
if (action === "place_limit_orders" && payload.place) {
|
|
35910
36232
|
let result = await this.exchange.bulkPlaceLimitOrders({
|
|
35911
36233
|
orders: trades.map((x) => ({
|
|
@@ -35952,7 +36274,17 @@ class ExchangeAccount {
|
|
|
35952
36274
|
kind: payload.kind
|
|
35953
36275
|
});
|
|
35954
36276
|
if (db_position) {
|
|
35955
|
-
|
|
36277
|
+
const config = db_position.expand?.config;
|
|
36278
|
+
const params = {
|
|
36279
|
+
entry: payload.params.entry !== undefined ? payload.params.entry : config.entry,
|
|
36280
|
+
stop: payload.params.stop !== undefined ? payload.params.stop : config.stop,
|
|
36281
|
+
risk_reward: payload.params.risk_reward !== undefined ? payload.params.risk_reward : config.risk_reward,
|
|
36282
|
+
risk: payload.params.risk !== undefined ? payload.params.risk : config.risk,
|
|
36283
|
+
profit_percent: payload.params.profit_percent !== undefined ? payload.params.profit_percent : config.profit_percent,
|
|
36284
|
+
place_tp: payload.params.place_tp !== undefined ? payload.params.place_tp : true,
|
|
36285
|
+
profit: payload.params.profit !== undefined ? payload.params.profit : config.profit
|
|
36286
|
+
};
|
|
36287
|
+
return await this.app_db.createOrUpdatePositionConfig(db_position, params);
|
|
35956
36288
|
}
|
|
35957
36289
|
}
|
|
35958
36290
|
return await this.app_db.getPositionConfig({
|
|
@@ -35967,7 +36299,7 @@ class ExchangeAccount {
|
|
|
35967
36299
|
async getPositionStrategy() {
|
|
35968
36300
|
return await this.app_db.getPositionStrategy(this.instance);
|
|
35969
36301
|
}
|
|
35970
|
-
async
|
|
36302
|
+
async buildReduceConfig(payload) {
|
|
35971
36303
|
const positions = await this.syncAccount({
|
|
35972
36304
|
symbol: payload.symbol
|
|
35973
36305
|
});
|
|
@@ -35976,92 +36308,266 @@ class ExchangeAccount {
|
|
|
35976
36308
|
symbol: payload.symbol,
|
|
35977
36309
|
_positions: positions
|
|
35978
36310
|
});
|
|
35979
|
-
|
|
35980
|
-
|
|
35981
|
-
|
|
35982
|
-
|
|
35983
|
-
|
|
35984
|
-
|
|
35985
|
-
|
|
35986
|
-
|
|
35987
|
-
|
|
35988
|
-
|
|
35989
|
-
|
|
35990
|
-
|
|
35991
|
-
|
|
35992
|
-
|
|
35993
|
-
|
|
35994
|
-
|
|
35995
|
-
|
|
35996
|
-
|
|
35997
|
-
|
|
35998
|
-
|
|
35999
|
-
|
|
36311
|
+
if (payload.as_dict) {
|
|
36312
|
+
return {
|
|
36313
|
+
long: {
|
|
36314
|
+
minimum_pnl: config?.long_minimum_pnl || 0.0001,
|
|
36315
|
+
max_size: 0.003,
|
|
36316
|
+
profit: config?.long_profit,
|
|
36317
|
+
increase: false,
|
|
36318
|
+
not_reduce: config?.not_reduce,
|
|
36319
|
+
ratio: config?.reduce_ratio_long,
|
|
36320
|
+
use_full: payload.use_full ? payload.kind == "long" ? true : false : undefined
|
|
36321
|
+
},
|
|
36322
|
+
short: {
|
|
36323
|
+
minimum_pnl: config?.short_minimum_pnl || 0.0001,
|
|
36324
|
+
max_size: 0.003,
|
|
36325
|
+
profit: config?.short_profit,
|
|
36326
|
+
increase: false,
|
|
36327
|
+
not_reduce: config?.not_reduce,
|
|
36328
|
+
ratio: config?.reduce_ratio_short,
|
|
36329
|
+
use_full: payload.use_full ? payload.kind == "short" ? true : false : undefined
|
|
36330
|
+
},
|
|
36331
|
+
trigger: {
|
|
36332
|
+
long: payload.trigger?.long ? config.trigger_long : false,
|
|
36333
|
+
short: payload.trigger?.short ? config.trigger_short : false
|
|
36334
|
+
}
|
|
36335
|
+
};
|
|
36336
|
+
}
|
|
36337
|
+
return config;
|
|
36338
|
+
}
|
|
36339
|
+
async getOriginalPlannedStop(payload) {
|
|
36340
|
+
const config = await this.buildReduceConfig({
|
|
36341
|
+
symbol: payload.symbol,
|
|
36342
|
+
kind: payload.kind,
|
|
36343
|
+
as_dict: true
|
|
36344
|
+
});
|
|
36345
|
+
let result = await this.reduceMajorPositionEntry({
|
|
36346
|
+
symbol: payload.symbol,
|
|
36347
|
+
long: config.long,
|
|
36348
|
+
short: config.short,
|
|
36349
|
+
trigger: config.trigger
|
|
36000
36350
|
});
|
|
36001
36351
|
let _kind = payload.kind == "long" ? "short" : "long";
|
|
36002
36352
|
let orders = result[_kind];
|
|
36003
36353
|
return orders.result[payload.kind];
|
|
36004
36354
|
}
|
|
36005
|
-
async syncReduceClosePosition(
|
|
36006
|
-
let
|
|
36007
|
-
|
|
36008
|
-
|
|
36009
|
-
|
|
36010
|
-
|
|
36011
|
-
|
|
36012
|
-
|
|
36013
|
-
|
|
36014
|
-
|
|
36015
|
-
|
|
36016
|
-
|
|
36017
|
-
|
|
36018
|
-
|
|
36019
|
-
|
|
36020
|
-
|
|
36021
|
-
|
|
36022
|
-
|
|
36023
|
-
|
|
36024
|
-
|
|
36025
|
-
|
|
36026
|
-
|
|
36027
|
-
|
|
36028
|
-
|
|
36029
|
-
|
|
36030
|
-
increase: false,
|
|
36031
|
-
not_reduce: config?.not_reduce,
|
|
36032
|
-
ratio: config?.reduce_ratio_short,
|
|
36033
|
-
use_full: kind == "short" ? true : false
|
|
36034
|
-
};
|
|
36035
|
-
trigger = {
|
|
36036
|
-
long: config?.trigger_long,
|
|
36037
|
-
short: config?.trigger_short
|
|
36038
|
-
};
|
|
36039
|
-
}
|
|
36355
|
+
async syncReduceClosePosition(payload) {
|
|
36356
|
+
let { symbol, kind, trigger } = payload || {};
|
|
36357
|
+
const config = await this.buildReduceConfig({
|
|
36358
|
+
symbol,
|
|
36359
|
+
kind,
|
|
36360
|
+
as_dict: true,
|
|
36361
|
+
trigger: {
|
|
36362
|
+
long: trigger || false,
|
|
36363
|
+
short: trigger || false
|
|
36364
|
+
},
|
|
36365
|
+
use_full: true
|
|
36366
|
+
});
|
|
36367
|
+
return await this.reduceMajorPositionEntry({
|
|
36368
|
+
symbol,
|
|
36369
|
+
long: config.long,
|
|
36370
|
+
short: config.short,
|
|
36371
|
+
trigger: config.trigger
|
|
36372
|
+
});
|
|
36373
|
+
}
|
|
36374
|
+
async reduceMajorPositionEntry(payload) {
|
|
36375
|
+
const { symbol, long, short, trigger } = payload;
|
|
36376
|
+
let accountInfo = await this.getActiveAccount({
|
|
36377
|
+
symbol,
|
|
36378
|
+
full: true
|
|
36379
|
+
});
|
|
36040
36380
|
return await reduceMajorPositionEntry({
|
|
36041
36381
|
long,
|
|
36042
36382
|
short
|
|
36043
36383
|
}, accountInfo, trigger, this.exchange);
|
|
36044
36384
|
}
|
|
36045
|
-
async
|
|
36046
|
-
const {
|
|
36047
|
-
|
|
36048
|
-
|
|
36049
|
-
|
|
36050
|
-
|
|
36051
|
-
|
|
36052
|
-
|
|
36053
|
-
}
|
|
36054
|
-
|
|
36055
|
-
|
|
36056
|
-
|
|
36057
|
-
|
|
36058
|
-
|
|
36059
|
-
|
|
36385
|
+
async placeProfitAndStop(payload) {
|
|
36386
|
+
const { symbol, trigger, refresh, kind } = payload;
|
|
36387
|
+
if (refresh) {
|
|
36388
|
+
await this.syncAccount({
|
|
36389
|
+
symbol,
|
|
36390
|
+
live_refresh: true,
|
|
36391
|
+
update: true
|
|
36392
|
+
});
|
|
36393
|
+
}
|
|
36394
|
+
const config = await this.buildReduceConfig({
|
|
36395
|
+
symbol,
|
|
36396
|
+
as_dict: true,
|
|
36397
|
+
trigger: {
|
|
36398
|
+
long: trigger || false,
|
|
36399
|
+
short: trigger || false
|
|
36400
|
+
}
|
|
36060
36401
|
});
|
|
36061
|
-
|
|
36062
|
-
|
|
36402
|
+
if (!kind) {
|
|
36403
|
+
await this.updateTargetPnl({
|
|
36404
|
+
symbol,
|
|
36405
|
+
kind: "long"
|
|
36406
|
+
});
|
|
36407
|
+
await this.updateTargetPnl({
|
|
36408
|
+
symbol,
|
|
36409
|
+
kind: "short"
|
|
36410
|
+
});
|
|
36411
|
+
} else {
|
|
36412
|
+
await this.updateTargetPnl({
|
|
36413
|
+
symbol,
|
|
36414
|
+
kind
|
|
36415
|
+
});
|
|
36416
|
+
}
|
|
36417
|
+
if (payload.trigger) {
|
|
36418
|
+
return await this.reduceMajorPositionEntry({
|
|
36419
|
+
symbol,
|
|
36420
|
+
long: config.long,
|
|
36421
|
+
short: config.short,
|
|
36422
|
+
trigger: config.trigger
|
|
36423
|
+
});
|
|
36424
|
+
}
|
|
36425
|
+
return config;
|
|
36426
|
+
}
|
|
36427
|
+
async reEnterPositionOnEmpty(symbol) {
|
|
36428
|
+
await this.getLiveExchangeInstance({
|
|
36429
|
+
symbol,
|
|
36430
|
+
refresh: true
|
|
36431
|
+
});
|
|
36432
|
+
const db_positions = await this.syncAccount({
|
|
36433
|
+
symbol,
|
|
36434
|
+
update: true
|
|
36435
|
+
});
|
|
36436
|
+
await this.syncOrders({
|
|
36437
|
+
symbol,
|
|
36438
|
+
kind: "long",
|
|
36439
|
+
update: true
|
|
36440
|
+
});
|
|
36441
|
+
await this.syncOrders({
|
|
36442
|
+
symbol,
|
|
36443
|
+
kind: "short",
|
|
36444
|
+
update: true
|
|
36445
|
+
});
|
|
36446
|
+
const long_position = db_positions.find((x) => x.kind === "long");
|
|
36447
|
+
const short_position = db_positions.find((x) => x.kind === "short");
|
|
36448
|
+
if (long_position && long_position.quantity === 0) {
|
|
36449
|
+
await this.triggerTradeFromConfig({
|
|
36450
|
+
symbol,
|
|
36451
|
+
kind: "long"
|
|
36452
|
+
});
|
|
36453
|
+
}
|
|
36454
|
+
if (short_position && short_position.quantity === 0) {
|
|
36455
|
+
await this.triggerTradeFromConfig({
|
|
36456
|
+
symbol,
|
|
36457
|
+
kind: "short"
|
|
36458
|
+
});
|
|
36459
|
+
}
|
|
36460
|
+
if (long_position.target_pnl > 0 || short_position.target_pnl > 0) {
|
|
36461
|
+
await Promise.all([
|
|
36462
|
+
this.updateTargetPnl({
|
|
36463
|
+
symbol,
|
|
36464
|
+
kind: "long"
|
|
36465
|
+
}),
|
|
36466
|
+
this.updateTargetPnl({
|
|
36467
|
+
symbol,
|
|
36468
|
+
kind: "short"
|
|
36469
|
+
})
|
|
36470
|
+
]);
|
|
36471
|
+
}
|
|
36472
|
+
}
|
|
36473
|
+
async generate_config_params(payload) {
|
|
36474
|
+
const {
|
|
36475
|
+
entry,
|
|
36476
|
+
stop,
|
|
36477
|
+
risk_reward,
|
|
36478
|
+
risk,
|
|
36479
|
+
symbol,
|
|
36480
|
+
with_trades = false
|
|
36481
|
+
} = payload;
|
|
36482
|
+
const app_config = await this.buildAppConfig({
|
|
36483
|
+
entry,
|
|
36484
|
+
stop,
|
|
36485
|
+
risk_reward,
|
|
36486
|
+
risk,
|
|
36487
|
+
symbol
|
|
36488
|
+
});
|
|
36489
|
+
let config = generate_config_params(app_config, {
|
|
36490
|
+
entry,
|
|
36491
|
+
stop,
|
|
36492
|
+
risk_reward,
|
|
36493
|
+
risk,
|
|
36494
|
+
symbol
|
|
36495
|
+
});
|
|
36496
|
+
if (with_trades) {
|
|
36497
|
+
const app_config2 = await this.buildAppConfig({
|
|
36498
|
+
entry: config.entry,
|
|
36499
|
+
stop: config.stop,
|
|
36500
|
+
risk_reward: config.risk_reward,
|
|
36501
|
+
risk: config.risk,
|
|
36502
|
+
symbol,
|
|
36503
|
+
profit: 0,
|
|
36504
|
+
update_db: false
|
|
36505
|
+
});
|
|
36506
|
+
const { trades } = await this.placeConfigOrders(app_config2, {
|
|
36507
|
+
risk_reward: config.risk_reward,
|
|
36508
|
+
entry: config.entry,
|
|
36509
|
+
stop: config.stop,
|
|
36510
|
+
risk_per_trade: config.risk,
|
|
36511
|
+
avg_size: 0,
|
|
36512
|
+
neg_pnl: 0,
|
|
36513
|
+
min_size: app_config2.min_size,
|
|
36514
|
+
symbol
|
|
36515
|
+
}, false);
|
|
36516
|
+
config.trades = trades;
|
|
36517
|
+
}
|
|
36518
|
+
return { ...config, place_stop: false, profit_percent: 0 };
|
|
36519
|
+
}
|
|
36520
|
+
async build_short_order(payload) {
|
|
36521
|
+
const { symbol, kind } = payload;
|
|
36522
|
+
await this.syncOrders({
|
|
36523
|
+
symbol,
|
|
36524
|
+
kind,
|
|
36525
|
+
update: true
|
|
36526
|
+
});
|
|
36527
|
+
const position2 = await this.syncAccount({
|
|
36528
|
+
symbol,
|
|
36529
|
+
kind,
|
|
36530
|
+
as_view: true
|
|
36531
|
+
});
|
|
36532
|
+
const position_config = await this.getPositionConfig({
|
|
36533
|
+
symbol,
|
|
36534
|
+
kind
|
|
36535
|
+
});
|
|
36536
|
+
if (position2 && position_config && position2.entry > 0) {
|
|
36537
|
+
let next_order = position2.next_order;
|
|
36538
|
+
let take_profit = position2.take_profit;
|
|
36539
|
+
if (next_order && take_profit) {
|
|
36540
|
+
let config = await this.buildConfigForSymbol({
|
|
36541
|
+
symbol,
|
|
36542
|
+
risk: position_config.risk,
|
|
36543
|
+
risk_reward: position_config.risk_reward,
|
|
36544
|
+
kind,
|
|
36545
|
+
as_config: true
|
|
36546
|
+
});
|
|
36547
|
+
const focus = config.entries.filter((x) => {
|
|
36548
|
+
if (kind == "long") {
|
|
36549
|
+
return x.entry <= next_order;
|
|
36550
|
+
} else {
|
|
36551
|
+
return x.entry >= next_order;
|
|
36552
|
+
}
|
|
36553
|
+
});
|
|
36554
|
+
const focus_entry = focus.at(-1);
|
|
36555
|
+
if (focus_entry) {
|
|
36556
|
+
let entry = focus_entry.entry;
|
|
36557
|
+
let risk = Math.abs(focus_entry.neg_pnl);
|
|
36558
|
+
return await this.generate_config_params({
|
|
36559
|
+
entry,
|
|
36560
|
+
stop: take_profit,
|
|
36561
|
+
risk_reward: position_config.risk_reward,
|
|
36562
|
+
risk,
|
|
36563
|
+
symbol
|
|
36564
|
+
});
|
|
36565
|
+
}
|
|
36566
|
+
}
|
|
36567
|
+
}
|
|
36568
|
+
}
|
|
36063
36569
|
async extrapolateShortConfig(payload) {
|
|
36064
|
-
const { symbol, risk_reward = 199, kind } = payload;
|
|
36570
|
+
const { symbol, risk_reward = 199, kind, risk } = payload;
|
|
36065
36571
|
let reverse_kind = kind === "long" ? "short" : "long";
|
|
36066
36572
|
const position2 = await this.syncAccount({
|
|
36067
36573
|
symbol,
|
|
@@ -36069,30 +36575,40 @@ class ExchangeAccount {
|
|
|
36069
36575
|
as_view: true
|
|
36070
36576
|
});
|
|
36071
36577
|
if (position2) {
|
|
36578
|
+
let entry = position2.next_order || position2.avg_liquidation;
|
|
36579
|
+
if (kind == "short" && entry < 0) {
|
|
36580
|
+
const symbol_config = await this.recomputeSymbolConfig({
|
|
36581
|
+
symbol
|
|
36582
|
+
});
|
|
36583
|
+
entry = symbol_config?.support;
|
|
36584
|
+
}
|
|
36072
36585
|
return await this.generate_config_params({
|
|
36073
|
-
entry
|
|
36586
|
+
entry,
|
|
36074
36587
|
stop: position2.take_profit,
|
|
36075
36588
|
risk_reward,
|
|
36076
|
-
risk: position2.target_pnl,
|
|
36589
|
+
risk: risk || position2.target_pnl,
|
|
36077
36590
|
symbol
|
|
36078
36591
|
});
|
|
36079
36592
|
}
|
|
36080
36593
|
return null;
|
|
36081
36594
|
}
|
|
36082
36595
|
async triggerTradeFromConfig(payload) {
|
|
36596
|
+
const { symbol, kind, place = true } = payload;
|
|
36083
36597
|
const position2 = await this.syncAccount({
|
|
36084
|
-
symbol
|
|
36085
|
-
kind
|
|
36598
|
+
symbol,
|
|
36599
|
+
kind
|
|
36086
36600
|
});
|
|
36087
36601
|
if (position2?.config) {
|
|
36088
36602
|
const config = position2.expand.config;
|
|
36603
|
+
let entry = payload.tp ? position2.entry || config.entry : config.entry;
|
|
36089
36604
|
return await this.placeSharedOrder("place_limit_orders", {
|
|
36090
|
-
symbol
|
|
36091
|
-
entry
|
|
36605
|
+
symbol,
|
|
36606
|
+
entry,
|
|
36092
36607
|
stop: config.stop,
|
|
36093
36608
|
risk_reward: config.risk_reward,
|
|
36094
36609
|
risk: config.risk,
|
|
36095
|
-
place
|
|
36610
|
+
place,
|
|
36611
|
+
raw: payload.raw
|
|
36096
36612
|
});
|
|
36097
36613
|
}
|
|
36098
36614
|
}
|
|
@@ -36132,179 +36648,709 @@ class ExchangeAccount {
|
|
|
36132
36648
|
const opposite_kind = kind === "long" ? "short" : "long";
|
|
36133
36649
|
await this.syncOrders({
|
|
36134
36650
|
symbol,
|
|
36135
|
-
kind: opposite_kind,
|
|
36136
|
-
update: true
|
|
36651
|
+
kind: opposite_kind,
|
|
36652
|
+
update: true
|
|
36653
|
+
});
|
|
36654
|
+
await this.cancelOrders({
|
|
36655
|
+
symbol,
|
|
36656
|
+
kind: opposite_kind,
|
|
36657
|
+
stop: true
|
|
36658
|
+
});
|
|
36659
|
+
await this.syncReduceClosePosition({
|
|
36660
|
+
symbol,
|
|
36661
|
+
kind: opposite_kind,
|
|
36662
|
+
trigger: true
|
|
36663
|
+
});
|
|
36664
|
+
await this.syncOrders({
|
|
36665
|
+
symbol,
|
|
36666
|
+
kind,
|
|
36667
|
+
update: true
|
|
36668
|
+
});
|
|
36669
|
+
}
|
|
36670
|
+
}
|
|
36671
|
+
async windDownSymbol(payload) {
|
|
36672
|
+
const { symbol, risk_reward = 199 } = payload;
|
|
36673
|
+
const positions = await this.syncAccount({
|
|
36674
|
+
symbol,
|
|
36675
|
+
update: true
|
|
36676
|
+
});
|
|
36677
|
+
let long_position = positions.find((x) => x.kind === "long");
|
|
36678
|
+
let short_position = positions.find((x) => x.kind === "short");
|
|
36679
|
+
if (long_position && long_position.quantity > 0) {
|
|
36680
|
+
console.log("Start to wind down the long position");
|
|
36681
|
+
let config = long_position?.expand?.config;
|
|
36682
|
+
if (!config && long_position.config) {
|
|
36683
|
+
config = await this.getPositionConfig({
|
|
36684
|
+
symbol,
|
|
36685
|
+
kind: "long"
|
|
36686
|
+
});
|
|
36687
|
+
}
|
|
36688
|
+
if (config) {
|
|
36689
|
+
await this.getPositionConfig({
|
|
36690
|
+
symbol,
|
|
36691
|
+
kind: "long",
|
|
36692
|
+
params: {
|
|
36693
|
+
entry: config.entry,
|
|
36694
|
+
stop: config.stop,
|
|
36695
|
+
risk_reward: config.risk_reward,
|
|
36696
|
+
risk: config.risk,
|
|
36697
|
+
profit_percent: 0
|
|
36698
|
+
}
|
|
36699
|
+
});
|
|
36700
|
+
await this.updateTargetPnl({
|
|
36701
|
+
symbol,
|
|
36702
|
+
kind: "long"
|
|
36703
|
+
});
|
|
36704
|
+
} else {
|
|
36705
|
+
const existing_long_config = await this.app_db.getPositionConfig({
|
|
36706
|
+
symbol,
|
|
36707
|
+
kind: "long",
|
|
36708
|
+
account: this.instance
|
|
36709
|
+
});
|
|
36710
|
+
await this.app_db.update_db_position(long_position, {
|
|
36711
|
+
config: existing_long_config?.id
|
|
36712
|
+
});
|
|
36713
|
+
await this.getPositionConfig({
|
|
36714
|
+
symbol,
|
|
36715
|
+
kind: "long",
|
|
36716
|
+
params: {
|
|
36717
|
+
entry: existing_long_config.entry,
|
|
36718
|
+
stop: existing_long_config.stop,
|
|
36719
|
+
risk_reward: existing_long_config.risk_reward,
|
|
36720
|
+
risk: existing_long_config.risk,
|
|
36721
|
+
profit_percent: 0
|
|
36722
|
+
}
|
|
36723
|
+
});
|
|
36724
|
+
await this.updateTargetPnl({
|
|
36725
|
+
symbol,
|
|
36726
|
+
kind: "long"
|
|
36727
|
+
});
|
|
36728
|
+
}
|
|
36729
|
+
await this.triggerTradeFromConfig({
|
|
36730
|
+
symbol,
|
|
36731
|
+
kind: "long"
|
|
36732
|
+
});
|
|
36733
|
+
const new_config = await this.extrapolateShortConfig({
|
|
36734
|
+
symbol,
|
|
36735
|
+
kind: "short",
|
|
36736
|
+
risk_reward,
|
|
36737
|
+
risk: config?.risk
|
|
36738
|
+
});
|
|
36739
|
+
let short_config = await this.getPositionConfig({
|
|
36740
|
+
symbol,
|
|
36741
|
+
kind: "short"
|
|
36742
|
+
});
|
|
36743
|
+
if (!short_config) {
|
|
36744
|
+
short_config = await this.getPositionConfig({
|
|
36745
|
+
symbol,
|
|
36746
|
+
kind: "short",
|
|
36747
|
+
params: {
|
|
36748
|
+
entry: new_config.entry,
|
|
36749
|
+
stop: new_config.stop,
|
|
36750
|
+
risk_reward,
|
|
36751
|
+
risk: new_config.risk,
|
|
36752
|
+
profit_percent: 10
|
|
36753
|
+
}
|
|
36754
|
+
});
|
|
36755
|
+
}
|
|
36756
|
+
if (new_config && short_config) {
|
|
36757
|
+
console.log("updating short position");
|
|
36758
|
+
short_position = await this.app_db.update_db_position(short_position, {
|
|
36759
|
+
reduce_ratio: 0.95,
|
|
36760
|
+
config: short_config.id
|
|
36761
|
+
});
|
|
36762
|
+
console.log("Updating the short position config");
|
|
36763
|
+
await this.getPositionConfig({
|
|
36764
|
+
symbol,
|
|
36765
|
+
kind: "short",
|
|
36766
|
+
params: {
|
|
36767
|
+
entry: new_config.entry,
|
|
36768
|
+
stop: new_config.stop,
|
|
36769
|
+
risk_reward,
|
|
36770
|
+
risk: new_config.risk,
|
|
36771
|
+
profit_percent: 10
|
|
36772
|
+
}
|
|
36773
|
+
});
|
|
36774
|
+
console.log("placing the short trade based off config values");
|
|
36775
|
+
await this.triggerTradeFromConfig({
|
|
36776
|
+
symbol,
|
|
36777
|
+
kind: "short"
|
|
36778
|
+
});
|
|
36779
|
+
await this.updateTargetPnl({
|
|
36780
|
+
symbol,
|
|
36781
|
+
kind: "short"
|
|
36782
|
+
});
|
|
36783
|
+
console.log("updating the stop loss for the short position from the long");
|
|
36784
|
+
await this.verifyStopLoss({
|
|
36785
|
+
symbol,
|
|
36786
|
+
kind: "short"
|
|
36787
|
+
});
|
|
36788
|
+
}
|
|
36789
|
+
}
|
|
36790
|
+
if (long_position && long_position.quantity === 0 && short_position && short_position.quantity == 0) {
|
|
36791
|
+
await Promise.all([
|
|
36792
|
+
this.cancelOrders({
|
|
36793
|
+
symbol,
|
|
36794
|
+
kind: "long",
|
|
36795
|
+
all: true
|
|
36796
|
+
}),
|
|
36797
|
+
this.cancelOrders({
|
|
36798
|
+
symbol,
|
|
36799
|
+
kind: "short",
|
|
36800
|
+
all: true
|
|
36801
|
+
})
|
|
36802
|
+
]);
|
|
36803
|
+
await Promise.all([
|
|
36804
|
+
this.app_db.removePosition(long_position),
|
|
36805
|
+
this.app_db.removePosition(short_position)
|
|
36806
|
+
]);
|
|
36807
|
+
}
|
|
36808
|
+
}
|
|
36809
|
+
async updateTargetPnl(payload) {
|
|
36810
|
+
const { symbol, kind } = payload;
|
|
36811
|
+
const position2 = await this.syncAccount({
|
|
36812
|
+
symbol,
|
|
36813
|
+
kind
|
|
36814
|
+
});
|
|
36815
|
+
if (position2?.expand?.config) {
|
|
36816
|
+
const config = position2.expand.config;
|
|
36817
|
+
let _profit = config.profit;
|
|
36818
|
+
let _profit_percent = config?.profit_percent;
|
|
36819
|
+
if (_profit_percent && (position2?.quantity || 0) > 0) {
|
|
36820
|
+
_profit = to_f(position2.quantity * _profit_percent * position2.entry / 100);
|
|
36821
|
+
}
|
|
36822
|
+
await this.app_db.update_db_position(position2, {
|
|
36823
|
+
target_pnl: _profit
|
|
36824
|
+
});
|
|
36825
|
+
return _profit;
|
|
36826
|
+
}
|
|
36827
|
+
return 0;
|
|
36828
|
+
}
|
|
36829
|
+
async recomputeSymbolConfig(payload) {
|
|
36830
|
+
const { symbol, refresh = false } = payload;
|
|
36831
|
+
const _config = await this.app_db.getSymbolConfigFromDB(symbol);
|
|
36832
|
+
if (_config && !refresh) {
|
|
36833
|
+
return _config;
|
|
36834
|
+
}
|
|
36835
|
+
const config = await this.exchange.generateConfig({
|
|
36836
|
+
symbol,
|
|
36837
|
+
limit: _config?.candle_count || 5,
|
|
36838
|
+
interval: _config?.interval || "1w"
|
|
36839
|
+
});
|
|
36840
|
+
await this.app_db.updateSymbolConfigs({
|
|
36841
|
+
configs: [
|
|
36842
|
+
{
|
|
36843
|
+
symbol,
|
|
36844
|
+
support: config.support,
|
|
36845
|
+
resistance: config.resistance,
|
|
36846
|
+
leverage: config.leverage,
|
|
36847
|
+
min_size: config.min_size,
|
|
36848
|
+
price_places: config.price_places,
|
|
36849
|
+
decimal_places: config.decimal_places
|
|
36850
|
+
}
|
|
36851
|
+
]
|
|
36852
|
+
});
|
|
36853
|
+
return this.app_db.getSymbolConfigFromDB(symbol);
|
|
36854
|
+
}
|
|
36855
|
+
async buildConfigForSymbol(payload) {
|
|
36856
|
+
const {
|
|
36857
|
+
symbol,
|
|
36858
|
+
risk,
|
|
36859
|
+
risk_reward = 199,
|
|
36860
|
+
as_config = false,
|
|
36861
|
+
kind = "long"
|
|
36862
|
+
} = payload;
|
|
36863
|
+
const symbol_config = await this.recomputeSymbolConfig({
|
|
36864
|
+
symbol
|
|
36865
|
+
});
|
|
36866
|
+
const long_config = await this.generate_config_params({
|
|
36867
|
+
entry: kind === "long" ? symbol_config.resistance : symbol_config.support,
|
|
36868
|
+
stop: kind === "long" ? symbol_config.support : symbol_config.resistance,
|
|
36869
|
+
risk_reward,
|
|
36870
|
+
risk,
|
|
36871
|
+
symbol
|
|
36872
|
+
});
|
|
36873
|
+
if (as_config) {
|
|
36874
|
+
const app_config = buildAppConfig(symbol_config, {
|
|
36875
|
+
entry: long_config.entry,
|
|
36876
|
+
stop: long_config.stop,
|
|
36877
|
+
risk_reward,
|
|
36878
|
+
risk: long_config.risk,
|
|
36879
|
+
symbol
|
|
36880
|
+
});
|
|
36881
|
+
return app_config;
|
|
36882
|
+
}
|
|
36883
|
+
return long_config;
|
|
36884
|
+
}
|
|
36885
|
+
async triggerBullishMarket(payload) {
|
|
36886
|
+
let { symbol, profit_percent = 10, risk_reward = 199 } = payload;
|
|
36887
|
+
const bullish_instance = await this.app_db.getBullishMarket(symbol);
|
|
36888
|
+
if (!bullish_instance) {
|
|
36889
|
+
return false;
|
|
36890
|
+
}
|
|
36891
|
+
const db_instance = await this.app_db.get_exchange_db_instance(this.instance);
|
|
36892
|
+
if (db_instance.profit_percent) {
|
|
36893
|
+
profit_percent = db_instance.profit_percent;
|
|
36894
|
+
}
|
|
36895
|
+
const position2 = await this.syncAccount({
|
|
36896
|
+
symbol,
|
|
36897
|
+
update: true,
|
|
36898
|
+
kind: "long"
|
|
36899
|
+
});
|
|
36900
|
+
const long_config = await this.buildConfigForSymbol({
|
|
36901
|
+
symbol,
|
|
36902
|
+
risk: bullish_instance.risk,
|
|
36903
|
+
risk_reward
|
|
36904
|
+
});
|
|
36905
|
+
let changed = false;
|
|
36906
|
+
if (!position2?.config) {
|
|
36907
|
+
await this.buildAppConfig({
|
|
36908
|
+
entry: long_config.entry,
|
|
36909
|
+
stop: long_config.stop,
|
|
36910
|
+
risk_reward: long_config.risk_reward,
|
|
36911
|
+
risk: long_config.risk,
|
|
36912
|
+
symbol,
|
|
36913
|
+
profit_percent,
|
|
36914
|
+
update_db: true
|
|
36915
|
+
});
|
|
36916
|
+
changed = true;
|
|
36917
|
+
} else {
|
|
36918
|
+
if (position2.expand.config.entry !== long_config.entry || position2.expand.config.stop !== long_config.stop || position2.expand.config.risk !== long_config.risk) {
|
|
36919
|
+
changed = true;
|
|
36920
|
+
}
|
|
36921
|
+
await this.getPositionConfig({
|
|
36922
|
+
symbol,
|
|
36923
|
+
kind: "long",
|
|
36924
|
+
params: {
|
|
36925
|
+
entry: long_config.entry,
|
|
36926
|
+
stop: long_config.stop,
|
|
36927
|
+
risk: long_config.risk,
|
|
36928
|
+
risk_reward: position2?.expand?.config?.risk_reward || long_config.risk_reward
|
|
36929
|
+
}
|
|
36930
|
+
});
|
|
36931
|
+
}
|
|
36932
|
+
const short_position = await this.syncAccount({
|
|
36933
|
+
symbol,
|
|
36934
|
+
kind: "short",
|
|
36935
|
+
update: true
|
|
36936
|
+
});
|
|
36937
|
+
const orders = await this.getOrders({
|
|
36938
|
+
symbol,
|
|
36939
|
+
kind: "short",
|
|
36940
|
+
type: "limit",
|
|
36941
|
+
refresh: true
|
|
36942
|
+
});
|
|
36943
|
+
if (orders.length > 0) {
|
|
36944
|
+
await this.toggleStopBuying({
|
|
36945
|
+
should_stop: true,
|
|
36946
|
+
kind: "short",
|
|
36947
|
+
symbol
|
|
36948
|
+
});
|
|
36949
|
+
await this.cancelOrders({
|
|
36950
|
+
symbol,
|
|
36951
|
+
kind: "short",
|
|
36952
|
+
all: true
|
|
36953
|
+
});
|
|
36954
|
+
}
|
|
36955
|
+
if (short_position?.config) {
|
|
36956
|
+
await this.app_db.update_db_position(short_position, {
|
|
36957
|
+
config: null,
|
|
36958
|
+
reduce_ratio: 0.9
|
|
36959
|
+
});
|
|
36960
|
+
}
|
|
36961
|
+
if (changed) {
|
|
36962
|
+
const rr = await this.triggerTradeFromConfig({
|
|
36963
|
+
symbol,
|
|
36964
|
+
kind: "long",
|
|
36965
|
+
tp: true
|
|
36966
|
+
});
|
|
36967
|
+
await this.placeProfitAndStop({
|
|
36968
|
+
symbol,
|
|
36969
|
+
trigger: true
|
|
36970
|
+
});
|
|
36971
|
+
return rr;
|
|
36972
|
+
}
|
|
36973
|
+
return false;
|
|
36974
|
+
}
|
|
36975
|
+
async updateAllActiveSymbols(payload) {
|
|
36976
|
+
const { interval = 5 } = payload;
|
|
36977
|
+
const symbols = await this.app_db.getAllSymbolsFromPositions({
|
|
36978
|
+
no_position: true,
|
|
36979
|
+
kind: "long"
|
|
36980
|
+
});
|
|
36981
|
+
const all_open_symbols = await this.exchange.getAllOpenSymbols();
|
|
36982
|
+
await new Promise((resolve) => setTimeout(resolve, interval * 1000));
|
|
36983
|
+
for (const symbol of Array.from(new Set(symbols.concat(all_open_symbols)))) {
|
|
36984
|
+
await this.getLiveExchangeInstance({ symbol, refresh: true });
|
|
36985
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
36986
|
+
}
|
|
36987
|
+
}
|
|
36988
|
+
async updateAllPositionsWithNoConfig(payload) {
|
|
36989
|
+
const { kind } = payload;
|
|
36990
|
+
const symbols = await this.app_db.getAllSymbolsFromPositions({
|
|
36991
|
+
custom_filter: `config = null && kind = "${kind}"`
|
|
36992
|
+
});
|
|
36993
|
+
for (const symbol of symbols) {
|
|
36994
|
+
await this.syncAccount({
|
|
36995
|
+
symbol,
|
|
36996
|
+
update: true,
|
|
36997
|
+
kind,
|
|
36998
|
+
live_refresh: true
|
|
36999
|
+
});
|
|
37000
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
37001
|
+
}
|
|
37002
|
+
}
|
|
37003
|
+
async getSymbolsForPositions() {
|
|
37004
|
+
const positions = await this.app_db.getPositions({
|
|
37005
|
+
custom_filter: `account.owner:lower = "${this.instance.owner.toLowerCase()}" && account.exchange:lower = "${this.instance.exchange.toLowerCase()}" && quantity > 0`,
|
|
37006
|
+
symbol: "",
|
|
37007
|
+
account: {
|
|
37008
|
+
owner: "",
|
|
37009
|
+
exchange: ""
|
|
37010
|
+
}
|
|
37011
|
+
});
|
|
37012
|
+
return Array.from(new Set(positions.map((p) => p.symbol)));
|
|
37013
|
+
}
|
|
37014
|
+
async getNonEssentialSymbols() {
|
|
37015
|
+
const [all_open_symbols, essential_symbols] = await Promise.all([
|
|
37016
|
+
this.exchange.getAllOpenSymbols(),
|
|
37017
|
+
this.app_db.getAllSymbolConfigs({
|
|
37018
|
+
custom_filter: `essential = true`
|
|
37019
|
+
})
|
|
37020
|
+
]);
|
|
37021
|
+
const essential_symbols_set = new Set(essential_symbols.map((s2) => s2.symbol));
|
|
37022
|
+
const open_symbols_set = new Set(all_open_symbols);
|
|
37023
|
+
const non_essential_symbols = Array.from(essential_symbols_set).filter((s2) => !open_symbols_set.has(s2));
|
|
37024
|
+
const bullish_markets = await this.app_db.getBullishMarkets();
|
|
37025
|
+
const bullish_symbols = Array.from(new Set(bullish_markets.updated_bullish.map((m) => m.symbol)));
|
|
37026
|
+
const symbols = Array.from(new Set(essential_symbols.map((s2) => s2.symbol))).concat(bullish_symbols);
|
|
37027
|
+
const not_symbols_filter = symbols.map((s2) => `symbol:lower != "${s2.toLowerCase()}"`).join(" && ");
|
|
37028
|
+
const positions = await this.app_db.getPositions({
|
|
37029
|
+
custom_filter: `${not_symbols_filter} && account.owner:lower = "${this.instance.owner.toLowerCase()}" && account.exchange:lower = "${this.instance.exchange.toLowerCase()}"`,
|
|
37030
|
+
symbol: "",
|
|
37031
|
+
account: {
|
|
37032
|
+
owner: "",
|
|
37033
|
+
exchange: ""
|
|
37034
|
+
}
|
|
37035
|
+
});
|
|
37036
|
+
return Array.from(new Set(positions.map((p) => p.symbol).concat(non_essential_symbols)));
|
|
37037
|
+
}
|
|
37038
|
+
async _terminatePositions(payload) {
|
|
37039
|
+
const { symbol } = payload;
|
|
37040
|
+
let db_positions = await this.syncAccount({
|
|
37041
|
+
symbol,
|
|
37042
|
+
update: true,
|
|
37043
|
+
live_refresh: true
|
|
37044
|
+
});
|
|
37045
|
+
const symbol_config = await this.app_db.getSymbolConfigFromDB(symbol);
|
|
37046
|
+
let long_position = db_positions.find((x) => x.kind === "long");
|
|
37047
|
+
let short_position = db_positions.find((x) => x.kind === "short");
|
|
37048
|
+
if (long_position && long_position.quantity > 0 && symbol_config) {
|
|
37049
|
+
await this.toggleStopBuying({
|
|
37050
|
+
symbol,
|
|
37051
|
+
kind: "long",
|
|
37052
|
+
should_stop: true
|
|
37053
|
+
});
|
|
37054
|
+
await this.exchange.closePosition({
|
|
37055
|
+
symbol,
|
|
37056
|
+
kind: "long",
|
|
37057
|
+
price_places: symbol_config.price_places,
|
|
37058
|
+
decimal_places: symbol_config.decimal_places
|
|
37059
|
+
});
|
|
37060
|
+
await this.cancelOrders({
|
|
37061
|
+
symbol,
|
|
37062
|
+
kind: "long",
|
|
37063
|
+
all: true
|
|
37064
|
+
});
|
|
37065
|
+
}
|
|
37066
|
+
if (short_position && short_position.quantity > 0 && symbol_config) {
|
|
37067
|
+
await this.toggleStopBuying({
|
|
37068
|
+
symbol,
|
|
37069
|
+
kind: "short",
|
|
37070
|
+
should_stop: true
|
|
37071
|
+
});
|
|
37072
|
+
await this.exchange.closePosition({
|
|
37073
|
+
symbol,
|
|
37074
|
+
kind: "short",
|
|
37075
|
+
price_places: symbol_config.price_places,
|
|
37076
|
+
decimal_places: symbol_config.decimal_places
|
|
37077
|
+
});
|
|
37078
|
+
await this.cancelOrders({
|
|
37079
|
+
symbol,
|
|
37080
|
+
kind: "short",
|
|
37081
|
+
all: true
|
|
37082
|
+
});
|
|
37083
|
+
}
|
|
37084
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
37085
|
+
db_positions = await this.syncAccount({
|
|
37086
|
+
symbol,
|
|
37087
|
+
update: true,
|
|
37088
|
+
live_refresh: true
|
|
37089
|
+
});
|
|
37090
|
+
long_position = db_positions.find((x) => x.kind === "long");
|
|
37091
|
+
short_position = db_positions.find((x) => x.kind === "short");
|
|
37092
|
+
if (long_position && long_position.quantity === 0) {
|
|
37093
|
+
await this.app_db.removePosition(long_position);
|
|
37094
|
+
}
|
|
37095
|
+
if (short_position && short_position.quantity === 0) {
|
|
37096
|
+
await this.app_db.removePosition(short_position);
|
|
37097
|
+
}
|
|
37098
|
+
}
|
|
37099
|
+
async getOrders(payload) {
|
|
37100
|
+
const { symbol, kind, type, refresh = false } = payload;
|
|
37101
|
+
if (refresh) {
|
|
37102
|
+
await this.syncOrders({
|
|
37103
|
+
symbol,
|
|
37104
|
+
kind
|
|
37105
|
+
});
|
|
37106
|
+
}
|
|
37107
|
+
let side;
|
|
37108
|
+
if (kind == "long") {
|
|
37109
|
+
if (type === "limit") {
|
|
37110
|
+
side = "buy";
|
|
37111
|
+
} else {
|
|
37112
|
+
side = "sell";
|
|
37113
|
+
}
|
|
37114
|
+
} else {
|
|
37115
|
+
if (type === "limit") {
|
|
37116
|
+
side = "sell";
|
|
37117
|
+
} else {
|
|
37118
|
+
side = "buy";
|
|
37119
|
+
}
|
|
37120
|
+
}
|
|
37121
|
+
const orders = await this.app_db.getOrders(this.instance, {
|
|
37122
|
+
symbol,
|
|
37123
|
+
kind
|
|
37124
|
+
});
|
|
37125
|
+
return orders.filter((x) => {
|
|
37126
|
+
if (type === "stop") {
|
|
37127
|
+
return x.side === side && x.stop > 0;
|
|
37128
|
+
}
|
|
37129
|
+
if (type === "tp") {
|
|
37130
|
+
return x.side === side && x.stop === 0;
|
|
37131
|
+
}
|
|
37132
|
+
return x.side === side;
|
|
37133
|
+
});
|
|
37134
|
+
}
|
|
37135
|
+
async syncPositionConfigs(payload) {
|
|
37136
|
+
const { symbol, kind, refresh = false } = payload;
|
|
37137
|
+
const symbol_config = await this.recomputeSymbolConfig({
|
|
37138
|
+
symbol,
|
|
37139
|
+
refresh
|
|
37140
|
+
});
|
|
37141
|
+
const long_config = await this.getPositionConfig({
|
|
37142
|
+
symbol,
|
|
37143
|
+
kind: "long"
|
|
37144
|
+
});
|
|
37145
|
+
const short_config = await this.getPositionConfig({
|
|
37146
|
+
symbol,
|
|
37147
|
+
kind: "short"
|
|
37148
|
+
});
|
|
37149
|
+
if (long_config && kind === "long") {
|
|
37150
|
+
await this.app_db.updateScheduledTrade(long_config.id, {
|
|
37151
|
+
entry: symbol_config.resistance,
|
|
37152
|
+
stop: symbol_config.support
|
|
37153
|
+
});
|
|
37154
|
+
}
|
|
37155
|
+
if (short_config && kind === "short") {
|
|
37156
|
+
await this.app_db.updateScheduledTrade(short_config.id, {
|
|
37157
|
+
entry: symbol_config.support,
|
|
37158
|
+
stop: symbol_config.resistance
|
|
37159
|
+
});
|
|
37160
|
+
}
|
|
37161
|
+
}
|
|
37162
|
+
async terminatePositions(payload) {
|
|
37163
|
+
const { symbol } = payload;
|
|
37164
|
+
let db_positions = await this.syncAccount({
|
|
37165
|
+
symbol,
|
|
37166
|
+
update: true,
|
|
37167
|
+
live_refresh: true
|
|
37168
|
+
});
|
|
37169
|
+
const symbol_config = await this.recomputeSymbolConfig({
|
|
37170
|
+
symbol
|
|
37171
|
+
});
|
|
37172
|
+
let long_position = db_positions.find((x) => x.kind === "long");
|
|
37173
|
+
let short_position = db_positions.find((x) => x.kind === "short");
|
|
37174
|
+
if (long_position && long_position.quantity > 0 && symbol_config) {
|
|
37175
|
+
await this.toggleStopBuying({
|
|
37176
|
+
symbol,
|
|
37177
|
+
kind: "long",
|
|
37178
|
+
should_stop: true
|
|
37179
|
+
});
|
|
37180
|
+
await this.cancelOrders({
|
|
37181
|
+
symbol,
|
|
37182
|
+
kind: "long",
|
|
37183
|
+
all: true
|
|
37184
|
+
});
|
|
37185
|
+
await this.app_db.update_db_position(long_position, {
|
|
37186
|
+
config: null,
|
|
37187
|
+
reduce_ratio: 0.9
|
|
37188
|
+
});
|
|
37189
|
+
}
|
|
37190
|
+
const long_config = await this.getPositionConfig({
|
|
37191
|
+
symbol,
|
|
37192
|
+
kind: "long"
|
|
37193
|
+
});
|
|
37194
|
+
let the_same_config = false;
|
|
37195
|
+
if (long_config && long_position && long_position.quantity > 0) {
|
|
37196
|
+
const existing_short_config = await this.getPositionConfig({
|
|
37197
|
+
symbol,
|
|
37198
|
+
kind: "short"
|
|
37199
|
+
});
|
|
37200
|
+
const diff = (long_position.entry - long_config.stop) * long_position.quantity;
|
|
37201
|
+
if (existing_short_config) {
|
|
37202
|
+
the_same_config = long_config.entry === existing_short_config.stop && long_config.stop === existing_short_config.entry;
|
|
37203
|
+
}
|
|
37204
|
+
const short_config = await this.getPositionConfig({
|
|
37205
|
+
symbol,
|
|
37206
|
+
kind: "short",
|
|
37207
|
+
params: {
|
|
37208
|
+
entry: long_config.stop,
|
|
37209
|
+
stop: long_config.entry,
|
|
37210
|
+
risk_reward: long_config.risk_reward,
|
|
37211
|
+
profit_percent: 0,
|
|
37212
|
+
risk: long_config.risk,
|
|
37213
|
+
profit: Math.abs(diff),
|
|
37214
|
+
place_tp: false
|
|
37215
|
+
}
|
|
37216
|
+
});
|
|
37217
|
+
if (short_config) {
|
|
37218
|
+
await this.app_db.update_db_position(short_position, {
|
|
37219
|
+
config: short_config.id,
|
|
37220
|
+
reduce_ratio: 0.9
|
|
37221
|
+
});
|
|
37222
|
+
if (!the_same_config) {
|
|
37223
|
+
await this.placeTrade({
|
|
37224
|
+
symbol,
|
|
37225
|
+
kind: "short",
|
|
37226
|
+
place: true
|
|
37227
|
+
});
|
|
37228
|
+
}
|
|
37229
|
+
}
|
|
37230
|
+
await this.placeProfitAndStop({
|
|
37231
|
+
symbol,
|
|
37232
|
+
kind: "short"
|
|
36137
37233
|
});
|
|
37234
|
+
}
|
|
37235
|
+
if (long_position && short_position && long_position.quantity === 0 && short_position.quantity === 0) {
|
|
36138
37236
|
await this.cancelOrders({
|
|
36139
37237
|
symbol,
|
|
36140
|
-
kind:
|
|
36141
|
-
|
|
36142
|
-
});
|
|
36143
|
-
await this.syncReduceClosePosition(symbol, {
|
|
36144
|
-
kind: opposite_kind
|
|
37238
|
+
kind: "long",
|
|
37239
|
+
all: true
|
|
36145
37240
|
});
|
|
36146
|
-
await this.
|
|
37241
|
+
await this.cancelOrders({
|
|
36147
37242
|
symbol,
|
|
36148
|
-
kind,
|
|
36149
|
-
|
|
37243
|
+
kind: "short",
|
|
37244
|
+
all: true
|
|
36150
37245
|
});
|
|
37246
|
+
await this.app_db.removePosition(long_position);
|
|
37247
|
+
await this.app_db.removePosition(short_position);
|
|
37248
|
+
await this.app_db.unwindSymbolFromDB(symbol);
|
|
36151
37249
|
}
|
|
36152
37250
|
}
|
|
36153
|
-
async
|
|
36154
|
-
const
|
|
37251
|
+
async fetchAndUpdateTopMovers() {
|
|
37252
|
+
const db_instance = await this.app_db.get_exchange_db_instance(this.instance);
|
|
37253
|
+
const {
|
|
37254
|
+
bullish,
|
|
37255
|
+
bearish: _bearish,
|
|
37256
|
+
movePercent,
|
|
37257
|
+
totalRisk,
|
|
37258
|
+
max_non_essential = 0,
|
|
37259
|
+
exclude_coins
|
|
37260
|
+
} = db_instance;
|
|
37261
|
+
let dont_trade = exclude_coins?.bullish || [];
|
|
37262
|
+
let bullishMarkets = [];
|
|
37263
|
+
if (bullish) {
|
|
37264
|
+
const { movers } = await this.exchange.checkDelistedMovers({
|
|
37265
|
+
movePercent
|
|
37266
|
+
});
|
|
37267
|
+
bullishMarkets = movers;
|
|
37268
|
+
}
|
|
37269
|
+
const non_essential_symbols = await this.getNonEssentialSymbols();
|
|
37270
|
+
let symbols_to_remove = non_essential_symbols.filter((k) => !bullishMarkets.map((m) => m.symbol).includes(k)).slice(0, max_non_essential).concat(dont_trade);
|
|
37271
|
+
bullishMarkets = bullishMarkets.filter((m) => !symbols_to_remove.includes(m.symbol));
|
|
37272
|
+
if (symbols_to_remove.length > 0) {
|
|
37273
|
+
for (const symbol of symbols_to_remove) {
|
|
37274
|
+
await this.terminatePositions({ symbol });
|
|
37275
|
+
}
|
|
37276
|
+
}
|
|
37277
|
+
const result = await this.app_db.getBullishMarkets({
|
|
37278
|
+
new_markets: bullishMarkets.map((m) => ({
|
|
37279
|
+
symbol: m.symbol,
|
|
37280
|
+
percent: m.priceChangePercent
|
|
37281
|
+
})),
|
|
37282
|
+
totalRisk,
|
|
37283
|
+
max_count: max_non_essential
|
|
37284
|
+
});
|
|
37285
|
+
if (result.updated_bullish.length > max_non_essential) {
|
|
37286
|
+
return {
|
|
37287
|
+
updated_bullish: [],
|
|
37288
|
+
moved_to_winding: []
|
|
37289
|
+
};
|
|
37290
|
+
}
|
|
37291
|
+
return result;
|
|
37292
|
+
}
|
|
37293
|
+
async computeTargetPnl(payload) {
|
|
37294
|
+
const { symbol, kind } = payload;
|
|
37295
|
+
const reverse_kind = kind === "long" ? "short" : "long";
|
|
37296
|
+
const root_position = await this.syncAccount({
|
|
36155
37297
|
symbol,
|
|
36156
|
-
|
|
37298
|
+
kind
|
|
36157
37299
|
});
|
|
36158
|
-
|
|
36159
|
-
|
|
36160
|
-
|
|
36161
|
-
|
|
36162
|
-
|
|
36163
|
-
|
|
36164
|
-
|
|
36165
|
-
|
|
36166
|
-
|
|
36167
|
-
|
|
36168
|
-
|
|
36169
|
-
if (config) {
|
|
36170
|
-
console.log("cancelling any existing open orders for the long position");
|
|
36171
|
-
await this.cancelOrders({
|
|
36172
|
-
symbol,
|
|
36173
|
-
kind: "long",
|
|
36174
|
-
price: long_position.entry
|
|
36175
|
-
});
|
|
36176
|
-
console.log("updating the long position target_pnl");
|
|
36177
|
-
console.log("toggling the stop buying for the long position");
|
|
36178
|
-
await this.toggleStopBuying({
|
|
36179
|
-
symbol,
|
|
36180
|
-
kind: "long",
|
|
36181
|
-
should_stop: true
|
|
36182
|
-
});
|
|
36183
|
-
}
|
|
36184
|
-
const new_config = await this.extrapolateShortConfig({
|
|
36185
|
-
symbol,
|
|
36186
|
-
kind: "short",
|
|
36187
|
-
risk_reward
|
|
36188
|
-
});
|
|
36189
|
-
const short_config = await this.getPositionConfig({
|
|
36190
|
-
symbol,
|
|
36191
|
-
kind: "short"
|
|
36192
|
-
});
|
|
36193
|
-
if (new_config && short_config && (short_config.entry !== new_config.entry || short_config.stop !== new_config.stop || short_config.risk !== new_config.risk)) {
|
|
36194
|
-
console.log("updating short position");
|
|
36195
|
-
short_position = await this.app_db.update_db_position(short_position, {
|
|
36196
|
-
reduce_ratio: 0.95,
|
|
36197
|
-
config: short_config.id
|
|
37300
|
+
const reverse_position = await this.syncAccount({
|
|
37301
|
+
symbol,
|
|
37302
|
+
kind: reverse_kind
|
|
37303
|
+
});
|
|
37304
|
+
if (reverse_position?.expand?.config && root_position.quantity > 0) {
|
|
37305
|
+
const reverse_config = reverse_position.expand.config;
|
|
37306
|
+
const diff = Math.abs(reverse_config.stop - root_position.entry);
|
|
37307
|
+
const result = to_f(diff * root_position.quantity);
|
|
37308
|
+
if (root_position.target_pnl !== result) {
|
|
37309
|
+
await this.app_db.update_db_position(root_position, {
|
|
37310
|
+
target_pnl: result
|
|
36198
37311
|
});
|
|
36199
|
-
console.log("Updating the short position config");
|
|
36200
37312
|
await this.getPositionConfig({
|
|
37313
|
+
kind: reverse_kind,
|
|
36201
37314
|
symbol,
|
|
36202
|
-
kind: "short",
|
|
36203
37315
|
params: {
|
|
36204
|
-
|
|
36205
|
-
|
|
36206
|
-
risk_reward,
|
|
36207
|
-
risk: new_config.risk,
|
|
36208
|
-
profit_percent: 1
|
|
37316
|
+
...reverse_config,
|
|
37317
|
+
risk: result
|
|
36209
37318
|
}
|
|
36210
37319
|
});
|
|
36211
|
-
console.log("placing the short trade based off config values");
|
|
36212
|
-
await this.triggerTradeFromConfig({
|
|
36213
|
-
symbol,
|
|
36214
|
-
kind: "short"
|
|
36215
|
-
});
|
|
36216
|
-
console.log("updating the stop loss for the short position from the long");
|
|
36217
|
-
await this.verifyStopLoss({
|
|
36218
|
-
symbol,
|
|
36219
|
-
kind: "short"
|
|
36220
|
-
});
|
|
36221
37320
|
}
|
|
37321
|
+
return result;
|
|
36222
37322
|
}
|
|
36223
|
-
|
|
36224
|
-
this.app_db.removePosition(long_position);
|
|
36225
|
-
this.app_db.removePosition(short_position);
|
|
36226
|
-
}
|
|
37323
|
+
return 0;
|
|
36227
37324
|
}
|
|
36228
|
-
async
|
|
36229
|
-
const { symbol,
|
|
36230
|
-
|
|
36231
|
-
|
|
36232
|
-
|
|
37325
|
+
async placeTrade(payload) {
|
|
37326
|
+
const { symbol, kind, place, tp } = payload;
|
|
37327
|
+
if (place) {
|
|
37328
|
+
return await this.triggerTradeFromConfig({
|
|
37329
|
+
symbol,
|
|
37330
|
+
kind
|
|
37331
|
+
});
|
|
36233
37332
|
}
|
|
36234
|
-
|
|
36235
|
-
symbol
|
|
36236
|
-
});
|
|
36237
|
-
await this.app_db.updateSymbolConfigs({
|
|
36238
|
-
configs: [
|
|
36239
|
-
{
|
|
36240
|
-
symbol,
|
|
36241
|
-
support: config.support,
|
|
36242
|
-
resistance: config.resistance,
|
|
36243
|
-
leverage: config.leverage,
|
|
36244
|
-
min_size: config.min_size,
|
|
36245
|
-
price_places: config.price_places,
|
|
36246
|
-
decimal_places: config.decimal_places
|
|
36247
|
-
}
|
|
36248
|
-
]
|
|
36249
|
-
});
|
|
36250
|
-
const position2 = await this.syncAccount({
|
|
37333
|
+
await this.syncAccount({
|
|
36251
37334
|
symbol,
|
|
36252
|
-
|
|
36253
|
-
|
|
37335
|
+
live_refresh: true,
|
|
37336
|
+
update: true
|
|
36254
37337
|
});
|
|
36255
|
-
const
|
|
36256
|
-
|
|
36257
|
-
|
|
36258
|
-
|
|
36259
|
-
risk_reward: 199,
|
|
36260
|
-
risk: bullish_instance.risk,
|
|
36261
|
-
symbol
|
|
37338
|
+
const result = await this.syncOrders({
|
|
37339
|
+
symbol,
|
|
37340
|
+
kind,
|
|
37341
|
+
update: true
|
|
36262
37342
|
});
|
|
36263
|
-
|
|
36264
|
-
if (!position2?.config) {
|
|
36265
|
-
await this.buildAppConfig({
|
|
36266
|
-
entry: long_config.entry,
|
|
36267
|
-
stop: long_config.stop,
|
|
36268
|
-
risk_reward: long_config.risk_reward,
|
|
36269
|
-
risk: long_config.risk,
|
|
36270
|
-
symbol,
|
|
36271
|
-
profit_percent,
|
|
36272
|
-
update_db: true
|
|
36273
|
-
});
|
|
36274
|
-
changed = true;
|
|
36275
|
-
} else {
|
|
36276
|
-
if (position2.expand.config.entry !== long_config.entry || position2.expand.config.stop !== long_config.stop || position2.expand.config.risk !== long_config.risk) {
|
|
36277
|
-
changed = true;
|
|
36278
|
-
}
|
|
36279
|
-
await this.getPositionConfig({
|
|
36280
|
-
symbol,
|
|
36281
|
-
kind: "long",
|
|
36282
|
-
params: {
|
|
36283
|
-
entry: long_config.entry,
|
|
36284
|
-
stop: long_config.stop,
|
|
36285
|
-
risk: long_config.risk,
|
|
36286
|
-
risk_reward: position2?.expand?.config?.risk_reward || long_config.risk_reward
|
|
36287
|
-
}
|
|
36288
|
-
});
|
|
36289
|
-
}
|
|
36290
|
-
const short_position = await this.syncAccount({
|
|
37343
|
+
await this.updateTargetPnl({
|
|
36291
37344
|
symbol,
|
|
36292
|
-
kind
|
|
37345
|
+
kind
|
|
36293
37346
|
});
|
|
36294
|
-
if (
|
|
36295
|
-
await this.
|
|
36296
|
-
should_stop: true,
|
|
36297
|
-
kind: "short",
|
|
36298
|
-
symbol
|
|
36299
|
-
});
|
|
36300
|
-
}
|
|
36301
|
-
if (changed) {
|
|
36302
|
-
return this.triggerTradeFromConfig({
|
|
37347
|
+
if (tp) {
|
|
37348
|
+
await this.placeProfitAndStop({
|
|
36303
37349
|
symbol,
|
|
36304
|
-
|
|
37350
|
+
trigger: true
|
|
36305
37351
|
});
|
|
36306
37352
|
}
|
|
36307
|
-
return
|
|
37353
|
+
return result;
|
|
36308
37354
|
}
|
|
36309
37355
|
}
|
|
36310
37356
|
function getExchangeKlass(exchange) {
|
|
@@ -36316,10 +37362,17 @@ function getExchangeKlass(exchange) {
|
|
|
36316
37362
|
type: "future",
|
|
36317
37363
|
proxyAgent: payload.proxyAgent
|
|
36318
37364
|
});
|
|
37365
|
+
let main_client = null;
|
|
37366
|
+
if (exchange === "binance") {
|
|
37367
|
+
main_client = await initClient(credentials, {
|
|
37368
|
+
type: "spot",
|
|
37369
|
+
proxyAgent: payload.proxyAgent
|
|
37370
|
+
});
|
|
37371
|
+
}
|
|
36319
37372
|
if (!client) {
|
|
36320
37373
|
throw new Error(`Failed to initialize ${exchange} client`);
|
|
36321
37374
|
}
|
|
36322
|
-
return new func(client);
|
|
37375
|
+
return new func(client, main_client);
|
|
36323
37376
|
};
|
|
36324
37377
|
}
|
|
36325
37378
|
async function getExchangeAccount(payload) {
|
|
@@ -36495,7 +37548,9 @@ class App {
|
|
|
36495
37548
|
as_view: true,
|
|
36496
37549
|
symbol
|
|
36497
37550
|
});
|
|
36498
|
-
const active_account = await exchange_account.getActiveAccount(
|
|
37551
|
+
const active_account = await exchange_account.getActiveAccount({
|
|
37552
|
+
symbol
|
|
37553
|
+
});
|
|
36499
37554
|
const long_position = active_account.position.long;
|
|
36500
37555
|
const short_position = active_account.position.short;
|
|
36501
37556
|
const long_db_position = positions.find((p) => p.kind === "long");
|
|
@@ -36517,65 +37572,6 @@ class App {
|
|
|
36517
37572
|
balance: active_account.usd_balance
|
|
36518
37573
|
};
|
|
36519
37574
|
}
|
|
36520
|
-
async verifyStopLoss(payload) {
|
|
36521
|
-
const { account, symbol, kind, revert } = payload;
|
|
36522
|
-
const exchange_account = await this.getExchangeAccount(payload.account);
|
|
36523
|
-
await exchange_account.syncOrders({
|
|
36524
|
-
symbol,
|
|
36525
|
-
kind,
|
|
36526
|
-
update: true
|
|
36527
|
-
});
|
|
36528
|
-
let original = null;
|
|
36529
|
-
if (revert) {
|
|
36530
|
-
original = await exchange_account.getOriginalPlannedStop({
|
|
36531
|
-
...account,
|
|
36532
|
-
symbol,
|
|
36533
|
-
kind
|
|
36534
|
-
});
|
|
36535
|
-
}
|
|
36536
|
-
const position2 = await exchange_account.syncAccount({
|
|
36537
|
-
symbol,
|
|
36538
|
-
kind,
|
|
36539
|
-
as_view: true
|
|
36540
|
-
});
|
|
36541
|
-
if (original && position2?.stop_loss && original.quantity != position2.stop_loss.quantity) {
|
|
36542
|
-
const opposite_kind = kind === "long" ? "short" : "long";
|
|
36543
|
-
await exchange_account.cancelOrders({
|
|
36544
|
-
symbol,
|
|
36545
|
-
kind: opposite_kind,
|
|
36546
|
-
stop: true
|
|
36547
|
-
});
|
|
36548
|
-
return await exchange_account.syncOrders({
|
|
36549
|
-
symbol,
|
|
36550
|
-
kind,
|
|
36551
|
-
update: true
|
|
36552
|
-
});
|
|
36553
|
-
}
|
|
36554
|
-
if (true) {
|
|
36555
|
-
const opposite_kind = kind === "long" ? "short" : "long";
|
|
36556
|
-
await exchange_account.syncOrders({
|
|
36557
|
-
symbol,
|
|
36558
|
-
kind: opposite_kind,
|
|
36559
|
-
update: true
|
|
36560
|
-
});
|
|
36561
|
-
await exchange_account.cancelOrders({
|
|
36562
|
-
symbol,
|
|
36563
|
-
kind: opposite_kind,
|
|
36564
|
-
stop: true
|
|
36565
|
-
});
|
|
36566
|
-
await exchange_account.syncReduceClosePosition(symbol, {
|
|
36567
|
-
kind: opposite_kind
|
|
36568
|
-
});
|
|
36569
|
-
await exchange_account.syncOrders({
|
|
36570
|
-
symbol,
|
|
36571
|
-
kind,
|
|
36572
|
-
update: true
|
|
36573
|
-
});
|
|
36574
|
-
}
|
|
36575
|
-
}
|
|
36576
|
-
async updateTopMovers(payload) {
|
|
36577
|
-
return await this.app_db.getBullishMarkets(payload);
|
|
36578
|
-
}
|
|
36579
37575
|
async getWindingDownMarkets() {
|
|
36580
37576
|
return await this.app_db.getWindingDownMarkets();
|
|
36581
37577
|
}
|
|
@@ -36585,15 +37581,13 @@ class App {
|
|
|
36585
37581
|
async updateAllAccountWithSymbols(with_positions) {
|
|
36586
37582
|
const [accounts, symbol_configs] = await Promise.all([
|
|
36587
37583
|
this.app_db.getAccounts(),
|
|
36588
|
-
this.app_db.getAllSymbolConfigs(with_positions)
|
|
37584
|
+
this.app_db.getAllSymbolConfigs({ with_positions })
|
|
36589
37585
|
]);
|
|
36590
37586
|
for (const account of accounts) {
|
|
36591
37587
|
for (const symbol_config of symbol_configs) {
|
|
36592
37588
|
const exchange_account = await this.getExchangeAccount(account);
|
|
36593
37589
|
await exchange_account.getLiveExchangeInstance({
|
|
36594
37590
|
symbol: symbol_config.symbol,
|
|
36595
|
-
price_places: symbol_config.price_places,
|
|
36596
|
-
decimal_places: symbol_config.decimal_places,
|
|
36597
37591
|
refresh: true
|
|
36598
37592
|
});
|
|
36599
37593
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
@@ -36601,13 +37595,14 @@ class App {
|
|
|
36601
37595
|
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
36602
37596
|
}
|
|
36603
37597
|
}
|
|
36604
|
-
async windDownSymbol(
|
|
37598
|
+
async windDownSymbol(payload) {
|
|
37599
|
+
const { symbol, risk: _risk } = payload;
|
|
36605
37600
|
let winding_instance = await this.app_db.getWindingDownMarkets(symbol);
|
|
36606
37601
|
if (winding_instance && winding_instance.length > 0) {
|
|
36607
37602
|
winding_instance = winding_instance[0];
|
|
36608
37603
|
}
|
|
36609
37604
|
if (!winding_instance || winding_instance.length === 0) {
|
|
36610
|
-
|
|
37605
|
+
winding_instance = null;
|
|
36611
37606
|
}
|
|
36612
37607
|
const positions = await this.app_db.hasExistingPosition(symbol);
|
|
36613
37608
|
if (positions.length === 0) {
|
|
@@ -36626,6 +37621,17 @@ class App {
|
|
|
36626
37621
|
if (position_pairs.length > 0) {
|
|
36627
37622
|
console.log("removing position pairs");
|
|
36628
37623
|
for (const pair of position_pairs) {
|
|
37624
|
+
const exchange_account = await this.getExchangeAccount(pair.expand.account);
|
|
37625
|
+
await exchange_account.cancelOrders({
|
|
37626
|
+
symbol: pair.symbol,
|
|
37627
|
+
kind: "long",
|
|
37628
|
+
all: true
|
|
37629
|
+
});
|
|
37630
|
+
await exchange_account.cancelOrders({
|
|
37631
|
+
symbol: pair.symbol,
|
|
37632
|
+
kind: "short",
|
|
37633
|
+
all: true
|
|
37634
|
+
});
|
|
36629
37635
|
await this.app_db.removePosition(pair);
|
|
36630
37636
|
}
|
|
36631
37637
|
}
|
|
@@ -36633,23 +37639,118 @@ class App {
|
|
|
36633
37639
|
console.log("winding down not paired positions");
|
|
36634
37640
|
for (const pair of not_paired_positions) {
|
|
36635
37641
|
const exchange_account = await this.getExchangeAccount(pair.expand.account);
|
|
36636
|
-
await exchange_account.
|
|
37642
|
+
const result = await exchange_account.terminatePositions({
|
|
37643
|
+
symbol: pair.symbol
|
|
37644
|
+
});
|
|
37645
|
+
console.log("result", result);
|
|
36637
37646
|
}
|
|
36638
37647
|
}
|
|
36639
37648
|
}
|
|
36640
|
-
async
|
|
36641
|
-
const
|
|
36642
|
-
|
|
36643
|
-
movePercent: payload.movePercent
|
|
37649
|
+
async getNonEssentialSymbols() {
|
|
37650
|
+
const essential_symbols = await this.app_db.getAllSymbolConfigs({
|
|
37651
|
+
custom_filter: `essential = true`
|
|
36644
37652
|
});
|
|
36645
|
-
const
|
|
36646
|
-
|
|
36647
|
-
|
|
36648
|
-
|
|
36649
|
-
|
|
36650
|
-
|
|
37653
|
+
const bullish_markets = await this.app_db.getBullishMarkets();
|
|
37654
|
+
const bullish_symbols = Array.from(new Set(bullish_markets.updated_bullish.map((m) => m.symbol)));
|
|
37655
|
+
const symbols = Array.from(new Set(essential_symbols.map((s2) => s2.symbol))).concat(bullish_symbols);
|
|
37656
|
+
const not_symbols_filter = symbols.map((s2) => `symbol:lower != "${s2.toLowerCase()}"`).join(" && ");
|
|
37657
|
+
const positions = await this.app_db.getPositions({
|
|
37658
|
+
custom_filter: not_symbols_filter,
|
|
37659
|
+
symbol: "",
|
|
37660
|
+
account: {
|
|
37661
|
+
owner: "",
|
|
37662
|
+
exchange: ""
|
|
37663
|
+
}
|
|
36651
37664
|
});
|
|
36652
|
-
return
|
|
37665
|
+
return new Set(positions.map((p) => p.symbol));
|
|
37666
|
+
}
|
|
37667
|
+
async refreshAllPositionsWithSymbol(payload) {
|
|
37668
|
+
const { symbol } = payload;
|
|
37669
|
+
const positions = await this.app_db.getPositions({
|
|
37670
|
+
custom_filter: `symbol:lower="${symbol.toLowerCase()}"`,
|
|
37671
|
+
symbol: "",
|
|
37672
|
+
account: {
|
|
37673
|
+
owner: "",
|
|
37674
|
+
exchange: ""
|
|
37675
|
+
}
|
|
37676
|
+
});
|
|
37677
|
+
const exchanges = positions.map((p) => p.expand.account);
|
|
37678
|
+
const all_exchanges = {};
|
|
37679
|
+
for (const exchange of exchanges) {
|
|
37680
|
+
let id = `${exchange.owner}-${exchange.exchange}`;
|
|
37681
|
+
if (all_exchanges[id]) {
|
|
37682
|
+
continue;
|
|
37683
|
+
}
|
|
37684
|
+
all_exchanges[id] = exchange;
|
|
37685
|
+
}
|
|
37686
|
+
const unique_exchanges = Object.values(all_exchanges);
|
|
37687
|
+
for (const exchange of unique_exchanges) {
|
|
37688
|
+
const exchange_account = await this.getExchangeAccount({
|
|
37689
|
+
owner: exchange.owner,
|
|
37690
|
+
exchange: exchange.exchange
|
|
37691
|
+
});
|
|
37692
|
+
await exchange_account.syncAccount({
|
|
37693
|
+
symbol,
|
|
37694
|
+
update: true,
|
|
37695
|
+
live_refresh: true
|
|
37696
|
+
});
|
|
37697
|
+
await exchange_account.placeProfitAndStop({
|
|
37698
|
+
symbol,
|
|
37699
|
+
trigger: false
|
|
37700
|
+
});
|
|
37701
|
+
}
|
|
37702
|
+
}
|
|
37703
|
+
async getMoverExchangeInstances() {
|
|
37704
|
+
return await this.app_db.getMoverExchangeInstances();
|
|
37705
|
+
}
|
|
37706
|
+
async updateTpOnAllMarkets() {
|
|
37707
|
+
const move_instances = await this.getMoverExchangeInstances();
|
|
37708
|
+
for (const instance of move_instances) {
|
|
37709
|
+
const params = {
|
|
37710
|
+
account: {
|
|
37711
|
+
owner: instance.owner,
|
|
37712
|
+
exchange: instance.exchange
|
|
37713
|
+
}
|
|
37714
|
+
};
|
|
37715
|
+
const exchange_account = await this.getExchangeAccount(params.account);
|
|
37716
|
+
const symbols = await exchange_account.getSymbolsForPositions();
|
|
37717
|
+
for (const symbol of symbols) {
|
|
37718
|
+
await exchange_account.placeTrade({
|
|
37719
|
+
symbol,
|
|
37720
|
+
kind: "long",
|
|
37721
|
+
tp: true
|
|
37722
|
+
});
|
|
37723
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
37724
|
+
}
|
|
37725
|
+
}
|
|
37726
|
+
}
|
|
37727
|
+
async triggerMoverTask(payload) {
|
|
37728
|
+
const { callback, removeCallback } = payload;
|
|
37729
|
+
const move_instances = await this.getMoverExchangeInstances();
|
|
37730
|
+
for (const instance of move_instances) {
|
|
37731
|
+
const params = {
|
|
37732
|
+
account: {
|
|
37733
|
+
owner: instance.owner,
|
|
37734
|
+
exchange: instance.exchange
|
|
37735
|
+
}
|
|
37736
|
+
};
|
|
37737
|
+
const exchange_account = await this.getExchangeAccount(params.account);
|
|
37738
|
+
const result = await exchange_account.fetchAndUpdateTopMovers();
|
|
37739
|
+
const { updated_bullish } = result;
|
|
37740
|
+
for (const m of updated_bullish) {
|
|
37741
|
+
await callback({
|
|
37742
|
+
symbol: m.symbol,
|
|
37743
|
+
account: params.account
|
|
37744
|
+
});
|
|
37745
|
+
}
|
|
37746
|
+
const winding_down_symbols = await this.app_db.getWindingDownMarkets();
|
|
37747
|
+
for (const w of winding_down_symbols) {
|
|
37748
|
+
await removeCallback({
|
|
37749
|
+
symbol: w.symbol,
|
|
37750
|
+
account: params.account
|
|
37751
|
+
});
|
|
37752
|
+
}
|
|
37753
|
+
}
|
|
36653
37754
|
}
|
|
36654
37755
|
}
|
|
36655
37756
|
async function initApp(payload) {
|
|
@@ -36675,6 +37776,10 @@ async function getCredentials(account, exchange) {
|
|
|
36675
37776
|
apiKey = process.env.GBOZEE1_SUB_ACCOUNT_API_KEY;
|
|
36676
37777
|
apiSecret = process.env.GBOZEE1_SUB_ACCOUNT_API_SECRET;
|
|
36677
37778
|
break;
|
|
37779
|
+
case "tomi_account":
|
|
37780
|
+
apiKey = process.env.TOMI_ACCOUNT_API_KEY;
|
|
37781
|
+
apiSecret = process.env.TOMI_ACCOUNT_API_SECRET;
|
|
37782
|
+
break;
|
|
36678
37783
|
case "main_account":
|
|
36679
37784
|
default:
|
|
36680
37785
|
apiKey = process.env.MAIN_ACCOUNT_API_KEY;
|