-
-
Save BransonGitomeh/367436f77c3237cd5c8909eb8c3f4685 to your computer and use it in GitHub Desktop.
Trading Bot for Managing Futures Positions This trading bot automates the process of opening and managing futures trading positions on Binance Futures. It allows you to profit from both rising and falling markets by leveraging futures contracts. Features: Automated position opening based on predefined symbols Continuous monitoring of Return on E…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
BINANCE_API_KEY= | |
BINANCE_SECRET_KEY= | |
BINANCE_API_URL=https://fapi.binance.com |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require('dotenv').config(); | |
const axios = require('axios'); | |
const Binance = require('node-binance-api'); | |
// Extract necessary variables from environment | |
const { BINANCE_API_KEY, BINANCE_SECRET_KEY, NATS_URL } = process.env; | |
// Initialize Binance API client with authentication | |
const binance = new Binance().options({ | |
APIKEY: BINANCE_API_KEY, | |
APISECRET: BINANCE_SECRET_KEY, | |
useServerTime: true, | |
recvWindow: 5000, | |
}); | |
// Set binance object as global variable | |
global.binance = binance; | |
const assetInfoCache = {}; | |
const getAssetInfo = async function (symbol) { | |
// Check if the response is already cached | |
if (assetInfoCache[symbol]) { | |
return Promise.resolve(assetInfoCache[symbol]); | |
} | |
try { | |
const response = await axios({ | |
method: 'GET', | |
url: 'https://fapi.binance.com/fapi/v1/exchangeInfo', | |
}); | |
const { symbols } = response.data; | |
const symbolInfo = symbols.find(s => s.symbol === symbol); | |
const { notional } = symbolInfo.filters.find(filter => { | |
return filter.filterType == 'MIN_NOTIONAL' | |
}) | |
if (!symbolInfo.baseAssetPrecision) { | |
logger.info(symbolInfo); | |
} | |
// Store the response in the cache | |
assetInfoCache[symbol] = { | |
basePrecision: symbolInfo.baseAssetPrecision, | |
quotePrecision: symbolInfo.quotePrecision, | |
minNotional: Number(notional) | |
}; | |
return Promise.resolve(assetInfoCache[symbol]); | |
} catch (error) { | |
console.error(`Error getting asset info: ${error}`); | |
throw error; | |
} | |
} | |
async function getCurrentPrice(symbol) { | |
return new Promise(async (resolve, reject) => { | |
try { | |
binance.futuresTickerStream(symbol, ticker => { | |
const currentPrice = parseFloat(ticker.close); | |
resolve(currentPrice) | |
}); | |
} catch (error) { | |
console.error(`Error getting current price for symbol ${symbol}: ${error.message}`); | |
throw error; | |
} | |
}) | |
} | |
const openOrder = async (symbol) => { | |
const assetInfo = await getAssetInfo(symbol); | |
const { basePrecision, quotePrecision, minNotional } = assetInfo; | |
const { availableBalance } = await global.binance.futuresAccount(); | |
const riskPercentage = 0.2; // Risk 30% of available balance | |
const riskAmount = minNotional//availableBalance * riskPercentage; // Example risk amount | |
const leverage = 20; // Example leverage | |
const currentPrice = await getCurrentPrice(symbol) | |
let positionSize = Math.ceil(riskAmount / currentPrice); | |
const response = await global.binance.futuresSell(symbol, positionSize, undefined, { | |
leverage | |
}); | |
return response | |
} | |
const reverseFailingPosition = async (position) => { | |
const { symbol } = position | |
const assetInfo = await getAssetInfo(symbol); | |
const { basePrecision, quotePrecision, minNotional } = assetInfo; | |
const { availableBalance } = await global.binance.futuresAccount(); | |
const riskPercentage = 0.2; // Risk 30% of available balance | |
const riskAmount = minNotional//availableBalance * riskPercentage; // Example risk amount | |
const leverage = 20; // Example leverage | |
const currentPrice = await getCurrentPrice(symbol) | |
let positionSize = Math.ceil(riskAmount / currentPrice); | |
let response; | |
if (Number(position.positionAmt) > 0) { | |
response = await global.binance.futuresSell(symbol, positionSize * 2, undefined, { | |
leverage | |
}); | |
} else { | |
response = await global.binance.futuresBuy(symbol, positionSize * 2, undefined, { | |
leverage | |
}); | |
} | |
return response | |
} | |
const symbols = [ | |
"IMXUSDT", | |
"XRPUSDT", | |
// "ETHUSDT", | |
// "BTCUSDT", | |
"DOGEUSDT", | |
"BALUSDT", | |
"EOSUSDT", | |
// "ETCUSDT", | |
"BATUSDT", | |
"BELUSDT", | |
// "BNBUSDT" | |
]; | |
async function openOrdersSequentially(openPositions) { | |
for (const symbol of symbols) { | |
if (!openPositions.includes(symbol)) { | |
const response = await openOrder(symbol); | |
console.log(`Order for ${symbol}: ${JSON.stringify(response)}`); | |
} | |
} | |
} | |
function calculateROE(position) { | |
const entryPrice = parseFloat(position.entryPrice); | |
const markPrice = parseFloat(position.markPrice); | |
const positionAmt = parseFloat(position.positionAmt); | |
const leverage = parseFloat(position.leverage); | |
const unRealizedProfit = parseFloat(position.unRealizedProfit); | |
// Calculate the current value of the position | |
const currentValue = positionAmt * markPrice; | |
// Calculate the initial margin required for the position | |
const initialMargin = currentValue / leverage; | |
// Calculate the unrealized PnL of the position | |
const unrealizedPnl = parseFloat(position.unRealizedProfit); | |
// Calculate the return on equity (ROE) | |
const ROE = ((unrealizedPnl / initialMargin) * 100).toFixed(2); | |
if (unRealizedProfit > 0) | |
return Math.abs(ROE); | |
return -Math.abs(ROE); | |
} | |
const start = async () => { | |
const { serverTime: timestamp } = await binance.time(); | |
const binanceGeneralPositions = await global.binance.futuresPositionRisk({ timestamp }) || []; | |
if (!binanceGeneralPositions[0]) { | |
console.error("Could not get access to Latest Positions data from binance.futuresPositionRisk") | |
return; | |
} | |
const openPositions = binanceGeneralPositions.filter(position => { | |
return Number(position.positionAmt) !== 0 | |
}) | |
const openPositionsSymbols = openPositions.map(position => position.symbol) | |
await openOrdersSequentially(openPositionsSymbols); | |
const positionData = [] | |
for (const position of openPositions) { | |
try { | |
const binanceGeneralPositions = await global.binance.futuresPositionRisk({ timestamp }) || []; | |
const positionToMonitor = binanceGeneralPositions.find(generalPos => generalPos.symbol === position.symbol) | |
const ROE = await calculateROE(positionToMonitor) | |
const { symbol, unRealizedProfit, leverage } = position | |
positionData.push({ | |
symbol, | |
uPNL: Number(unRealizedProfit).toFixed(2), | |
uPNLKes: Number(Number(unRealizedProfit) * 131).toFixed(2), | |
ROE, | |
leverage | |
}) | |
if (ROE < -10) { | |
const attemptToFlipResponse = await reverseFailingPosition(positionToMonitor) | |
console.log("Successfully flipped position ", attemptToFlipResponse) | |
console.table(positionToMonitor) | |
} | |
} catch (error) { | |
console.log(error) | |
} | |
} | |
const sortedPositionData = positionData.sort((a, b) => a.ROE - b.ROE) | |
console.table(sortedPositionData) | |
start().catch(console.log) | |
} | |
start().catch(console.log) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
currently logs look like this
and the configurations of which markets to operate on can be changed in the code here