Skip to content
This repository has been archived by the owner on Jun 24, 2022. It is now read-only.

Squashed commit of logging improvements #5

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Squashed commit of the following:commit 54d20d2d8b2509381dedbd6bd6bdf…
…21496fad48fAuthor: Roger Watkins <[email protected]>Date: Sat Nov 3 00:38:41 2018 +0000 More tidying up of log messages. Fix logging responses. Log warning if STOP not filled.commit f2355e6c1fa8f6cc4a9c30e4901357aacaf29be7Author: Roger Watkins <[email protected]>Date: Thu Nov 1 23:58:14 2018 +0000 Add moment.js for timer support. Output price updates every 5 minutes.commit 5080b3efe0c7ada2607931da2172bae0d8b572f1Author: Roger Watkins <[email protected]>Date: Thu Nov 1 23:19:41 2018 +0000 Add winston logger to script and add some helpful logging to see what is going on, including order entries and cancellations.commit c402d6f491a3339132d36bf3a4dea5ccb47634abAuthor: Tony Ho <[email protected]>Date: Wed Oct 31 22:39:36 2018 +1100 Enable automatic reconnection of WebSockets
  • Loading branch information
Roger Watkins committed Nov 4, 2018
commit 563044764ef31ca3c34a64cad619436837c73fab
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,6 @@ typings/
.next

package-lock.json

# VScode
.vscode
109 changes: 82 additions & 27 deletions binance-oco.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,23 +66,60 @@ const { F: nonBnbFees } = argv;

pair = pair.toUpperCase();

const { createLogger, format, transports } = require('winston');

const loggerFormat = format.printf(info => `${info.timestamp} - ${JSON.stringify(info.message)}`);

const logPath = `${process.env.LOGBASEPATH}${pair}-${new Date()}.log`;

const moment = require('moment');

let lastPriceUpdate;

const options = {
console: {
level: 'debug',
handleExceptions: true,
format: format.combine(
format.timestamp(),
loggerFormat,
),
},
file: {
level: 'info',
filename: `${logPath}`,
handleExceptions: true,
format: format.combine(
format.timestamp(),
format.json(),
),
},
};
const logger = createLogger({
transports: [
new transports.Console(options.console),
new transports.File(options.file),
],
});


const Binance = require('node-binance-api');

