@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.
- package/dist/index.d.ts +158 -45
- package/dist/index.js +833 -222
- 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(
|
|
32172
|
+
async getAllSymbolConfigs(payload) {
|
|
32173
|
+
const { with_positions = false, custom_filter } = payload || {
|
|
32174
|
+
with_positions: false
|
|
32175
|
+
};
|
|
32176
|
+
let filter = custom_filter || undefined;
|
|
32161
32177
|
if (with_positions) {
|
|
32162
32178
|
const positions = await this.pb.collection("positions").getFullList({
|
|
32163
32179
|
fields: `symbol`
|
|
32164
32180
|
});
|
|
32165
32181
|
const symbol_set = new Set(positions.map((p) => p.symbol));
|
|
32166
|
-
|
|
32167
|
-
return await this.pb.collection("symbol_configs").getFullList({
|
|
32168
|
-
filter
|
|
32169
|
-
});
|
|
32182
|
+
filter = Array.from(symbol_set).map((s2) => `symbol:lower="${s2.toLowerCase()}"`).join(" || ");
|
|
32170
32183
|
}
|
|
32171
|
-
return await this.pb.collection("symbol_configs").getFullList(
|
|
32184
|
+
return await this.pb.collection("symbol_configs").getFullList({
|
|
32185
|
+
filter
|
|
32186
|
+
});
|
|
32172
32187
|
}
|
|
32173
32188
|
async get_exchange_db_instance(account) {
|
|
32174
32189
|
const result = await this.pb.collection("exchange_accounts").getFirstListItem(`owner="${account.owner}" && exchange="${account.exchange}"`, {
|
|
@@ -32176,9 +32191,9 @@ class AppDatabase {
|
|
|
32176
32191
|
});
|
|
32177
32192
|
return result;
|
|
32178
32193
|
}
|
|
32179
|
-
async getPositions(
|
|
32180
|
-
const { symbol, as_view = false } = options;
|
|
32181
|
-
|
|
32194
|
+
async getPositions(options) {
|
|
32195
|
+
const { symbol, as_view = false, account, custom_filter } = options;
|
|
32196
|
+
let default_params = as_view ? {
|
|
32182
32197
|
table: "positions_view",
|
|
32183
32198
|
params: {
|
|
32184
32199
|
filter: `symbol:lower="${symbol.toLowerCase()}" && account:lower="${account.owner.toLowerCase()} ${account.exchange.toLowerCase()}"`,
|
|
@@ -32191,6 +32206,9 @@ class AppDatabase {
|
|
|
32191
32206
|
expand: "account,config"
|
|
32192
32207
|
}
|
|
32193
32208
|
};
|
|
32209
|
+
if (custom_filter) {
|
|
32210
|
+
default_params.params.filter = custom_filter;
|
|
32211
|
+
}
|
|
32194
32212
|
return await this.pb.collection(default_params.table).getFullList(default_params.params);
|
|
32195
32213
|
}
|
|
32196
32214
|
async _createOrUpdatePosition(db_position, params) {
|
|
@@ -32208,7 +32226,8 @@ class AppDatabase {
|
|
|
32208
32226
|
}
|
|
32209
32227
|
async createOrUpdatePositions(account, options) {
|
|
32210
32228
|
const { symbol, long_position, usd_balance, short_position } = options;
|
|
32211
|
-
const db_positions = await this.getPositions(
|
|
32229
|
+
const db_positions = await this.getPositions({
|
|
32230
|
+
account,
|
|
32212
32231
|
symbol
|
|
32213
32232
|
});
|
|
32214
32233
|
const exchange_db_instance = await this.get_exchange_db_instance(account);
|
|
@@ -32236,7 +32255,13 @@ class AppDatabase {
|
|
|
32236
32255
|
return await this.pb.collection("positions").update(position.id, payload);
|
|
32237
32256
|
}
|
|
32238
32257
|
async getSymbolConfigFromDB(symbol) {
|
|
32239
|
-
|
|
32258
|
+
const item = await this.pb.collection("symbol_configs").getFullList({
|
|
32259
|
+
filter: `symbol:lower="${symbol.toLowerCase()}"`
|
|
32260
|
+
});
|
|
32261
|
+
if (item.length > 0) {
|
|
32262
|
+
return item[0];
|
|
32263
|
+
}
|
|
32264
|
+
return null;
|
|
32240
32265
|
}
|
|
32241
32266
|
async getRunningInstanceFromDB(account, symbol, options) {
|
|
32242
32267
|
const { delay = 60 * 1000 } = options || {
|
|
@@ -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
|
-
|
|
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
|
-
|
|
32399
|
-
|
|
32400
|
-
|
|
32401
|
-
|
|
32402
|
-
kind: payload.entry > payload.stop ? "long" : "short",
|
|
32403
|
-
entry: payload.entry,
|
|
32404
|
-
stop: payload.stop,
|
|
32405
|
-
risk_reward: payload.risk_reward,
|
|
32406
|
-
risk: payload.risk,
|
|
32407
|
-
profit_percent: payload.profit_percent,
|
|
32408
|
-
place_tp: true
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
],
|
|
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:
|
|
34010
|
-
decimal_places:
|
|
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(
|
|
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
|
|
34278
|
-
|
|
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
|
-
],
|
|
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
|
|
34688
|
-
decimal_places
|
|
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(
|
|
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(
|
|
35595
|
-
|
|
35596
|
-
|
|
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 (
|
|
35599
|
-
data.config.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(
|
|
35610
|
-
const
|
|
35611
|
-
const
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
-
|
|
35918
|
-
|
|
35919
|
-
|
|
35920
|
-
|
|
35921
|
-
|
|
35922
|
-
|
|
35923
|
-
|
|
35924
|
-
|
|
35925
|
-
|
|
35926
|
-
|
|
35927
|
-
|
|
35928
|
-
|
|
35929
|
-
|
|
35930
|
-
|
|
35931
|
-
|
|
35932
|
-
|
|
35933
|
-
|
|
35934
|
-
|
|
35935
|
-
|
|
35936
|
-
|
|
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(
|
|
35944
|
-
let
|
|
35945
|
-
|
|
35946
|
-
|
|
35947
|
-
|
|
35948
|
-
|
|
35949
|
-
|
|
35950
|
-
|
|
35951
|
-
|
|
35952
|
-
|
|
35953
|
-
|
|
35954
|
-
|
|
35955
|
-
|
|
35956
|
-
|
|
35957
|
-
|
|
35958
|
-
|
|
35959
|
-
|
|
35960
|
-
|
|
35961
|
-
|
|
35962
|
-
|
|
35963
|
-
|
|
35964
|
-
|
|
35965
|
-
|
|
35966
|
-
|
|
35967
|
-
|
|
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
|
|
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
|
|
36023
|
-
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
|
|
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
|
|
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(
|
|
36082
|
-
|
|
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(
|
|
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
|
-
|
|
36109
|
-
await this.cancelOrders({
|
|
36416
|
+
await this.getPositionConfig({
|
|
36110
36417
|
symbol,
|
|
36111
36418
|
kind: "long",
|
|
36112
|
-
|
|
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
|
-
|
|
36115
|
-
|
|
36116
|
-
|
|
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
|
-
|
|
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
|
-
|
|
36466
|
+
let short_config = await this.getPositionConfig({
|
|
36128
36467
|
symbol,
|
|
36129
36468
|
kind: "short"
|
|
36130
36469
|
});
|
|
36131
|
-
if (
|
|
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:
|
|
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
|
-
|
|
36163
|
-
|
|
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
|
|
36167
|
-
const { symbol,
|
|
36168
|
-
const
|
|
36169
|
-
|
|
36170
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|