@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.
Files changed (3) hide show
  1. package/dist/index.d.ts +249 -78
  2. package/dist/index.js +1496 -391
  3. 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(with_positions) {
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
- const filter = Array.from(symbol_set).map((s2) => `symbol:lower="${s2.toLowerCase()}"`).join(" || ");
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(account, options) {
32180
- const { symbol, as_view = false } = options;
32181
- const default_params = as_view ? {
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(account, {
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
- return await this.pb.collection("symbol_configs").getFirstListItem(`symbol:lower="${symbol.toLowerCase()}"`);
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
- await this.pb.collection("scheduled_trades").update(db_position.config, {
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
- config = await this.pb.collection("scheduled_trades").create({
32399
- symbol: db_position.symbol,
32400
- account: db_position.account,
32401
- profit: payload.risk,
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
- return createLimitPurchaseOrders(client, symbol, price_places, decimal_places, [order]);
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
- const quantity = Math.abs(position2.positionAmt);
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
- ], "%.3f", "%.1f");
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: "%.1f",
34010
- decimal_places: "%.3f",
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: "1w"
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
- constructor(client) {
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(account, symbol) {
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
- await this.client.setLeverage({
34308
- symbol: payload.symbol,
34309
- leverage: payload.leverage || maxLeverage
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: to_f((minNotional || 0) / support, decimal_places),
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
- for (const m of validMovers) {
34357
- const isActive = await isSymbolActive({
34486
+ const isActivePromises = validMovers.map(async (m) => {
34487
+ return await isSymbolActive({
34358
34488
  client: this.client,
34359
34489
  symbol: m.symbol
34360
34490
  });
34361
- if (isActive) {
34362
- activeMovers.push(m);
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
- return { movers: activeMovers, delisted };
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
- ], "%.3f", "%.1f");
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: "%.1f",
34748
- decimal_places: "%.3f",
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
- constructor(client) {
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(account, symbol) {
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(this.instance, payload.symbol);
35657
- if (payload.price_places) {
35658
- data.config.price_places = payload.price_places;
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 (payload.decimal_places) {
35661
- data.config.decimal_places = payload.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(symbol, full) {
35672
- const symbol_config = await this.app_db.getSymbolConfigFromDB(symbol);
35673
- const live_exchange_instance = await this.getLiveExchangeInstance({
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(this.instance, {
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(symbol);
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(symbol);
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
- await this.app_db.createOrUpdatePositionConfig(db_position, payload.params);
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 getOriginalPlannedStop(payload) {
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
- let result = await this.syncReduceClosePosition(payload.symbol, {
35980
- long: {
35981
- minimum_pnl: config?.long_minimum_pnl || 0.0001,
35982
- max_size: 0.003,
35983
- profit: config?.long_profit,
35984
- increase: false,
35985
- not_reduce: config?.not_reduce,
35986
- ratio: config?.reduce_ratio_long
35987
- },
35988
- short: {
35989
- minimum_pnl: config?.short_minimum_pnl || 0.0001,
35990
- max_size: 0.003,
35991
- profit: config?.short_profit,
35992
- increase: false,
35993
- not_reduce: config?.not_reduce,
35994
- ratio: config?.reduce_ratio_short
35995
- },
35996
- trigger: {
35997
- long: false,
35998
- short: false
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(symbol, payload) {
36006
- let accountInfo = await this.getActiveAccount(symbol, true);
36007
- let { long, short, trigger, kind } = payload || {};
36008
- if (!long || !short) {
36009
- const positions = await this.syncAccount({
36010
- symbol
36011
- });
36012
- const config = build_reduce_config({
36013
- account: this.instance,
36014
- symbol,
36015
- _positions: positions
36016
- });
36017
- long = {
36018
- minimum_pnl: config?.long_minimum_pnl,
36019
- max_size: 0.003,
36020
- profit: config?.long_profit,
36021
- increase: false,
36022
- not_reduce: config?.not_reduce,
36023
- ratio: config?.reduce_ratio_long,
36024
- use_full: kind == "long" ? true : false
36025
- };
36026
- short = {
36027
- minimum_pnl: config?.short_minimum_pnl,
36028
- max_size: 0.003,
36029
- profit: config?.short_profit,
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 generate_config_params(payload) {
36046
- const { entry, stop, risk_reward, risk, symbol } = payload;
36047
- const app_config = await this.buildAppConfig({
36048
- entry,
36049
- stop,
36050
- risk_reward,
36051
- risk,
36052
- symbol
36053
- });
36054
- let config = generate_config_params(app_config, {
36055
- entry,
36056
- stop,
36057
- risk_reward,
36058
- risk,
36059
- symbol
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
- return { ...config, place_stop: false, profit_percent: 0 };
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: position2.next_order || position2.avg_liquidation,
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: payload.symbol,
36085
- kind: payload.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: payload.symbol,
36091
- entry: config.entry,
36605
+ symbol,
36606
+ entry,
36092
36607
  stop: config.stop,
36093
36608
  risk_reward: config.risk_reward,
36094
36609
  risk: config.risk,
36095
- place: true
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: opposite_kind,
36141
- stop: true
36142
- });
36143
- await this.syncReduceClosePosition(symbol, {
36144
- kind: opposite_kind
37238
+ kind: "long",
37239
+ all: true
36145
37240
  });
36146
- await this.syncOrders({
37241
+ await this.cancelOrders({
36147
37242
  symbol,
36148
- kind,
36149
- update: true
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 windDownSymbol(symbol, risk_reward = 199) {
36154
- const positions = await this.syncAccount({
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
- update: true
37298
+ kind
36157
37299
  });
36158
- let long_position = positions.find((x) => x.kind === "long");
36159
- let short_position = positions.find((x) => x.kind === "short");
36160
- if (long_position && long_position.quantity > 0) {
36161
- console.log("Start to wind down the long position");
36162
- let config = long_position?.expand?.config;
36163
- if (!config && long_position.config) {
36164
- config = await this.getPositionConfig({
36165
- symbol,
36166
- kind: "long"
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
- entry: new_config.entry,
36205
- stop: new_config.stop,
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
- if (long_position && long_position.quantity === 0 && short_position && short_position.quantity == 0) {
36224
- this.app_db.removePosition(long_position);
36225
- this.app_db.removePosition(short_position);
36226
- }
37323
+ return 0;
36227
37324
  }
36228
- async triggerBullishMarket(payload) {
36229
- const { symbol, profit_percent = 10 } = payload;
36230
- const bullish_instance = await this.app_db.getBullishMarket(symbol);
36231
- if (!bullish_instance) {
36232
- return false;
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
- const config = await this.exchange.generateConfig({
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
- update: true,
36253
- kind: "long"
37335
+ live_refresh: true,
37336
+ update: true
36254
37337
  });
36255
- const symbol_config = await this.app_db.getSymbolConfigFromDB(symbol);
36256
- const long_config = await this.generate_config_params({
36257
- entry: symbol_config.resistance,
36258
- stop: symbol_config.support,
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
- let changed = false;
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: "short"
37345
+ kind
36293
37346
  });
36294
- if (short_position?.config) {
36295
- await this.toggleStopBuying({
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
- kind: "long"
37350
+ trigger: true
36305
37351
  });
36306
37352
  }
36307
- return false;
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(symbol);
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(symbol) {
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
- return true;
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.windDownSymbol(pair.symbol, winding_instance?.risk_reward || 199);
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 fetchAndUpdateTopMovers(payload) {
36641
- const exchange_account = await this.getExchangeAccount(payload.account);
36642
- const { movers } = await exchange_account.exchange.checkDelistedMovers({
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 result = await this.updateTopMovers({
36646
- new_markets: movers.map((m) => ({
36647
- symbol: m.symbol,
36648
- percent: m.priceChangePercent
36649
- })),
36650
- totalRisk: payload.totalRisk
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 result;
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;