Skip to content

Instantly share code, notes, and snippets.

@BransonGitomeh
Last active June 22, 2023 19:57
Show Gist options
  • Save BransonGitomeh/367436f77c3237cd5c8909eb8c3f4685 to your computer and use it in GitHub Desktop.
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…
BINANCE_API_KEY=
BINANCE_SECRET_KEY=
BINANCE_API_URL=https://fapi.binance.com
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)
@BransonGitomeh
Copy link
Author

currently logs look like this

image

and the configurations of which markets to operate on can be changed in the code here

const symbols = [
    "IMXUSDT",
    "XRPUSDT",
    // "ETHUSDT",
    // "BTCUSDT",
    "DOGEUSDT",
    "BALUSDT",
    "EOSUSDT",
    // "ETCUSDT",
    "BATUSDT",
    "BELUSDT",
    // "BNBUSDT"
];

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment