From 0332a20277c8d9142efe3a71135fbaa9625093ff Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Mon, 17 Jul 2023 18:27:00 +0200 Subject: [PATCH 01/23] refactoring: simplify open positions check --- app.js | 54 ++++++++---------------------------------------------- 1 file changed, 8 insertions(+), 46 deletions(-) diff --git a/app.js b/app.js index 63e1ff5..e59fe75 100644 --- a/app.js +++ b/app.js @@ -202,7 +202,6 @@ function handleNewOrder(order, liquidity_trigger) { // _liquidity_trigger: "liq1,liq2,...liqN" const position = newPosition({...order, "liquidity_trigger": `\"${liquidity_trigger}\"`}); tradesHistory.set(order.symbol, position); - incOpenPosition(); } function handleDcaOrder(order, liquidity_trigger) { @@ -293,7 +292,6 @@ wsClient.on('update', (data) => { if (process.env.TRACE_TRADES != TRACE_TRADES_LEVEL_OFF) traceTrade(order_type, trade_info, traceTradeFields); tradesHistory.delete(order.symbol); - decOpenPosition(); } }); } else { @@ -672,10 +670,6 @@ async function getBalance() { //fetch positions var positions = await linearClient.getPosition(); var positionList = []; - var openPositions = await totalOpenPositions(); - if(openPositions === null) { - openPositions = 0; - } var marg = await getMargin(); var time = await getServerTime(); //loop through positions.result[i].data get open symbols with size > 0 calculate pnl and to array @@ -964,44 +958,10 @@ async function takeProfit(symbol, position) { } -function incOpenPosition() { - openPositions = (openPositions ?? 0) + 1; -} - -function decOpenPosition() { - openPositions = (openPositions ?? 0) - 1; - if (openPositions < 0) { - logIT("decOpenPosition ERROR: open position < 0"); - openPositions = undefined; - } -} - -//fetch how how openPositions there are -async function totalOpenPositions() { - if (openPositions === undefined) { - try{ - var positions = await linearClient.getPosition(); - var open = 0; - for (var i = 0; i < positions.result.length; i++) { - if (positions.result[i].data.size > 0) { - open++; - } - } - openPositions = open; - - } - catch (error) { - return null; - } - } - - return openPositions; -} - //against trend async function scalp(pair, liquidationInfo, source, new_trades_disabled = false) { //check how many positions are open - const open_positions = await totalOpenPositions(); + const open_positions = openPositions logIT("scalp - Open positions: " + open_positions); const trigger_qty = liquidationInfo.qty; @@ -1161,8 +1121,14 @@ async function checkLeverage(symbol) { } //create loop that checks for open positions every second async function checkOpenPositions() { - //gor through all pairs and getPosition() + //go through all pairs and getPosition() var positions = await linearClient.getPosition(); + if (positions.ret_msg != "OK") { + logIT("checkOpenPositions - getPosition fails", LOG_LEVEL.ERROR); + rateLimit = baseRateLimit + 2000; + return; + } + openPositions = positions.result.filter(el => el.data.size > 0).length; const data = await linearClient.getWalletBalance(); //check rate_limit_status @@ -1679,10 +1645,6 @@ async function reportWebhook() { //fetch positions var positions = await linearClient.getPosition(); var positionList = []; - var openPositions = await totalOpenPositions(); - if(openPositions === null) { - openPositions = 0; - } var marg = await getMargin(); var time = await getServerTime(); //loop through positions.result[i].data get open symbols with size > 0 calculate pnl and to array From 53fa35867534c946ba2cdacb37372daa4dd99a7f Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Wed, 19 Jul 2023 13:55:03 +0200 Subject: [PATCH 02/23] app: add dca limit orders to average entry price dca feature must be enabled with "DCA_TYPE=DCA_AVERAGE_ENTRIES" and allows to place additional DCA_SAFETY_ORDERS, as limits orders. The position size fro any additional order is scaled by DCA_VOLUME_SCALE and the price deviation for any orders is DCA_PRICE_DEVIATION_PRC. Unfilled limit orders ore handles when the trade will be closed and also after in the main loop a routine perform a consistency check and remove orphan orders. WARNING: This an experimental feature, play with it at your own risk. --- app.js | 85 ++++++++++++++++++++++++++++++++++++++++++++++------- example.env | 4 +++ order.js | 5 ++-- 3 files changed, 80 insertions(+), 14 deletions(-) diff --git a/app.js b/app.js index e59fe75..b2c3aad 100644 --- a/app.js +++ b/app.js @@ -1,4 +1,4 @@ -import pkg from 'bybit-api-gnome'; +import pkg, { ContractClient } from 'bybit-api-gnome'; const { WebsocketClient, WS_KEY_MAP, LinearClient, AccountAssetClient, SpotClientV3} = pkg; import { WebsocketClient as binanceWS } from 'binance'; import dotenv from 'dotenv'; @@ -20,7 +20,7 @@ import session from 'express-session'; import { Server } from 'socket.io' import { newPosition, incrementPosition, closePosition, updatePosition } from './position.js'; import { loadJson, storeJson, traceTrade } from './utils.js'; -import { createMarketOrder } from './order.js'; +import { createMarketOrder, createLimitOrder, cancelOrder } from './order.js'; import { logIT, LOG_LEVEL } from './log.js'; dotenv.config(); @@ -188,6 +188,12 @@ const linearClient = new LinearClient({ secret: secret, livenet: true, }); +//create linear client +const contractClient = new ContractClient({ + key: key, + secret: secret, + livenet: true, +}); //account client if (process.env.WITHDRAW == "true" || process.env.TRANSFER_TO_SPOT == "true"){ const accountClient = new AccountAssetClient({ @@ -241,7 +247,7 @@ wsClient.on('update', (data) => { } else if (topic === "order") { let close_position = false; const filled_orders = data.data.filter(el => el.order_status == 'Filled'); - filled_orders.forEach( order => { + filled_orders.forEach( async order => { let trade_info = tradesHistory.get(order.symbol); @@ -289,6 +295,16 @@ wsClient.on('update', (data) => { storeJson(globalStatsPath, globalTradesStats); logIT(`#trade_stats:close# ${order.symbol}: ${JSON.stringify(trade_info)}`); logIT(`#global_stats:close# ${JSON.stringify(globalTradesStats)}`); + + //only needed with DCA_AVERAGE_ENTRIES features on. + if (process.env.DCA_TYPE == "DCA_AVERAGE_ENTRIES") { + let res = await cancelOrder(linearClient, order.symbol); + if (res.ret_msg != "OK") + logIT(`on-update - error cancelling orphan orders for ${order.symbol}`, LOG_LEVEL.ERROR); + else + logIT(`on-update - successfully cancel orphan orders for ${order.symbol}`); + } + if (process.env.TRACE_TRADES != TRACE_TRADES_LEVEL_OFF) traceTrade(order_type, trade_info, traceTradeFields); tradesHistory.delete(order.symbol); @@ -1035,15 +1051,32 @@ async function scalp(pair, liquidationInfo, source, new_trades_disabled = false) let size = settings.pairs[settingsIndex].order_size.toFixed(decimalPlaces); let order = await createMarketOrder(linearClient, pair, side, size, take_profit, stop_loss); if (order.ret_msg != "OK") { - logIT(`Scalp exit: Error placing new ${side} order: ${order.ret_msg}`); + logIT(`scalp exit: Error placing new ${side} order: ${order.ret_msg}`); return; + } else { + handleNewOrder(order.result, trigger_qty); + logIT(chalk.bgGreenBright(`scalp - ${side} Order Placed for ${pair} at ${settings.pairs[settingsIndex].order_size} size`)); + + if (process.env.USE_DCA_FEATURE == "true" && process.env.DCA_TYPE == "DCA_AVERAGE_ENTRIES") { + let dca_size = size; + for (let i = 1; i <= process.env.DCA_SAFETY_ORDERS; i++) { + let dca_price = side == "Buy" ? price * (1 - process.env.DCA_PRICE_DEVIATION_PRC * i / 100) : price * (1 + process.env.DCA_PRICE_DEVIATION_PRC * i /100) + dca_price = dca_price.toFixed(decimalPlaces) + dca_size = (dca_size * process.env.DCA_VOLUME_SCALE).toFixed(decimalPlaces) + const dcaOrder = await createLimitOrder(linearClient, pair, side, dca_size, dca_price); + if (dcaOrder.ret_msg != "OK") { + logIT(`scalp exit: Error placing new ${side} DCA[${i}] order: ${dcaOrder.ret_msg} for ${pair} at price ${dca_price}`, LOG_LEVEL.ERROR); + return; + } + logIT(chalk.bgGreenBright(`scalp - ${side} DCA[${i}] Order Placed for ${pair} at ${dca_size} size`)); + } + } + + if(process.env.USE_DISCORD == "true") { + orderWebhook(pair, settings.pairs[settingsIndex].order_size, side, position.size, position.percentGain, trigger_qty, source); + } } - handleNewOrder(order.result, trigger_qty); - logIT(chalk.bgGreenBright(`scalp - ${side} Order Placed for ${pair} at ${settings.pairs[settingsIndex].order_size} size`)); - if(process.env.USE_DISCORD == "true") { - orderWebhook(pair, settings.pairs[settingsIndex].order_size, side, position.size, position.percentGain, trigger_qty, source); - } - } else if (position.percentGain < 0 && process.env.USE_DCA_FEATURE == "true") { + } else if (position.percentGain < 0 && process.env.USE_DCA_FEATURE == "true" && process.env.DCA_TYPE == "DCA_LIQUIDATIONS") { //Long/Short liquidation //make sure order is less than max order size @@ -1200,6 +1233,30 @@ async function checkOpenPositions() { console.log("¦ Open Positions ¦"); console.table(postionList); } + return postionList; +} + +async function getNewOrders() { + const openOrdersResp = await contractClient.getHistoricOrders({orderStatus: "New"}); + if (openOrdersResp.retMsg != "OK") { + logIT(`closeQuitPosition - error getting orders list: ${openOrdersResp.retMsg}`, LOG_LEVEL.ERROR); + return []; + } + + return openOrdersResp.result.list; +} + +async function closeOrphanOrders(openPositionsList, openOrders) { + const orphans = openOrders.filter(el => openPositionsList.find( el2 => el2.symbol == el.symbol) == undefined); + if(orphans != undefined) { + orphans.forEach(async el => { + let res = await cancelOrder(linearClient, el.symbol); + if (res.ret_msg != "OK") + logIT(`closeQuitPosition - error cancelling orphan orders for ${el.symbol}`, LOG_LEVEL.ERROR); + else + logIT(`closeQuitPosition - successfully cancel orphan orders for ${el.symbol}`); + }); + } } async function getMinTradingSize() { @@ -1796,7 +1853,13 @@ async function main() { try { await getBalance(); await updateSettings(); - await checkOpenPositions(); + const newOrders = await getNewOrders(); + const openPositionList = await checkOpenPositions(); + + //only needed with DCA_AVERAGE_ENTRIES features on. + if (process.env.DCA_TYPE == "DCA_AVERAGE_ENTRIES") { + await closeOrphanOrders(openPositionList, newOrders); + } await sleep(rateLimit); } catch (e) { console.log(e); diff --git a/example.env b/example.env index 365cb29..551b521 100644 --- a/example.env +++ b/example.env @@ -46,3 +46,7 @@ TRACE_TRADES = OFF # verbosity: OFF, ON, MAX TRACE_TRADES_FIELDS = symbol, size, side, sizeUSD, pnl, liq, price, stop_loss, take_profit, fee, _max_loss, _liquidity_trigger, _dca_count, _start_price, _start_time, _end_time PLACE_ORDERS_SEQUENTIALLY = false LOG_LEVEL = INFO +DCA_TYPE = DCA_LIQUIDATIONS #add size on new liquidations. Instead DCA_AVERAGE_ENTRIES add limits orders (read doc). +DCA_SAFETY_ORDERS = 2 #WORK WITH DCA_AVERAGE_ENTRIES +DCA_VOLUME_SCALE = 1.3 #WORK WITH DCA_AVERAGE_ENTRIES +DCA_PRICE_DEVIATION_PRC = 2 #WORK WITH DCA_AVERAGE_ENTRIES diff --git a/order.js b/order.js index 247c5b8..e9c2ed4 100644 --- a/order.js +++ b/order.js @@ -45,7 +45,6 @@ export async function createLimitOrder(linearClient, pair, side, size, price, ta return order; } -export async function cancelOrder(linearClient, pair, id) { - res = await linearClient.cancelOrder({pair: pair, orderId: id}); - return res; +export async function cancelOrder(linearClient, pair) { + return await linearClient.cancelAllActiveOrders({'symbol': pair}); } \ No newline at end of file From 2d6f8d97ee9cdd7ff4f336a929a94de8618bd040 Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Thu, 20 Jul 2023 10:02:24 +0200 Subject: [PATCH 03/23] scalp: increment openPosition count to handle burst of liquidations and multiple scalp enqueued --- app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app.js b/app.js index b2c3aad..5ec5446 100644 --- a/app.js +++ b/app.js @@ -1055,6 +1055,7 @@ async function scalp(pair, liquidationInfo, source, new_trades_disabled = false) return; } else { handleNewOrder(order.result, trigger_qty); + openPositions++; // increment here as async liquidation could be already enqueued and need synched openPositions status logIT(chalk.bgGreenBright(`scalp - ${side} Order Placed for ${pair} at ${settings.pairs[settingsIndex].order_size} size`)); if (process.env.USE_DCA_FEATURE == "true" && process.env.DCA_TYPE == "DCA_AVERAGE_ENTRIES") { From 67717bd336e6719019308059d34057f25f980115 Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Thu, 20 Jul 2023 10:42:24 +0200 Subject: [PATCH 04/23] app: fix undefined tikSize handling --- app.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app.js b/app.js index 5ec5446..6348008 100644 --- a/app.js +++ b/app.js @@ -1318,8 +1318,13 @@ async function getMinTradingSize() { "tickSize": data.result[i].price_filter.tick_size, "tradeable": tradeable } - //add to array - minOrderSizes.push(minOrderSizeJson); + + if (minOrderSizeJson.tickSize == undefined) { + logIT(`getMinTradingSize - bad tickSize: ignore pair ${minOrderSizeJson.pair}`, LOG_LEVEL.ERROR); + } else { + //add to array + minOrderSizes.push(minOrderSizeJson); + } } catch (e) { await sleep(10); From 1f21d84d5c63462387b028c94476e2d10997431c Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Thu, 20 Jul 2023 10:45:54 +0200 Subject: [PATCH 05/23] app: fix handle undefine close_type when receiving update message from ws --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index 6348008..df31899 100644 --- a/app.js +++ b/app.js @@ -252,7 +252,7 @@ wsClient.on('update', (data) => { let trade_info = tradesHistory.get(order.symbol); // 26/05/2023 patch as ByBit change order.create_type - const order_type = trade_info._close_type ? trade_info._close_type : order.create_type; + const order_type = trade_info?._close_type ? trade_info._close_type : order.create_type; switch(order_type) { case 'CreateByUser': From f7a27e2774c4679ccd8e3d05caa58fadf166f669 Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Wed, 9 Aug 2023 23:34:57 +0200 Subject: [PATCH 06/23] feature: add a paused list to manually set tp on paused tokens set PAUSED_LIST in config when you want to set a custom take profit manually, for example directy from the exchange ui. PAUSED token will be normally tracked but tp ad sl won't be recalculated. --- app.js | 6 +++++- example.env | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app.js b/app.js index df31899..5dd8d7d 100644 --- a/app.js +++ b/app.js @@ -1187,6 +1187,10 @@ async function checkOpenPositions() { logIT("Rate limit status: " + chalk.red(positions.rate_limit_status)); } + // pairs in paused list are not handled + // in this way user could set custom tp/sl and wait the trade to be completed + const pausedList = process.env.PAUSED_LIST.replace(/ /g, "").split(","); + //logIT("Positions: " + JSON.stringify(positions, null, 2)); var totalPositions = 0; var postionList = []; @@ -1194,7 +1198,7 @@ async function checkOpenPositions() { for (var i = 0; i < positions.result.length; i++) { if (positions.result[i].data.size > 0) { //logIT("Open Position for " + positions.result[i].data.symbol + " with size " + positions.result[i].data.size + " and side " + positions.result[i].data.side + " and pnl " + positions.result[i].data.unrealised_pnl); - if (process.env.USE_RECALC_SL_TP == "true") + if (process.env.USE_RECALC_SL_TP == "true" && !pausedList.includes(positions.result[i].data.symbol)) takeProfit(positions.result[i].data.symbol, positions.result[i].data); //get usd value of position diff --git a/example.env b/example.env index 551b521..78ebe3a 100644 --- a/example.env +++ b/example.env @@ -50,3 +50,4 @@ DCA_TYPE = DCA_LIQUIDATIONS #add size on new liquidations. Instead DCA_AVERAGE_E DCA_SAFETY_ORDERS = 2 #WORK WITH DCA_AVERAGE_ENTRIES DCA_VOLUME_SCALE = 1.3 #WORK WITH DCA_AVERAGE_ENTRIES DCA_PRICE_DEVIATION_PRC = 2 #WORK WITH DCA_AVERAGE_ENTRIES +PAUSED_LIST = NOTHING #Add active trades that you want to manually set a take profit From a25ed1c71300a6fdd3c5a11eda9c5f88761793aa Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Wed, 9 Aug 2023 23:49:01 +0200 Subject: [PATCH 07/23] order: add generic params to limit orders method --- order.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/order.js b/order.js index e9c2ed4..46acf09 100644 --- a/order.js +++ b/order.js @@ -22,7 +22,7 @@ export async function createMarketOrder(linearClient, pair, side, size, take_pro return order; } -export async function createLimitOrder(linearClient, pair, side, size, price, take_profit = 0, stop_loss = 0) { +export async function createLimitOrder(linearClient, pair, side, size, price, params = {}) { var cfg = { side: side, @@ -32,14 +32,10 @@ export async function createLimitOrder(linearClient, pair, side, size, price, ta time_in_force: "GoodTillCancel", reduce_only: false, close_on_trigger: false, - price: price + price: price, + ...params }; - if (take_profit != 0) - cfg['take_profit'] = take_profit; - if (stop_loss != 0) - cfg['stop_loss'] = stop_loss; - // send order payload const order = await linearClient.placeActiveOrder(cfg); return order; From 5ffcf7c3a797fa9b8811b37b72cd45814400f624 Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Thu, 10 Aug 2023 19:27:04 +0200 Subject: [PATCH 08/23] app: hanlde DCA count on DCA_AVERAGE_ENTRIES enabled --- app.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app.js b/app.js index 5dd8d7d..4141cf5 100644 --- a/app.js +++ b/app.js @@ -263,6 +263,12 @@ wsClient.on('update', (data) => { if (trade_info._start_price === 0) { trade_info._start_price = order.last_exec_price; traceTrade("start", trade_info, traceTradeFields); + } else { + // handle fill of DCA orders when DCA type is DCA_AVERAGE_ENTRIES + if (process.env.USE_DCA_FEATURE == "true" && process.env.DCA_TYPE == "DCA_AVERAGE_ENTRIES") { + trade_info._dca_count++; + traceTrade("dca", trade_info, traceTradeFields); + } } } break; From 6b9f3d65b06af86700a79dd42605fa31955d8273 Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Thu, 10 Aug 2023 19:44:43 +0200 Subject: [PATCH 09/23] app: simplify trade_info._liquidity_trigger log Now liquidity_trigger store only liquidation value that happen on a specific dca order without considering past liquidation value. Past liquidation value are tracked anyway by previous log occurring on previous DCA order. --- app.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app.js b/app.js index 4141cf5..6c21e62 100644 --- a/app.js +++ b/app.js @@ -204,9 +204,7 @@ if (process.env.WITHDRAW == "true" || process.env.TRANSFER_TO_SPOT == "true"){ } function handleNewOrder(order, liquidity_trigger) { - // Add liquidity_trigger to order as list of liquidity to keep count of dca order i.e - // _liquidity_trigger: "liq1,liq2,...liqN" - const position = newPosition({...order, "liquidity_trigger": `\"${liquidity_trigger}\"`}); + const position = newPosition({...order, "liquidity_trigger": liquidity_trigger}); tradesHistory.set(order.symbol, position); } @@ -214,9 +212,7 @@ function handleDcaOrder(order, liquidity_trigger) { let trade_info = tradesHistory.get(order.symbol); if (trade_info !== undefined) { trade_info._dca_count++; - //remove "" before append a new liquidity item. - trade_info._liquidity_trigger = trade_info._liquidity_trigger.replace(/"/g, ""); - trade_info._liquidity_trigger = `\"${trade_info._liquidity_trigger} ${liquidity_trigger}\"`; + trade_info._liquidity_trigger = liquidity_trigger; if (process.env.TRACE_TRADES != TRACE_TRADES_LEVEL_OFF) traceTrade("dca", trade_info, traceTradeFields); } From 6439d3d93a74946eccc6fcc4d29175839e74a664 Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Sun, 13 Aug 2023 11:13:04 +0200 Subject: [PATCH 10/23] app: major fix settings update Settings was not synched with minOrderSize update --- app.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app.js b/app.js index 6c21e62..385c110 100644 --- a/app.js +++ b/app.js @@ -1341,15 +1341,20 @@ async function getMinTradingSize() { //update settings.json with min order sizes - const settings = JSON.parse(fs.readFileSync('settings.json', 'utf8')); + let settings = JSON.parse(fs.readFileSync('settings.json', 'utf8')); + let updated = false; for (var i = 0; i < minOrderSizes.length; i++) { var settingsIndex = settings.pairs.findIndex(x => x.symbol === minOrderSizes[i].pair); if(settingsIndex !== -1) { settings.pairs[settingsIndex].order_size = minOrderSizes[i].minOrderSize; settings.pairs[settingsIndex].max_position_size = minOrderSizes[i].maxPositionSize; - + updated = true; } } + + if (updated) { + fs.writeFileSync('settings.json', JSON.stringify(settings, null, 2)); + } } else { logIT("Error fetching balance"); From bbe02a5447bcec990304b0d032d79656065575ec Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Fri, 18 Aug 2023 11:59:15 +0200 Subject: [PATCH 11/23] cache exchange calls avoid to perform the same rest api call many times in the same main loop --- app.js | 88 +++++++++++------------------------ exchange.js | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+), 60 deletions(-) create mode 100644 exchange.js diff --git a/app.js b/app.js index 385c110..f194478 100644 --- a/app.js +++ b/app.js @@ -22,6 +22,7 @@ import { newPosition, incrementPosition, closePosition, updatePosition } from '. import { loadJson, storeJson, traceTrade } from './utils.js'; import { createMarketOrder, createLimitOrder, cancelOrder } from './order.js'; import { logIT, LOG_LEVEL } from './log.js'; +import { CachedLinearClient } from './exchange.js' dotenv.config(); @@ -88,8 +89,6 @@ const TRACE_TRADES_LEVEL_MAX = "MAX"; const traceTradeFields = process.env.TRACE_TRADES_FIELDS.replace(/ /g,"").split(",") -var rateLimit = 2000; -var baseRateLimit = 2000; var lastReport = 0; var pairs = []; var liquidationOrders = []; @@ -188,6 +187,8 @@ const linearClient = new LinearClient({ secret: secret, livenet: true, }); +const cachedLinearClient = new CachedLinearClient(linearClient); + //create linear client const contractClient = new ContractClient({ key: key, @@ -598,10 +599,7 @@ async function getServerTime() { //Get margin async function getMargin() { - const data = await linearClient.getWalletBalance(); - var usedBalance = data.result['USDT'].used_margin; - var balance = usedBalance; - return balance; + return (await cachedLinearClient.getWalletBalance()).used_margin; } //get account balance @@ -610,9 +608,9 @@ async function getBalance() { try{ // get ping var started = Date.now(); - const data = await linearClient.getWalletBalance(); + const data = await cachedLinearClient.getWalletBalance(); var elapsed = (Date.now() - started); - if (data.ret_code != 0) { + if (!data) { logIT(chalk.redBright("Error fetching balance. err: " + data.ret_code + "; msg: " + data.ret_msg)); getBalanceTryCount++; if (getBalanceTryCount == 3) @@ -620,11 +618,11 @@ async function getBalance() { return; } getBalanceTryCount = 0 - var availableBalance = data.result['USDT'].available_balance; + var availableBalance = data.available_balance; // save balance global to reduce api requests - global_balance = data.result['USDT'].available_balance; - var usedBalance = data.result['USDT'].used_margin; - var balance = availableBalance + usedBalance; + global_balance = data.available_balance; + var usedBalance = data.used_margin; + var balance = data.whole_balance; //load settings.json const settings = JSON.parse(fs.readFileSync('account.json', 'utf8')); @@ -686,7 +684,7 @@ async function getBalance() { var percentGain = percentGain.toFixed(6); var diff = diff.toFixed(6); //fetch positions - var positions = await linearClient.getPosition(); + var positions = await cachedLinearClient.getPosition(); var positionList = []; var marg = await getMargin(); var time = await getServerTime(); @@ -702,7 +700,7 @@ async function getBalance() { var size = size.toFixed(4); var ios = positions.result[i].data.is_isolated; - var priceFetch = await linearClient.getTickers({symbol: symbol}); + var priceFetch = await cachedLinearClient.getTickers({symbol: symbol}); var test = priceFetch.result[0].last_price; let side = positions.result[i].data.side; @@ -754,6 +752,7 @@ async function getBalance() { } //create data payload + const positionsCount = await cachedLinearClient.getOpenPositions(); const posidata = { balance: balance.toFixed(2).toString(), leverage: process.env.LEVERAGE.toString(), @@ -761,7 +760,7 @@ async function getBalance() { profitUSDT: diff.toString(), profit: percentGain.toString(), servertime: time.toString(), - positioncount: openPositions.toString(), + positioncount: positionsCount.toString(), ping: elapsed, runningStatus: runningStatus_Label[runningStatus].toString(), trade_count: globalTradesStats.trade_count, @@ -798,14 +797,10 @@ async function getBalance() { //send data to gui io.sockets.emit("positions", positionsData); - - - - - return balance; } catch (e) { + logIT(`getBalance error ${e}`, LOG_LEVEL.ERROR); return null; } @@ -813,7 +808,7 @@ async function getBalance() { //get position async function getPosition(pair, side) { //gor through all pairs and getPosition() - var positions = await linearClient.getPosition(pair); + var positions = await cachedLinearClient.getPosition(pair); const error_result = {side: null, entryPrice: null, size: null, percentGain: null}; if (positions.result == null) logIT("Open positions response is null"); @@ -1151,43 +1146,16 @@ async function setPositionMode() { } async function checkLeverage(symbol) { - var position = await linearClient.getPosition({symbol: symbol}); + var position = await cachedLinearClient.getPosition({symbol: symbol}); var leverage = position.result[0].leverage; return leverage; } //create loop that checks for open positions every second async function checkOpenPositions() { //go through all pairs and getPosition() - var positions = await linearClient.getPosition(); - if (positions.ret_msg != "OK") { - logIT("checkOpenPositions - getPosition fails", LOG_LEVEL.ERROR); - rateLimit = baseRateLimit + 2000; - return; - } + var positions = await cachedLinearClient.getPosition(); openPositions = positions.result.filter(el => el.data.size > 0).length; - const data = await linearClient.getWalletBalance(); - - //check rate_limit_status - if (positions.rate_limit_status > 100) { - rateLimit = baseRateLimit; - logIT("Rate limit status: " + chalk.green(positions.rate_limit_status)); - } - else if (positions.rate_limit_status > 75) { - rateLimit = rateLimit + 500; - logIT("Rate limit status: " + chalk.greenBright(positions.rate_limit_status)); - } - else if (positions.rate_limit_status > 50) { - rateLimit = rateLimit + 1000; - logIT("Rate limit status: " + chalk.yellowBright(positions.rate_limit_status)); - } - else if (positions.rate_limit_status > 25) { - rateLimit = rateLimit + 2000; - logIT("Rate limit status: " + chalk.yellow(positions.rate_limit_status)); - } - else { - rateLimit = rateLimit + 200; - logIT("Rate limit status: " + chalk.red(positions.rate_limit_status)); - } + const data = await cachedLinearClient.getWalletBalance(); // pairs in paused list are not handled // in this way user could set custom tp/sl and wait the trade to be completed @@ -1209,7 +1177,7 @@ async function checkOpenPositions() { var profit = positions.result[i].data.unrealised_pnl; //get available Balance - var availableBalance = data.result['USDT'].available_balance; + var availableBalance = data.available_balance; //calculate the profit % change in USD var margin = positions.result[i].data.position_value/process.env.LEVERAGE; @@ -1270,11 +1238,11 @@ async function getMinTradingSize() { const url = "https://api.bybit.com/v2/public/symbols"; const response = await fetch(url); const data = await response.json(); - var balance = await getBalance(); + var balance = (await cachedLinearClient.getWalletBalance()).whole_balance; if (balance !== null) { - var tickers = await linearClient.getTickers(); - var positions = await linearClient.getPosition(); + var tickers = await cachedLinearClient.getTickers(); + var positions = await cachedLinearClient.getPosition(); var minOrderSizes = []; logIT("Fetching min Trading Sizes for pairs, this could take a minute..."); @@ -1694,7 +1662,7 @@ async function reportWebhook() { if(process.env.USE_DISCORD == "true") { const settings = JSON.parse(fs.readFileSync('account.json', 'utf8')); //fetch balance first if not startingBalance will be null - var balance = await getBalance(); + var balance = (await cachedLinearClient.getWalletBalance()).whole_balance; //check if starting balance is set if (settings.startingBalance === 0) { settings.startingBalance = balance; @@ -1717,7 +1685,7 @@ async function reportWebhook() { var diff = diff.toFixed(6); var balance = balance.toFixed(2); //fetch positions - var positions = await linearClient.getPosition(); + var positions = await cachedLinearClient.getPosition(); var positionList = []; var marg = await getMargin(); var time = await getServerTime(); @@ -1733,7 +1701,7 @@ async function reportWebhook() { var size = size.toFixed(4); var ios = positions.result[i].data.is_isolated; - var priceFetch = await linearClient.getTickers({symbol: symbol}); + var priceFetch = await cachedLinearClient.getTickers({symbol: symbol}); var test = priceFetch.result[0].last_price; let side = positions.result[i].data.side; @@ -1868,6 +1836,7 @@ async function main() { while (true) { try { + cachedLinearClient.invalidate(); await getBalance(); await updateSettings(); const newOrders = await getNewOrders(); @@ -1877,11 +1846,10 @@ async function main() { if (process.env.DCA_TYPE == "DCA_AVERAGE_ENTRIES") { await closeOrphanOrders(openPositionList, newOrders); } - await sleep(rateLimit); + await sleep(cachedLinearClient.getRateLimit()); } catch (e) { console.log(e); sleep(1000); - rateLimit = rateLimit + 1000; } } } diff --git a/exchange.js b/exchange.js new file mode 100644 index 0000000..0e2fe55 --- /dev/null +++ b/exchange.js @@ -0,0 +1,130 @@ +import { logIT, LOG_LEVEL } from './log.js'; +import chalk from 'chalk'; + +var fetch_i = 0; + + +const baseRateLimit = 2000; + +const checkResponse = (resp, latestRateLimit = baseRateLimit) => { + let rateLimit = undefined; + + if (resp.ret_msg != "OK") { + return [false, undefined]; + } + + //check rate_limit_status + if (resp.rate_limit_status) { + //check rate_limit_status + if (resp.rate_limit_status > 100) { + rateLimit = baseRateLimit; + logIT("Rate limit status: " + chalk.green(resp.rate_limit_status)); + } + else if (resp.rate_limit_status > 75) { + rateLimit = latestRateLimit + 500; + logIT("Rate limit status: " + chalk.greenBright(resp.rate_limit_status)); + } + else if (resp.rate_limit_status > 50) { + rateLimit = latestRateLimit + 1000; + logIT("Rate limit status: " + chalk.yellowBright(resp.rate_limit_status)); + } + else if (resp.rate_limit_status > 25) { + rateLimit = latestRateLimit + 2000; + logIT("Rate limit status: " + chalk.yellow(resp.rate_limit_status)); + } + else { + rateLimit = latestRateLimit + 4000; + logIT("Rate limit status: " + chalk.red(resp.rate_limit_status)); + } + } + return [true, rateLimit]; +} + +export class CachedLinearClient { + constructor(linearClient) { + this.linearClient = linearClient; + this.walletBalance = {res: undefined, invalidated: true}; + this.positions = {res: undefined, invalidated: true}; + this.tickers = {res: undefined, invalidated: true}; + this.rateLimit = baseRateLimit; + } + + async getWalletBalance() { + let rate_limit = undefined; + if (this.walletBalance.invalidated) { + //let rate_limit = undefined; + this.walletBalance.res = await this.linearClient.getWalletBalance(); + const [res, rate_limit ] = checkResponse(this.walletBalance.res, this.rateLimit); + if (!res) { + throw Error(`CachedLinearClient::getWalletBalance fail err: ${this.walletBalance.res.ret_msg}`); + } + this.walletBalance.invalidated = false; + if (rate_limit) { + this.rateLimit = rate_limit; + } + } + + return { + 'available_balance': this.walletBalance.res.result['USDT'].available_balance, + 'used_margin': this.walletBalance.res.result['USDT'].used_margin, + 'whole_balance': this.walletBalance.res.result['USDT'].available_balance + this.walletBalance.res.result['USDT'].used_margin + }; + } + + async getPosition() { + let rate_limit = undefined; + if (this.positions.invalidated) { + //let rate_limit = undefined; + this.positions.res = await this.linearClient.getPosition(); + const [res, rate_limit ] = checkResponse(this.positions.res, this.rateLimit); + if (!res) { + throw Error(`CachedLinearClient::getPosition fail err: ${this.positions.res.ret_msg}`); + } + this.positions.invalidated = false; + if (rate_limit) { + this.rateLimit = rate_limit; + } + } + return this.positions.res; + } + + async getOpenPositions() { + const positions = await this.getPosition(); + const openPositions = positions.result.filter(el => el.data.size > 0).length; + return openPositions; + } + + async getTickers(symbolObj = undefined) { + if (this.tickers.invalidated) { + this.tickers.res = await this.linearClient.getTickers(); + const [res] = checkResponse(this.tickers.res, this.rateLimit); + if (!res) { + throw Error(`CachedLinearClient::getTickers fail err: ${this.tickers.res.ret_msg}`); + } + + this.tickers.invalidated = false; + } + + let ticker = {result: []}; + if (symbolObj) { + const t = this.tickers.res.result.find(el => el.symbol == symbolObj.symbol); + if (t == undefined) { + throw Error(`CachedLinearClient::getTickers fail symbol not found: ${symbolObj.symbol}`); + } else { + return {result: [t]} + } + } + + return symbolObj ? ticker : this.tickers.res; + } + + getRateLimit() { + return this.rateLimit; + } + + invalidate(){ + this.walletBalance.invalidated = true; + this.positions.invalidated = true; + this.tickers.invalidated = true; + } +} \ No newline at end of file From fe2aa3abc5b98df82cba254825fd462aca8d9aaa Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Fri, 18 Aug 2023 15:51:19 +0200 Subject: [PATCH 12/23] feature: testnet to handle orders require the api for testnet account require a real api key to receive liquidation info --- app.js | 359 +++++++++++++++++++++++++++++----------------------- example.env | 3 + 2 files changed, 205 insertions(+), 157 deletions(-) diff --git a/app.js b/app.js index f194478..c193f31 100644 --- a/app.js +++ b/app.js @@ -63,6 +63,8 @@ const PORT = process.env.PORT || 3000; const __dirname = path.dirname(new URL(import.meta.url).pathname); const key = process.env.API_KEY; const secret = process.env.API_SECRET; +const key_webSocket = process.env.USE_TESTNET == "true" ? process.env.API_KEY_WEBSOCKET : process.env.API_KEY; +const secret_webSocket = process.env.USE_TESTNET == "true" ? process.env.API_SECRET_WEBSOCKET : process.env.API_SECRET; const stopLossCoins = new Map(); // keep tracks of opened positions @@ -173,11 +175,23 @@ server.listen(PORT, () => { //create ws client const wsClient = new WebsocketClient({ + key: key_webSocket, + secret: secret_webSocket, + market: 'linear', + livenet: true, +}); + +let wsTestClient = null; +if (process.env.USE_TESTNET == "true") { + wsTestClient = new WebsocketClient({ key: key, secret: secret, market: 'linear', livenet: true, -}); + testnet: true, + }); +} + const binanceClient = new binanceWS({ beautify: true, }); @@ -186,6 +200,7 @@ const linearClient = new LinearClient({ key: key, secret: secret, livenet: true, + testnet: process.env.USE_TESTNET == "true", }); const cachedLinearClient = new CachedLinearClient(linearClient); @@ -194,6 +209,7 @@ const contractClient = new ContractClient({ key: key, secret: secret, livenet: true, + testnet: process.env.USE_TESTNET == "true", }); //account client if (process.env.WITHDRAW == "true" || process.env.TRANSFER_TO_SPOT == "true"){ @@ -225,178 +241,206 @@ function tradeOrdersQueue_enqueue(orderFnObj) { tradeOrdersQueue.push(orderFnObj); } -wsClient.on('update', (data) => { - logIT(`raw message received ${JSON.stringify(data, null, 2)}`, LOG_LEVEL.DEBUG); +function wsHandleStopOrder(data) { + const order_data = data.data; + //check for stoploss trigger + if (order_data[0].stop_order_type === "StopLoss" && order_data[0].order_status === "Triggered"){ + //add coin to timeout + addCoinToTimeout(order_data[0].symbol, process.env.STOP_LOSS_TIMEOUT); + messageWebhook(order_data[0].symbol + " hit Stop Loss!\n Waiting " + process.env.STOP_LOSS_TIMEOUT + " ms for timeout..."); + } + let trade_info = tradesHistory.get(order_data[0].symbol); + if (trade_info !== undefined && order_data[0].order_status === "Triggered" && (order_data[0].stop_order_type === "StopLoss" || order_data[0].stop_order_type === "TakeProfit")) { + trade_info._close_type = order_data[0].stop_order_type; + } +} - const topic = data.topic; - if (topic === "stop_order") { - const order_data = data.data; - //check for stoploss trigger - if (order_data[0].stop_order_type === "StopLoss" && order_data[0].order_status === "Triggered"){ - //add coin to timeout - addCoinToTimeout(order_data[0].symbol, process.env.STOP_LOSS_TIMEOUT); - messageWebhook(order_data[0].symbol + " hit Stop Loss!\n Waiting " + process.env.STOP_LOSS_TIMEOUT + " ms for timeout..."); - } - let trade_info = tradesHistory.get(order_data[0].symbol); - if (trade_info !== undefined && order_data[0].order_status === "Triggered" && (order_data[0].stop_order_type === "StopLoss" || order_data[0].stop_order_type === "TakeProfit")) { - trade_info._close_type = order_data[0].stop_order_type; - } - } else if (topic === "order") { - let close_position = false; - const filled_orders = data.data.filter(el => el.order_status == 'Filled'); - filled_orders.forEach( async order => { - - let trade_info = tradesHistory.get(order.symbol); - - // 26/05/2023 patch as ByBit change order.create_type - const order_type = trade_info?._close_type ? trade_info._close_type : order.create_type; - - switch(order_type) { - case 'CreateByUser': - // new trade - if (trade_info !== undefined) { - // update price with executed order price - // verify that it's starts order not dca - if (trade_info._start_price === 0) { - trade_info._start_price = order.last_exec_price; - traceTrade("start", trade_info, traceTradeFields); - } else { - // handle fill of DCA orders when DCA type is DCA_AVERAGE_ENTRIES - if (process.env.USE_DCA_FEATURE == "true" && process.env.DCA_TYPE == "DCA_AVERAGE_ENTRIES") { - trade_info._dca_count++; - traceTrade("dca", trade_info, traceTradeFields); - } +function wsHandleOrder(data) { + let close_position = false; + const filled_orders = data.data.filter(el => el.order_status == 'Filled'); + filled_orders.forEach( async order => { + + let trade_info = tradesHistory.get(order.symbol); + + // 26/05/2023 patch as ByBit change order.create_type + const order_type = trade_info?._close_type ? trade_info._close_type : order.create_type; + + switch(order_type) { + case 'CreateByUser': + // new trade + if (trade_info !== undefined) { + // update price with executed order price + // verify that it's starts order not dca + if (trade_info._start_price === 0) { + trade_info._start_price = order.last_exec_price; + traceTrade("start", trade_info, traceTradeFields); + } else { + // handle fill of DCA orders when DCA type is DCA_AVERAGE_ENTRIES + if (process.env.USE_DCA_FEATURE == "true" && process.env.DCA_TYPE == "DCA_AVERAGE_ENTRIES") { + trade_info._dca_count++; + traceTrade("dca", trade_info, traceTradeFields); } } - break; - case 'StopLoss': - close_position = true; - globalTradesStats.consecutive_wins = 0; - globalTradesStats.consecutive_losses += 1; - globalTradesStats.max_consecutive_losses = Math.max(globalTradesStats.max_consecutive_losses, globalTradesStats.consecutive_losses); - globalTradesStats.losses_count += 1; - break; - case 'TakeProfit': - close_position = true; - globalTradesStats.consecutive_losses = 0; - globalTradesStats.consecutive_wins += 1; - globalTradesStats.max_consecutive_wins = Math.max(globalTradesStats.max_consecutive_wins, globalTradesStats.consecutive_wins); - globalTradesStats.wins_count += 1; - if (drawdownThreshold > 0 && trade_info._max_loss > drawdownThreshold) { - addCoinToTimeout(order.symbol, process.env.STOP_LOSS_TIMEOUT); - logIT(`handleTakeProfit::addCoinToTimeout for ${order.symbol} as during the trade have a loss greater than drawdownThreshold`); - } - break; - default: - // NOP - } - - if (close_position) { - globalTradesStats.trade_count += 1; - globalTradesStats.max_loss = Math.min(globalTradesStats.max_loss, trade_info._max_loss); - closePosition(trade_info, order); - storeJson(globalStatsPath, globalTradesStats); - logIT(`#trade_stats:close# ${order.symbol}: ${JSON.stringify(trade_info)}`); - logIT(`#global_stats:close# ${JSON.stringify(globalTradesStats)}`); - - //only needed with DCA_AVERAGE_ENTRIES features on. - if (process.env.DCA_TYPE == "DCA_AVERAGE_ENTRIES") { - let res = await cancelOrder(linearClient, order.symbol); - if (res.ret_msg != "OK") - logIT(`on-update - error cancelling orphan orders for ${order.symbol}`, LOG_LEVEL.ERROR); - else - logIT(`on-update - successfully cancel orphan orders for ${order.symbol}`); } + break; + case 'StopLoss': + close_position = true; + globalTradesStats.consecutive_wins = 0; + globalTradesStats.consecutive_losses += 1; + globalTradesStats.max_consecutive_losses = Math.max(globalTradesStats.max_consecutive_losses, globalTradesStats.consecutive_losses); + globalTradesStats.losses_count += 1; + break; + case 'TakeProfit': + close_position = true; + globalTradesStats.consecutive_losses = 0; + globalTradesStats.consecutive_wins += 1; + globalTradesStats.max_consecutive_wins = Math.max(globalTradesStats.max_consecutive_wins, globalTradesStats.consecutive_wins); + globalTradesStats.wins_count += 1; + if (drawdownThreshold > 0 && trade_info._max_loss > drawdownThreshold) { + addCoinToTimeout(order.symbol, process.env.STOP_LOSS_TIMEOUT); + logIT(`handleTakeProfit::addCoinToTimeout for ${order.symbol} as during the trade have a loss greater than drawdownThreshold`); + } + break; + default: + // NOP + } - if (process.env.TRACE_TRADES != TRACE_TRADES_LEVEL_OFF) - traceTrade(order_type, trade_info, traceTradeFields); - tradesHistory.delete(order.symbol); + if (close_position) { + globalTradesStats.trade_count += 1; + globalTradesStats.max_loss = Math.min(globalTradesStats.max_loss, trade_info._max_loss); + closePosition(trade_info, order); + storeJson(globalStatsPath, globalTradesStats); + logIT(`#trade_stats:close# ${order.symbol}: ${JSON.stringify(trade_info)}`); + logIT(`#global_stats:close# ${JSON.stringify(globalTradesStats)}`); + + //only needed with DCA_AVERAGE_ENTRIES features on. + if (process.env.DCA_TYPE == "DCA_AVERAGE_ENTRIES") { + let res = await cancelOrder(linearClient, order.symbol); + if (res.ret_msg != "OK") + logIT(`on-update - error cancelling orphan orders for ${order.symbol}`, LOG_LEVEL.ERROR); + else + logIT(`on-update - successfully cancel orphan orders for ${order.symbol}`); } - }); + + if (process.env.TRACE_TRADES != TRACE_TRADES_LEVEL_OFF) + traceTrade(order_type, trade_info, traceTradeFields); + tradesHistory.delete(order.symbol); + } + }); +}; + +function wsHandleLiquidations(data) { + var pair = data.data.symbol; + var price = parseFloat(data.data.price); + var side = data.data.side; + //convert to float + var qty = parseFloat(data.data.qty) * price; + //create timestamp + var timestamp = Math.floor(Date.now() / 1000); + //find what index of liquidationOrders array is the pair + var index = liquidationOrders.findIndex(x => x.pair === pair); + + var dir = ""; + if (side === "Buy") { + dir = "Long"; } else { - var pair = data.data.symbol; - var price = parseFloat(data.data.price); - var side = data.data.side; - //convert to float - var qty = parseFloat(data.data.qty) * price; - //create timestamp - var timestamp = Math.floor(Date.now() / 1000); - //find what index of liquidationOrders array is the pair - var index = liquidationOrders.findIndex(x => x.pair === pair); - - var dir = ""; - if (side === "Buy") { - dir = "Long"; - } else { - dir = "Short"; + dir = "Short"; + } + + //get blacklisted pairs + const blacklist = []; + var blacklist_all = process.env.BLACKLIST; + blacklist_all = blacklist_all.replaceAll(" ", ""); + blacklist_all.split(',').forEach(item => { + blacklist.push(item); + }); + + // get whitelisted pairs + const whitelist = []; + var whitelist_all = process.env.WHITELIST; + whitelist_all = whitelist_all.replaceAll(" ", ""); + whitelist_all.split(',').forEach(item => { + whitelist.push(item); + }); + + //if pair is not in liquidationOrders array and not in blacklist, add it + if (index === -1 && (!blacklist.includes(pair)) && (process.env.USE_WHITELIST == "false" || (process.env.USE_WHITELIST == "true" && whitelist.includes(pair)))) { + liquidationOrders.push({pair: pair, price: price, side: side, qty: qty, amount: 1, timestamp: timestamp}); + index = liquidationOrders.findIndex(x => x.pair === pair); + } + //if pair is in liquidationOrders array, update it + else if ((!blacklist.includes(pair)) && (process.env.USE_WHITELIST == "false" || (process.env.USE_WHITELIST == "true" && whitelist.includes(pair)))) { + //check if timesstamp is withing 5 seconds of previous timestamp + if (timestamp - liquidationOrders[index].timestamp <= 5) { + liquidationOrders[index].price = price; + liquidationOrders[index].side = side; + //add qty to existing qty and round to 2 decimal places + liquidationOrders[index].qty = parseFloat((liquidationOrders[index].qty + qty).toFixed(2)); + liquidationOrders[index].timestamp = timestamp; + liquidationOrders[index].amount = liquidationOrders[index].amount + 1; + } - - //get blacklisted pairs - const blacklist = []; - var blacklist_all = process.env.BLACKLIST; - blacklist_all = blacklist_all.replaceAll(" ", ""); - blacklist_all.split(',').forEach(item => { - blacklist.push(item); - }); - - // get whitelisted pairs - const whitelist = []; - var whitelist_all = process.env.WHITELIST; - whitelist_all = whitelist_all.replaceAll(" ", ""); - whitelist_all.split(',').forEach(item => { - whitelist.push(item); - }); - - //if pair is not in liquidationOrders array and not in blacklist, add it - if (index === -1 && (!blacklist.includes(pair)) && (process.env.USE_WHITELIST == "false" || (process.env.USE_WHITELIST == "true" && whitelist.includes(pair)))) { - liquidationOrders.push({pair: pair, price: price, side: side, qty: qty, amount: 1, timestamp: timestamp}); - index = liquidationOrders.findIndex(x => x.pair === pair); + //if timestamp is more than 5 seconds from previous timestamp, overwrite + else { + liquidationOrders[index].price = price; + liquidationOrders[index].side = side; + liquidationOrders[index].qty = qty; + liquidationOrders[index].timestamp = timestamp; + liquidationOrders[index].amount = 1; } - //if pair is in liquidationOrders array, update it - else if ((!blacklist.includes(pair)) && (process.env.USE_WHITELIST == "false" || (process.env.USE_WHITELIST == "true" && whitelist.includes(pair)))) { - //check if timesstamp is withing 5 seconds of previous timestamp - if (timestamp - liquidationOrders[index].timestamp <= 5) { - liquidationOrders[index].price = price; - liquidationOrders[index].side = side; - //add qty to existing qty and round to 2 decimal places - liquidationOrders[index].qty = parseFloat((liquidationOrders[index].qty + qty).toFixed(2)); - liquidationOrders[index].timestamp = timestamp; - liquidationOrders[index].amount = liquidationOrders[index].amount + 1; - - } - //if timestamp is more than 5 seconds from previous timestamp, overwrite - else { - liquidationOrders[index].price = price; - liquidationOrders[index].side = side; - liquidationOrders[index].qty = qty; - liquidationOrders[index].timestamp = timestamp; - liquidationOrders[index].amount = 1; - } - if (liquidationOrders[index].qty > process.env.MIN_LIQUIDATION_VOLUME) { + if (liquidationOrders[index].qty > process.env.MIN_LIQUIDATION_VOLUME) { - if (stopLossCoins.has(pair) == true && process.env.USE_STOP_LOSS_TIMEOUT == "true") { - logIT(chalk.yellow(liquidationOrders[index].pair + " is not allowed to trade cause it is on timeout")); - } else { - if (process.env.PLACE_ORDERS_SEQUENTIALLY == "true") - tradeOrdersQueue_enqueue({'pair': pair, 'fn': scalp.bind(null, pair, {...liquidationOrders[index]}, 'Bybit', runningStatus != runningStatus_RUN)}); - else - scalp(pair, {...liquidationOrders[index]}, 'Bybit', runningStatus != runningStatus_RUN); - } - - } - else { - logIT(chalk.magenta("[" + liquidationOrders[index].amount + "] " + dir + " Liquidation order for " + liquidationOrders[index].pair + " @Bybit with a cumulative value of " + liquidationOrders[index].qty + " USDT")); - logIT(chalk.yellow("Not enough liquidations to trade " + liquidationOrders[index].pair)); + if (stopLossCoins.has(pair) == true && process.env.USE_STOP_LOSS_TIMEOUT == "true") { + logIT(chalk.yellow(liquidationOrders[index].pair + " is not allowed to trade cause it is on timeout")); + } else { + if (process.env.PLACE_ORDERS_SEQUENTIALLY == "true") + tradeOrdersQueue_enqueue({'pair': pair, 'fn': scalp.bind(null, pair, {...liquidationOrders[index]}, 'Bybit', runningStatus != runningStatus_RUN)}); + else + scalp(pair, {...liquidationOrders[index]}, 'Bybit', runningStatus != runningStatus_RUN); } - + } else { - logIT(chalk.gray("Liquidation Found for Blacklisted pair: " + pair + " ignoring...")); + logIT(chalk.magenta("[" + liquidationOrders[index].amount + "] " + dir + " Liquidation order for " + liquidationOrders[index].pair + " @Bybit with a cumulative value of " + liquidationOrders[index].qty + " USDT")); + logIT(chalk.yellow("Not enough liquidations to trade " + liquidationOrders[index].pair)); } + + } + else { + logIT(chalk.gray("Liquidation Found for Blacklisted pair: " + pair + " ignoring...")); + } +} + +wsClient.on('update', (data) => { + logIT(`raw message received ${JSON.stringify(data, null, 2)}`, LOG_LEVEL.DEBUG); + + const topic = data.topic; + if (topic === "stop_order") { + wsHandleStopOrder(data); + } else if (topic === "order") { + wsHandleOrder(data); + } else { + wsHandleLiquidations(data); } }); +// using testnet needs to receive update notifications for +// orders and stop_orders, instead liquidations comes from regular net. +if (process.env.USE_TESTNET == "true") { + wsTestClient.on('update', (data) => { + logIT(`raw message received ${JSON.stringify(data, null, 2)}`, LOG_LEVEL.DEBUG); + + const topic = data.topic; + if (topic === "stop_order") { + wsHandleStopOrder(data); + } else if (topic === "order") { + wsHandleOrder(data); + } + + }); +} + binanceClient.on('formattedMessage', (data) => { //console.log('raw message received ', JSON.stringify(data, null, 2)); var pair = data.liquidationOrder.symbol; @@ -522,11 +566,12 @@ binanceClient.on('error', (data) => { logIT('ws saw error ', data?.wsKey); }); +const wsClientPtr = process.env.USE_TESTNET == "true" ? wsTestClient : wsClient; //subscribe to stop_order to see when we hit stop-loss -wsClient.subscribe('stop_order') +wsClientPtr.subscribe('stop_order'); //subscribe to order to see when orders where executed -wsClient.subscribe('order') +wsClientPtr.subscribe('order'); //run websocket async function liquidationEngine(pairs) { diff --git a/example.env b/example.env index 78ebe3a..a3d67ac 100644 --- a/example.env +++ b/example.env @@ -1,5 +1,8 @@ API_KEY = apikeyhere API_SECRET = apisecrethere +API_KEY_WEBSOCKET = NONE +API_SECRET_WEBSOCKET = NONE +USE_TESTNET= false # testnet allows to place order on testnet but liquidation data require a real api key LIQ_SOURCE = bybit GUI_PASSWORD = password GUI_SESSION_PASSWORD = secret From 69977d6d3ca10f971f07a9584d3a7f022b904569 Mon Sep 17 00:00:00 2001 From: Alessandro Date: Sat, 19 Aug 2023 21:48:30 +0200 Subject: [PATCH 13/23] trace trades as json format --- utils.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/utils.js b/utils.js index da76468..09ee600 100644 --- a/utils.js +++ b/utils.js @@ -33,7 +33,30 @@ function jsonToCsv(json) { return csv; } -export function traceTrade(step, obj, fields) { +export function traceTrade(step, obj, fields, format = "JSON") { + if (format == "JSON") { + traceTradeAsJSON(step, obj, fields); + } else { + traceTradeAsCSV(step, obj, fields); + } +} + +export function traceTradeAsJSON(step, obj, fields) { + //Object.entries(obj).forEach( ([k, v]) => position[k] = v ); + + let tradeObj = {'step': step, ...obj}; + let records = []; + + if (fs.existsSync("trades.json")) { + let jsonFile = fs.readFileSync("trades.json","utf-8"); + records = JSON.parse(jsonFile); + } + + records.push(tradeObj); + fs.writeFileSync("trades.json", JSON.stringify(records, null, '\t')); +} + +export function traceTradeAsCSV(step, obj, fields) { let csv_line = moment().local().toString() + "," + step; fields.forEach((key) => (csv_line += "," + (obj[key] ?? ""))); csv_line += "\n"; From be62e19f7c35d04d16e15afe3b2e8d86db5ba0f3 Mon Sep 17 00:00:00 2001 From: Alessandro Date: Sat, 19 Aug 2023 22:57:51 +0200 Subject: [PATCH 14/23] fix missing use_dca_feature on closeOrphanOrders --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index c193f31..485347b 100644 --- a/app.js +++ b/app.js @@ -1888,7 +1888,7 @@ async function main() { const openPositionList = await checkOpenPositions(); //only needed with DCA_AVERAGE_ENTRIES features on. - if (process.env.DCA_TYPE == "DCA_AVERAGE_ENTRIES") { + if (process.env.USE_DCA_FEATURE == "true" && process.env.DCA_TYPE == "DCA_AVERAGE_ENTRIES") { await closeOrphanOrders(openPositionList, newOrders); } await sleep(cachedLinearClient.getRateLimit()); From 3371599c553919a2cce05c7e52f94c892fb80314 Mon Sep 17 00:00:00 2001 From: Alessandro Date: Tue, 22 Aug 2023 00:18:08 +0200 Subject: [PATCH 15/23] trades history: store roi --- example.env | 2 +- position.js | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/example.env b/example.env index a3d67ac..148733b 100644 --- a/example.env +++ b/example.env @@ -46,7 +46,7 @@ CHECK_FOR_UPDATE = false TIMEOUT_BLACKLIST_FOR_BIG_DRAWDOWN = false DRAWDOWN_THRESHOLD = 3.5 TRACE_TRADES = OFF # verbosity: OFF, ON, MAX -TRACE_TRADES_FIELDS = symbol, size, side, sizeUSD, pnl, liq, price, stop_loss, take_profit, fee, _max_loss, _liquidity_trigger, _dca_count, _start_price, _start_time, _end_time +TRACE_TRADES_FIELDS = symbol, size, side, sizeUSD, pnl, liq, price, stop_loss, take_profit, fee, _max_loss, _liquidity_trigger, _dca_count, _start_price, _start_time, _end_time, _roi PLACE_ORDERS_SEQUENTIALLY = false LOG_LEVEL = INFO DCA_TYPE = DCA_LIQUIDATIONS #add size on new liquidations. Instead DCA_AVERAGE_ENTRIES add limits orders (read doc). diff --git a/position.js b/position.js index b3868f5..b1aa4b1 100644 --- a/position.js +++ b/position.js @@ -14,6 +14,8 @@ export function closePosition(position, order) { position.price = order.last_exec_price; const usdValue = position.price * position.size / process.env.LEVERAGE; position.sizeUSD = usdValue.toFixed(3); + position._roi = position.side == "Buy" ? (position.price - position._start_price) / position._start_price : + (position._start_price - position.price) / position._start_price; }; export function updatePosition(position, obj = {}) { @@ -39,6 +41,7 @@ export function newPosition(order) { "_start_price" : order.last_exec_price, "_start_time" : order.created_time, "_end_time": undefined, + "_roi": undefined, }; const usdValue = position.price * position.size / process.env.LEVERAGE; position.sizeUSD = usdValue.toFixed(3); From c10862ae8a983b96122e0d355a1ed08f3f3ce73a Mon Sep 17 00:00:00 2001 From: Alessandro Date: Wed, 30 Aug 2023 20:40:00 +0200 Subject: [PATCH 16/23] dump liquidations data in a separate file --- app.js | 10 +++++++++- utils.js | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/app.js b/app.js index 485347b..fc23879 100644 --- a/app.js +++ b/app.js @@ -19,7 +19,7 @@ import bodyParser from 'body-parser' import session from 'express-session'; import { Server } from 'socket.io' import { newPosition, incrementPosition, closePosition, updatePosition } from './position.js'; -import { loadJson, storeJson, traceTrade } from './utils.js'; +import { loadJson, storeJson, traceTrade, dumpLiquidationInfo } from './utils.js'; import { createMarketOrder, createLimitOrder, cancelOrder } from './order.js'; import { logIT, LOG_LEVEL } from './log.js'; import { CachedLinearClient } from './exchange.js' @@ -1048,6 +1048,14 @@ async function scalp(pair, liquidationInfo, source, new_trades_disabled = false) return; } + dumpLiquidationInfo({ + 'time': moment().utc().format(), + 'pair': pair, + 'side': side, + 'price': liquidationInfo.price, + 'size': liquidationInfo.qty, + }); + //load min order size json const tickData = JSON.parse(fs.readFileSync('min_order_sizes.json', 'utf8')); var index = tickData.findIndex(x => x.pair === pair); diff --git a/utils.js b/utils.js index 09ee600..19202ff 100644 --- a/utils.js +++ b/utils.js @@ -78,3 +78,17 @@ export function traceTradeAsCSV(step, obj, fields) { } ); } + +export function dumpLiquidationInfo(liqInfo) { + let line = `${liqInfo.time},${liqInfo.pair},${liqInfo.side},${liqInfo.size}`; + if (fs.existsSync("liqInfo.csv")) { + line = '\n' + line; + } + fs.appendFile("liqInfo.csv",line, + function (err) { + if (err) { + logIT("Logging error: " + err); + return console.log("Logging error: " + err); + } + }); +} From cb5837ff4f838f9a9deea5eff73b993578c6da2d Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Fri, 22 Sep 2023 09:12:51 +0200 Subject: [PATCH 17/23] App: open positions side balanced --- app.js | 8 ++++++++ example.env | 1 + 2 files changed, 9 insertions(+) diff --git a/app.js b/app.js index fc23879..0d56943 100644 --- a/app.js +++ b/app.js @@ -1087,6 +1087,14 @@ async function scalp(pair, liquidationInfo, source, new_trades_disabled = false) return; } + // evaluate process.env.TRADE_POSITIONS_SIDE_BALANCE to have equals number of long and short + const maxTradeForSide = Math.round(process.env.MAX_OPEN_POSITIONS / process.env.TRADE_POSITIONS_SIDE_BALANCE == true ? 2 : 1); + const tradesForSide = Array.from(tradesHistory.values()).filter(el => el.side == side).length; + if (tradesForSide > maxTradeForSide) { + logIT(chalk.redBright("scalp - Max {side} Positions Reached!")); + return; + } + //get current price var priceFetch = await linearClient.getTickers({symbol: pair}); var price = priceFetch.result[0].last_price; diff --git a/example.env b/example.env index 148733b..0c95410 100644 --- a/example.env +++ b/example.env @@ -54,3 +54,4 @@ DCA_SAFETY_ORDERS = 2 #WORK WITH DCA_AVERAGE_ENTRIES DCA_VOLUME_SCALE = 1.3 #WORK WITH DCA_AVERAGE_ENTRIES DCA_PRICE_DEVIATION_PRC = 2 #WORK WITH DCA_AVERAGE_ENTRIES PAUSED_LIST = NOTHING #Add active trades that you want to manually set a take profit +TRADE_POSITIONS_SIDE_BALANCE = false # keeps the number of open long and short positions balanced From d77e1d287ebf343beaeecad1934a51296157b035 Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Wed, 27 Sep 2023 14:02:22 +0200 Subject: [PATCH 18/23] app: fix orphan orders handling Remove orphan order handling from main loop as sometimes happens that new order is placed but not available by bybit api and new order are prematurely cancelled. Orphan order are handled only at start and when the order is closed. --- app.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/app.js b/app.js index 0d56943..c55350e 100644 --- a/app.js +++ b/app.js @@ -1284,7 +1284,7 @@ async function getNewOrders() { async function closeOrphanOrders(openPositionsList, openOrders) { const orphans = openOrders.filter(el => openPositionsList.find( el2 => el2.symbol == el.symbol) == undefined); - if(orphans != undefined) { + if(orphans.length > 0) { orphans.forEach(async el => { let res = await cancelOrder(linearClient, el.symbol); if (res.ret_msg != "OK") @@ -1292,6 +1292,8 @@ async function closeOrphanOrders(openPositionsList, openOrders) { else logIT(`closeQuitPosition - successfully cancel orphan orders for ${el.symbol}`); }); + } else { + logIT(`closeQuitPosition - Orphan orders not found`); } } @@ -1872,6 +1874,16 @@ async function main() { logIT("Updating settings.json with smart settings"); await createSettings(); } + + // Only needed with DCA_AVERAGE_ENTRIES features on. + // Check if there are orphan limit orders created by DCA. + // Happens when the trade was closed when the app is not running. + if (process.env.USE_DCA_FEATURE == "true" && process.env.DCA_TYPE == "DCA_AVERAGE_ENTRIES") { + const openPositionList = await checkOpenPositions(); + const newOrders = await getNewOrders(); + await closeOrphanOrders(openPositionList, newOrders); + } + } catch (err) { logIT(chalk.red("Error in main()")); @@ -1898,15 +1910,10 @@ async function main() { while (true) { try { cachedLinearClient.invalidate(); + await checkOpenPositions(); await getBalance(); await updateSettings(); - const newOrders = await getNewOrders(); - const openPositionList = await checkOpenPositions(); - //only needed with DCA_AVERAGE_ENTRIES features on. - if (process.env.USE_DCA_FEATURE == "true" && process.env.DCA_TYPE == "DCA_AVERAGE_ENTRIES") { - await closeOrphanOrders(openPositionList, newOrders); - } await sleep(cachedLinearClient.getRateLimit()); } catch (e) { console.log(e); From fcce816f5ee365cad9d6066f78a7b3980af409ab Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Wed, 27 Sep 2023 18:36:34 +0200 Subject: [PATCH 19/23] Trace Position: fix missing fields --- app.js | 4 +++- example.env | 2 +- position.js | 17 +++++++++++------ utils.js | 2 +- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/app.js b/app.js index c55350e..ca9dffd 100644 --- a/app.js +++ b/app.js @@ -273,11 +273,13 @@ function wsHandleOrder(data) { // verify that it's starts order not dca if (trade_info._start_price === 0) { trade_info._start_price = order.last_exec_price; + // TODO: Handle new order should be called here to have price field with a value + trade_info._averaged_price = order.last_exec_price; traceTrade("start", trade_info, traceTradeFields); } else { // handle fill of DCA orders when DCA type is DCA_AVERAGE_ENTRIES if (process.env.USE_DCA_FEATURE == "true" && process.env.DCA_TYPE == "DCA_AVERAGE_ENTRIES") { - trade_info._dca_count++; + incrementPosition(trade_info, order); traceTrade("dca", trade_info, traceTradeFields); } } diff --git a/example.env b/example.env index 0c95410..4a022a4 100644 --- a/example.env +++ b/example.env @@ -46,7 +46,7 @@ CHECK_FOR_UPDATE = false TIMEOUT_BLACKLIST_FOR_BIG_DRAWDOWN = false DRAWDOWN_THRESHOLD = 3.5 TRACE_TRADES = OFF # verbosity: OFF, ON, MAX -TRACE_TRADES_FIELDS = symbol, size, side, sizeUSD, pnl, liq, price, stop_loss, take_profit, fee, _max_loss, _liquidity_trigger, _dca_count, _start_price, _start_time, _end_time, _roi +TRACE_TRADES_FIELDS = symbol, size, side, sizeUSD, pnl, liq, price, stop_loss, take_profit, fee, _max_loss, _liquidity_trigger, _dca_count, _start_price, _averaged_price, _start_time, _update_time, _roi PLACE_ORDERS_SEQUENTIALLY = false LOG_LEVEL = INFO DCA_TYPE = DCA_LIQUIDATIONS #add size on new liquidations. Instead DCA_AVERAGE_ENTRIES add limits orders (read doc). diff --git a/position.js b/position.js index b1aa4b1..63e4b87 100644 --- a/position.js +++ b/position.js @@ -1,21 +1,25 @@ export function incrementPosition(position, order, aux = {}) { - let updated_position = position; - position.size = order.qty; + const tmp_position_size = position.size; + position._dca_count++; + position._update_time = order.update_time; + position.size += order.qty; position.price = order.last_exec_price; + position._averaged_price = (position.price * tmp_position_size + order.qty * order.last_exec_price) / position.size; const usdValue = position.price * position.size / process.env.LEVERAGE; position.sizeUSD = usdValue.toFixed(3); + // TODO: consider cum_exec_fee, Object.entries(aux).forEach( ([k, v]) => position[k] = v ); }; export function closePosition(position, order) { let updated_position = position; - position._end_time= order.create_time; + position._update_time= order.update_time; position.price = order.last_exec_price; const usdValue = position.price * position.size / process.env.LEVERAGE; position.sizeUSD = usdValue.toFixed(3); - position._roi = position.side == "Buy" ? (position.price - position._start_price) / position._start_price : - (position._start_price - position.price) / position._start_price; + position._roi = position.side == "Buy" ? (position.price - position._averaged_price) / position._start_price : + (position._averaged_price - position.price) / position._start_price; }; export function updatePosition(position, obj = {}) { @@ -39,8 +43,9 @@ export function newPosition(order) { "_liquidity_trigger": order.liquidity_trigger, "_dca_count" : 0, "_start_price" : order.last_exec_price, + "_averaged_price" : order.last_exec_price, "_start_time" : order.created_time, - "_end_time": undefined, + "_update_time": undefined, "_roi": undefined, }; const usdValue = position.price * position.size / process.env.LEVERAGE; diff --git a/utils.js b/utils.js index 19202ff..f579bc2 100644 --- a/utils.js +++ b/utils.js @@ -44,7 +44,7 @@ export function traceTrade(step, obj, fields, format = "JSON") { export function traceTradeAsJSON(step, obj, fields) { //Object.entries(obj).forEach( ([k, v]) => position[k] = v ); - let tradeObj = {'step': step, ...obj}; + let tradeObj = {'date': new Date().toISOString(), 'step': step, ...obj}; let records = []; if (fs.existsSync("trades.json")) { From b235222e03413b5eae6f58b1c6b76ec3b4c6f11e Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Thu, 28 Sep 2023 09:44:38 +0200 Subject: [PATCH 20/23] App: remove settings files from repo Settings files are created during execution and should be removed from repo --- account.json | 4 - min_order_sizes.json | 1208 ----------------------- research.json | 1025 -------------------- settings.json | 2171 ------------------------------------------ 4 files changed, 4408 deletions(-) delete mode 100644 account.json delete mode 100644 min_order_sizes.json delete mode 100644 research.json delete mode 100644 settings.json diff --git a/account.json b/account.json deleted file mode 100644 index 57a2e31..0000000 --- a/account.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "startingBalance": 0, - "config_set": false -} \ No newline at end of file diff --git a/min_order_sizes.json b/min_order_sizes.json deleted file mode 100644 index 22e3808..0000000 --- a/min_order_sizes.json +++ /dev/null @@ -1,1208 +0,0 @@ -[ - { - "pair": "1INCHUSDT", - "minOrderSize": 8.007715660510806, - "maxPositionSize": 95.09162346856583, - "tickSize": "0.0005" - }, - { - "pair": "AAVEUSDT", - "minOrderSize": 0.055941906000549005, - "maxPositionSize": 0.6643101337565194, - "tickSize": "0.01" - }, - { - "pair": "ACHUSDT", - "minOrderSize": 118.80745244993734, - "maxPositionSize": 1410.838497843006, - "tickSize": "0.000001" - }, - { - "pair": "ADAUSDT", - "minOrderSize": 10.581327287642784, - "maxPositionSize": 125.65326154075807, - "tickSize": "0.0001" - }, - { - "pair": "AGIXUSDT", - "minOrderSize": 9.060636370345671, - "maxPositionSize": 107.59505689785485, - "tickSize": "0.00005" - }, - { - "pair": "AGLDUSDT", - "minOrderSize": 9.990017821568628, - "maxPositionSize": 118.63146163112746, - "tickSize": "0.0001" - }, - { - "pair": "AKROUSDT", - "minOrderSize": 918.8294119026151, - "maxPositionSize": 10911.099266343554, - "tickSize": "0.000001" - }, - { - "pair": "ALGOUSDT", - "minOrderSize": 18.88752210936052, - "maxPositionSize": 224.28932504865622, - "tickSize": "0.0001" - }, - { - "pair": "ALICEUSDT", - "minOrderSize": 2.6467060202597406, - "maxPositionSize": 31.429633990584417, - "tickSize": "0.005" - }, - { - "pair": "ALPHAUSDT", - "minOrderSize": 38.18198848899298, - "maxPositionSize": 453.4111133067916, - "tickSize": "0.00005" - }, - { - "pair": "ANKRUSDT", - "minOrderSize": 124.15252120621385, - "maxPositionSize": 1474.3111893237894, - "tickSize": "0.00001" - }, - { - "pair": "ANTUSDT", - "minOrderSize": 1.6636437841632654, - "maxPositionSize": 19.755769936938776, - "tickSize": "0.005" - }, - { - "pair": "APEUSDT", - "minOrderSize": 0.9699969707758211, - "maxPositionSize": 11.518714027962876, - "tickSize": "0.001" - }, - { - "pair": "API3USDT", - "minOrderSize": 2.5911807191354104, - "maxPositionSize": 30.770271039733, - "tickSize": "0.001" - }, - { - "pair": "APTUSDT", - "minOrderSize": 0.34789409962444523, - "maxPositionSize": 4.1312424330402875, - "tickSize": "0.0005" - }, - { - "pair": "ARBUSDT", - "minOrderSize": 3.240005779968204, - "maxPositionSize": 38.47506863712242, - "tickSize": "0.0005" - }, - { - "pair": "ARPAUSDT", - "minOrderSize": 98.7624732541798, - "maxPositionSize": 1172.8043698933852, - "tickSize": "0.00001" - }, - { - "pair": "ARUSDT", - "minOrderSize": 0.4867360008598042, - "maxPositionSize": 5.779990010210174, - "tickSize": "0.001" - }, - { - "pair": "ASTRUSDT", - "minOrderSize": 64.18783104251969, - "maxPositionSize": 762.2304936299213, - "tickSize": "0.000005" - }, - { - "pair": "ATOMUSDT", - "minOrderSize": 0.3576315935070633, - "maxPositionSize": 4.2468751728963765, - "tickSize": "0.001" - }, - { - "pair": "AUDIOUSDT", - "minOrderSize": 14.13779837391606, - "maxPositionSize": 167.88635569025325, - "tickSize": "0.0001" - }, - { - "pair": "AVAXUSDT", - "minOrderSize": 0.23533067385681294, - "maxPositionSize": 2.794551752049654, - "tickSize": "0.005" - }, - { - "pair": "AXSUSDT", - "minOrderSize": 0.4783952196244132, - "maxPositionSize": 5.680943233039907, - "tickSize": "0.001" - }, - { - "pair": "BAKEUSDT", - "minOrderSize": 21.97265375309973, - "maxPositionSize": 260.9252633180593, - "tickSize": "0.0005" - }, - { - "pair": "BALUSDT", - "minOrderSize": 0.5852013311127064, - "maxPositionSize": 6.949265806963389, - "tickSize": "0.005" - }, - { - "pair": "BANDUSDT", - "minOrderSize": 2.1703553094781687, - "maxPositionSize": 25.77296930005325, - "tickSize": "0.001" - }, - { - "pair": "BATUSDT", - "minOrderSize": 16.14228622257426, - "maxPositionSize": 191.68964889306932, - "tickSize": "0.0005" - }, - { - "pair": "BCHUSDT", - "minOrderSize": 0.03292348361227787, - "maxPositionSize": 0.39096636789579975, - "tickSize": "0.05" - }, - { - "pair": "BELUSDT", - "minOrderSize": 6.690622572554171, - "maxPositionSize": 79.45114304908077, - "tickSize": "0.0001" - }, - { - "pair": "BICOUSDT", - "minOrderSize": 10.872038600160042, - "maxPositionSize": 129.10545837690051, - "tickSize": "0.0001" - }, - { - "pair": "BITUSDT", - "minOrderSize": 7.608600468919173, - "maxPositionSize": 90.35213056841516, - "tickSize": "0.0001" - }, - { - "pair": "BLURUSDT", - "minOrderSize": 7.641408457442821, - "maxPositionSize": 90.74172543213349, - "tickSize": "0.0001" - }, - { - "pair": "BLZUSDT", - "minOrderSize": 49.32745094033645, - "maxPositionSize": 585.7634799164954, - "tickSize": "0.00001" - }, - { - "pair": "BNBUSDT", - "minOrderSize": 0.012805300883443293, - "maxPositionSize": 0.15206294799088912, - "tickSize": "0.05" - }, - { - "pair": "BNXUSDT", - "minOrderSize": 7.03959805043178, - "maxPositionSize": 83.59522684887739, - "tickSize": "0.0005" - }, - { - "pair": "BOBAUSDT", - "minOrderSize": 17.179883124130665, - "maxPositionSize": 204.01111209905167, - "tickSize": "0.00005" - }, - { - "pair": "BSVUSDT", - "minOrderSize": 0.1127504086085754, - "maxPositionSize": 1.338911102226833, - "tickSize": "0.05" - }, - { - "pair": "BSWUSDT", - "minOrderSize": 21.831426198178896, - "maxPositionSize": 259.24818610337445, - "tickSize": "0.0001" - }, - { - "pair": "BTCUSDT", - "minOrderSize": 0.001, - "maxPositionSize": 0.0017033353396877797, - "tickSize": "0.10" - }, - { - "pair": "BUSDUSDT", - "minOrderSize": 4.080824260312375, - "maxPositionSize": 48.45978809120946, - "tickSize": "0.0001" - }, - { - "pair": "C98USDT", - "minOrderSize": 16.602555076171083, - "maxPositionSize": 197.15534152953157, - "tickSize": "0.0005" - }, - { - "pair": "CEEKUSDT", - "minOrderSize": 45.8226787093873, - "maxPositionSize": 544.1443096739742, - "tickSize": "0.00005" - }, - { - "pair": "CELOUSDT", - "minOrderSize": 6.574076243870969, - "maxPositionSize": 78.06715539596775, - "tickSize": "0.001" - }, - { - "pair": "CELRUSDT", - "minOrderSize": 164.68393014949496, - "maxPositionSize": 1955.6216705252527, - "tickSize": "0.00005" - }, - { - "pair": "CFXUSDT", - "minOrderSize": 10.508759014077246, - "maxPositionSize": 124.79151329216731, - "tickSize": "0.00001" - }, - { - "pair": "CHRUSDT", - "minOrderSize": 25.78069115243517, - "maxPositionSize": 306.14570743516765, - "tickSize": "0.0001" - }, - { - "pair": "CHZUSDT", - "minOrderSize": 34.30915211447812, - "maxPositionSize": 407.4211813594277, - "tickSize": "0.00005" - }, - { - "pair": "CKBUSDT", - "minOrderSize": 786.8585465637067, - "maxPositionSize": 9343.945240444016, - "tickSize": "0.000005" - }, - { - "pair": "COCOSUSDT", - "minOrderSize": 2.72364000748413, - "maxPositionSize": 32.34322508887404, - "tickSize": "0.0005" - }, - { - "pair": "COMPUSDT", - "minOrderSize": 0.09369947749885058, - "maxPositionSize": 1.1126812952988507, - "tickSize": "0.05" - }, - { - "pair": "COREUSDT", - "minOrderSize": 2.0689986148223354, - "maxPositionSize": 24.56935855101523, - "tickSize": "0.0005" - }, - { - "pair": "COTIUSDT", - "minOrderSize": 53.900122602486114, - "maxPositionSize": 640.0639559045226, - "tickSize": "0.00001" - }, - { - "pair": "CREAMUSDT", - "minOrderSize": 0.30102860200886267, - "maxPositionSize": 3.5747146488552444, - "tickSize": "0.001" - }, - { - "pair": "CROUSDT", - "minOrderSize": 59.37257496285506, - "maxPositionSize": 705.0493276839039, - "tickSize": "0.00005" - }, - { - "pair": "CRVUSDT", - "minOrderSize": 4.259067159038663, - "maxPositionSize": 50.57642251358413, - "tickSize": "0.001" - }, - { - "pair": "CTCUSDT", - "minOrderSize": 11.20992098789879, - "maxPositionSize": 133.11781173129816, - "tickSize": "0.00005" - }, - { - "pair": "CTKUSDT", - "minOrderSize": 5.248425535925831, - "maxPositionSize": 62.32505323911924, - "tickSize": "0.0001" - }, - { - "pair": "CTSIUSDT", - "minOrderSize": 28.061461419621345, - "maxPositionSize": 333.2298543580035, - "tickSize": "0.00005" - }, - { - "pair": "CVCUSDT", - "minOrderSize": 40.36770596414777, - "maxPositionSize": 479.36650832425477, - "tickSize": "0.00001" - }, - { - "pair": "CVXUSDT", - "minOrderSize": 0.7668724875258702, - "maxPositionSize": 9.106610789369709, - "tickSize": "0.005" - }, - { - "pair": "DARUSDT", - "minOrderSize": 23.492376202881847, - "maxPositionSize": 278.9719674092219, - "tickSize": "0.0005" - }, - { - "pair": "DASHUSDT", - "minOrderSize": 0.07039598050431779, - "maxPositionSize": 0.8359522684887738, - "tickSize": "0.05" - }, - { - "pair": "DENTUSDT", - "minOrderSize": 3802.1709619402986, - "maxPositionSize": 45150.78017304105, - "tickSize": "0.000001" - }, - { - "pair": "DGBUSDT", - "minOrderSize": 421.0668668595042, - "maxPositionSize": 5000.169043956613, - "tickSize": "0.00001" - }, - { - "pair": "DODOUSDT", - "minOrderSize": 22.885610731049972, - "maxPositionSize": 271.7666274312184, - "tickSize": "0.00005" - }, - { - "pair": "DOGEUSDT", - "minOrderSize": 53.38477107007204, - "maxPositionSize": 633.9441564571055, - "tickSize": "0.00001" - }, - { - "pair": "DOTUSDT", - "minOrderSize": 0.6508986380070266, - "maxPositionSize": 7.729421326333441, - "tickSize": "0.001" - }, - { - "pair": "DUSKUSDT", - "minOrderSize": 22.57881271438068, - "maxPositionSize": 268.1234009832706, - "tickSize": "0.00001" - }, - { - "pair": "DYDXUSDT", - "minOrderSize": 1.586581265550798, - "maxPositionSize": 18.840652528415728, - "tickSize": "0.001" - }, - { - "pair": "EGLDUSDT", - "minOrderSize": 0.09413226954272519, - "maxPositionSize": 1.1178207008198617, - "tickSize": "0.05" - }, - { - "pair": "ENJUSDT", - "minOrderSize": 10.358137919186786, - "maxPositionSize": 123.0028877903431, - "tickSize": "0.0005" - }, - { - "pair": "ENSUSDT", - "minOrderSize": 0.30281777646359587, - "maxPositionSize": 3.5959610955052006, - "tickSize": "0.01" - }, - { - "pair": "EOSUSDT", - "minOrderSize": 3.5535547264167398, - "maxPositionSize": 42.198462376198776, - "tickSize": "0.001" - }, - { - "pair": "ETCUSDT", - "minOrderSize": 0.1947409111896799, - "maxPositionSize": 2.3125483203774486, - "tickSize": "0.005" - }, - { - "pair": "ETHUSDT", - "minOrderSize": 0.01, - "maxPositionSize": 0.026609657409769373, - "tickSize": "0.01" - }, - { - "pair": "ETHWUSDT", - "minOrderSize": 1.1872785526361784, - "maxPositionSize": 14.098932812554619, - "tickSize": "0.001" - }, - { - "pair": "FETUSDT", - "minOrderSize": 11.030926309066308, - "maxPositionSize": 130.9922499201624, - "tickSize": "0.00005" - }, - { - "pair": "FILUSDT", - "minOrderSize": 0.7048119092512537, - "maxPositionSize": 8.369641422358638, - "tickSize": "0.001" - }, - { - "pair": "FITFIUSDT", - "minOrderSize": 303.0429197918216, - "maxPositionSize": 3598.634672527882, - "tickSize": "0.00005" - }, - { - "pair": "FLMUSDT", - "minOrderSize": 42.65753292726322, - "maxPositionSize": 506.5582035112507, - "tickSize": "0.00005" - }, - { - "pair": "FLOWUSDT", - "minOrderSize": 4.163357784678244, - "maxPositionSize": 49.439873693054146, - "tickSize": "0.0005" - }, - { - "pair": "FLRUSDT", - "minOrderSize": 98.42857452789181, - "maxPositionSize": 1168.8393225187153, - "tickSize": "0.00001" - }, - { - "pair": "FTMUSDT", - "minOrderSize": 8.864565618094824, - "maxPositionSize": 105.26671671487605, - "tickSize": "0.0001" - }, - { - "pair": "FXSUSDT", - "minOrderSize": 0.4603486866049244, - "maxPositionSize": 5.466640653433478, - "tickSize": "0.0005" - }, - { - "pair": "GALAUSDT", - "minOrderSize": 98.81035808969698, - "maxPositionSize": 1173.3730023151516, - "tickSize": "0.00001" - }, - { - "pair": "GALUSDT", - "minOrderSize": 2.289203746812693, - "maxPositionSize": 27.184294493400735, - "tickSize": "0.0005" - }, - { - "pair": "GFTUSDT", - "minOrderSize": 79.06745433947624, - "maxPositionSize": 938.9260202812804, - "tickSize": "0.00005" - }, - { - "pair": "GLMRUSDT", - "minOrderSize": 10.905491026622073, - "maxPositionSize": 129.50270594113712, - "tickSize": "0.00005" - }, - { - "pair": "GMTUSDT", - "minOrderSize": 10.411053055427843, - "maxPositionSize": 123.63125503320562, - "tickSize": "0.0001" - }, - { - "pair": "GMXUSDT", - "minOrderSize": 0.05245386102824787, - "maxPositionSize": 0.6228895997104434, - "tickSize": "0.005" - }, - { - "pair": "GPTUSDT", - "minOrderSize": 45.541086829050286, - "maxPositionSize": 540.8004060949722, - "tickSize": "0.00005" - }, - { - "pair": "GRTUSDT", - "minOrderSize": 27.439930464521343, - "maxPositionSize": 325.8491742661909, - "tickSize": "0.00001" - }, - { - "pair": "GTCUSDT", - "minOrderSize": 2.1339933357068066, - "maxPositionSize": 25.34117086151833, - "tickSize": "0.005" - }, - { - "pair": "HBARUSDT", - "minOrderSize": 66.9062257255417, - "maxPositionSize": 794.5114304908077, - "tickSize": "0.00001" - }, - { - "pair": "HFTUSDT", - "minOrderSize": 6.519397426743443, - "maxPositionSize": 77.41784444257839, - "tickSize": "0.0001" - }, - { - "pair": "HIGHUSDT", - "minOrderSize": 1.9235145215667768, - "maxPositionSize": 22.841734943605477, - "tickSize": "0.0005" - }, - { - "pair": "HNTUSDT", - "minOrderSize": 2.9557123068890503, - "maxPositionSize": 35.09908364430747, - "tickSize": "0.001" - }, - { - "pair": "HOOKUSDT", - "minOrderSize": 2.096670406995885, - "maxPositionSize": 24.897961083076137, - "tickSize": "0.0005" - }, - { - "pair": "HOTUSDT", - "minOrderSize": 2202.0136527282552, - "maxPositionSize": 26148.91212614803, - "tickSize": "0.000001" - }, - { - "pair": "ICPUSDT", - "minOrderSize": 0.8072741673994851, - "maxPositionSize": 9.586380737868884, - "tickSize": "0.001" - }, - { - "pair": "ICXUSDT", - "minOrderSize": 19.144796952559886, - "maxPositionSize": 227.3444638116487, - "tickSize": "0.0001" - }, - { - "pair": "IDUSDT", - "minOrderSize": 8.464182891080887, - "maxPositionSize": 100.51217183158553, - "tickSize": "0.00005" - }, - { - "pair": "ILVUSDT", - "minOrderSize": 0.06805689215561864, - "maxPositionSize": 0.8081755943479714, - "tickSize": "0.005" - }, - { - "pair": "IMXUSDT", - "minOrderSize": 3.5091926570813605, - "maxPositionSize": 41.671662802841155, - "tickSize": "0.0001" - }, - { - "pair": "INJUSDT", - "minOrderSize": 0.9366717847179135, - "maxPositionSize": 11.122977443525224, - "tickSize": "0.0005" - }, - { - "pair": "IOSTUSDT", - "minOrderSize": 390.97623704556355, - "maxPositionSize": 4642.842814916067, - "tickSize": "0.000001" - }, - { - "pair": "IOTAUSDT", - "minOrderSize": 19.36307492256532, - "maxPositionSize": 229.93651470546322, - "tickSize": "0.0005" - }, - { - "pair": "IOTXUSDT", - "minOrderSize": 157.0684882928709, - "maxPositionSize": 1865.1882984778422, - "tickSize": "0.00005" - }, - { - "pair": "JASMYUSDT", - "minOrderSize": 861.5360962164448, - "maxPositionSize": 10230.741142570281, - "tickSize": "0.000001" - }, - { - "pair": "JOEUSDT", - "minOrderSize": 7.629250858586804, - "maxPositionSize": 90.59735394571831, - "tickSize": "0.00005" - }, - { - "pair": "JSTUSDT", - "minOrderSize": 157.85930562354764, - "maxPositionSize": 1874.5792542796285, - "tickSize": "0.00001" - }, - { - "pair": "KAVAUSDT", - "minOrderSize": 4.51676337677305, - "maxPositionSize": 53.636565099179975, - "tickSize": "0.0001" - }, - { - "pair": "KDAUSDT", - "minOrderSize": 4.232530915057113, - "maxPositionSize": 50.26130461630323, - "tickSize": "0.0001" - }, - { - "pair": "KLAYUSDT", - "minOrderSize": 17.27087826779661, - "maxPositionSize": 205.09167943008478, - "tickSize": "0.0005" - }, - { - "pair": "KNCUSDT", - "minOrderSize": 5.753708739695088, - "maxPositionSize": 68.32529128387917, - "tickSize": "0.0001" - }, - { - "pair": "KSMUSDT", - "minOrderSize": 0.11780136621965319, - "maxPositionSize": 1.3988912238583817, - "tickSize": "0.05" - }, - { - "pair": "LDOUSDT", - "minOrderSize": 1.6877545636438924, - "maxPositionSize": 20.042085443271223, - "tickSize": "0.0005" - }, - { - "pair": "LINAUSDT", - "minOrderSize": 342.2273107640638, - "maxPositionSize": 4063.949315323258, - "tickSize": "0.00001" - }, - { - "pair": "LINKUSDT", - "minOrderSize": 0.5581932718707204, - "maxPositionSize": 6.6285451034648055, - "tickSize": "0.001" - }, - { - "pair": "LITUSDT", - "minOrderSize": 3.8781420277830643, - "maxPositionSize": 46.052936579923895, - "tickSize": "0.001" - }, - { - "pair": "LOOKSUSDT", - "minOrderSize": 28.754337010229282, - "maxPositionSize": 341.4577519964728, - "tickSize": "0.00005" - }, - { - "pair": "LPTUSDT", - "minOrderSize": 0.5883266846420324, - "maxPositionSize": 6.986379380124134, - "tickSize": "0.001" - }, - { - "pair": "LQTYUSDT", - "minOrderSize": 1.7955626745374451, - "maxPositionSize": 21.322306760132157, - "tickSize": "0.0005" - }, - { - "pair": "LRCUSDT", - "minOrderSize": 11.130331161114146, - "maxPositionSize": 132.17268253823048, - "tickSize": "0.0001" - }, - { - "pair": "LTCUSDT", - "minOrderSize": 0.1, - "maxPositionSize": 0.5239406402413943, - "tickSize": "0.01" - }, - { - "pair": "LUNA2USDT", - "minOrderSize": 3.1185365502677893, - "maxPositionSize": 37.03262153443, - "tickSize": "0.001" - }, - { - "pair": "MAGICUSDT", - "minOrderSize": 2.811566028281714, - "maxPositionSize": 33.38734658584535, - "tickSize": "0.0001" - }, - { - "pair": "MANAUSDT", - "minOrderSize": 6.806825770207081, - "maxPositionSize": 80.8310560212091, - "tickSize": "0.0001" - }, - { - "pair": "MASKUSDT", - "minOrderSize": 0.5907140972753623, - "maxPositionSize": 7.014729905144927, - "tickSize": "0.001" - }, - { - "pair": "MATICUSDT", - "minOrderSize": 3.576002168099667, - "maxPositionSize": 42.46502574618355, - "tickSize": "0.0001" - }, - { - "pair": "MINAUSDT", - "minOrderSize": 5.243699049530426, - "maxPositionSize": 62.26892621317382, - "tickSize": "0.0001" - }, - { - "pair": "MKRUSDT", - "minOrderSize": 0.005894327217932032, - "maxPositionSize": 0.06999513571294289, - "tickSize": "0.5" - }, - { - "pair": "MTLUSDT", - "minOrderSize": 3.432937986355597, - "maxPositionSize": 40.76613858797272, - "tickSize": "0.0001" - }, - { - "pair": "NEARUSDT", - "minOrderSize": 2.0934397900359527, - "maxPositionSize": 24.85959750667694, - "tickSize": "0.001" - }, - { - "pair": "NEOUSDT", - "minOrderSize": 0.3144520345008487, - "maxPositionSize": 3.734117909697578, - "tickSize": "0.001" - }, - { - "pair": "NKNUSDT", - "minOrderSize": 38.888725037687244, - "maxPositionSize": 461.80360982253603, - "tickSize": "0.00001" - }, - { - "pair": "OCEANUSDT", - "minOrderSize": 11.439593800729723, - "maxPositionSize": 135.84517638366546, - "tickSize": "0.0001" - }, - { - "pair": "OGNUSDT", - "minOrderSize": 35.848085058927005, - "maxPositionSize": 425.6960100747582, - "tickSize": "0.0001" - }, - { - "pair": "OMGUSDT", - "minOrderSize": 2.270711571699165, - "maxPositionSize": 26.964699913927582, - "tickSize": "0.001" - }, - { - "pair": "ONEUSDT", - "minOrderSize": 196.90469909178745, - "maxPositionSize": 2338.243301714976, - "tickSize": "0.00001" - }, - { - "pair": "ONTUSDT", - "minOrderSize": 17.66765180407456, - "maxPositionSize": 209.8033651733854, - "tickSize": "0.00005" - }, - { - "pair": "OPUSDT", - "minOrderSize": 1.7894925895420821, - "maxPositionSize": 21.250224500812223, - "tickSize": "0.0001" - }, - { - "pair": "PAXGUSDT", - "minOrderSize": 0.0020554348316691885, - "maxPositionSize": 0.02440828862607161, - "tickSize": "1" - }, - { - "pair": "PEOPLEUSDT", - "minOrderSize": 179.55626745374448, - "maxPositionSize": 2132.230676013216, - "tickSize": "0.00005" - }, - { - "pair": "QTUMUSDT", - "minOrderSize": 1.2857814735646689, - "maxPositionSize": 15.268654998580445, - "tickSize": "0.005" - }, - { - "pair": "REEFUSDT", - "minOrderSize": 1535.189179359699, - "maxPositionSize": 18230.371504896426, - "tickSize": "0.000005" - }, - { - "pair": "RENUSDT", - "minOrderSize": 38.24289051604429, - "maxPositionSize": 454.13432487802595, - "tickSize": "0.00001" - }, - { - "pair": "REQUSDT", - "minOrderSize": 41.65059545473125, - "maxPositionSize": 494.60082102493357, - "tickSize": "0.00001" - }, - { - "pair": "RLCUSDT", - "minOrderSize": 2.2988873498025946, - "maxPositionSize": 27.299287278905812, - "tickSize": "0.0005" - }, - { - "pair": "RNDRUSDT", - "minOrderSize": 3.3219994875096788, - "maxPositionSize": 39.448743914177435, - "tickSize": "0.00005" - }, - { - "pair": "ROSEUSDT", - "minOrderSize": 70.0451498745489, - "maxPositionSize": 831.7861547602682, - "tickSize": "0.00001" - }, - { - "pair": "RPLUSDT", - "minOrderSize": 0.08803298641900649, - "maxPositionSize": 1.045391713725702, - "tickSize": "0.005" - }, - { - "pair": "RSRUSDT", - "minOrderSize": 1031.3581151821863, - "maxPositionSize": 12247.377617788463, - "tickSize": "0.000001" - }, - { - "pair": "RSS3USDT", - "minOrderSize": 24.004283104829213, - "maxPositionSize": 285.0508618698469, - "tickSize": "0.00005" - }, - { - "pair": "RUNEUSDT", - "minOrderSize": 2.9113766222857147, - "maxPositionSize": 34.572597389642866, - "tickSize": "0.001" - }, - { - "pair": "RVNUSDT", - "minOrderSize": 159.21590903125, - "maxPositionSize": 1890.688919746094, - "tickSize": "0.00005" - }, - { - "pair": "SANDUSDT", - "minOrderSize": 6.3271146712201185, - "maxPositionSize": 75.1344867207389, - "tickSize": "0.0001" - }, - { - "pair": "SCRTUSDT", - "minOrderSize": 6.309484939938081, - "maxPositionSize": 74.9251336617647, - "tickSize": "0.0001" - }, - { - "pair": "SCUSDT", - "minOrderSize": 1042.9701308085978, - "maxPositionSize": 12385.2703033521, - "tickSize": "0.000001" - }, - { - "pair": "SFPUSDT", - "minOrderSize": 8.826174255521872, - "maxPositionSize": 104.81081928432224, - "tickSize": "0.0001" - }, - { - "pair": "SKLUSDT", - "minOrderSize": 100.9142676702154, - "maxPositionSize": 1198.356928583808, - "tickSize": "0.00001" - }, - { - "pair": "SLPUSDT", - "minOrderSize": 1515.214598959108, - "maxPositionSize": 17993.173362639405, - "tickSize": "0.00001" - }, - { - "pair": "SNXUSDT", - "minOrderSize": 1.636918582811245, - "maxPositionSize": 19.438408170883534, - "tickSize": "0.001" - }, - { - "pair": "SOLUSDT", - "minOrderSize": 0.1909188847814886, - "maxPositionSize": 2.267161756780177, - "tickSize": "0.001" - }, - { - "pair": "SPELLUSDT", - "minOrderSize": 5907.140972753624, - "maxPositionSize": 70147.29905144928, - "tickSize": "0.000001" - }, - { - "pair": "SSVUSDT", - "minOrderSize": 0.10690956776918034, - "maxPositionSize": 1.2695511172590166, - "tickSize": "0.005" - }, - { - "pair": "STGUSDT", - "minOrderSize": 6.1090037038369305, - "maxPositionSize": 72.54441898306355, - "tickSize": "0.0001" - }, - { - "pair": "STMXUSDT", - "minOrderSize": 735.063529522092, - "maxPositionSize": 8728.879413074845, - "tickSize": "0.000005" - }, - { - "pair": "STORJUSDT", - "minOrderSize": 11.417163224649862, - "maxPositionSize": 135.57881329271711, - "tickSize": "0.0005" - }, - { - "pair": "STXUSDT", - "minOrderSize": 3.963945802285436, - "maxPositionSize": 47.07185640213956, - "tickSize": "0.00005" - }, - { - "pair": "SUNUSDT", - "minOrderSize": 648.5166700397773, - "maxPositionSize": 7701.135456722355, - "tickSize": "0.000005" - }, - { - "pair": "SUSHIUSDT", - "minOrderSize": 3.798627466169618, - "maxPositionSize": 45.10870116076422, - "tickSize": "0.001" - }, - { - "pair": "SWEATUSDT", - "minOrderSize": 456.9425191928251, - "maxPositionSize": 5426.192415414798, - "tickSize": "0.00001" - }, - { - "pair": "SXPUSDT", - "minOrderSize": 12.618969879876161, - "maxPositionSize": 149.8502673235294, - "tickSize": "0.0005" - }, - { - "pair": "THETAUSDT", - "minOrderSize": 3.9679977328660443, - "maxPositionSize": 47.11997307778428, - "tickSize": "0.0001" - }, - { - "pair": "TLMUSDT", - "minOrderSize": 208.00853642255677, - "maxPositionSize": 2470.101370017862, - "tickSize": "0.000005" - }, - { - "pair": "TOMOUSDT", - "minOrderSize": 6.2418488073506895, - "maxPositionSize": 74.12195458728944, - "tickSize": "0.0005" - }, - { - "pair": "TRBUSDT", - "minOrderSize": 0.28354276669217393, - "maxPositionSize": 3.3670703544695657, - "tickSize": "0.005" - }, - { - "pair": "TRUUSDT", - "minOrderSize": 51.692165772986684, - "maxPositionSize": 613.844468554217, - "tickSize": "0.00005" - }, - { - "pair": "TRXUSDT", - "minOrderSize": 62.57180336505987, - "maxPositionSize": 743.040164960086, - "tickSize": "0.00001" - }, - { - "pair": "TUSDT", - "minOrderSize": 98.57139712696494, - "maxPositionSize": 1170.5353408827089, - "tickSize": "0.00001" - }, - { - "pair": "TWTUSDT", - "minOrderSize": 3.5243642638996975, - "maxPositionSize": 41.85182563380891, - "tickSize": "0.0005" - }, - { - "pair": "UNFIUSDT", - "minOrderSize": 0.832756618898764, - "maxPositionSize": 9.888984849422823, - "tickSize": "0.0005" - }, - { - "pair": "UNIUSDT", - "minOrderSize": 0.6795477277759253, - "maxPositionSize": 8.069629267339113, - "tickSize": "0.001" - }, - { - "pair": "USDCUSDT", - "minOrderSize": 4.078782418893225, - "maxPositionSize": 48.43554122435705, - "tickSize": "0.0001" - }, - { - "pair": "VETUSDT", - "minOrderSize": 176.06597283801298, - "maxPositionSize": 2090.7834274514043, - "tickSize": "0.00005" - }, - { - "pair": "WAVESUSDT", - "minOrderSize": 1.901528934546303, - "maxPositionSize": 22.580656097737346, - "tickSize": "0.0005" - }, - { - "pair": "WOOUSDT", - "minOrderSize": 20.009461321551303, - "maxPositionSize": 237.61235319342174, - "tickSize": "0.0001" - }, - { - "pair": "XCNUSDT", - "minOrderSize": 961.3036016981133, - "maxPositionSize": 11415.480270165097, - "tickSize": "0.00001" - }, - { - "pair": "XEMUSDT", - "minOrderSize": 102.92745634343434, - "maxPositionSize": 1222.2635440782828, - "tickSize": "0.0001" - }, - { - "pair": "XLMUSDT", - "minOrderSize": 38.41590265032988, - "maxPositionSize": 456.1888439726673, - "tickSize": "0.00005" - }, - { - "pair": "XMRUSDT", - "minOrderSize": 0.025854280185220426, - "maxPositionSize": 0.3070195771994926, - "tickSize": "0.05" - }, - { - "pair": "XNOUSDT", - "minOrderSize": 4.562264686814418, - "maxPositionSize": 54.176893155921206, - "tickSize": "0.0001" - }, - { - "pair": "XRPUSDT", - "minOrderSize": 7.07380644081916, - "maxPositionSize": 84.00145148472753, - "tickSize": "0.0001" - }, - { - "pair": "XTZUSDT", - "minOrderSize": 3.6134107014184402, - "maxPositionSize": 42.909252079343986, - "tickSize": "0.001" - }, - { - "pair": "YFIUSDT", - "minOrderSize": 0.00046449313631908835, - "maxPositionSize": 0.005515855993789174, - "tickSize": "5" - }, - { - "pair": "YGGUSDT", - "minOrderSize": 15.816559065580135, - "maxPositionSize": 187.8216389037641, - "tickSize": "0.0001" - }, - { - "pair": "ZECUSDT", - "minOrderSize": 0.10912790552074966, - "maxPositionSize": 1.2958938780589024, - "tickSize": "0.05" - }, - { - "pair": "ZENUSDT", - "minOrderSize": 0.3877404177321157, - "maxPositionSize": 4.604417460568874, - "tickSize": "0.001" - }, - { - "pair": "ZILUSDT", - "minOrderSize": 144.84460807391616, - "maxPositionSize": 1720.0297208777545, - "tickSize": "0.00001" - }, - { - "pair": "ZRXUSDT", - "minOrderSize": 17.652348511043744, - "maxPositionSize": 209.62163856864447, - "tickSize": "0.0001" - } -] \ No newline at end of file diff --git a/research.json b/research.json deleted file mode 100644 index 031841a..0000000 --- a/research.json +++ /dev/null @@ -1,1025 +0,0 @@ -{ - "data": [ - { - "long_price": 0.003698812926088466, - "name": "10000NFT", - "short_price": 0.00408816165515041 - }, - { - "long_price": 0.0004794590497472634, - "name": "1000BONK", - "short_price": 0.0005810794183249999 - }, - { - "long_price": 0.0005709526641, - "name": "1000BTT", - "short_price": 0.000631336040048636 - }, - { - "long_price": 0.03160453231463757, - "name": "1000FLOKI", - "short_price": 0.036718649313125 - }, - { - "long_price": 0.11540577520416, - "name": "1000LUNC", - "short_price": 0.12755375154144 - }, - { - "long_price": 0.028214345578250002, - "name": "1000XEC", - "short_price": 0.031184276691750005 - }, - { - "long_price": 0.4747207608, - "name": "1INCH", - "short_price": 0.5246913672 - }, - { - "long_price": 67.01257278499999, - "name": "AAVE", - "short_price": 75.1883884438604 - }, - { - "long_price": 0.03138163400801, - "name": "ACH", - "short_price": 0.03562260118813 - }, - { - "long_price": 0.3508514561375, - "name": "ADA", - "short_price": 0.38778318836250003 - }, - { - "long_price": 0.3923924220790475, - "name": "AGIX", - "short_price": 0.49071978915410003 - }, - { - "long_price": 0.3697404778517857, - "name": "AGLD", - "short_price": 0.4232510348625 - }, - { - "long_price": 0.004030766162052565, - "name": "AKRO", - "short_price": 0.0045902017728 - }, - { - "long_price": 0.19515736831249997, - "name": "ALGO", - "short_price": 0.22502826032604498 - }, - { - "long_price": 1.4050191230999998, - "name": "ALICE", - "short_price": 1.5591283379999998 - }, - { - "long_price": 0.09652832331099999, - "name": "ALPHA", - "short_price": 0.10783041756999999 - }, - { - "long_price": 0.03000525400215, - "name": "ANKR", - "short_price": 0.033693984701999996 - }, - { - "long_price": 2.2267579796000003, - "name": "ANT", - "short_price": 2.4745662480000004 - }, - { - "long_price": 3.89157180663, - "name": "APE", - "short_price": 4.30121094417 - }, - { - "long_price": 1.44447947944, - "name": "API3", - "short_price": 1.59796105377111 - }, - { - "long_price": 10.606702212002748, - "name": "APT", - "short_price": 12.474251481985 - }, - { - "long_price": 7.60873795275, - "name": "AR", - "short_price": 8.416580249999999 - }, - { - "long_price": 1.1266181148160248, - "name": "ARB", - "short_price": 1.30876619158831 - }, - { - "long_price": 0.037425581407500005, - "name": "ARPA", - "short_price": 0.0440563624875 - }, - { - "long_price": 0.057974764213635, - "name": "ASTR", - "short_price": 0.064077370972965 - }, - { - "long_price": 10.648183062974999, - "name": "ATOM", - "short_price": 11.769044438025 - }, - { - "long_price": 0.26378494888470005, - "name": "AUDIO", - "short_price": 0.30072072660000004 - }, - { - "long_price": 15.98862462651, - "name": "AVAX", - "short_price": 17.67163774509 - }, - { - "long_price": 7.833736689396625, - "name": "AXS", - "short_price": 8.658340551438375 - }, - { - "long_price": 0.16899167506249999, - "name": "BAKE", - "short_price": 0.18750684894999997 - }, - { - "long_price": 6.4733972050588005, - "name": "BAL", - "short_price": 7.227373251 - }, - { - "long_price": 1.68963622838505, - "name": "BAND", - "short_price": 1.86944600409 - }, - { - "long_price": 0.23253353109999997, - "name": "BAT", - "short_price": 0.2570107449 - }, - { - "long_price": 114.867034068, - "name": "BCH", - "short_price": 126.958300812 - }, - { - "long_price": 0.5481438448573749, - "name": "BEL", - "short_price": 0.6179107240355 - }, - { - "long_price": 0.34448339895627367, - "name": "BICO", - "short_price": 0.38426563000874997 - }, - { - "long_price": 0.522579767751184, - "name": "BIT", - "short_price": 2.0152688290758154 - }, - { - "long_price": 0.4899935595855486, - "name": "BLUR", - "short_price": 0.58353655056 - }, - { - "long_price": 0.074329201902, - "name": "BLZ", - "short_price": 0.08417653284000001 - }, - { - "long_price": 297.64659658825, - "name": "BNB", - "short_price": 328.97781728175005 - }, - { - "long_price": 0.525296457761075, - "name": "BNX", - "short_price": 0.6111434077375001 - }, - { - "long_price": 0.21973323266726102, - "name": "BOBA", - "short_price": 0.2474576162725 - }, - { - "long_price": 33.55851883508746, - "name": "BSV", - "short_price": 37.09099450193877 - }, - { - "long_price": 0.1689787304695225, - "name": "BSW", - "short_price": 0.18676596525578804 - }, - { - "long_price": 26161.988135429998, - "name": "BTC", - "short_price": 28915.88162337 - }, - { - "long_price": 0.21030991217135997, - "name": "C98", - "short_price": 0.24283334040000001 - }, - { - "long_price": 0.08224070605266603, - "name": "CEEK", - "short_price": 0.09089762247926247 - }, - { - "long_price": 0.56783058, - "name": "CELO", - "short_price": 0.62760222 - }, - { - "long_price": 0.0226288060385, - "name": "CELR", - "short_price": 0.027155368585000002 - }, - { - "long_price": 0.33530682634503, - "name": "CFX", - "short_price": 0.37060228174977006 - }, - { - "long_price": 0.14585218330000002, - "name": "CHR", - "short_price": 0.16245011966945 - }, - { - "long_price": 0.109717702024, - "name": "CHZ", - "short_price": 0.12126693381600001 - }, - { - "long_price": 0.004708968214222501, - "name": "CKB", - "short_price": 0.0061908559525 - }, - { - "long_price": 1.3429684624295621, - "name": "COCOS", - "short_price": 1.5002104583024998 - }, - { - "long_price": 39.859401624125, - "name": "COMP", - "short_price": 44.055128110875 - }, - { - "long_price": 1.8604767478011328, - "name": "CORE", - "short_price": 2.0563164054644103 - }, - { - "long_price": 0.06984527105724998, - "name": "COTI", - "short_price": 0.07719740485275 - }, - { - "long_price": 11.991535374199998, - "name": "CREAM", - "short_price": 13.865018066408723 - }, - { - "long_price": 0.06369184667492082, - "name": "CRO", - "short_price": 0.0707246273825 - }, - { - "long_price": 0.87728624, - "name": "CRV", - "short_price": 0.9696321600000001 - }, - { - "long_price": 0.33005804869479555, - "name": "CTC", - "short_price": 0.38080478269125 - }, - { - "long_price": 0.7256989940145001, - "name": "CTK", - "short_price": 0.8020883618055 - }, - { - "long_price": 0.13183666978125, - "name": "CTSI", - "short_price": 0.1459187900118375 - }, - { - "long_price": 0.09283842980754756, - "name": "CVC", - "short_price": 0.10382522215649999 - }, - { - "long_price": 4.832304969290999, - "name": "CVX", - "short_price": 5.340968650269 - }, - { - "long_price": 0.156654744925, - "name": "DAR", - "short_price": 0.1820373471 - }, - { - "long_price": 53.70466731724999, - "name": "DASH", - "short_price": 62.95728259999999 - }, - { - "long_price": 0.000982429656, - "name": "DENT", - "short_price": 0.00108701800272 - }, - { - "long_price": 0.008912555663, - "name": "DGB", - "short_price": 0.00988726475 - }, - { - "long_price": 0.16068333761819625, - "name": "DODO", - "short_price": 0.1808370609398925 - }, - { - "long_price": 0.070499250970325, - "name": "DOGE", - "short_price": 0.077920224756675 - }, - { - "long_price": 5.759608227375, - "name": "DOT", - "short_price": 6.365882777625 - }, - { - "long_price": 0.162040941799, - "name": "DUSK", - "short_price": 0.206594676845 - }, - { - "long_price": 2.35143781975, - "name": "DYDX", - "short_price": 2.59895759025 - }, - { - "long_price": 39.93330011392499, - "name": "EGLD", - "short_price": 44.13680538907499 - }, - { - "long_price": 0.356985522832, - "name": "ENJ", - "short_price": 0.39456294628800004 - }, - { - "long_price": 12.380842329975, - "name": "ENS", - "short_price": 13.746962634750002 - }, - { - "long_price": 1.05779415445, - "name": "EOS", - "short_price": 1.16914090755 - }, - { - "long_price": 19.2426332832, - "name": "ETC", - "short_price": 21.2681736288 - }, - { - "long_price": 1687.7685440774999, - "name": "ETH", - "short_price": 1865.4283908224998 - }, - { - "long_price": 3.2101400739991295, - "name": "ETHW", - "short_price": 3.5480495554727223 - }, - { - "long_price": 0.33418231301076, - "name": "FET", - "short_price": 0.3752268498504 - }, - { - "long_price": 5.269355515199998, - "name": "FIL", - "short_price": 5.8240245168 - }, - { - "long_price": 0.012506938641108571, - "name": "FITFI", - "short_price": 0.01438357464 - }, - { - "long_price": 0.08703737436, - "name": "FLM", - "short_price": 0.09619920324000002 - }, - { - "long_price": 0.8858437146, - "name": "FLOW", - "short_price": 0.9941158430699251 - }, - { - "long_price": 0.0363192256846715, - "name": "FLR", - "short_price": 0.04319956569886376 - }, - { - "long_price": 0.40939090593685007, - "name": "FTM", - "short_price": 0.46773487499924 - }, - { - "long_price": 7.6436909965477895, - "name": "FXS", - "short_price": 8.603484869616 - }, - { - "long_price": 1.6159479413025, - "name": "GAL", - "short_price": 1.8150260678549999 - }, - { - "long_price": 0.037239198219, - "name": "GALA", - "short_price": 0.041208828354 - }, - { - "long_price": 0.048313609810000005, - "name": "GFT", - "short_price": 0.05413681257621956 - }, - { - "long_price": 0.34308683746492685, - "name": "GLMR", - "short_price": 0.388863569405 - }, - { - "long_price": 0.35730970015275, - "name": "GMT", - "short_price": 0.39825624051474 - }, - { - "long_price": 70.13080090772655, - "name": "GMX", - "short_price": 79.32277034705886 - }, - { - "long_price": 0.08007686034, - "name": "GPT", - "short_price": 0.09123493872667301 - }, - { - "long_price": 0.13239089657499997, - "name": "GRT", - "short_price": 0.14912857729553 - }, - { - "long_price": 1.7856998916749995, - "name": "GTC", - "short_price": 2.4036535451249996 - }, - { - "long_price": 0.056492657022, - "name": "HBAR", - "short_price": 0.06243925249800001 - }, - { - "long_price": 0.5761854538240323, - "name": "HFT", - "short_price": 0.6749605747149999 - }, - { - "long_price": 1.2297070514319999, - "name": "HNT", - "short_price": 1.4765435787999999 - }, - { - "long_price": 1.8133529530567498, - "name": "HOOK", - "short_price": 2.00423221127325 - }, - { - "long_price": 0.0016903867104, - "name": "HOT", - "short_price": 0.0018683221536 - }, - { - "long_price": 4.6086498372861, - "name": "ICP", - "short_price": 5.093770872789901 - }, - { - "long_price": 0.19511028146749998, - "name": "ICX", - "short_price": 0.21595726604586 - }, - { - "long_price": 0.43419345438975493, - "name": "ID", - "short_price": 0.52225799403275 - }, - { - "long_price": 53.46373924779889, - "name": "ILV", - "short_price": 65.669440615875 - }, - { - "long_price": 1.03409852238, - "name": "IMX", - "short_price": 1.1931038113232701 - }, - { - "long_price": 3.971034418775499, - "name": "INJ", - "short_price": 4.3890380418045 - }, - { - "long_price": 0.00957636943125, - "name": "IOST", - "short_price": 0.010647256611000001 - }, - { - "long_price": 0.194144155075, - "name": "IOTA", - "short_price": 0.214580381925 - }, - { - "long_price": 0.023499300738, - "name": "IOTX", - "short_price": 0.025972911342 - }, - { - "long_price": 0.004285952913375, - "name": "JASMY", - "short_price": 0.004764081390525 - }, - { - "long_price": 0.023642653999037557, - "name": "JST", - "short_price": 0.026765210847 - }, - { - "long_price": 0.8286016193549999, - "name": "KAVA", - "short_price": 0.9158228424450001 - }, - { - "long_price": 0.8800856249859076, - "name": "KDA", - "short_price": 1.001974626135 - }, - { - "long_price": 0.21546746662, - "name": "KLAY", - "short_price": 0.23814825258 - }, - { - "long_price": 0.642343973963, - "name": "KNC", - "short_price": 0.7171911573 - }, - { - "long_price": 31.647689171375003, - "name": "KSM", - "short_price": 34.979024873625 - }, - { - "long_price": 2.16790220443746, - "name": "LDO", - "short_price": 2.3993140598217 - }, - { - "long_price": 0.010711503459999999, - "name": "LINA", - "short_price": 0.012029707199999998 - }, - { - "long_price": 6.6613371138, - "name": "LINK", - "short_price": 7.38939904480876 - }, - { - "long_price": 0.9574020568124998, - "name": "LIT", - "short_price": 1.0799916367499998 - }, - { - "long_price": 0.12955641210463853, - "name": "LOOKS", - "short_price": 0.14808301703 - }, - { - "long_price": 6.3294303888000005, - "name": "LPT", - "short_price": 7.053319762500001 - }, - { - "long_price": 2.0289263181251997, - "name": "LQTY", - "short_price": 2.2853017702785 - }, - { - "long_price": 0.3329061213045, - "name": "LRC", - "short_price": 0.36794887091549994 - }, - { - "long_price": 84.66222995999999, - "name": "LTC", - "short_price": 93.57404364 - }, - { - "long_price": 1.2163749532997998, - "name": "LUNA2", - "short_price": 1.3500779866896 - }, - { - "long_price": 1.2841434637651, - "name": "MAGIC", - "short_price": 1.56257312500716 - }, - { - "long_price": 0.5492377728, - "name": "MANA", - "short_price": 0.6070522752 - }, - { - "long_price": 5.8407559685126, - "name": "MASK", - "short_price": 6.84547199175 - }, - { - "long_price": 1.03834790874125, - "name": "MATIC", - "short_price": 1.14764768860875 - }, - { - "long_price": 0.7039100976265438, - "name": "MINA", - "short_price": 0.8258596942327125 - }, - { - "long_price": 646.3256354329999, - "name": "MKR", - "short_price": 714.359912847 - }, - { - "long_price": 1.07827826953, - "name": "MTL", - "short_price": 1.2732448242499999 - }, - { - "long_price": 1.7810276934449998, - "name": "NEAR", - "short_price": 2.0005216139999997 - }, - { - "long_price": 11.927453775475, - "name": "NEO", - "short_price": 13.182975225525 - }, - { - "long_price": 0.095394858532, - "name": "NKN", - "short_price": 0.11192212232000001 - }, - { - "long_price": 0.324436869881875, - "name": "OCEAN", - "short_price": 0.36256580147499995 - }, - { - "long_price": 0.104040904805, - "name": "OGN", - "short_price": 0.1179333991 - }, - { - "long_price": 1.704775, - "name": "OMG", - "short_price": 1.995 - }, - { - "long_price": 0.01862751538825, - "name": "ONE", - "short_price": 0.02136096470455 - }, - { - "long_price": 0.21204281955249998, - "name": "ONT", - "short_price": 0.2343631163475 - }, - { - "long_price": 2.070112122193375, - "name": "OP", - "short_price": 2.3343938684946752 - }, - { - "long_price": 0.020924576224499995, - "name": "PEOPLE", - "short_price": 0.0231271631955 - }, - { - "long_price": 2.9320286885999995, - "name": "QTUM", - "short_price": 3.2840443994196 - }, - { - "long_price": 0.0023765956656, - "name": "REEF", - "short_price": 0.002660670610565 - }, - { - "long_price": 0.09536691340799999, - "name": "REN", - "short_price": 0.10653323192676001 - }, - { - "long_price": 0.0931800121578, - "name": "REQ", - "short_price": 0.111220277466 - }, - { - "long_price": 1.5996744911775, - "name": "RLC", - "short_price": 2.1509224645000002 - }, - { - "long_price": 1.0986183032172, - "name": "RNDR", - "short_price": 1.2930116379648602 - }, - { - "long_price": 0.0530668633425, - "name": "ROSE", - "short_price": 0.058652848957499996 - }, - { - "long_price": 38.18921950575, - "name": "RPL", - "short_price": 47.23962542257515 - }, - { - "long_price": 0.0036093670416, - "name": "RSR", - "short_price": 0.004105925532 - }, - { - "long_price": 0.13839111302625, - "name": "RSS3", - "short_price": 0.16945130546999998 - }, - { - "long_price": 1.2767216199412499, - "name": "RUNE", - "short_price": 1.4192417814750002 - }, - { - "long_price": 0.023384007636, - "name": "RVN", - "short_price": 0.025845482123999997 - }, - { - "long_price": 0.5853677083592501, - "name": "SAND", - "short_price": 0.6469853618707501 - }, - { - "long_price": 0.0035267107401952143, - "name": "SC", - "short_price": 0.0041851253363499995 - }, - { - "long_price": 0.5870141020162727, - "name": "SCRT", - "short_price": 0.6488050601232488 - }, - { - "long_price": 0.41922804576249995, - "name": "SFP", - "short_price": 0.4633573137375 - }, - { - "long_price": 0.010003653835831572, - "name": "SHIB1000", - "short_price": 0.011056670029077 - }, - { - "long_price": 0.0363586844775, - "name": "SKL", - "short_price": 0.0431728374 - }, - { - "long_price": 0.002436876879000744, - "name": "SLP", - "short_price": 0.002725700796 - }, - { - "long_price": 2.2690986759, - "name": "SNX", - "short_price": 2.58462428473431 - }, - { - "long_price": 19.534819568744997, - "name": "SOL", - "short_price": 21.62381888644434 - }, - { - "long_price": 0.0006300006444449999, - "name": "SPELL", - "short_price": 0.0007042383102999999 - }, - { - "long_price": 34.842587988213, - "name": "SSV", - "short_price": 38.90148906612938 - }, - { - "long_price": 0.6071609493733001, - "name": "STG", - "short_price": 0.68087506248132 - }, - { - "long_price": 0.0050695040474999994, - "name": "STMX", - "short_price": 0.0056230849125 - }, - { - "long_price": 0.3273349716, - "name": "STORJ", - "short_price": 0.3617912844 - }, - { - "long_price": 0.8961469901128299, - "name": "STX", - "short_price": 1.0682637391724101 - }, - { - "long_price": 0.005772830697336133, - "name": "SUN", - "short_price": 0.0070414922945 - }, - { - "long_price": 0.9853772447025, - "name": "SUSHI", - "short_price": 1.0891011651975002 - }, - { - "long_price": 0.008294282432427975, - "name": "SWEAT", - "short_price": 0.009167364793736183 - }, - { - "long_price": 0.28352139007499993, - "name": "SXP", - "short_price": 0.313365746925 - }, - { - "long_price": 0.03836466088846, - "name": "T", - "short_price": 0.042527037242 - }, - { - "long_price": 0.9373377264499999, - "name": "THETA", - "short_price": 1.0360048555499999 - }, - { - "long_price": 0.018052551991664514, - "name": "TLM", - "short_price": 0.0211179754716075 - }, - { - "long_price": 0.5535601185496201, - "name": "TOMO", - "short_price": 0.6481592208 - }, - { - "long_price": 13.064270054725, - "name": "TRB", - "short_price": 14.5734083005 - }, - { - "long_price": 0.072243638571575, - "name": "TRU", - "short_price": 0.0887178706553 - }, - { - "long_price": 0.06112869125999999, - "name": "TRX", - "short_price": 0.06756329034 - }, - { - "long_price": 1.0676121408397288, - "name": "TWT", - "short_price": 1.183562240975 - }, - { - "long_price": 4.4557649666375, - "name": "UNFI", - "short_price": 5.009521589122797 - }, - { - "long_price": 5.5258941413925, - "name": "UNI", - "short_price": 6.107567208907501 - }, - { - "long_price": 0.949087709953695, - "name": "USDC", - "short_price": 1.0489916794225052 - }, - { - "long_price": 0.021273928527200003, - "name": "VET", - "short_price": 0.023513289424800007 - }, - { - "long_price": 1.9609026907724998, - "name": "WAVES", - "short_price": 2.185190933881815 - }, - { - "long_price": 0.1846697838235, - "name": "WOO", - "short_price": 0.20410870843649997 - }, - { - "long_price": 0.0039283087126313, - "name": "XCN", - "short_price": 0.004814224568750001 - }, - { - "long_price": 0.036126318847500005, - "name": "XEM", - "short_price": 0.04023511695 - }, - { - "long_price": 0.09073402307664, - "name": "XLM", - "short_price": 0.10543332269399999 - }, - { - "long_price": 147.12321687600001, - "name": "XMR", - "short_price": 162.62589058 - }, - { - "long_price": 0.8252733935961417, - "name": "XNO", - "short_price": 0.92352868806 - }, - { - "long_price": 0.4563486668499, - "name": "XRP", - "short_price": 0.5557085919 - }, - { - "long_price": 1.0369858479749998, - "name": "XTZ", - "short_price": 1.158930622512985 - }, - { - "long_price": 8070.793936892499, - "name": "YFI", - "short_price": 8920.351193407501 - }, - { - "long_price": 0.23804213877091276, - "name": "YGG", - "short_price": 0.272465505732204 - }, - { - "long_price": 34.587214518500005, - "name": "ZEC", - "short_price": 38.22797394150001 - }, - { - "long_price": 9.620754883087498, - "name": "ZEN", - "short_price": 10.824377385155913 - }, - { - "long_price": 0.025764934885499996, - "name": "ZIL", - "short_price": 0.0284770332945 - }, - { - "long_price": 0.210103634475, - "name": "ZRX", - "short_price": 0.23255349492769 - } - ], - "total": 204 -} \ No newline at end of file diff --git a/settings.json b/settings.json deleted file mode 100644 index b131ff5..0000000 --- a/settings.json +++ /dev/null @@ -1,2171 +0,0 @@ -{ - "pairs": [ - { - "symbol": "1INCHUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 7.997332066732092, - "max_position_size": 94.96831829244358, - "long_price": 0.479467968408, - "short_price": 0.519444453528 - }, - { - "symbol": "AAVEUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.05600110896096757, - "max_position_size": 0.6650131689114898, - "long_price": 67.68269851285, - "short_price": 74.4365045594218 - }, - { - "symbol": "ACHUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 119.19730540603793, - "max_position_size": 1415.4680016967004, - "long_price": 0.0316954503480901, - "short_price": 0.0352663751762487 - }, - { - "symbol": "ADAUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 10.602760052042678, - "max_position_size": 125.90777561800678, - "long_price": 0.35435997069887504, - "short_price": 0.383905356478875 - }, - { - "symbol": "AGIXUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 9.155467223907428, - "max_position_size": 108.72117328390068, - "long_price": 0.396316346299838, - "short_price": 0.48581259126255905 - }, - { - "symbol": "AGLDUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 10.078260420479843, - "max_position_size": 119.67934249319812, - "long_price": 0.3734378826303036, - "short_price": 0.419018524513875 - }, - { - "symbol": "AKROUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 915.4438750842509, - "max_position_size": 10870.896016625476, - "long_price": 0.00407107382367309, - "short_price": 0.004544299755072 - }, - { - "symbol": "ALGOUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 19.022598916900098, - "max_position_size": 225.8933621381886, - "long_price": 0.19710894199562498, - "short_price": 0.22277797772278451 - }, - { - "symbol": "ALICEUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 2.645870576623377, - "max_position_size": 31.4197130974026, - "long_price": 1.4190693143309998, - "short_price": 1.5435370546199998 - }, - { - "symbol": "ALPHAUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 38.045197833800195, - "max_position_size": 451.7867242763772, - "long_price": 0.09749360654410999, - "short_price": 0.10675211339429999 - }, - { - "symbol": "ANKRUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 124.49253553315002, - "max_position_size": 1478.3488594561563, - "long_price": 0.030305306542171503, - "short_price": 0.03335704485498 - }, - { - "symbol": "ANTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 1.6802642012371138, - "max_position_size": 19.953137389690724, - "long_price": 2.2490255593960002, - "short_price": 2.4498205855200004 - }, - { - "symbol": "APEUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.9694600732809898, - "max_position_size": 11.512338370211753, - "long_price": 3.9304875246963, - "short_price": 4.2581988347283 - }, - { - "symbol": "API3USDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 2.5903628022886207, - "max_position_size": 30.760558277177367, - "long_price": 1.4589242742344, - "short_price": 1.581981443233399 - }, - { - "symbol": "APTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.3488114272995763, - "max_position_size": 4.142135699182468, - "long_price": 10.712769234122776, - "short_price": 12.34950896716515 - }, - { - "symbol": "ARUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.4864661757402102, - "max_position_size": 5.776785836914996, - "long_price": 7.684825332277501, - "short_price": 8.3324144475 - }, - { - "symbol": "ARBUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 3.232559054343515, - "max_position_size": 38.386638770329235, - "long_price": 1.137884295964185, - "short_price": 1.295678529672427 - }, - { - "symbol": "ARPAUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 99.79526544207692, - "max_position_size": 1185.0687771246633, - "long_price": 0.037799837221575004, - "short_price": 0.043615798862625 - }, - { - "symbol": "ASTRUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 64.0566056909291, - "max_position_size": 760.6721925797831, - "long_price": 0.058554511855771346, - "short_price": 0.06343659726323535 - }, - { - "symbol": "ATOMUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.360332568800849, - "max_position_size": 4.278949254510081, - "long_price": 10.75466489360475, - "short_price": 11.65135399364475 - }, - { - "symbol": "AUDIOUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 14.035965167068552, - "max_position_size": 166.67708635893902, - "long_price": 0.26642279837354704, - "short_price": 0.29771351933400003 - }, - { - "symbol": "AVAXUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.23539229855574817, - "max_position_size": 2.795283545349509, - "long_price": 16.1485108727751, - "short_price": 17.494921367639098 - }, - { - "symbol": "AXSUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.4813515284111046, - "max_position_size": 5.716049399881866, - "long_price": 7.912074056290591, - "short_price": 8.571757145923991 - }, - { - "symbol": "BAKEUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 21.965717994609168, - "max_position_size": 260.8429011859838, - "long_price": 0.17068159181312498, - "short_price": 0.18563178046049997 - }, - { - "symbol": "BALUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.5854368804597702, - "max_position_size": 6.95206295545977, - "long_price": 6.538131177109388, - "short_price": 7.15509951849 - }, - { - "symbol": "BANDUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 2.201318578065911, - "max_position_size": 26.140658114532688, - "long_price": 1.7065325906689004, - "short_price": 1.8507515440491 - }, - { - "symbol": "BATUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 16.13719084356436, - "max_position_size": 191.62914126732673, - "long_price": 0.23485886641099998, - "short_price": 0.254440637451 - }, - { - "symbol": "BCHUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.0329263893979798, - "max_position_size": 0.39100087410101014, - "long_price": 116.01570440868, - "short_price": 125.68871780388001 - }, - { - "symbol": "BELUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 6.6962049104354975, - "max_position_size": 79.51743331142153, - "long_price": 0.5536252833059486, - "short_price": 0.611731616795145 - }, - { - "symbol": "BICOUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 10.888938236237308, - "max_position_size": 129.30614155531802, - "long_price": 0.3479282329458364, - "short_price": 0.38042297370866246 - }, - { - "symbol": "BITUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 7.606198782900879, - "max_position_size": 90.32361054694792, - "long_price": 0.5278055654286958, - "short_price": 1.9951161407850573 - }, - { - "symbol": "BLURUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 7.549825251065409, - "max_position_size": 89.65417485640172, - "long_price": 0.4948934951814041, - "short_price": 0.5777011850543999 - }, - { - "symbol": "BLZUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 49.21658035994686, - "max_position_size": 584.4468917743689, - "long_price": 0.07507249392102, - "short_price": 0.08333476751160002 - }, - { - "symbol": "BNBUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.012783186472156864, - "max_position_size": 0.15180033935686274, - "long_price": 300.6230625541325, - "short_price": 325.68803910893257 - }, - { - "symbol": "BNXUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 7.0313040345125115, - "max_position_size": 83.49673540983608, - "long_price": 0.5305494223386857, - "short_price": 0.6050319736601251 - }, - { - "symbol": "BOBAUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 17.1455530738481, - "max_position_size": 203.60344275194615, - "long_price": 0.22193056499393363, - "short_price": 0.24498304010977498 - }, - { - "symbol": "BSVUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.113341882837274, - "max_position_size": 1.3459348586926287, - "long_price": 33.89410402343834, - "short_price": 36.72008455691939 - }, - { - "symbol": "BSWUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 21.906670365591403, - "max_position_size": 260.1417105913979, - "long_price": 0.17066851777421774, - "short_price": 0.18489830560323015 - }, - { - "symbol": "BTCUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.001, - "max_position_size": 0.0016995619292656454, - "long_price": 26423.6080167843, - "short_price": 28626.722807136302 - }, - { - "symbol": "C98USDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 17.013113519832988, - "max_position_size": 202.03072304801674, - "long_price": 0.21241301129307358, - "short_price": 0.240405006996 - }, - { - "symbol": "CEEKUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 45.654237400560234, - "max_position_size": 542.1440691316527, - "long_price": 0.0830631131131927, - "short_price": 0.08998864625446985 - }, - { - "symbol": "CELOUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 6.57200110967742, - "max_position_size": 78.04251317741935, - "long_price": 0.5735088857999999, - "short_price": 0.6213261978 - }, - { - "symbol": "CELRUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 165.63580032520326, - "max_position_size": 1966.9251288617886, - "long_price": 0.022855094098885, - "short_price": 0.026883814899150003 - }, - { - "symbol": "CFXUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 10.524164289588555, - "max_position_size": 124.97445093886407, - "long_price": 0.3386598946084803, - "short_price": 0.36689625893227235 - }, - { - "symbol": "CHRUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 25.788865113924054, - "max_position_size": 306.2427732278481, - "long_price": 0.14731070513300001, - "short_price": 0.1608256184727555 - }, - { - "symbol": "CHZUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 34.44328561284869, - "max_position_size": 409.0140166525782, - "long_price": 0.11081487904423999, - "short_price": 0.12005426447784001 - }, - { - "symbol": "CKBUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 782.8320245917388, - "max_position_size": 9296.130292026897, - "long_price": 0.004756057896364726, - "short_price": 0.006128947392975 - }, - { - "symbol": "COCOSUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 2.7291632203616882, - "max_position_size": 32.40881324179504, - "long_price": 1.3563981470538578, - "short_price": 1.4852083537194747 - }, - { - "symbol": "COMPUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.09421134538728325, - "max_position_size": 1.1187597264739884, - "long_price": 40.25799564036625, - "short_price": 43.61457682976625 - }, - { - "symbol": "COREUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 2.0826172696141074, - "max_position_size": 24.73108007666752, - "long_price": 1.8790815152791442, - "short_price": 2.035753241409766 - }, - { - "symbol": "COTIUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 54.40834140739752, - "max_position_size": 646.0990542128455, - "long_price": 0.07054372376782249, - "short_price": 0.07642543080422251 - }, - { - "symbol": "CREAMUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.3014233383636633, - "max_position_size": 3.5794021430685015, - "long_price": 12.111450727941998, - "short_price": 13.726367885744637 - }, - { - "symbol": "CROUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 59.48380566423358, - "max_position_size": 706.3701922627738, - "long_price": 0.06432876514167003, - "short_price": 0.070017381108675 - }, - { - "symbol": "CRVUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 4.253278379958247, - "max_position_size": 50.507680762004185, - "long_price": 0.8860591024, - "short_price": 0.9599358384000001 - }, - { - "symbol": "CTCUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 11.27304105132107, - "max_position_size": 133.8673624844377, - "long_price": 0.3333586291817435, - "short_price": 0.3769967348643375 - }, - { - "symbol": "CTKUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 5.243392984171922, - "max_position_size": 62.26529168704157, - "long_price": 0.7329559839546451, - "short_price": 0.794067478187445 - }, - { - "symbol": "CTSIUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 28.1495038894646, - "max_position_size": 334.27535868739204, - "long_price": 0.1331550364790625, - "short_price": 0.14445960211171913 - }, - { - "symbol": "CVCUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 40.427033316797306, - "max_position_size": 480.0710206369679, - "long_price": 0.09376681410562303, - "short_price": 0.10278696993493498 - }, - { - "symbol": "CVXUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.7651907395305165, - "max_position_size": 9.086640031924883, - "long_price": 4.880628018983909, - "short_price": 5.28755896376631 - }, - { - "symbol": "DARUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 23.621105437681166, - "max_position_size": 280.5006270724638, - "long_price": 0.15822129237425, - "short_price": 0.180216973629 - }, - { - "symbol": "DASHUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.07001100838487972, - "max_position_size": 0.8313807245704468, - "long_price": 54.24171399042249, - "short_price": 62.32770977399999 - }, - { - "symbol": "DENTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 3793.892633147114, - "max_position_size": 45052.475018621975, - "long_price": 0.0009922539525599999, - "short_price": 0.0010761478226928 - }, - { - "symbol": "DGBUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 420.0660503092784, - "max_position_size": 4988.28434742268, - "long_price": 0.00900168121963, - "short_price": 0.0097883921025 - }, - { - "symbol": "DODOUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 22.916989246344208, - "max_position_size": 272.13924730033744, - "long_price": 0.16229017099437823, - "short_price": 0.17902869033049357 - }, - { - "symbol": "DOGEUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 53.305084877027745, - "max_position_size": 632.9978829147044, - "long_price": 0.07120424348002825, - "short_price": 0.07714102250910825 - }, - { - "symbol": "DOTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.6518382159654456, - "max_position_size": 7.740578814589666, - "long_price": 5.81720430964875, - "short_price": 6.30222394984875 - }, - { - "symbol": "DUSKUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 22.575437353870022, - "max_position_size": 268.0833185772065, - "long_price": 0.16366135121699, - "short_price": 0.20452873007654998 - }, - { - "symbol": "DYDXUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 1.5960206376811596, - "max_position_size": 18.952745072463767, - "long_price": 2.3749521979475, - "short_price": 2.5729680143475 - }, - { - "symbol": "EGLDUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.09442967990730013, - "max_position_size": 1.121352448899189, - "long_price": 40.33263311506424, - "short_price": 43.695437335184245 - }, - { - "symbol": "ENJUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 10.394491551020408, - "max_position_size": 123.43458716836734, - "long_price": 0.36055537806032, - "short_price": 0.39061731682512 - }, - { - "symbol": "ENSUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.3027221907875186, - "max_position_size": 3.5948260156017833, - "long_price": 12.504650753274749, - "short_price": 13.609493008402502 - }, - { - "symbol": "EOSUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 3.552433032258065, - "max_position_size": 42.185142258064516, - "long_price": 1.0683720959945, - "short_price": 1.1574494984745 - }, - { - "symbol": "ETCUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.19542641189448443, - "max_position_size": 2.3206886412470022, - "long_price": 19.435059616032, - "short_price": 21.055491892512 - }, - { - "symbol": "ETHUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.01, - "max_position_size": 0.026610474597430597, - "long_price": 1704.6462295182748, - "short_price": 1846.7741069142746 - }, - { - "symbol": "ETHWUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 1.185177628853985, - "max_position_size": 14.07398434264107, - "long_price": 3.242241474739121, - "short_price": 3.512569059917995 - }, - { - "symbol": "FETUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 10.92983017167382, - "max_position_size": 129.7917332886266, - "long_price": 0.3375241361408676, - "short_price": 0.371474581351896 - }, - { - "symbol": "FILUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.7048331928732054, - "max_position_size": 8.369894165369313, - "long_price": 5.322049070351999, - "short_price": 5.765784271632 - }, - { - "symbol": "FITFIUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 305.2165309363296, - "max_position_size": 3624.4463048689136, - "long_price": 0.012632008027519657, - "short_price": 0.0142397388936 - }, - { - "symbol": "FLMUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 42.46629169359042, - "max_position_size": 504.2872138613862, - "long_price": 0.0879077481036, - "short_price": 0.09523721120760002 - }, - { - "symbol": "FLOWUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 4.170563651995907, - "max_position_size": 49.52544336745138, - "long_price": 0.894702151746, - "short_price": 0.9841746846392259 - }, - { - "symbol": "FLRUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 98.54028266021767, - "max_position_size": 1170.1658565900848, - "long_price": 0.03668241794151821, - "short_price": 0.042767570041875126 - }, - { - "symbol": "FTMUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 8.83678310127955, - "max_position_size": 104.93679932769464, - "long_price": 0.4134848149962186, - "short_price": 0.46305752624924756 - }, - { - "symbol": "FXSUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.46551361681709136, - "max_position_size": 5.527974199702959, - "long_price": 7.720127906513268, - "short_price": 8.51745002091984 - }, - { - "symbol": "GALUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 2.2807952353764347, - "max_position_size": 27.08444342009516, - "long_price": 1.632107420715525, - "short_price": 1.79687580717645 - }, - { - "symbol": "GALAUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 99.04328361691785, - "max_position_size": 1176.1389929508994, - "long_price": 0.03761159020119, - "short_price": 0.04079674007046 - }, - { - "symbol": "GFTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 78.28320245917388, - "max_position_size": 929.6130292026897, - "long_price": 0.04879674590810001, - "short_price": 0.053595444450457365 - }, - { - "symbol": "GLMRUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 10.883121495726497, - "max_position_size": 129.23706776175214, - "long_price": 0.34651770583957614, - "short_price": 0.38497493371095 - }, - { - "symbol": "GMTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 10.405109009193055, - "max_position_size": 123.56066948416752, - "long_price": 0.3608827971542775, - "short_price": 0.39427367810959263 - }, - { - "symbol": "GMXUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.052538723331829025, - "max_position_size": 0.6238973395654697, - "long_price": 70.83210891680382, - "short_price": 78.52954264358827 - }, - { - "symbol": "GPTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 45.02365401104973, - "max_position_size": 534.6558913812155, - "long_price": 0.0808776289434, - "short_price": 0.09032258933940629 - }, - { - "symbol": "GRTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 27.50348085048937, - "max_position_size": 326.60383509956125, - "long_price": 0.13371480554074996, - "short_price": 0.1476372915225747 - }, - { - "symbol": "GTCUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 2.1166964612987016, - "max_position_size": 25.135770477922076, - "long_price": 1.8035568905917496, - "short_price": 2.3796170096737495 - }, - { - "symbol": "HBARUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 66.77549472304163, - "max_position_size": 792.9589998361193, - "long_price": 0.057057583592220004, - "short_price": 0.06181485997302001 - }, - { - "symbol": "HFTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 6.496557219387756, - "max_position_size": 77.1466169802296, - "long_price": 0.5819473083622726, - "short_price": 0.6682109689678499 - }, - { - "symbol": "HNTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 2.9167077222619904, - "max_position_size": 34.63590420186113, - "long_price": 1.2420041219463198, - "short_price": 1.4617781430119998 - }, - { - "symbol": "HOOKUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 2.1068462709410554, - "max_position_size": 25.018799467425026, - "long_price": 1.8314864825873174, - "short_price": 1.9841898891605174 - }, - { - "symbol": "HOTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 2204.8921471861477, - "max_position_size": 26183.0942478355, - "long_price": 0.0017072905775040001, - "short_price": 0.001849638932064 - }, - { - "symbol": "ICPUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.8060614615232444, - "max_position_size": 9.571979855588527, - "long_price": 4.654736335658961, - "short_price": 5.042833164062002 - }, - { - "symbol": "ICXUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 19.22000324528302, - "max_position_size": 228.23753853773584, - "long_price": 0.19706138428217498, - "short_price": 0.2137976933854014 - }, - { - "symbol": "IDUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 8.341127303991813, - "max_position_size": 99.05088673490276, - "long_price": 0.43853538893365246, - "short_price": 0.5170354140924225 - }, - { - "symbol": "ILVUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.0677469563222213, - "max_position_size": 0.8044951063263779, - "long_price": 53.99837664027688, - "short_price": 65.01274620971625 - }, - { - "symbol": "IMXUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 3.5493385783972133, - "max_position_size": 42.14839561846691, - "long_price": 1.0444395076038002, - "short_price": 1.1811727732100374 - }, - { - "symbol": "INJUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.9317723960667734, - "max_position_size": 11.064797203292933, - "long_price": 4.010744762963254, - "short_price": 4.345147661386455 - }, - { - "symbol": "IOSTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 391.0403731285989, - "max_position_size": 4643.604430902111, - "long_price": 0.0096721331255625, - "short_price": 0.01054078404489 - }, - { - "symbol": "IOTAUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 19.35696288836105, - "max_position_size": 229.86393429928742, - "long_price": 0.19608559662574998, - "short_price": 0.21243457810575 - }, - { - "symbol": "IOTXUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 157.6263322243714, - "max_position_size": 1871.8126951644101, - "long_price": 0.023734293745379997, - "short_price": 0.02571318222858 - }, - { - "symbol": "JASMYUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 861.9929528242014, - "max_position_size": 10236.166314787391, - "long_price": 0.00432881244250875, - "short_price": 0.00471644057661975 - }, - { - "symbol": "JSTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 158.17704534161493, - "max_position_size": 1878.352413431677, - "long_price": 0.023879080539027934, - "short_price": 0.02649755873853 - }, - { - "symbol": "KAVAUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 4.510339481957052, - "max_position_size": 53.56028134823998, - "long_price": 0.8368876355485498, - "short_price": 0.9066646140205501 - }, - { - "symbol": "KDAUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 4.194174665980443, - "max_position_size": 49.80582415851775, - "long_price": 0.8888864812357666, - "short_price": 0.9919548798736499 - }, - { - "symbol": "KLAYUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 17.63913717748918, - "max_position_size": 209.464753982684, - "long_price": 0.2176221412862, - "short_price": 0.2357667700542 - }, - { - "symbol": "KNCUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 5.746214480327176, - "max_position_size": 68.23629695388522, - "long_price": 0.64876741370263, - "short_price": 0.710019245727 - }, - { - "symbol": "KSMUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.11742480368876082, - "max_position_size": 1.3944195438040343, - "long_price": 31.964166063088754, - "short_price": 34.62923462488875 - }, - { - "symbol": "LDOUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 1.7013113519832987, - "max_position_size": 20.203072304801672, - "long_price": 2.1895812264818346, - "short_price": 2.375320919223483 - }, - { - "symbol": "LINAUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 343.85153485232075, - "max_position_size": 4083.236976371308, - "long_price": 0.010818618494599998, - "short_price": 0.011909410127999998 - }, - { - "symbol": "LINKUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.5610134500894948, - "max_position_size": 6.662034719812749, - "long_price": 6.727950484938, - "short_price": 7.315505054360672 - }, - { - "symbol": "LITUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 3.854910773888364, - "max_position_size": 45.777065439924314, - "long_price": 0.9669760773806247, - "short_price": 1.0691917203824997 - }, - { - "symbol": "LOOKSUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 28.877680283486892, - "max_position_size": 342.92245336640684, - "long_price": 0.13085197622568492, - "short_price": 0.1466021868597 - }, - { - "symbol": "LPTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.5869548671852493, - "max_position_size": 6.9700890478248345, - "long_price": 6.392724692688001, - "short_price": 6.982786564875001 - }, - { - "symbol": "LQTYUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 1.7902639226713537, - "max_position_size": 21.25938408172232, - "long_price": 2.0492155813064517, - "short_price": 2.262448752575715 - }, - { - "symbol": "LRCUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 11.138984931656644, - "max_position_size": 132.27544606342263, - "long_price": 0.336235182517545, - "short_price": 0.3642693822063449 - }, - { - "symbol": "LTCUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.1, - "max_position_size": 0.523095764, - "long_price": 85.50885225959999, - "short_price": 92.6383032036 - }, - { - "symbol": "LUNA2USDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 3.1127889136745615, - "max_position_size": 36.96436834988541, - "long_price": 1.2285387028327979, - "short_price": 1.336577206822704 - }, - { - "symbol": "MAGICUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 2.8388773691911102, - "max_position_size": 33.71166875914443, - "long_price": 1.296984898402751, - "short_price": 1.5469473937570883 - }, - { - "symbol": "MANAUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 6.78428352980353, - "max_position_size": 80.56336691641691, - "long_price": 0.554730150528, - "short_price": 0.600981752448 - }, - { - "symbol": "MASKUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.5937113052600904, - "max_position_size": 7.050321749963572, - "long_price": 5.899163528197725, - "short_price": 6.7770172718325 - }, - { - "symbol": "MATICUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 3.5745597754188974, - "max_position_size": 42.4478973330994, - "long_price": 1.0487313878286624, - "short_price": 1.1361712117226626 - }, - { - "symbol": "MINAUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 5.21921440758294, - "max_position_size": 61.9781710900474, - "long_price": 0.7109491986028093, - "short_price": 0.8176010972903854 - }, - { - "symbol": "MKRUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.005922442860465117, - "max_position_size": 0.07032900896802326, - "long_price": 652.7888917873299, - "short_price": 707.21631371853 - }, - { - "symbol": "MTLUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 3.450161463166808, - "max_position_size": 40.97066737510584, - "long_price": 1.0890610522253, - "short_price": 1.2605123760074999 - }, - { - "symbol": "NEARUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 2.0960085843621403, - "max_position_size": 24.890101939300415, - "long_price": 1.7988379703794497, - "short_price": 1.9805163978599998 - }, - { - "symbol": "NEOUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.31406202312316944, - "max_position_size": 3.729486524587637, - "long_price": 12.04672831322975, - "short_price": 13.05114547326975 - }, - { - "symbol": "NKNUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 38.83569088829585, - "max_position_size": 461.17382929851317, - "long_price": 0.09634880711732, - "short_price": 0.11080290109680001 - }, - { - "symbol": "OCEANUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 11.432774096520765, - "max_position_size": 135.76419239618406, - "long_price": 0.32768123858069376, - "short_price": 0.35894014346024994 - }, - { - "symbol": "OGNUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 35.61748853146854, - "max_position_size": 422.95767631118883, - "long_price": 0.10508131385305, - "short_price": 0.11675406510900001 - }, - { - "symbol": "OMGUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 2.298161696559504, - "max_position_size": 27.290670146644107, - "long_price": 1.7218227499999998, - "short_price": 1.9750500000000002 - }, - { - "symbol": "ONEUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 196.55767911239752, - "max_position_size": 2334.1224394597207, - "long_price": 0.0188137905421325, - "short_price": 0.0211473550575045 - }, - { - "symbol": "ONTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 17.650598605154865, - "max_position_size": 209.600858436214, - "long_price": 0.21416324774802498, - "short_price": 0.23201948518402501 - }, - { - "symbol": "OPUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 1.796737229032543, - "max_position_size": 21.336254594761446, - "long_price": 2.0908132434153086, - "short_price": 2.3110499298097285 - }, - { - "symbol": "PEOPLEUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 180.29383575221243, - "max_position_size": 2140.9892995575224, - "long_price": 0.021133821986744995, - "short_price": 0.022895891563545 - }, - { - "symbol": "QTUMUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 1.2853756113564672, - "max_position_size": 15.263835384858044, - "long_price": 2.9613489754859996, - "short_price": 3.251203955425404 - }, - { - "symbol": "REEFUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 1531.8198075187972, - "max_position_size": 18190.360214285716, - "long_price": 0.002400361622256, - "short_price": 0.00263406390445935 - }, - { - "symbol": "RENUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 38.27391215479993, - "max_position_size": 454.5027068382491, - "long_price": 0.09632058254208, - "short_price": 0.10546789960749241 - }, - { - "symbol": "REQUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 41.57796620408163, - "max_position_size": 493.7383486734694, - "long_price": 0.094111812279378, - "short_price": 0.11010807469134 - }, - { - "symbol": "RLCUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 2.3046610226244346, - "max_position_size": 27.36784964366516, - "long_price": 1.615671236089275, - "short_price": 2.1294132398550003 - }, - { - "symbol": "RNDRUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 3.3281390900922982, - "max_position_size": 39.521651694846035, - "long_price": 1.1096044862493721, - "short_price": 1.2800815215852115 - }, - { - "symbol": "ROSEUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 69.9629239010989, - "max_position_size": 830.8097213255495, - "long_price": 0.053597531975925, - "short_price": 0.058066320467924995 - }, - { - "symbol": "RPLUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.08852141403432545, - "max_position_size": 1.0511917916576146, - "long_price": 38.571111700807506, - "short_price": 46.7672291683494 - }, - { - "symbol": "RSRUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 1029.9900626895856, - "max_position_size": 12231.131994438827, - "long_price": 0.003645460712016, - "short_price": 0.00406486627668 - }, - { - "symbol": "RSS3USDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 23.940309565217397, - "max_position_size": 284.29117608695657, - "long_price": 0.13977502415651252, - "short_price": 0.16775679241529998 - }, - { - "symbol": "RUNEUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 2.904234275124733, - "max_position_size": 34.4877820171062, - "long_price": 1.2894888361406625, - "short_price": 1.4050493636602501 - }, - { - "symbol": "RVNUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 160.1037598428291, - "max_position_size": 1901.2321481335953, - "long_price": 0.02361784771236, - "short_price": 0.025587027302759996 - }, - { - "symbol": "SANDUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 6.330030585676558, - "max_position_size": 75.16911320490911, - "long_price": 0.5912213854428426, - "short_price": 0.6405155082520425 - }, - { - "symbol": "SCUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 1041.5748179959103, - "max_position_size": 12368.700963701433, - "long_price": 0.0035619778475971665, - "short_price": 0.004143274082986499 - }, - { - "symbol": "SCRTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 6.280272330456227, - "max_position_size": 74.57823392416769, - "long_price": 0.5928842430364354, - "short_price": 0.6423170095220163 - }, - { - "symbol": "SFPUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 8.898538300939071, - "max_position_size": 105.67014232365146, - "long_price": 0.42342032622012493, - "short_price": 0.458723740600125 - }, - { - "symbol": "SKLUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 101.23330901863355, - "max_position_size": 1202.1455445962733, - "long_price": 0.036722271322275, - "short_price": 0.042741109026 - }, - { - "symbol": "SLPUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 1514.7363152416358, - "max_position_size": 17987.493743494422, - "long_price": 0.0024612456477907515, - "short_price": 0.00269844378804 - }, - { - "symbol": "SNXUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 1.6423380443369613, - "max_position_size": 19.502764276501413, - "long_price": 2.291789662659, - "short_price": 2.558778041886967 - }, - { - "symbol": "SOLUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.19043046632705524, - "max_position_size": 2.261361787633781, - "long_price": 19.730167764432448, - "short_price": 21.407580697579895 - }, - { - "symbol": "SPELLUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 5931.06359243086, - "max_position_size": 70431.38016011645, - "long_price": 0.0006363006508894499, - "short_price": 0.0006971959271969999 - }, - { - "symbol": "SSVUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.10655441129707113, - "max_position_size": 1.2653336341527197, - "long_price": 35.191013868095126, - "short_price": 38.512474175468085 - }, - { - "symbol": "STGUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 6.118997879561496, - "max_position_size": 72.66309981979276, - "long_price": 0.6132325588670331, - "short_price": 0.6740663118565068 - }, - { - "symbol": "STMXUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 734.8315036970245, - "max_position_size": 8726.124106402165, - "long_price": 0.0051201990879749994, - "short_price": 0.005566854063374999 - }, - { - "symbol": "STORJUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 11.413559350140059, - "max_position_size": 135.53601728291318, - "long_price": 0.33060832131600004, - "short_price": 0.35817337155600004 - }, - { - "symbol": "STXUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 3.9023518536608734, - "max_position_size": 46.34042826222286, - "long_price": 0.9051084600139583, - "short_price": 1.057581101780686 - }, - { - "symbol": "SUNUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 649.8629486443382, - "max_position_size": 7717.122515151515, - "long_price": 0.0058305590043094945, - "short_price": 0.0069710773715549994 - }, - { - "symbol": "SUSHIUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 3.8009707910447763, - "max_position_size": 45.13652814365671, - "long_price": 0.995231017149525, - "short_price": 1.0782101535455253 - }, - { - "symbol": "SWEATUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 458.3397849268842, - "max_position_size": 5442.784946006749, - "long_price": 0.008377225256752255, - "short_price": 0.009075691145798821 - }, - { - "symbol": "SXPUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 12.997258972886764, - "max_position_size": 154.3424503030303, - "long_price": 0.2863566039757499, - "short_price": 0.31023208945575004 - }, - { - "symbol": "TUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 98.35000453777457, - "max_position_size": 1167.906303886073, - "long_price": 0.0387483074973446, - "short_price": 0.04210176686958 - }, - { - "symbol": "THETAUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 3.955961833009709, - "max_position_size": 46.97704676699029, - "long_price": 0.9467111037145, - "short_price": 1.0256448069945 - }, - { - "symbol": "TLMUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 207.1500095577021, - "max_position_size": 2459.9063634977124, - "long_price": 0.01823307751158116, - "short_price": 0.020906795716891424 - }, - { - "symbol": "TOMOUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 6.2783369614792, - "max_position_size": 74.55525141756549, - "long_price": 0.5590957197351163, - "short_price": 0.641677628592 - }, - { - "symbol": "TRBUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.2829611588888889, - "max_position_size": 3.3601637618055555, - "long_price": 13.19491275527225, - "short_price": 14.427674217495001 - }, - { - "symbol": "TRUUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 51.44748343434344, - "max_position_size": 610.9388657828283, - "long_price": 0.07296607495729074, - "short_price": 0.087830691948747 - }, - { - "symbol": "TRXUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 62.47532486967189, - "max_position_size": 741.8944828273536, - "long_price": 0.06173997817259999, - "short_price": 0.0668876574366 - }, - { - "symbol": "TWTUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 3.5263008983124196, - "max_position_size": 41.87482316745998, - "long_price": 1.078288262248126, - "short_price": 1.17172661856525 - }, - { - "symbol": "UNFIUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.8313048430072427, - "max_position_size": 9.871745010711006, - "long_price": 4.500322616303875, - "short_price": 4.959426373231569 - }, - { - "symbol": "UNIUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.6779768199667222, - "max_position_size": 8.050974737104825, - "long_price": 5.581153082806424, - "short_price": 6.046491536818426 - }, - { - "symbol": "USDCUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 4.077494934454118, - "max_position_size": 48.420252346642656, - "long_price": 0.958578587053232, - "short_price": 1.0385017626282802 - }, - { - "symbol": "VETUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 175.25336292473122, - "max_position_size": 2081.133684731183, - "long_price": 0.021486667812472004, - "short_price": 0.023278156530552006 - }, - { - "symbol": "WAVESUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 1.9004853955223882, - "max_position_size": 22.568264071828356, - "long_price": 1.9805117176802247, - "short_price": 2.1633390245429966 - }, - { - "symbol": "WOOUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 19.993330166830226, - "max_position_size": 237.4207957311089, - "long_price": 0.18651648166173498, - "short_price": 0.20206762135213496 - }, - { - "symbol": "XCNUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 970.152544761905, - "max_position_size": 11520.561469047621, - "long_price": 0.003967591799757613, - "short_price": 0.004766082323062501 - }, - { - "symbol": "XEMUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 102.37790673366835, - "max_position_size": 1215.7376424623114, - "long_price": 0.036487582035975005, - "short_price": 0.0398327657805 - }, - { - "symbol": "XLMUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 38.769178763082785, - "max_position_size": 460.38399781160797, - "long_price": 0.0916413633074064, - "short_price": 0.10437898946706 - }, - { - "symbol": "XMRUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.02592835308940503, - "max_position_size": 0.3078991929366847, - "long_price": 148.59444904476, - "short_price": 160.9996316742 - }, - { - "symbol": "XNOUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 4.567982834080718, - "max_position_size": 54.24479615470852, - "long_price": 0.8335261275321031, - "short_price": 0.9142934011794 - }, - { - "symbol": "XRPUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 7.171138134459698, - "max_position_size": 85.1572653467089, - "long_price": 0.460912153518399, - "short_price": 0.5501515059809999 - }, - { - "symbol": "XTZUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 3.6058767150442486, - "max_position_size": 42.819785991150454, - "long_price": 1.0473557064547498, - "short_price": 1.1473413162878552 - }, - { - "symbol": "YFIUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.0004638179496869665, - "max_position_size": 0.005507838152532727, - "long_price": 8151.5018762614245, - "short_price": 8831.147681473427 - }, - { - "symbol": "YGGUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 15.617633913376773, - "max_position_size": 185.45940272134916, - "long_price": 0.2404225601586219, - "short_price": 0.26974085067488196 - }, - { - "symbol": "ZECUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.10909345884872826, - "max_position_size": 1.2954848238286478, - "long_price": 34.933086663685, - "short_price": 37.845694202085014 - }, - { - "symbol": "ZENUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 0.3875442921818528, - "max_position_size": 4.602088469659503, - "long_price": 9.716962431918374, - "short_price": 10.716133611304354 - }, - { - "symbol": "ZILUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 144.90187368421056, - "max_position_size": 1720.70975, - "long_price": 0.026022584234354995, - "short_price": 0.028192262961554998 - }, - { - "symbol": "ZRXUSDT", - "leverage": "5", - "min_volume": "6850", - "take_profit": "0.7", - "stop_loss": "30", - "order_size": 17.79319077729258, - "max_position_size": 211.29414048034934, - "long_price": 0.21220467081975, - "short_price": 0.2302279599784131 - } - ] -} \ No newline at end of file From 6734df9d03ee6fa6fead3262938d9cc2c6334b47 Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Sat, 7 Oct 2023 19:55:39 +0200 Subject: [PATCH 21/23] fix start sequence initializing settings --- app.js | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/app.js b/app.js index ca9dffd..7917c24 100644 --- a/app.js +++ b/app.js @@ -101,6 +101,9 @@ const drawdownThreshold = process.env.TIMEOUT_BLACKLIST_FOR_BIG_DRAWDOWN == "tr // queue to sequentially execute scalp method var tradeOrdersQueue = []; +var settings = {}; // a memory copy of settings file +var minOrderSizes = []; // a memory copy of min order size + app.use(bodyParser.urlencoded({ extended: false })); app.use('/css', express.static('gui/css')); app.use('/img', express.static('gui/img')); @@ -1309,7 +1312,7 @@ async function getMinTradingSize() { var tickers = await cachedLinearClient.getTickers(); var positions = await cachedLinearClient.getPosition(); - var minOrderSizes = []; + minOrderSizes = []; //update global variable TODO: refactoring to avoid global logIT("Fetching min Trading Sizes for pairs, this could take a minute..."); for (var i = 0; i < data.result.length; i++) { logIT("Pair: " + data.result[i].name + " Min Trading Size: " + data.result[i].lot_size_filter.min_trading_qty); @@ -1374,19 +1377,22 @@ async function getMinTradingSize() { //update settings.json with min order sizes - let settings = JSON.parse(fs.readFileSync('settings.json', 'utf8')); - let updated = false; - for (var i = 0; i < minOrderSizes.length; i++) { - var settingsIndex = settings.pairs.findIndex(x => x.symbol === minOrderSizes[i].pair); - if(settingsIndex !== -1) { - settings.pairs[settingsIndex].order_size = minOrderSizes[i].minOrderSize; - settings.pairs[settingsIndex].max_position_size = minOrderSizes[i].maxPositionSize; - updated = true; - } - } + if (fs.existsSync('settings.json')) { // check existence of the file + if (Object.keys(settings).length === 0) // avoid read file if it's already loaded in the global settings TODO: avoid global + settings = JSON.parse(fs.readFileSync('settings.json', 'utf8')); + let updated = false; + for (var i = 0; i < minOrderSizes.length; i++) { + var settingsIndex = settings.pairs.findIndex(x => x.symbol === minOrderSizes[i].pair); + if(settingsIndex !== -1) { + settings.pairs[settingsIndex].order_size = minOrderSizes[i].minOrderSize; + settings.pairs[settingsIndex].max_position_size = minOrderSizes[i].maxPositionSize; + updated = true; + } + } - if (updated) { - fs.writeFileSync('settings.json', JSON.stringify(settings, null, 2)); + if (updated) { + fs.writeFileSync('settings.json', JSON.stringify(settings, null, 2)); + } } } else { @@ -1441,7 +1447,7 @@ async function createSettings() { .then(res => res.json()) .then((out) => { //create settings.json file with multiple pairs - var settings = {}; + settings = {}; // use global var TODO: avoid global settings["pairs"] = []; for (var i = 0; i < out.data.length; i++) { //logIT("Adding Smart Settings for " + out.data[i].name + " to settings.json"); From c42223fb9aedc4ff33483536967b573c5a0467ba Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Sun, 8 Oct 2023 18:13:58 +0200 Subject: [PATCH 22/23] filters: add filters to exclude some pairs from trading --- app.js | 47 ++++++++++++++++++++++++++++++++++++++++++++++- example.env | 1 + filters.js | 27 +++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 filters.js diff --git a/app.js b/app.js index 7917c24..48d6493 100644 --- a/app.js +++ b/app.js @@ -23,6 +23,7 @@ import { loadJson, storeJson, traceTrade, dumpLiquidationInfo } from './utils.js import { createMarketOrder, createLimitOrder, cancelOrder } from './order.js'; import { logIT, LOG_LEVEL } from './log.js'; import { CachedLinearClient } from './exchange.js' +import { checkListingDate } from './filters.js' dotenv.config(); @@ -101,6 +102,9 @@ const drawdownThreshold = process.env.TIMEOUT_BLACKLIST_FOR_BIG_DRAWDOWN == "tr // queue to sequentially execute scalp method var tradeOrdersQueue = []; +// set filters to discard some symbol +var filteredPairs = []; + var settings = {}; // a memory copy of settings file var minOrderSizes = []; // a memory copy of min order size @@ -1084,6 +1088,13 @@ async function scalp(pair, liquidationInfo, source, new_trades_disabled = false) return; } + // handle filteredPair + const filtered = filteredPairs.find(el => el.symbol == pair); + if (filtered !== undefined) { + logIT(`scalp - discard order as pair ${pair} is in filter list reason ${filtered.reason}`); + return; + } + // place new order if (position.size === 0) { @@ -1854,8 +1865,30 @@ async function reportWebhook() { } } +async function applyFilters(pairs) { + let i = 0; + let filtered = []; + for(let i = 0; i < pairs.length; i++){ + let sym = pairs[i]; + + if (parseInt(env.FILTER_MIN_LISTING_DAYS) != 0) { + const wasListed = await checkListingDate(sym, parseInt(env.FILTER_MIN_LISTING_DAYS)); + if (!wasListed) { + logIT(`applyFilters - discard symbol ${sym} as it's not listed at list from ${env.FILTER_MIN_LISTING_DAYS} days`); + filtered.push({symbol: sym, reason: "FILTER_MIN_LISTING_DAYS"}); + } + } + + if (i%50 == 0) // rate limit to 100 request per second (limit is 120 x 5 sec) + await sleep(1000); + } + + return filtered; +} async function main() { + let initDone = false; + //logIT("Starting Lick Hunter!"); logIT("Starting Lick Hunter!"); runningStatus = runningStatus_RUN; @@ -1863,6 +1896,17 @@ async function main() { try{ pairs = await getSymbols(); + // set globally filtered pairs + let tmpFilters = await applyFilters(pairs.map(el => el.split(".")[1])); + if (tmpFilters.length > 0) { + logIT(`filteredPairs ${JSON.stringify(tmpFilters)}`); + filteredPairs = tmpFilters; + // TODO: filter disabled symbols from wssocket + } + // set initDone to true anyway but force the main loop to wait for filters initialization. + if (tmpFilters.length >= 0 ) + initDone = true; + //load local file acccount.json with out require and see if "config_set" is true var account = JSON.parse(fs.readFileSync('account.json', 'utf8')); if (account.config_set == false) { @@ -1915,7 +1959,8 @@ async function main() { } }, 100); - while (true) { + // start main loop when the initialization is completed + while (initDone) { try { cachedLinearClient.invalidate(); await checkOpenPositions(); diff --git a/example.env b/example.env index 4a022a4..8fbaaab 100644 --- a/example.env +++ b/example.env @@ -55,3 +55,4 @@ DCA_VOLUME_SCALE = 1.3 #WORK WITH DCA_AVERAGE_ENTRIES DCA_PRICE_DEVIATION_PRC = 2 #WORK WITH DCA_AVERAGE_ENTRIES PAUSED_LIST = NOTHING #Add active trades that you want to manually set a take profit TRADE_POSITIONS_SIDE_BALANCE = false # keeps the number of open long and short positions balanced +FILTER_MIN_LISTING_DAYS=30 diff --git a/filters.js b/filters.js new file mode 100644 index 0000000..77921de --- /dev/null +++ b/filters.js @@ -0,0 +1,27 @@ +import fetch from 'node-fetch'; +import { logIT, LOG_LEVEL } from './log.js'; + +export async function checkListingDate(symbol, days) { + let res = false; + try { + const today = new Date(); // Current date and time + today.setHours(0, 0, 0, 0); // Set the time to 00:00 + + const startDaysAgo = new Date(today); + const endDaysAgo = new Date(today); + startDaysAgo.setDate(today.getDate() - days); + endDaysAgo.setDate(today.getDate() - (days - 1)); + const startTimestamp = startDaysAgo.getTime(); + const endTimestamp = endDaysAgo.getTime(); + + const url = `https://api.bybit.com/v5/market/kline?category=linear&symbol=${symbol}&interval=D&start=${startTimestamp}&end=${endTimestamp}`; + + const response = await fetch(url); + const data = await response.json(); + res = data.result.list.length > 0; + } catch (error) { + console.error('Error:', error.message); + throw error; + } + return res; +} \ No newline at end of file From bbdb3d6269b12cf55d7a2c8f6f121a5f477af491 Mon Sep 17 00:00:00 2001 From: Alessandro Arrabito Date: Sun, 8 Oct 2023 18:33:32 +0200 Subject: [PATCH 23/23] filters: add volatility filters --- app.js | 10 +++++++++- example.env | 2 ++ filters.js | 19 ++++++++++++++++++- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/app.js b/app.js index 48d6493..d6c2577 100644 --- a/app.js +++ b/app.js @@ -23,7 +23,7 @@ import { loadJson, storeJson, traceTrade, dumpLiquidationInfo } from './utils.js import { createMarketOrder, createLimitOrder, cancelOrder } from './order.js'; import { logIT, LOG_LEVEL } from './log.js'; import { CachedLinearClient } from './exchange.js' -import { checkListingDate } from './filters.js' +import { checkListingDate, getVolatility } from './filters.js' dotenv.config(); @@ -1103,6 +1103,14 @@ async function scalp(pair, liquidationInfo, source, new_trades_disabled = false) return; } + // check volatility filter + if (parseFloat(env.FILTER_CHECK_VOLATILITY_PRC) != 0) { + const volatility = await getVolatility(pair, parseInt(env.FILTER_CHECK_VOLATILITY_PERIOD)); + if (volatility > parseFloat(env.FILTER_CHECK_VOLATILITY_PRC)) { // if volatility > env.FILTER_CHECK_VOLATILITY_PRC discard token + logIT("scalp - discard order as token ${pair} have too big volatility ${volatility}"); + } + } + // evaluate process.env.TRADE_POSITIONS_SIDE_BALANCE to have equals number of long and short const maxTradeForSide = Math.round(process.env.MAX_OPEN_POSITIONS / process.env.TRADE_POSITIONS_SIDE_BALANCE == true ? 2 : 1); const tradesForSide = Array.from(tradesHistory.values()).filter(el => el.side == side).length; diff --git a/example.env b/example.env index 8fbaaab..b431aa9 100644 --- a/example.env +++ b/example.env @@ -56,3 +56,5 @@ DCA_PRICE_DEVIATION_PRC = 2 #WORK WITH DCA_AVERAGE_ENTRIES PAUSED_LIST = NOTHING #Add active trades that you want to manually set a take profit TRADE_POSITIONS_SIDE_BALANCE = false # keeps the number of open long and short positions balanced FILTER_MIN_LISTING_DAYS=30 +FILTER_CHECK_VOLATILITY_PRC = 0.0 # max allowed volatility 20% - 0 to disable filter +FILTER_CHECK_VOLATILITY_PERIOD = 10 # calc volatility over period of days diff --git a/filters.js b/filters.js index 77921de..aebe06e 100644 --- a/filters.js +++ b/filters.js @@ -24,4 +24,21 @@ export async function checkListingDate(symbol, days) { throw error; } return res; -} \ No newline at end of file +} + +export async function getVolatility(symbol, days) { + let vol = 0; + try { + const url = `https://api.bybit.com/v5/market/kline?category=linear&symbol=${symbol}&interval=D&limit=${days}`; + const response = await fetch(url); + const data = await response.json(); + const historicalData = data.result.list; + + // data are in format ts, ohlcv + vol = Math.max(...historicalData.map(item => (Number(item[2]) - Number(item[3])) / Number(item[3]))); + } catch (error) { + throw error; + } + + return vol; +}