Skip to content

Commit

Permalink
Merge branch 'develop/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
bmino committed Apr 4, 2019
2 parents 66e46bf + 2598ea3 commit 3ec438c
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 60 deletions.
50 changes: 13 additions & 37 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 3 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"name": "binance-triangle-arbitrage",
"version": "4.4.4",
"version": "4.4.5",
"private": true,
"engines": {
"node": "11.10.0",
"node": "11.10.1",
"npm": "6.9.0"
},
"scripts": {
Expand All @@ -13,9 +13,7 @@
"blessed": "^0.1.81",
"lodash": "^4.17.11",
"node-binance-api": "^0.9.0",
"pino": "^5.11.1"
},
"devDependencies": {
"pino": "^5.11.1",
"pino-pretty": "^2.5.0"
}
}
63 changes: 47 additions & 16 deletions src/main/ArbitrageExecution.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@ const _ = require ('lodash');
const ArbitrageExecution = {

inProgressIds: new Set(),
inProgressSymbols: new Set(),
orderHistory: {},
balances: {},

executeCalculatedPosition(calculated) {
if (!ArbitrageExecution.isSafeToExecute(calculated)) return false;

// Register trade id as being executed
ArbitrageExecution.inProgressIds.add(calculated.id);
ArbitrageExecution.orderHistory[calculated.id] = new Date().getTime();
ArbitrageExecution.inProgressSymbols.add(calculated.trade.symbol.a);
ArbitrageExecution.inProgressSymbols.add(calculated.trade.symbol.b);
ArbitrageExecution.inProgressSymbols.add(calculated.trade.symbol.c);

const before = new Date().getTime();
const initialBalances = _.cloneDeep(ArbitrageExecution.balances);
Expand All @@ -34,30 +39,54 @@ const ArbitrageExecution = {
})
.then(() => {
ArbitrageExecution.inProgressIds.delete(calculated.id);
ArbitrageExecution.inProgressSymbols.delete(calculated.trade.symbol.a);
ArbitrageExecution.inProgressSymbols.delete(calculated.trade.symbol.b);
ArbitrageExecution.inProgressSymbols.delete(calculated.trade.symbol.c);
});
},

