@gbozee/ultimate 0.0.2-18 → 0.0.2-20

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 +158 -45
  2. package/dist/index.js +833 -222
  3. package/package.json +3 -1
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 || {
@@ -32388,28 +32413,54 @@ class AppDatabase {
32388
32413
  async createOrUpdatePositionConfig(db_position, payload) {
32389
32414
  let config = null;
32390
32415
  if (db_position.config) {
32391
- await this.pb.collection("scheduled_trades").update(db_position.config, {
32416
+ const obj = {
32392
32417
  entry: payload.entry,
32393
32418
  stop: payload.stop,
32394
32419
  risk_reward: payload.risk_reward,
32395
32420
  risk: payload.risk
32396
- });
32421
+ };
32422
+ if (payload.profit_percent !== undefined) {
32423
+ obj.profit_percent = payload.profit_percent;
32424
+ }
32425
+ return await this.pb.collection("scheduled_trades").update(db_position.config, obj);
32397
32426
  } 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
32427
+ const kind = payload.entry > payload.stop ? "long" : "short";
32428
+ const account = db_position.expand?.account;
32429
+ const configs = await this.pb.collection("scheduled_trades").getFullList({
32430
+ filter: `symbol:lower="${db_position.symbol.toLowerCase()}" && kind="${kind}" && account.owner:lower="${account.owner.toLowerCase()}" && account.exchange:lower="${account.exchange.toLowerCase()}"`
32409
32431
  });
32432
+ if (configs.length > 0) {
32433
+ config = configs[0];
32434
+ await this.pb.collection("scheduled_trades").update(config.id, {
32435
+ entry: payload.entry,
32436
+ stop: payload.stop,
32437
+ risk_reward: payload.risk_reward,
32438
+ risk: payload.risk,
32439
+ profit_percent: payload.profit_percent
32440
+ });
32441
+ for (const _config of configs) {
32442
+ if (_config.id !== config.id) {
32443
+ await this.pb.collection("scheduled_trades").delete(_config.id);
32444
+ }
32445
+ }
32446
+ } else {
32447
+ config = await this.pb.collection("scheduled_trades").create({
32448
+ symbol: db_position.symbol,
32449
+ account: db_position.account,
32450
+ profit: payload.risk,
32451
+ kind,
32452
+ entry: payload.entry,
32453
+ stop: payload.stop,
32454
+ risk_reward: payload.risk_reward,
32455
+ risk: payload.risk,
32456
+ profit_percent: payload.profit_percent,
32457
+ place_tp: true
32458
+ });
32459
+ }
32410
32460
  await this.pb.collection("positions").update(db_position.id, {
32411
32461
  config: config?.id
32412
32462
  });
32463
+ return config;
32413
32464
  }
32414
32465
  }
32415
32466
  async getPositionConfig(payload) {
@@ -32458,7 +32509,7 @@ class AppDatabase {
32458
32509
  moved_to_winding: []
32459
32510
  };
32460
32511
  }
32461
- const { new_markets, totalRisk } = options;
32512
+ const { new_markets, totalRisk, max_count: _max_count } = options;
32462
32513
  const newMarketSymbols = new Set(new_markets.map((m) => m.symbol));
32463
32514
  console.log(`Processing ${new_markets.length} new top movers with total risk ${totalRisk}`);
32464
32515
  let currentBullish = [];
@@ -33192,6 +33243,10 @@ class Signal {
33192
33243
  limit_orders = trade_zones.slice(1).filter((x) => x >= this.to_f(current_price));
33193
33244
  market_orders = trade_zones.slice(1).filter((x) => x < this.to_f(current_price));
33194
33245
  }
33246
+ if (market_orders.length === 1) {
33247
+ limit_orders = limit_orders.concat(market_orders);
33248
+ market_orders = [];
33249
+ }
33195
33250
  const increase_position = Boolean(this.support) && this.increase_position;
33196
33251
  const market_trades = limit_orders.length > 0 ? market_orders.map((x, i2) => {
33197
33252
  const defaultStopLoss = i2 === 0 ? limit_orders[limit_orders.length - 1] : market_orders[i2 - 1];
@@ -33338,6 +33393,8 @@ class Signal {
33338
33393
  });
33339
33394
  const multiplier = start - index;
33340
33395
  const incurred_fees = fees.reduce((a, b) => a + b, 0) + previous_risks.reduce((a, b) => a + b, 0);
33396
+ if (index === 0) {
33397
+ }
33341
33398
  let quantity = determine_position_size({
33342
33399
  entry,
33343
33400
  stop,
@@ -33819,7 +33876,11 @@ async function placeTpOrder(client, payload) {
33819
33876
  price: payload.tp,
33820
33877
  quantity: _quantity
33821
33878
  };
33822
- return createLimitPurchaseOrders(client, symbol, price_places, decimal_places, [order]);
33879
+ const rr = await createLimitPurchaseOrders(client, symbol, price_places, decimal_places, [order]);
33880
+ if (payload.kind == "long") {
33881
+ console.log("rr", { rr, price_places, decimal_places });
33882
+ }
33883
+ return rr;
33823
33884
  }
33824
33885
  return { error: "No quantity" };
33825
33886
  }
@@ -33935,17 +33996,21 @@ async function allWalletBalances(client) {
33935
33996
  balance: to_f(x.balance, "%.8f")
33936
33997
  }));
33937
33998
  }
33938
- function buildPosition(position2, orders) {
33999
+ function buildPosition(position2, orders, options) {
34000
+ const { price_places = "%.1f", decimal_places = "%.3f" } = options;
33939
34001
  const entry = position2.entryPrice;
33940
- const quantity = Math.abs(position2.positionAmt);
34002
+ let quantity = Math.abs(position2.positionAmt);
33941
34003
  const kind = position2.kind;
34004
+ if (Number.isNaN(quantity)) {
34005
+ quantity = 0;
34006
+ }
33942
34007
  const limitOrders = orders.filter((x) => x.kind === kind && !x.isStop).filter((o) => {
33943
34008
  return kind === "long" ? o.side === "buy" : o.side === "sell";
33944
34009
  });
33945
34010
  const avg = determine_average_entry_and_size([
33946
34011
  { price: entry, quantity },
33947
34012
  ...limitOrders.map((o) => ({ price: o.price, quantity: o.qty }))
33948
- ], "%.3f", "%.1f");
34013
+ ], decimal_places, price_places);
33949
34014
  const stopOrders = orders.filter((x) => x.kind === kind && x.isStop)[0];
33950
34015
  const tpOrders = orders.filter((x) => x.kind === kind && !x.isStop).filter((x) => x.kind === "long" ? x.side === "sell" : x.side === "buy")[0];
33951
34016
  const avg_entry = avg.entry;
@@ -33980,7 +34045,7 @@ var emptyPosition = {
33980
34045
  tp_quantity: 0,
33981
34046
  stop_quantity: 0
33982
34047
  };