const binance = new Binance().options({
APIKEY: process.env.APIKEY,
APISECRET: process.env.APISECRET,
useServerTime: true,
reconnect: false,
reconnect: true,
}, () => {
binance.exchangeInfo((exchangeInfoError, exchangeInfoData) => {
if (exchangeInfoError) {
console.error('Could not pull exchange info', exchangeInfoError.body);
logger.error('Could not pull exchange info', exchangeInfoError.body);
process.exit(1);
}

const symbolData = exchangeInfoData.symbols.find(ei => ei.symbol === pair);
if (!symbolData) {
console.error(`Could not pull exchange info for ${pair}`);
logger.error(`Could not pull exchange info for ${pair}`);
process.exit(1);
}

Expand Down Expand Up @@ -205,12 +242,12 @@ const binance = new Binance().options({

const sellComplete = function (error, response) {
if (error) {
console.error('Sell error', error.body);
logger.error(`Sell error ${error.body}`);
process.exit(1);
}

console.log('Sell response', response);
console.log(`order id: ${response.orderId}`);
logger.debug(`Sell response ${response}`);
logger.info(`>>> SELL order placed ${response.symbol} : #${response.orderId} >>>`);

if (!(stopPrice && targetPrice)) {
process.exit();
Expand All @@ -224,10 +261,12 @@ const binance = new Binance().options({
};

const placeStopOrder = function () {
logger.info(`>>> Placing SELL order ${pair} (STOP) - (stop: ${stopPrice}, limit: ${limitPrice || stopPrice}) for ${stopSellAmount}.`);
binance.sell(pair, stopSellAmount, limitPrice || stopPrice, { stopPrice, type: 'STOP_LOSS_LIMIT', newOrderRespType: 'FULL' }, sellComplete);
};

const placeTargetOrder = function () {
logger.info(`>>> Placing SELL order ${pair} (TARGET) - (limit: ${targetPrice}) for ${targetSellAmount}.`);
binance.sell(pair, targetSellAmount, targetPrice, { type: 'LIMIT', newOrderRespType: 'FULL' }, sellComplete);
if (stopPrice && targetSellAmount !== stopSellAmount) {
stopSellAmount -= targetSellAmount;
Expand All @@ -249,12 +288,12 @@ const binance = new Binance().options({

const buyComplete = function (error, response) {
if (error) {
console.error('Buy error', error.body);
logger.error(`Buy error ${error.body}`);
process.exit(1);
}

console.log('Buy response', response);
console.log(`order id: ${response.orderId}`);
logger.debug(`Buy response : ${response}`);
logger.info(`>>> BUY order placed ${response.symbol} : #${response.orderId} >>>`);

if (response.status === 'FILLED') {
calculateStopAndTargetAmounts(response.fills[0].commissionAsset);
Expand All @@ -265,15 +304,18 @@ const binance = new Binance().options({
};

if (buyPrice === 0) {
logger.info(`>>> Placing a BUY MARKET order ${pair} for ${amount}.`);
binance.marketBuy(pair, amount, { type: 'MARKET', newOrderRespType: 'FULL' }, buyComplete);
} else if (buyPrice > 0) {
binance.prices(pair, (error, ticker) => {
const currentPrice = ticker[pair];
console.log(`${pair} price: ${currentPrice}`);
logger.info(`${pair} price: ${currentPrice}`);

if (buyPrice > currentPrice) {
logger.info(`>>> Placing a BUY order ${pair} - (trigger: ${buyPrice}, limit: ${buyLimitPrice || buyPrice}) for ${amount}.`);
binance.buy(pair, amount, buyLimitPrice || buyPrice, { stopPrice: buyPrice, type: 'STOP_LOSS_LIMIT', newOrderRespType: 'FULL' }, buyComplete);
} else {
logger.info(`>>> Placing a BUY order ${pair} - (limit: ${buyPrice}) for ${amount}.`);
binance.buy(pair, amount, buyPrice, { type: 'LIMIT', newOrderRespType: 'FULL' }, buyComplete);
}
});
Expand All @@ -288,53 +330,61 @@ const binance = new Binance().options({

if (buyOrderId) {
if (!cancelPrice) {
console.log(`${symbol} trade update. price: ${price} buy: ${buyPrice}`);
if (!lastPriceUpdate || moment().diff(lastPriceUpdate, 'minute') > 5) {
logger.info(`${symbol} trade update. price: ${price} buy: ${buyPrice}`);
lastPriceUpdate = moment();
}
} else {
console.log(`${symbol} trade update. price: ${price} buy: ${buyPrice} cancel: ${cancelPrice}`);
if (!lastPriceUpdate || moment().diff(lastPriceUpdate, 'minute') > 5) {
logger.info(`${symbol} trade update. price: ${price} buy: ${buyPrice} cancel: ${cancelPrice}`);
lastPriceUpdate = moment();
}

if (((price < buyPrice && price <= cancelPrice)
|| (price > buyPrice && price >= cancelPrice))
&& !isCancelling) {
isCancelling = true;
logger.info(`<<< Cancel BUY order ${symbol} : #${buyOrderId} - (reason: cancel price ${cancelPrice} was breached).`);
binance.cancel(symbol, buyOrderId, (error, response) => {
isCancelling = false;
if (error) {
console.error(`${symbol} cancel error:`, error.body);
logger.error(`${symbol} cancel error:`, error.body);
return;
}

console.log(`${symbol} cancel response:`, response);
logger.info(`<<< BUY Order ${symbol} : #${buyOrderId} cancelled. <<<`);
logger.debug(`${symbol} cancel response: ${response}`);
process.exit(0);
});
}
}
} else if (stopOrderId || targetOrderId) {
console.log(`${symbol} trade update. price: ${price} stop: ${stopPrice} target: ${targetPrice}`);

logger.info(`${symbol} trade update. price: ${price} stop: ${stopPrice} target: ${targetPrice}`);
if (stopOrderId && !targetOrderId && price >= targetPrice && !isCancelling) {
isCancelling = true;
logger.info(`<<< Cancel STOP order ${symbol} : #${stopOrderId} - (reason: target price ${targetPrice} was hit).`);
binance.cancel(symbol, stopOrderId, (error, response) => {
isCancelling = false;
if (error) {
console.error(`${symbol} cancel error:`, error.body);
logger.error(`${symbol} cancel error: ${error.body}`);
return;
}

logger.info(`<<< STOP ${symbol} : #${stopOrderId} cancelled. <<<`);
stopOrderId = 0;
console.log(`${symbol} cancel response:`, response);
logger.debug(`${symbol} cancel response: ${response}`);
placeTargetOrder();
});
} else if (targetOrderId && !stopOrderId && price <= stopPrice && !isCancelling) {
isCancelling = true;
logger.info(`<<< Cancel TARGET order ${symbol} : #${targetOrderId} - (reason: stop price ${stopPrice} was hit).`);
binance.cancel(symbol, targetOrderId, (error, response) => {
isCancelling = false;
if (error) {
console.error(`${symbol} cancel error:`, error.body);
logger.error(`${symbol} cancel error: ${error.body}`);
return;
}

logger.info(`<<< TARGET ${symbol} : #${targetOrderId} cancelled. <<<`);
targetOrderId = 0;
console.log(`${symbol} cancel response:`, response);
logger.debug(`${symbol} cancel response: ${response}`);
if (targetSellAmount !== stopSellAmount) {
stopSellAmount += targetSellAmount;
}
Expand All @@ -349,15 +399,19 @@ const binance = new Binance().options({
s: symbol, p: price, q: quantity, S: side, o: orderType, i: orderId, X: orderStatus,
} = data;

console.log(`${symbol} ${side} ${orderType} ORDER #${orderId} (${orderStatus})`);
console.log(`..price: ${price}, quantity: ${quantity}`);

logger.info(`Order Executed: ${symbol} ${side} ${orderType} ORDER #${orderId} (${orderStatus})`);
logger.info(`At price: ${price}, quantity: ${quantity}`);
if (orderStatus === 'NEW' || orderStatus === 'PARTIALLY_FILLED') {
return;
}

if (orderStatus !== 'FILLED') {
console.log(`Order ${orderStatus}. Reason: ${data.r}`);
logger.error(`Order ${orderStatus}. Reason: ${data.r}`);
if (orderId === stopOrderId) {
logger.error(`WARNING STOP ORDER ${symbol} WAS NOT FILLED - YOU MUST CLOSE THE REMAINING POSITION OF ${stopSellAmount} MANUALLY.`);
}
// TODO: What if the incomplete order was a sell or target - we need script to stay
// alive in this case.
process.exit(1);
}

Expand Down Expand Up @@ -390,4 +444,5 @@ const binance = new Binance().options({
process.on('exit', () => {
const endpoints = binance.websockets.subscriptions();
binance.websockets.terminate(Object.entries(endpoints));
logger.info('Script terminated.');
});
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
"homepage": "https://github.com/tony-ho/binance-oco#readme",
"dependencies": {
"dotenv": "^6.0.0",
"moment": "^2.22.2",
"node-binance-api": "^0.8.5",
"winston": "^3.1.0",
"yargs": "^11.0.0"
},
"devDependencies": {
Expand Down