isSafeToExecute(calculated) {
const SECONDS_IN_ONE_DAY = 60 * 60 * 24;

// Profit Threshold is Not Satisfied
if (calculated.percent < CONFIG.TRADING.PROFIT_THRESHOLD) return false;

// Age Threshold is Not Satisfied
const ageInMilliseconds = new Date().getTime() - Math.min(calculated.times.ab, calculated.times.bc, calculated.times.ca);
if (ageInMilliseconds > CONFIG.TRADING.AGE_THRESHOLD) return false;

if (CONFIG.TRADING.EXECUTION_CAP && Object.keys(ArbitrageExecution.orderHistory).length >= CONFIG.TRADING.EXECUTION_CAP && ArbitrageExecution.inProgressIds.size === 0) {
const msg = `Cannot exceed execution cap of ${CONFIG.TRADING.EXECUTION_CAP} execution`;
if (CONFIG.TRADING.EXECUTION_CAP && ArbitrageExecution.inProgressIds.size === 0 && ArbitrageExecution.getExecutionAttemptCount() >= CONFIG.TRADING.EXECUTION_CAP) {
const msg = `Cannot exceed user defined execution cap of ${CONFIG.TRADING.EXECUTION_CAP} executions`;
logger.execution.error(msg);
process.exit();
return false;
}
if (CONFIG.TRADING.EXECUTION_CAP && Object.keys(ArbitrageExecution.orderHistory).length >= CONFIG.TRADING.EXECUTION_CAP) {
if (CONFIG.TRADING.EXECUTION_CAP && ArbitrageExecution.getExecutionAttemptCount() >= CONFIG.TRADING.EXECUTION_CAP) {
logger.execution.trace(`Blocking execution because ${Object.keys(ArbitrageExecution.orderHistory).length}/${CONFIG.TRADING.EXECUTION_CAP} executions have been attempted`);
return false;
}
if (ArbitrageExecution.inProgressIds.has(calculated.id)) {
logger.execution.trace(`Blocking execution because ${calculated.id} is already being executed`);
logger.execution.trace(`Blocking execution because ${calculated.id} is currently being executed`);
return false;
}
if (ArbitrageExecution.inProgressSymbols.has(calculated.trade.symbol.a)) {
logger.execution.trace(`Blocking execution because ${calculated.trade.symbol.a} is currently involved in an execution`);
return false;
}
if (ArbitrageExecution.inProgressSymbols.has(calculated.trade.symbol.b)) {
logger.execution.trace(`Blocking execution because ${calculated.trade.symbol.b} is currently involved in an execution`);
return false;
}
if (ArbitrageExecution.inProgressSymbols.has(calculated.trade.symbol.c)) {
logger.execution.trace(`Blocking execution because ${calculated.trade.symbol.c} is currently involved in an execution`);
return false;
}
if (ArbitrageExecution.tradesInXSeconds(10) >= 3) {
logger.execution.trace(`Blocking execution because ${ArbitrageExecution.tradesInXSeconds(10)} trades have already been executed in the last 10 seconds`);
if (ArbitrageExecution.executedTradesInLastXSeconds(SECONDS_IN_ONE_DAY) > 10000) {
logger.execution.trace(`Blocking execution because ${ArbitrageExecution.executedTradesInLastXSeconds(SECONDS_IN_ONE_DAY)} trades have been completed in the past 24 hours`);
return false;
}
if (ArbitrageExecution.executedTradesInLastXSeconds(10) >= 7) {
logger.execution.trace(`Blocking execution because ${ArbitrageExecution.executedTradesInLastXSeconds(10)} trades have been completed in the last 10 seconds`);
return false;
}

Expand All @@ -81,13 +110,19 @@ const ArbitrageExecution = {
return differences;
},

tradesInXSeconds(seconds) {
executedTradesInLastXSeconds(seconds) {
const timeFloor = new Date().getTime() - (seconds * 1000);
return Object.values(ArbitrageExecution.orderHistory).filter(time => time > timeFloor).length;
return Object.values(ArbitrageExecution.orderHistory).filter(time => time > timeFloor).length * 3;
},

getExecutionAttemptCount() {
return Object.keys(ArbitrageExecution.orderHistory).length;
},

execute(calculated) {
return ArbitrageExecution.getExecutionStrategy()(calculated);
ArbitrageExecution.orderHistory[calculated.id] = new Date().getTime();
return ArbitrageExecution.getExecutionStrategy()(calculated)
.then(() => ArbitrageExecution.orderHistory[calculated.id] = new Date().getTime());
},

getExecutionStrategy() {
Expand All @@ -109,12 +144,8 @@ const ArbitrageExecution = {

linearExecutionStrategy(calculated) {
return BinanceApi.marketBuyOrSell(calculated.trade.ab.method)(calculated.trade.ab.ticker, calculated.ab.market)
.then(() => {
return BinanceApi.marketBuyOrSell(calculated.trade.bc.method)(calculated.trade.bc.ticker, calculated.bc.market);
})
.then(() => {
return BinanceApi.marketBuyOrSell(calculated.trade.ca.method)(calculated.trade.ca.ticker, calculated.ca.market);
});
.then(() => BinanceApi.marketBuyOrSell(calculated.trade.bc.method)(calculated.trade.bc.ticker, calculated.bc.market))
.then(() => BinanceApi.marketBuyOrSell(calculated.trade.ca.method)(calculated.trade.ca.ticker, calculated.ca.market));
}

};
Expand Down
4 changes: 2 additions & 2 deletions src/main/Main.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ function calculateArbitrage() {

MarketCache.relationships.forEach(relationship => {
try {
let calculated = CalculationNode.optimize(relationship);
const calculated = CalculationNode.optimize(relationship);
if (calculated) {
if (CONFIG.HUD.ENABLED) results[calculated.id] = calculated;
if (ArbitrageExecution.isSafeToExecute(calculated)) ArbitrageExecution.executeCalculatedPosition(calculated);
ArbitrageExecution.executeCalculatedPosition(calculated);
}
} catch (error) {
logger.performance.debug(error.message);
Expand Down

0 comments on commit 3ec438c

Please sign in to comment.