33983
- async function fetchBinanceAccount(client, json) {
34048
+ async function fetchBinanceAccount(client, json, options) {
33984
34049
  const [position2, balance, orders, current_price, all_balances] = await Promise.all([
33985
34050
  getPositionInfo(client, json.symbol),
33986
34051
  getWalletBalance(client, json.symbol.toLowerCase().endsWith("usdt") ? "USDT" : "USDC"),
@@ -33995,19 +34060,19 @@ async function fetchBinanceAccount(client, json) {
33995
34060
  const long_position = buildPosition(position2.long || {
33996
34061
  ...emptyPosition,
33997
34062
  kind: "long"
33998
- }, orders);
34063
+ }, orders, options);
33999
34064
  const short_position = buildPosition(position2.short || {
34000
34065
  ...emptyPosition,
34001
34066
  kind: "short"
34002
- }, orders);
34067
+ }, orders, options);
34003
34068
  const result = {
34004
34069
  id: `${json.owner}-${json.symbol}-binance`,
34005
34070
  owner: json.owner,
34006
34071
  config: {
34007
34072
  symbol: json.symbol,
34008
34073
  id: 0,
34009
- price_places: "%.1f",
34010
- decimal_places: "%.3f",
34074
+ price_places: options.price_places,
34075
+ decimal_places: options.decimal_places,
34011
34076
  trades: {}
34012
34077
  },
34013
34078
  exchange: "binance",
@@ -34126,6 +34191,43 @@ function calculateSupportResistance(klines) {
34126
34191
  const resistance = Math.max(...highs);
34127
34192
  return { support, resistance };
34128
34193
  }
34194
+ async function getTopMovers(payload) {
34195
+ const { client, percentThreshold = 20 } = payload;
34196
+ const data = await client.get24hrChangeStatistics();
34197
+ const movers = data.filter((s2) => parseFloat(s2.priceChangePercent) >= percentThreshold).map((s2) => ({
34198
+ symbol: s2.symbol,
34199
+ priceChangePercent: parseFloat(s2.priceChangePercent),
34200
+ lastPrice: parseFloat(s2.lastPrice),
34201
+ highPrice: parseFloat(s2.highPrice),
34202
+ lowPrice: parseFloat(s2.lowPrice),
34203
+ volume: parseFloat(s2.volume)
34204
+ })).sort((a, b) => Math.abs(b.priceChangePercent) - Math.abs(a.priceChangePercent));
34205
+ return movers;
34206
+ }
34207
+ async function isSymbolActive(payload) {
34208
+ const { client, symbol } = payload;
34209
+ try {
34210
+ const depth_data = await client.getOrderBook({
34211
+ symbol,
34212
+ limit: 5
34213
+ });
34214
+ if (depth_data.asks.length === 0 && depth_data.bids.length === 0) {
34215
+ return false;
34216
+ }
34217
+ return true;
34218
+ } catch (err) {
34219
+ if (err.response && err.response.data && err.response.data.code === -1121) {
34220
+ return false;
34221
+ }
34222
+ console.error(`Error checking ${symbol}:`, err.message);
34223
+ return false;
34224
+ }
34225
+ }
34226
+ async function getActiveSymbols(payload) {
34227
+ const { client } = payload;
34228
+ const response = await client.getExchangeInfo();
34229
+ return response.symbols;
34230
+ }
34129
34231
 
34130
34232
  class BinanceExchange {
34131
34233
  client;
@@ -34205,10 +34307,19 @@ class BinanceExchange {
34205
34307
  raw: payload.raw || false
34206
34308
  });
34207
34309
  }
34208
- async getExchangeAccountInfo(account, symbol) {
34310
+ async getExchangeAccountInfo(options) {
34311
+ const {
34312
+ price_places = "%.1f",
34313
+ decimal_places = "%.3f",
34314
+ account,
34315
+ symbol
34316
+ } = options;
34209
34317
  return await fetchBinanceAccount(this.client, {
34210
34318
  owner: account.owner,
34211
34319
  symbol
34320
+ }, {
34321
+ price_places,
34322
+ decimal_places
34212
34323
  });
34213
34324
  }
34214
34325
  async cancelOrders(payload) {
@@ -34274,8 +34385,8 @@ class BinanceExchange {
34274
34385
  return maxLeverage;
34275
34386
  }
34276
34387
  async generateConfig(payload) {
34277
- const response = await this.client.getExchangeInfo();
34278
- const symbols = response.symbols;
34388
+ const symbols = await getActiveSymbols({ client: this.client });
34389
+ console.log("symbols", symbols);
34279
34390
  const { symbol, limit = 5 } = payload;
34280
34391
  const klines = await getWeeklyKlines({
34281
34392
  client: this.client,
@@ -34306,6 +34417,40 @@ class BinanceExchange {
34306
34417
  };
34307
34418
  return configObj;
34308
34419
  }
34420
+ async checkDelistedMovers(payload) {
34421
+ const movers = await getTopMovers({
34422
+ client: this.client,
34423
+ percentThreshold: payload.movePercent
34424
+ });
34425
+ const _activeSymbols = await getActiveSymbols({ client: this.client });
34426
+ const activeSymbols = _activeSymbols.map((s2) => s2.symbol);
34427
+ const delisted = movers.map((x) => x.symbol).filter((symbol) => !activeSymbols.includes(symbol));
34428
+ const validMovers = movers.filter((m) => !delisted.includes(m.symbol)).filter((m) => activeSymbols.includes(m.symbol));
34429
+ const activeMovers = [];
34430
+ for (const m of validMovers) {
34431
+ const isActive = await isSymbolActive({
34432
+ client: this.client,
34433
+ symbol: m.symbol
34434
+ });
34435
+ if (isActive) {
34436
+ activeMovers.push(m);
34437
+ }
34438
+ }
34439
+ console.log(`Top movers:`, movers);
34440
+ console.log(`Delisted movers:`, delisted);
34441
+ return { movers: activeMovers, delisted };
34442
+ }
34443
+ async closePosition(payload) {
34444
+ const { symbol, kind, price_places, decimal_places } = payload;
34445
+ const currentPrice = await this.get_current_price(symbol);
34446
+ return this.placeTpOrder({
34447
+ price_places,
34448
+ decimal_places,
34449
+ symbol,
34450
+ take_profit: currentPrice,
34451
+ kind
34452
+ });
34453
+ }
34309
34454
  }
34310
34455
  function getPricePlaces(target) {
34311
34456
  const numStr = target.toString();
@@ -34621,7 +34766,8 @@ async function allWalletBalances2(client) {
34621
34766
  balance: to_f(x.walletBalance, "%.8f")
34622
34767
  }));
34623
34768
  }
34624
- function buildPosition2(position2, orders) {
34769
+ function buildPosition2(position2, orders, options) {
34770
+ const { price_places = "%.1f", decimal_places = "%.3f" } = options;
34625
34771
  const entry = parseFloat(position2.avgPrice || "0");
34626
34772
  const quantity = parseFloat(position2.size || "0");
34627
34773
  const kind = position2.positionIdx === 1 ? "long" : "short";
@@ -34631,7 +34777,7 @@ function buildPosition2(position2, orders) {
34631
34777
  const avg = determine_average_entry_and_size([
34632
34778
  { price: entry, quantity },
34633
34779
  ...limitOrders.map((o) => ({ price: o.price, quantity: o.qty }))
34634
- ], "%.3f", "%.1f");
34780
+ ], decimal_places, price_places);
34635
34781
  const stopOrders = orders.filter((x) => x.kind === kind && x.isStop)[0];
34636
34782
  const tpOrders = orders.filter((x) => x.kind === kind && !x.isStop).filter((x) => x.kind === "long" ? x.side === "sell" : x.side === "buy")[0];
34637
34783
  const avg_entry = avg.entry;
@@ -34666,7 +34812,8 @@ var emptyPosition2 = {
34666
34812
  tp_quantity: 0,
34667
34813
  stop_quantity: 0
34668
34814
  };
34669
- async function fetchBybitAccount(client, json) {
34815
+ async function fetchBybitAccount(client, json, options) {
34816
+ const { price_places = "%.1f", decimal_places = "%.3f" } = options;
34670
34817
  const [position2, balance, orders, current_price, all_balances] = await Promise.all([
34671
34818
  getPositionInfo2(client, json.symbol),
34672
34819
  getWalletBalance2(client, "USDT"),
@@ -34684,8 +34831,8 @@ async function fetchBybitAccount(client, json) {
34684
34831
  config: {
34685
34832
  symbol: json.symbol,
34686
34833
  id: 0,
34687
- price_places: "%.1f",
34688
- decimal_places: "%.3f",
34834
+ price_places,
34835
+ decimal_places,
34689
34836
  trades: {}
34690
34837
  },
34691
34838
  exchange: "bybit",
@@ -34698,12 +34845,18 @@ async function fetchBybitAccount(client, json) {
34698
34845
  ...emptyPosition2,
34699
34846
  positionIdx: 1,
34700
34847
  kind: "long"
34701
- }, orders),
34848
+ }, orders, {
34849
+ price_places,
34850
+ decimal_places
34851
+ }),
34702
34852
  short_position: buildPosition2(position2.short || {
34703
34853
  ...emptyPosition2,
34704
34854
  positionIdx: 2,
34705
34855
  kind: "short"
34706
- }, orders),
34856
+ }, orders, {
34857
+ price_places,
34858
+ decimal_places
34859
+ }),
34707
34860
  current_price,
34708
34861
  orders: limitOrders,
34709
34862
  entries: [],
@@ -34872,10 +35025,19 @@ class BybitExchange {
34872
35025
  raw: payload.raw || false
34873
35026
  });
34874
35027
  }
34875
- async getExchangeAccountInfo(account, symbol) {
35028
+ async getExchangeAccountInfo(options) {
35029
+ const {
35030
+ price_places = "%.1f",
35031
+ decimal_places = "%.3f",
35032
+ account,
35033
+ symbol
35034
+ } = options;
34876
35035
  return await fetchBybitAccount(this.client, {
34877
35036
  owner: account.owner,
34878
35037
  symbol
35038
+ }, {
35039
+ price_places,
35040
+ decimal_places
34879
35041
  });
34880
35042
  }
34881
35043
  async cancelOrders(payload) {
@@ -34928,6 +35090,10 @@ class BybitExchange {
34928
35090
  }
34929
35091
  async generateConfig(payload) {
34930
35092
  }
35093
+ async checkDelistedMovers(payload) {
35094
+ }
35095
+ async closePosition(payload) {
35096
+ }
34931
35097
  }
34932
35098
 
34933
35099
  // src/helpers/accounts.ts
@@ -35083,12 +35249,12 @@ function calculateHedge(kind, active_account, targetPnl = 100, ratio = 0.9, use_
35083
35249
  return {
35084
35250
  [kind]: {
35085
35251
  price: to_f(takeProfitPrice, active_account.price_places),
35086
- quantity: to_f(position2.quantity, active_account.decimal_places),
35252
+ quantity: to_f(position2.quantity || 0, active_account.decimal_places),
35087
35253
  type: "TAKE_PROFIT"
35088
35254
  },
35089
35255
  [oppositeKind]: {
35090
35256
  stop_price: to_f(stopLossPrice, active_account.price_places),
35091
- quantity: to_f(stopLossQuantity, active_account.decimal_places),
35257
+ quantity: to_f(stopLossQuantity || 0, active_account.decimal_places),
35092
35258
  type: "STOP_LOSS"
35093
35259
  }
35094
35260
  };
@@ -35157,7 +35323,9 @@ function processPosition(codeNode, input, kind) {
35157
35323
  owner: active_account.owner,
35158
35324
  risk: codeNode.profit || 150,
35159
35325
  increase: codeNode.increase,
35160
- not_reduce: codeNode.not_reduce
35326
+ not_reduce: codeNode.not_reduce,
35327
+ price_places: active_account.price_places,
35328
+ decimal_places: active_account.decimal_places
35161
35329
  };
35162
35330
  }
35163
35331
  async function reduceMajorPositionCalculation(input, exchange_instance) {
@@ -35180,11 +35348,13 @@ async function reduceMajorPositionCalculation(input, exchange_instance) {
35180
35348
  });
35181
35349
  if (conditionsCheck) {
35182
35350
  const async_tp = async () => {
35183
- if (input.stop) {
35351
+ if (input.stop && input.stop !== Infinity) {
35184
35352
  await exchange_instance.placeTpOrder({
35185
35353
  symbol: input.position.symbol,
35186
35354
  kind: input.kind,
35187
- take_profit: input.stop
35355
+ take_profit: input.stop,
35356
+ price_places: input.price_places,
35357
+ decimal_places: input.decimal_places
35188
35358
  });
35189
35359
  }
35190
35360
  };
@@ -35194,7 +35364,9 @@ async function reduceMajorPositionCalculation(input, exchange_instance) {
35194
35364
  symbol: input.position.symbol,
35195
35365
  kind: input.to_place.kind,
35196
35366
  price: input.to_place.stop_price,
35197
- quantity: input.to_place.quantity
35367
+ quantity: input.to_place.quantity,
35368
+ price_places: input.price_places,
35369
+ decimal_places: input.decimal_places
35198
35370
  }).then((r2) => {
35199
35371
  console.log("placeNewOrderData", r2);
35200
35372
  });
@@ -35202,12 +35374,14 @@ async function reduceMajorPositionCalculation(input, exchange_instance) {
35202
35374
  };
35203
35375
  let placeNewOrderData = null;
35204
35376
  const async_place_stop = async () => {
35205
- if (!input.not_reduce && input.to_place.stop_price) {
35377
+ if (!input.not_reduce && input.to_place.stop_price && input.to_place.quantity) {
35206
35378
  await exchange_instance.placeStopOrder({
35207
35379
  symbol: input.position.symbol,
35208
35380
  kind: input.to_place.kind,
35209
35381
  stop: input.to_place.stop_price,
35210
- quantity: Math.abs(input.to_place.quantity)
35382
+ quantity: Math.abs(input.to_place.quantity),
35383
+ price_places: input.price_places,
35384
+ decimal_places: input.decimal_places
35211
35385
  });
35212
35386
  }
35213
35387
  };
@@ -35586,17 +35760,26 @@ class ExchangeAccount {
35586
35760
  this.app_db = options.app_db;
35587
35761
  }
35588
35762
  async getLiveExchangeInstance(payload) {
35763
+ const symbol_config = await this.recomputeSymbolConfig({
35764
+ symbol: payload.symbol,
35765
+ refresh: payload.refresh_symbol_config
35766
+ });
35589
35767
  const result = await this.app_db.getLiveExchangeInstance({
35590
35768
  account: this.instance,
35591
35769
  symbol: payload.symbol
35592
35770
  });
35593
35771
  if (payload.refresh || !result) {
35594
- const data = await this.exchange.getExchangeAccountInfo(this.instance, payload.symbol);
35595
- if (payload.price_places) {
35596
- data.config.price_places = payload.price_places;
35772
+ const data = await this.exchange.getExchangeAccountInfo({
35773
+ account: this.instance,
35774
+ symbol: payload.symbol,
35775
+ price_places: symbol_config?.price_places,
35776
+ decimal_places: symbol_config?.decimal_places
35777
+ });
35778
+ if (symbol_config?.price_places) {
35779
+ data.config.price_places = symbol_config.price_places;
35597
35780
  }
35598
- if (payload.decimal_places) {
35599
- data.config.decimal_places = payload.decimal_places;
35781
+ if (symbol_config?.decimal_places) {
35782
+ data.config.decimal_places = symbol_config.decimal_places;
35600
35783
  }
35601
35784
  return await this.app_db.createOrUpdateLiveExchangeInstance({
35602
35785
  account: this.instance,
@@ -35606,11 +35789,15 @@ class ExchangeAccount {
35606
35789
  }
35607
35790
  return result;
35608
35791
  }
35609
- async getActiveAccount(symbol, full) {
35610
- const symbol_config = await this.app_db.getSymbolConfigFromDB(symbol);
35611
- const live_exchange_instance = await this.getLiveExchangeInstance({
35792
+ async getActiveAccount(payload) {
35793
+ const { symbol, full = false, refresh = false } = payload;
35794
+ const symbol_config = await this.recomputeSymbolConfig({
35612
35795
  symbol
35613
35796
  });
35797
+ const live_exchange_instance = await this.getLiveExchangeInstance({
35798
+ symbol,
35799
+ refresh
35800
+ });
35614
35801
  const raw_active_account = live_exchange_instance.data;
35615
35802
  const _all = get_active_accounts({
35616
35803
  active_account: raw_active_account,
@@ -35622,9 +35809,10 @@ class ExchangeAccount {
35622
35809
  return _all.active_account;
35623
35810
  }
35624
35811
  async syncAccount(options) {
35625
- const { symbol, update = false } = options;
35812
+ const { symbol, update = false, live_refresh = false } = options;
35626
35813
  if (!update) {
35627
- const db_positions2 = await this.app_db.getPositions(this.instance, {
35814
+ const db_positions2 = await this.app_db.getPositions({
35815
+ account: this.instance,
35628
35816
  symbol: options.symbol,
35629
35817
  as_view: options.as_view
35630
35818
  });
@@ -35634,7 +35822,10 @@ class ExchangeAccount {
35634
35822
  }
35635
35823
  return db_positions2;
35636
35824
  }
35637
- const active_account = await this.getActiveAccount(symbol);
35825
+ const active_account = await this.getActiveAccount({
35826
+ refresh: live_refresh,
35827
+ symbol
35828
+ });
35638
35829
  if (options.leverage) {
35639
35830
  await this.exchange.setLeverage({ symbol, leverage: options.leverage });
35640
35831
  }
@@ -35661,7 +35852,9 @@ class ExchangeAccount {
35661
35852
  });
35662
35853
  return db_orders;
35663
35854
  }
35664
- const active_account = await this.getActiveAccount(symbol);
35855
+ const active_account = await this.getActiveAccount({
35856
+ symbol
35857
+ });
35665
35858
  const orders = kind === "long" ? active_account.orders.long.entries : active_account.orders.short.entries;
35666
35859
  const stop_orders = kind === "long" ? active_account.orders.long.stop_orders : active_account.orders.short.stop_orders;
35667
35860
  const tp_orders = kind === "long" ? active_account.orders.long.tp_orders : active_account.orders.short.tp_orders;
@@ -35789,7 +35982,8 @@ class ExchangeAccount {
35789
35982
  final_stop: solution.stop,
35790
35983
  kind: app_config.kind,
35791
35984
  quantity: trades[0]?.avg_size,
35792
- is_limit: true
35985
+ is_limit: true,
35986
+ neg_pnl: trades[0]?.neg_pnl
35793
35987
  };
35794
35988
  if (place) {
35795
35989
  let arr = [
@@ -35890,7 +36084,7 @@ class ExchangeAccount {
35890
36084
  kind: payload.kind
35891
36085
  });
35892
36086
  if (db_position) {
35893
- await this.app_db.createOrUpdatePositionConfig(db_position, payload.params);
36087
+ return await this.app_db.createOrUpdatePositionConfig(db_position, payload.params);
35894
36088
  }
35895
36089
  }
35896
36090
  return await this.app_db.getPositionConfig({
@@ -35905,7 +36099,7 @@ class ExchangeAccount {
35905
36099
  async getPositionStrategy() {
35906
36100
  return await this.app_db.getPositionStrategy(this.instance);
35907
36101
  }
35908
- async getOriginalPlannedStop(payload) {
36102
+ async buildReduceConfig(payload) {
35909
36103
  const positions = await this.syncAccount({
35910
36104
  symbol: payload.symbol
35911
36105
  });
@@ -35914,72 +36108,168 @@ class ExchangeAccount {
35914
36108
  symbol: payload.symbol,
35915
36109
  _positions: positions
35916
36110
  });
35917
- let result = await this.syncReduceClosePosition(payload.symbol, {
35918
- long: {
35919
- minimum_pnl: config?.long_minimum_pnl || 0.0001,
35920
- max_size: 0.003,
35921
- profit: config?.long_profit,
35922
- increase: false,
35923
- not_reduce: config?.not_reduce,
35924
- ratio: config?.reduce_ratio_long
35925
- },
35926
- short: {
35927
- minimum_pnl: config?.short_minimum_pnl || 0.0001,
35928
- max_size: 0.003,
35929
- profit: config?.short_profit,
35930
- increase: false,
35931
- not_reduce: config?.not_reduce,
35932
- ratio: config?.reduce_ratio_short
35933
- },
35934
- trigger: {
35935
- long: false,
35936
- short: false
35937
- }
36111
+ if (payload.as_dict) {
36112
+ return {
36113
+ long: {
36114
+ minimum_pnl: config?.long_minimum_pnl || 0.0001,
36115
+ max_size: 0.003,
36116
+ profit: config?.long_profit,
36117
+ increase: false,
36118
+ not_reduce: config?.not_reduce,
36119
+ ratio: config?.reduce_ratio_long,
36120
+ use_full: payload.use_full ? payload.kind == "long" ? true : false : undefined
36121
+ },
36122
+ short: {
36123
+ minimum_pnl: config?.short_minimum_pnl || 0.0001,
36124
+ max_size: 0.003,
36125
+ profit: config?.short_profit,
36126
+ increase: false,
36127
+ not_reduce: config?.not_reduce,
36128
+ ratio: config?.reduce_ratio_short,
36129
+ use_full: payload.use_full ? payload.kind == "short" ? true : false : undefined
36130
+ },
36131
+ trigger: {
36132
+ long: payload.trigger?.long ? config.trigger_long : false,
36133
+ short: payload.trigger?.short ? config.trigger_short : false
36134
+ }
36135
+ };
36136
+ }
36137
+ return config;
36138
+ }
36139
+ async getOriginalPlannedStop(payload) {
36140
+ const config = await this.buildReduceConfig({
36141
+ symbol: payload.symbol,
36142
+ kind: payload.kind,
36143
+ as_dict: true
36144
+ });
36145
+ let result = await this.reduceMajorPositionEntry({
36146
+ symbol: payload.symbol,
36147
+ long: config.long,
36148
+ short: config.short,
36149
+ trigger: config.trigger
35938
36150
  });
35939
36151
  let _kind = payload.kind == "long" ? "short" : "long";
35940
36152
  let orders = result[_kind];
35941
36153
  return orders.result[payload.kind];
35942
36154
  }
35943
- async syncReduceClosePosition(symbol, payload) {
35944
- let accountInfo = await this.getActiveAccount(symbol, true);
35945
- let { long, short, trigger, kind } = payload || {};
35946
- if (!long || !short) {
35947
- const positions = await this.syncAccount({
35948
- symbol
35949
- });
35950
- const config = build_reduce_config({
35951
- account: this.instance,
35952
- symbol,
35953
- _positions: positions
35954
- });
35955
- long = {
35956
- minimum_pnl: config?.long_minimum_pnl,
35957
- max_size: 0.003,
35958
- profit: config?.long_profit,
35959
- increase: false,
35960
- not_reduce: config?.not_reduce,
35961
- ratio: config?.reduce_ratio_long,
35962
- use_full: kind == "long" ? true : false
35963
- };
35964
- short = {
35965
- minimum_pnl: config?.short_minimum_pnl,
35966
- max_size: 0.003,
35967
- profit: config?.short_profit,
35968
- increase: false,
35969
- not_reduce: config?.not_reduce,
35970
- ratio: config?.reduce_ratio_short,
35971
- use_full: kind == "short" ? true : false
35972
- };
35973
- trigger = {
35974
- long: config?.trigger_long,
35975
- short: config?.trigger_short
35976
- };
35977
- }
36155
+ async syncReduceClosePosition(payload) {
36156
+ let { symbol, kind, trigger } = payload || {};
36157
+ const config = await this.buildReduceConfig({
36158
+ symbol,
36159
+ kind,
36160
+ as_dict: true,
36161
+ trigger: {
36162
+ long: trigger || false,
36163
+ short: trigger || false
36164
+ },
36165
+ use_full: true
36166
+ });
36167
+ return await this.reduceMajorPositionEntry({
36168
+ symbol,
36169
+ long: config.long,
36170
+ short: config.short,
36171
+ trigger: config.trigger
36172
+ });
36173
+ }
36174
+ async reduceMajorPositionEntry(payload) {
36175
+ const { symbol, long, short, trigger } = payload;
36176
+ let accountInfo = await this.getActiveAccount({
36177
+ symbol,
36178
+ full: true
36179
+ });
35978
36180
  return await reduceMajorPositionEntry({
35979
36181
  long,
35980
36182
  short
35981
36183
  }, accountInfo, trigger, this.exchange);
35982
36184
  }
36185
+ async placeProfitAndStop(payload) {
36186
+ const { symbol, trigger, refresh, kind } = payload;
36187
+ if (refresh) {
36188
+ await this.syncAccount({
36189
+ symbol,
36190
+ live_refresh: true,
36191
+ update: true
36192
+ });
36193
+ }
36194
+ const config = await this.buildReduceConfig({
36195
+ symbol,
36196
+ as_dict: true,
36197
+ trigger: {
36198
+ long: trigger || false,
36199
+ short: trigger || false
36200
+ }
36201
+ });
36202
+ if (!kind) {
36203
+ await this.updateTargetPnl({
36204
+ symbol,
36205
+ kind: "long"
36206
+ });
36207
+ await this.updateTargetPnl({
36208
+ symbol,
36209
+ kind: "short"
36210
+ });
36211
+ } else {
36212
+ await this.updateTargetPnl({
36213
+ symbol,
36214
+ kind
36215
+ });
36216
+ }
36217
+ if (payload.trigger) {
36218
+ return await this.reduceMajorPositionEntry({
36219
+ symbol,
36220
+ long: config.long,
36221
+ short: config.short,
36222
+ trigger: config.trigger
36223
+ });
36224
+ }
36225
+ return config;
36226
+ }
36227
+ async reEnterPositionOnEmpty(symbol) {
36228
+ await this.getLiveExchangeInstance({
36229
+ symbol,
36230
+ refresh: true
36231
+ });
36232
+ const db_positions = await this.syncAccount({
36233
+ symbol,
36234
+ update: true
36235
+ });
36236
+ await this.syncOrders({
36237
+ symbol,
36238
+ kind: "long",
36239
+ update: true
36240
+ });
36241
+ await this.syncOrders({
36242
+ symbol,
36243
+ kind: "short",
36244
+ update: true
36245
+ });
36246
+ const long_position = db_positions.find((x) => x.kind === "long");
36247
+ const short_position = db_positions.find((x) => x.kind === "short");
36248
+ if (long_position && long_position.quantity === 0) {
36249
+ await this.triggerTradeFromConfig({
36250
+ symbol,
36251
+ kind: "long"
36252
+ });
36253
+ }
36254
+ if (short_position && short_position.quantity === 0) {
36255
+ await this.triggerTradeFromConfig({
36256
+ symbol,
36257
+ kind: "short"
36258
+ });
36259
+ }
36260
+ if (long_position.target_pnl > 0 || short_position.target_pnl > 0) {
36261
+ await Promise.all([
36262
+ this.updateTargetPnl({
36263
+ symbol,
36264
+ kind: "long"
36265
+ }),
36266
+ this.updateTargetPnl({
36267
+ symbol,
36268
+ kind: "short"
36269
+ })
36270
+ ]);
36271
+ }
36272
+ }
35983
36273
  async generate_config_params(payload) {
35984
36274
  const { entry, stop, risk_reward, risk, symbol } = payload;
35985
36275
  const app_config = await this.buildAppConfig({
@@ -35989,6 +36279,13 @@ class ExchangeAccount {
35989
36279
  risk,
35990
36280
  symbol
35991
36281
  });
36282
+ console.log({
36283
+ entry,
36284
+ stop,
36285
+ risk_reward,
36286
+ risk,
36287
+ symbol
36288
+ });
35992
36289
  let config = generate_config_params(app_config, {
35993
36290
  entry,
35994
36291
  stop,
@@ -35999,7 +36296,7 @@ class ExchangeAccount {
35999
36296
  return { ...config, place_stop: false, profit_percent: 0 };
36000
36297
  }
36001
36298
  async extrapolateShortConfig(payload) {
36002
- const { symbol, risk_reward = 199, kind } = payload;
36299
+ const { symbol, risk_reward = 199, kind, risk } = payload;
36003
36300
  let reverse_kind = kind === "long" ? "short" : "long";
36004
36301
  const position2 = await this.syncAccount({
36005
36302
  symbol,
@@ -36007,30 +36304,38 @@ class ExchangeAccount {
36007
36304
  as_view: true
36008
36305
  });
36009
36306
  if (position2) {
36307
+ let entry = position2.next_order || position2.avg_liquidation;
36308
+ if (kind == "short" && entry < 0) {
36309
+ const symbol_config = await this.recomputeSymbolConfig({
36310
+ symbol
36311
+ });
36312
+ entry = symbol_config?.support;
36313
+ }
36010
36314
  return await this.generate_config_params({
36011
- entry: position2.next_order || position2.avg_liquidation,
36315
+ entry,
36012
36316
  stop: position2.take_profit,
36013
36317
  risk_reward,
36014
- risk: position2.target_pnl,
36318
+ risk: risk || position2.target_pnl,
36015
36319
  symbol
36016
36320
  });
36017
36321
  }
36018
36322
  return null;
36019
36323
  }
36020
36324
  async triggerTradeFromConfig(payload) {
36325
+ const { symbol, kind, place = true } = payload;
36021
36326
  const position2 = await this.syncAccount({
36022
- symbol: payload.symbol,
36023
- kind: payload.kind
36327
+ symbol,
36328
+ kind
36024
36329
  });
36025
36330
  if (position2?.config) {
36026
36331
  const config = position2.expand.config;
36027
36332
  return await this.placeSharedOrder("place_limit_orders", {
36028
- symbol: payload.symbol,
36333
+ symbol,
36029
36334
  entry: config.entry,
36030
36335
  stop: config.stop,
36031
36336
  risk_reward: config.risk_reward,
36032
36337
  risk: config.risk,
36033
- place: true
36338
+ place
36034
36339
  });
36035
36340
  }
36036
36341
  }
@@ -36078,8 +36383,10 @@ class ExchangeAccount {
36078
36383
  kind: opposite_kind,
36079
36384
  stop: true
36080
36385
  });
36081
- await this.syncReduceClosePosition(symbol, {
36082
- kind: opposite_kind
36386
+ await this.syncReduceClosePosition({
36387
+ symbol,
36388
+ kind: opposite_kind,
36389
+ trigger: true
36083
36390
  });
36084
36391
  await this.syncOrders({
36085
36392
  symbol,
@@ -36088,7 +36395,8 @@ class ExchangeAccount {
36088
36395
  });
36089
36396
  }
36090
36397
  }
36091
- async windDownSymbol(symbol, risk_reward = 199) {
36398
+ async windDownSymbol(payload) {
36399
+ const { symbol, risk_reward = 199 } = payload;
36092
36400
  const positions = await this.syncAccount({
36093
36401
  symbol,
36094
36402
  update: true
@@ -36105,30 +36413,74 @@ class ExchangeAccount {
36105
36413
  });
36106
36414
  }
36107
36415
  if (config) {
36108
- console.log("cancelling any existing open orders for the long position");
36109
- await this.cancelOrders({
36416
+ await this.getPositionConfig({
36110
36417
  symbol,
36111
36418
  kind: "long",
36112
- price: long_position.entry
36419
+ params: {
36420
+ entry: config.entry,
36421
+ stop: config.stop,
36422
+ risk_reward: config.risk_reward,
36423
+ risk: config.risk,
36424
+ profit_percent: 0
36425
+ }
36426
+ });
36427
+ await this.updateTargetPnl({
36428
+ symbol,
36429
+ kind: "long"
36430
+ });
36431
+ } else {
36432
+ const existing_long_config = await this.app_db.getPositionConfig({
36433
+ symbol,
36434
+ kind: "long",
36435
+ account: this.instance
36113
36436
  });
36114
- console.log("updating the long position target_pnl");
36115
- console.log("toggling the stop buying for the long position");
36116
- await this.toggleStopBuying({
36437
+ await this.app_db.update_db_position(long_position, {
36438
+ config: existing_long_config?.id
36439
+ });
36440
+ await this.getPositionConfig({
36117
36441
  symbol,
36118
36442
  kind: "long",
36119
- should_stop: true
36443
+ params: {
36444
+ entry: existing_long_config.entry,
36445
+ stop: existing_long_config.stop,
36446
+ risk_reward: existing_long_config.risk_reward,
36447
+ risk: existing_long_config.risk,
36448
+ profit_percent: 0
36449
+ }
36450
+ });
36451
+ await this.updateTargetPnl({
36452
+ symbol,
36453
+ kind: "long"
36120
36454
  });
36121
36455
  }
36456
+ await this.triggerTradeFromConfig({
36457
+ symbol,
36458
+ kind: "long"
36459
+ });
36122
36460
  const new_config = await this.extrapolateShortConfig({
36123
36461
  symbol,
36124
36462
  kind: "short",
36125
- risk_reward
36463
+ risk_reward,
36464
+ risk: config?.risk
36126
36465
  });
36127
- const short_config = await this.getPositionConfig({
36466
+ let short_config = await this.getPositionConfig({
36128
36467
  symbol,
36129
36468
  kind: "short"
36130
36469
  });
36131
- if (new_config && short_config && (short_config.entry !== new_config.entry || short_config.stop !== new_config.stop || short_config.risk !== new_config.risk)) {
36470
+ if (!short_config) {
36471
+ short_config = await this.getPositionConfig({
36472
+ symbol,
36473
+ kind: "short",
36474
+ params: {
36475
+ entry: new_config.entry,
36476
+ stop: new_config.stop,
36477
+ risk_reward,
36478
+ risk: new_config.risk,
36479
+ profit_percent: 10
36480
+ }
36481
+ });
36482
+ }
36483
+ if (new_config && short_config) {
36132
36484
  console.log("updating short position");
36133
36485
  short_position = await this.app_db.update_db_position(short_position, {
36134
36486
  reduce_ratio: 0.95,
@@ -36143,7 +36495,7 @@ class ExchangeAccount {
36143
36495
  stop: new_config.stop,
36144
36496
  risk_reward,
36145
36497
  risk: new_config.risk,
36146
- profit_percent: 1
36498
+ profit_percent: 10
36147
36499
  }
36148
36500
  });
36149
36501
  console.log("placing the short trade based off config values");
@@ -36151,6 +36503,10 @@ class ExchangeAccount {
36151
36503
  symbol,
36152
36504
  kind: "short"
36153
36505
  });
36506
+ await this.updateTargetPnl({
36507
+ symbol,
36508
+ kind: "short"
36509
+ });
36154
36510
  console.log("updating the stop loss for the short position from the long");
36155
36511
  await this.verifyStopLoss({
36156
36512
  symbol,
@@ -36159,18 +36515,53 @@ class ExchangeAccount {
36159
36515
  }
36160
36516
  }
36161
36517
  if (long_position && long_position.quantity === 0 && short_position && short_position.quantity == 0) {
36162
- this.app_db.removePosition(long_position);
36163
- this.app_db.removePosition(short_position);
36518
+ await Promise.all([
36519
+ this.cancelOrders({
36520
+ symbol,
36521
+ kind: "long",
36522
+ all: true
36523
+ }),
36524
+ this.cancelOrders({
36525
+ symbol,
36526
+ kind: "short",
36527
+ all: true
36528
+ })
36529
+ ]);
36530
+ await Promise.all([
36531
+ this.app_db.removePosition(long_position),
36532
+ this.app_db.removePosition(short_position)
36533
+ ]);
36164
36534
  }
36165
36535
  }
36166
- async triggerBullishMarket(payload) {
36167
- const { symbol, profit_percent = 10 } = payload;
36168
- const bullish_instance = await this.app_db.getBullishMarket(symbol);
36169
- if (!bullish_instance) {
36170
- return false;
36536
+ async updateTargetPnl(payload) {
36537
+ const { symbol, kind } = payload;
36538
+ const position2 = await this.syncAccount({
36539
+ symbol,
36540
+ kind
36541
+ });
36542
+ if (position2?.expand?.config) {
36543
+ const config = position2.expand.config;
36544
+ let _profit = config.profit;
36545
+ let _profit_percent = config?.profit_percent;
36546
+ if (_profit_percent && (position2?.quantity || 0) > 0) {
36547
+ _profit = to_f(position2.quantity * _profit_percent * position2.entry / 100);
36548
+ }
36549
+ await this.app_db.update_db_position(position2, {
36550
+ target_pnl: _profit
36551
+ });
36552
+ return _profit;
36553
+ }
36554
+ return 0;
36555
+ }
36556
+ async recomputeSymbolConfig(payload) {
36557
+ const { symbol, refresh = false } = payload;
36558
+ const _config = await this.app_db.getSymbolConfigFromDB(symbol);
36559
+ if (_config && !refresh) {
36560
+ return _config;
36171
36561
  }
36172
36562
  const config = await this.exchange.generateConfig({
36173
- symbol
36563
+ symbol,
36564
+ limit: _config?.candle_count || 5
36174
36565
  });
36175
36566
  await this.app_db.updateSymbolConfigs({
36176
36567
  configs: [
@@ -36185,16 +36576,27 @@ class ExchangeAccount {
36185
36576
  }
36186
36577
  ]
36187
36578
  });
36579
+ return this.app_db.getSymbolConfigFromDB(symbol);
36580
+ }
36581
+ async triggerBullishMarket(payload) {
36582
+ const { symbol, profit_percent = 10, risk_reward = 199 } = payload;
36583
+ const bullish_instance = await this.app_db.getBullishMarket(symbol);
36584
+ if (!bullish_instance) {
36585
+ return false;
36586
+ }
36587
+ const symbol_config = await this.recomputeSymbolConfig({
36588
+ symbol,
36589
+ refresh: true
36590
+ });
36188
36591
  const position2 = await this.syncAccount({
36189
36592
  symbol,
36190
36593
  update: true,
36191
36594
  kind: "long"
36192
36595
  });
36193
- const symbol_config = await this.app_db.getSymbolConfigFromDB(symbol);
36194
36596
  const long_config = await this.generate_config_params({
36195
36597
  entry: symbol_config.resistance,
36196
36598
  stop: symbol_config.support,
36197
- risk_reward: 199,
36599
+ risk_reward,
36198
36600
  risk: bullish_instance.risk,
36199
36601
  symbol
36200
36602
  });
@@ -36237,13 +36639,174 @@ class ExchangeAccount {
36237
36639
  });
36238
36640
  }
36239
36641
  if (changed) {
36240
- return this.triggerTradeFromConfig({
36642
+ const rr = await this.triggerTradeFromConfig({
36241
36643
  symbol,
36242
36644
  kind: "long"
36243
36645
  });
36646
+ return rr;
36244
36647
  }
36245
36648
  return false;
36246
36649
  }
36650
+ async updateAllActiveSymbols() {
36651
+ const symbols = await this.app_db.getAllSymbolsFromPositions({
36652
+ no_position: true,
36653
+ kind: "long"
36654
+ });
36655
+ for (const symbol of symbols) {
36656
+ await this.getLiveExchangeInstance({ symbol, refresh: true });
36657
+ await new Promise((resolve) => setTimeout(resolve, 1000));
36658
+ }
36659
+ }
36660
+ async updateAllPositionsWithNoConfig(payload) {
36661
+ const { kind } = payload;
36662
+ const symbols = await this.app_db.getAllSymbolsFromPositions({
36663
+ custom_filter: `config = null && kind = "${kind}"`
36664
+ });
36665
+ for (const symbol of symbols) {
36666
+ await this.syncAccount({
36667
+ symbol,
36668
+ update: true,
36669
+ kind,
36670
+ live_refresh: true
36671
+ });
36672
+ await new Promise((resolve) => setTimeout(resolve, 1000));
36673
+ }
36674
+ }
36675
+ async getNonEssentialSymbols() {
36676
+ const essential_symbols = await this.app_db.getAllSymbolConfigs({
36677
+ custom_filter: `essential = true`
36678
+ });
36679
+ const bullish_markets = await this.app_db.getBullishMarkets();
36680
+ const bullish_symbols = Array.from(new Set(bullish_markets.updated_bullish.map((m) => m.symbol)));
36681
+ const symbols = Array.from(new Set(essential_symbols.map((s2) => s2.symbol))).concat(bullish_symbols);
36682
+ const not_symbols_filter = symbols.map((s2) => `symbol:lower != "${s2.toLowerCase()}"`).join(" && ");
36683
+ const positions = await this.app_db.getPositions({
36684
+ custom_filter: `${not_symbols_filter} && account.owner:lower = "${this.instance.owner.toLowerCase()}" && account.exchange:lower = "${this.instance.exchange.toLowerCase()}"`,
36685
+ symbol: "",
36686
+ account: {
36687
+ owner: "",
36688
+ exchange: ""
36689
+ }
36690
+ });
36691
+ return Array.from(new Set(positions.map((p) => p.symbol)));
36692
+ }
36693
+ async terminatePositions(payload) {
36694
+ const { symbol } = payload;
36695
+ const symbol_config = await this.app_db.getSymbolConfigFromDB(symbol);
36696
+ let db_positions = await this.syncAccount({
36697
+ symbol,
36698
+ update: true,
36699
+ live_refresh: true
36700
+ });
36701
+ let long_position = db_positions.find((x) => x.kind === "long");
36702
+ let short_position = db_positions.find((x) => x.kind === "short");
36703
+ if (long_position && long_position.quantity > 0 && symbol_config) {
36704
+ await this.exchange.closePosition({
36705
+ symbol,
36706
+ kind: "long",
36707
+ price_places: symbol_config.price_places,
36708
+ decimal_places: symbol_config.decimal_places
36709
+ });
36710
+ await this.cancelOrders({
36711
+ symbol,
36712
+ kind: "long",
36713
+ all: true
36714
+ });
36715
+ }
36716
+ if (short_position && short_position.quantity > 0 && symbol_config) {
36717
+ await this.exchange.closePosition({
36718
+ symbol,
36719
+ kind: "short",
36720
+ price_places: symbol_config.price_places,
36721
+ decimal_places: symbol_config.decimal_places
36722
+ });
36723
+ await this.cancelOrders({
36724
+ symbol,
36725
+ kind: "short",
36726
+ all: true
36727
+ });
36728
+ }
36729
+ await new Promise((resolve) => setTimeout(resolve, 3000));
36730
+ db_positions = await this.syncAccount({
36731
+ symbol,
36732
+ update: true,
36733
+ live_refresh: true
36734
+ });
36735
+ long_position = db_positions.find((x) => x.kind === "long");
36736
+ short_position = db_positions.find((x) => x.kind === "short");
36737
+ if (long_position && long_position.quantity === 0) {
36738
+ await this.app_db.removePosition(long_position);
36739
+ }
36740
+ if (short_position && short_position.quantity === 0) {
36741
+ await this.app_db.removePosition(short_position);
36742
+ }
36743
+ }
36744
+ async fetchAndUpdateTopMovers() {
36745
+ const db_instance = await this.app_db.get_exchange_db_instance(this.instance);
36746
+ const {
36747
+ bullish,
36748
+ bearish: _bearish,
36749
+ movePercent,
36750
+ totalRisk,
36751
+ max_non_essential = 0
36752
+ } = db_instance;
36753
+ let bullishMarkets = [];
36754
+ if (bullish) {
36755
+ const { movers } = await this.exchange.checkDelistedMovers({
36756
+ movePercent
36757
+ });
36758
+ bullishMarkets = movers;
36759
+ }
36760
+ const non_essential_symbols = await this.getNonEssentialSymbols();
36761
+ let symbols_to_remove = non_essential_symbols.filter((k) => !bullishMarkets.map((m) => m.symbol).includes(k)).slice(0, max_non_essential);
36762
+ bullishMarkets = bullishMarkets.filter((m) => !symbols_to_remove.includes(m.symbol));
36763
+ if (symbols_to_remove.length > 0) {
36764
+ for (const symbol of symbols_to_remove) {
36765
+ await this.terminatePositions({ symbol });
36766
+ }
36767
+ }
36768
+ const result = await this.app_db.getBullishMarkets({
36769
+ new_markets: bullishMarkets.map((m) => ({
36770
+ symbol: m.symbol,
36771
+ percent: m.priceChangePercent
36772
+ })),
36773
+ totalRisk,
36774
+ max_count: max_non_essential
36775
+ });
36776
+ return result;
36777
+ }
36778
+ async computeTargetPnl(payload) {
36779
+ const { symbol, kind } = payload;
36780
+ const reverse_kind = kind === "long" ? "short" : "long";
36781
+ const root_position = await this.syncAccount({
36782
+ symbol,
36783
+ kind
36784
+ });
36785
+ const reverse_position = await this.syncAccount({
36786
+ symbol,
36787
+ kind: reverse_kind
36788
+ });
36789
+ if (reverse_position?.expand?.config && root_position.quantity > 0) {
36790
+ const reverse_config = reverse_position.expand.config;
36791
+ const diff = Math.abs(reverse_config.stop - root_position.entry);
36792
+ const result = to_f(diff * root_position.quantity);
36793
+ if (root_position.target_pnl !== result) {
36794
+ await this.app_db.update_db_position(root_position, {
36795
+ target_pnl: result
36796
+ });
36797
+ await this.getPositionConfig({
36798
+ kind: reverse_kind,
36799
+ symbol,
36800
+ params: {
36801
+ ...reverse_config,
36802
+ risk: result
36803
+ }
36804
+ });
36805
+ }
36806
+ return result;
36807
+ }
36808
+ return 0;
36809
+ }
36247
36810
  }
36248
36811
  function getExchangeKlass(exchange) {
36249
36812
  const func = exchange === "binance" ? BinanceExchange : BybitExchange;
@@ -36433,7 +36996,9 @@ class App {
36433
36996
  as_view: true,
36434
36997
  symbol
36435
36998
  });
36436
- const active_account = await exchange_account.getActiveAccount(symbol);
36999
+ const active_account = await exchange_account.getActiveAccount({
37000
+ symbol
37001
+ });
36437
37002
  const long_position = active_account.position.long;
36438
37003
  const short_position = active_account.position.short;
36439
37004
  const long_db_position = positions.find((p) => p.kind === "long");
@@ -36455,65 +37020,6 @@ class App {
36455
37020
  balance: active_account.usd_balance
36456
37021
  };
36457
37022
  }
36458
- async verifyStopLoss(payload) {
36459
- const { account, symbol, kind, revert } = payload;
36460
- const exchange_account = await this.getExchangeAccount(payload.account);
36461
- await exchange_account.syncOrders({
36462
- symbol,
36463
- kind,
36464
- update: true
36465
- });
36466
- let original = null;
36467
- if (revert) {
36468
- original = await exchange_account.getOriginalPlannedStop({
36469
- ...account,
36470
- symbol,
36471
- kind
36472
- });
36473
- }
36474
- const position2 = await exchange_account.syncAccount({
36475
- symbol,
36476
- kind,
36477
- as_view: true
36478
- });
36479
- if (original && position2?.stop_loss && original.quantity != position2.stop_loss.quantity) {
36480
- const opposite_kind = kind === "long" ? "short" : "long";
36481
- await exchange_account.cancelOrders({
36482
- symbol,
36483
- kind: opposite_kind,
36484
- stop: true
36485
- });
36486
- return await exchange_account.syncOrders({
36487
- symbol,
36488
- kind,
36489
- update: true
36490
- });
36491
- }
36492
- if (true) {
36493
- const opposite_kind = kind === "long" ? "short" : "long";
36494
- await exchange_account.syncOrders({
36495
- symbol,
36496
- kind: opposite_kind,
36497
- update: true
36498
- });
36499
- await exchange_account.cancelOrders({
36500
- symbol,
36501
- kind: opposite_kind,
36502
- stop: true
36503
- });
36504
- await exchange_account.syncReduceClosePosition(symbol, {
36505
- kind: opposite_kind
36506
- });
36507
- await exchange_account.syncOrders({
36508
- symbol,
36509
- kind,
36510
- update: true
36511
- });
36512
- }
36513
- }
36514
- async updateTopMovers(payload) {
36515
- return await this.app_db.getBullishMarkets(payload);
36516
- }
36517
37023
  async getWindingDownMarkets() {
36518
37024
  return await this.app_db.getWindingDownMarkets();
36519
37025
  }
@@ -36523,15 +37029,13 @@ class App {
36523
37029
  async updateAllAccountWithSymbols(with_positions) {
36524
37030
  const [accounts, symbol_configs] = await Promise.all([
36525
37031
  this.app_db.getAccounts(),
36526
- this.app_db.getAllSymbolConfigs(with_positions)
37032
+ this.app_db.getAllSymbolConfigs({ with_positions })
36527
37033
  ]);
36528
37034
  for (const account of accounts) {
36529
37035
  for (const symbol_config of symbol_configs) {
36530
37036
  const exchange_account = await this.getExchangeAccount(account);
36531
37037
  await exchange_account.getLiveExchangeInstance({
36532
37038
  symbol: symbol_config.symbol,
36533
- price_places: symbol_config.price_places,
36534
- decimal_places: symbol_config.decimal_places,
36535
37039
  refresh: true
36536
37040
  });
36537
37041
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -36539,13 +37043,14 @@ class App {
36539
37043
  await new Promise((resolve) => setTimeout(resolve, 5000));
36540
37044
  }
36541
37045
  }
36542
- async windDownSymbol(symbol) {
37046
+ async windDownSymbol(payload) {
37047
+ const { symbol, risk } = payload;
36543
37048
  let winding_instance = await this.app_db.getWindingDownMarkets(symbol);
36544
37049
  if (winding_instance && winding_instance.length > 0) {
36545
37050
  winding_instance = winding_instance[0];
36546
37051
  }
36547
37052
  if (!winding_instance || winding_instance.length === 0) {
36548
- return true;
37053
+ winding_instance = null;
36549
37054
  }
36550
37055
  const positions = await this.app_db.hasExistingPosition(symbol);
36551
37056
  if (positions.length === 0) {
@@ -36571,8 +37076,67 @@ class App {
36571
37076
  console.log("winding down not paired positions");
36572
37077
  for (const pair of not_paired_positions) {
36573
37078
  const exchange_account = await this.getExchangeAccount(pair.expand.account);
36574
- await exchange_account.windDownSymbol(pair.symbol, winding_instance?.risk_reward || 199);
37079
+ const result = await exchange_account.windDownSymbol({
37080
+ symbol: pair.symbol,
37081
+ risk_reward: winding_instance?.risk_reward || 199,
37082
+ risk
37083
+ });
37084
+ console.log("result", result);
37085
+ }
37086
+ }
37087
+ }
37088
+ async getNonEssentialSymbols() {
37089
+ const essential_symbols = await this.app_db.getAllSymbolConfigs({
37090
+ custom_filter: `essential = true`
37091
+ });
37092
+ const bullish_markets = await this.app_db.getBullishMarkets();
37093
+ const bullish_symbols = Array.from(new Set(bullish_markets.updated_bullish.map((m) => m.symbol)));
37094
+ const symbols = Array.from(new Set(essential_symbols.map((s2) => s2.symbol))).concat(bullish_symbols);
37095
+ const not_symbols_filter = symbols.map((s2) => `symbol:lower != "${s2.toLowerCase()}"`).join(" && ");
37096
+ const positions = await this.app_db.getPositions({
37097
+ custom_filter: not_symbols_filter,
37098
+ symbol: "",
37099
+ account: {
37100
+ owner: "",
37101
+ exchange: ""
37102
+ }
37103
+ });
37104
+ return new Set(positions.map((p) => p.symbol));
37105
+ }
37106
+ async refreshAllPositionsWithSymbol(payload) {
37107
+ const { symbol } = payload;
37108
+ const positions = await this.app_db.getPositions({
37109
+ custom_filter: `symbol:lower="${symbol.toLowerCase()}"`,
37110
+ symbol: "",
37111
+ account: {
37112
+ owner: "",
37113
+ exchange: ""
37114
+ }
37115
+ });
37116
+ const exchanges = positions.map((p) => p.expand.account);
37117
+ const all_exchanges = {};
37118
+ for (const exchange of exchanges) {
37119
+ let id = `${exchange.owner}-${exchange.exchange}`;
37120
+ if (all_exchanges[id]) {
37121
+ continue;
36575
37122
  }
37123
+ all_exchanges[id] = exchange;
37124
+ }
37125
+ const unique_exchanges = Object.values(all_exchanges);
37126
+ for (const exchange of unique_exchanges) {
37127
+ const exchange_account = await this.getExchangeAccount({
37128
+ owner: exchange.owner,
37129
+ exchange: exchange.exchange
37130
+ });
37131
+ await exchange_account.syncAccount({
37132
+ symbol,
37133
+ update: true,
37134
+ live_refresh: true
37135
+ });
37136
+ await exchange_account.placeProfitAndStop({
37137
+ symbol,
37138
+ trigger: false
37139
+ });
36576
37140
  }
36577
37141
  }
36578
37142
  }
@@ -36582,7 +37146,54 @@ async function initApp(payload) {
36582
37146
  const app = new App(app_db, payload.getCredentials);
36583
37147
  return app;
36584
37148
  }
37149
+ async function getCredentials(account, exchange) {
37150
+ console.log(`Fetching credentials for account: ${account}, exchange: ${exchange}`);
37151
+ let apiKey;
37152
+ let apiSecret;
37153
+ switch (account) {
37154
+ case "sub_account":
37155
+ apiKey = process.env.SUB_ACCOUNT_API_KEY;
37156
+ apiSecret = process.env.SUB_ACCOUNT_API_SECRET;
37157
+ break;
37158
+ case "tola_sub_account":
37159
+ apiKey = process.env.TOLA_SUB_ACCOUNT_API_KEY;
37160
+ apiSecret = process.env.TOLA_SUB_ACCOUNT_API_SECRET;
37161
+ break;
37162
+ case "gbozee1_sub_account":
37163
+ apiKey = process.env.GBOZEE1_SUB_ACCOUNT_API_KEY;
37164
+ apiSecret = process.env.GBOZEE1_SUB_ACCOUNT_API_SECRET;
37165
+ break;
37166
+ case "tomi_account":
37167
+ apiKey = process.env.TOMI_ACCOUNT_API_KEY;
37168
+ apiSecret = process.env.TOMI_ACCOUNT_API_SECRET;
37169
+ break;
37170
+ case "main_account":
37171
+ default:
37172
+ apiKey = process.env.MAIN_ACCOUNT_API_KEY;
37173
+ apiSecret = process.env.MAIN_ACCOUNT_API_SECRET;
37174
+ break;
37175
+ }
37176
+ if (!apiKey || !apiSecret) {
37177
+ throw new Error(`Missing API Key or Secret for account '${account}' in .env file. Please check your environment variables.`);
37178
+ }
37179
+ return {
37180
+ api_key: apiKey,
37181
+ api_secret: apiSecret
37182
+ };
37183
+ }
37184
+ async function initialize() {
37185
+ const app = await initApp({
37186
+ db: {
37187
+ host: process.env.POCKETBASE_HOST,
37188
+ email: process.env.POCKETBASE_EMAIL,
37189
+ password: process.env.POCKETBASE_PASSWORD
37190
+ },
37191
+ getCredentials: (account, exchange) => getCredentials
37192
+ });
37193
+ return app;
37194
+ }
36585
37195
  export {
37196
+ initialize,
36586
37197
  initApp,
36587
37198
  ExchangeAccount,
36588
37199
  AppDatabase