bmino / binance-triangle-arbitrage

Detect in-market cryptocurrency arbitrage
MIT License
1.07k stars 336 forks source link

Viability of Triangle Arbitriage #114

Closed dlasher closed 3 years ago

dlasher commented 3 years ago

BOT DETAILS:

--- api.binance.com ping statistics --- 10 packets transmitted, 10 received, 0% packet loss, time 9014ms rtt min/avg/max/mdev = 1.576/1.594/1.612/0.013 ms

Looking at a netstat, I grabbed a collection of IP addresses used once the bot is running:

3.114.36.221 3.115.110.55 13.113.78.50 18.176.165.233 18.181.1.96 52.193.113.2 52.197.214.212 54.250.165.183

Traceroutes to all those IP's reveals a direct path, right into AWS in Toyko, all <2ms

Trading Example:

Here's an example today of a trade, which was over the threshold for profit, executed VERY quickly, 155ms.

["9/17/2020, 6:29:06 AM"] INFO : Attempting to execute BTC-BNB-ETH with an age of 58 ms and expected profit of 0.0758% ["9/17/2020, 6:29:06 AM"] INFO : Buying 2.4 BNBBTC @ market price ["9/17/2020, 6:29:06 AM"] INFO : Successfully bought 2.40000000 BNBBTC @ a quote of 0.00601032 in 58 ms ["9/17/2020, 6:29:06 AM"] INFO : Selling 2.4 BNBETH @ market price ["9/17/2020, 6:29:06 AM"] INFO : Successfully sold 2.40000000 BNBETH @ a quote of 0.17280000 in 62 ms ["9/17/2020, 6:29:06 AM"] INFO : Selling 0.172 ETHBTC @ market price ["9/17/2020, 6:29:06 AM"] INFO : Successfully sold 0.17200000 ETHBTC @ a quote of 0.00598284 in 31 ms ["9/17/2020, 6:29:06 AM"] INFO : Executed BTC-BNB-ETH position in 155 ms ["9/17/2020, 6:29:06 AM"] DEBUG: BNBBTC Stats: ["9/17/2020, 6:29:06 AM"] DEBUG: Expected Conversion: 0.00599976 BTC into 2.40000000 BNB ["9/17/2020, 6:29:06 AM"] DEBUG: Observed Conversion: 0.00601032 BTC into 2.40000000 BNB ["9/17/2020, 6:29:06 AM"] DEBUG: Price Error: 0.17600704% ["9/17/2020, 6:29:06 AM"] DEBUG: ["9/17/2020, 6:29:06 AM"] DEBUG: BNBETH Stats: ["9/17/2020, 6:29:06 AM"] DEBUG: Expected Conversion: 2.40000000 BNB into 0.17310582 ETH ["9/17/2020, 6:29:06 AM"] DEBUG: Observed Conversion: 2.40000000 BNB into 0.17280000 ETH ["9/17/2020, 6:29:06 AM"] DEBUG: Price Error: 0.17697917% ["9/17/2020, 6:29:06 AM"] DEBUG: ["9/17/2020, 6:29:06 AM"] DEBUG: ETHBTC Stats: ["9/17/2020, 6:29:06 AM"] DEBUG: Expected Conversion: 0.17300000 ETH into 0.00601781 BTC ["9/17/2020, 6:29:06 AM"] DEBUG: Observed Conversion: 0.17200000 ETH into 0.00598284 BTC ["9/17/2020, 6:29:06 AM"] DEBUG: Price Error: 0.00300860% ["9/17/2020, 6:29:06 AM"] INFO : ["9/17/2020, 6:29:06 AM"] INFO : BTC delta: -0.00002748 (-0.4572%) ["9/17/2020, 6:29:06 AM"] INFO : BNB delta: 0.00000000 ( 0.0000%) ["9/17/2020, 6:29:06 AM"] INFO : ETH delta: 0.00080000 ( 0.4651%) ["9/17/2020, 6:29:06 AM"] INFO : BNB commission: -0.00538301 ["9/17/2020, 6:29:06 AM"] INFO :

DISCUSSION:

As you can see, it spent more BTC than expected, got less ETH than expected, ended up with less BTC than expected, even having taken less than 200ms to execute the entire chain! (/tiphat to the programmer of the bot, nicely done)

STARTED WITH: 0.00599976 BTC ENDED WITH : 0.00598284 BTC (also spent BNB on every trade to execute it)

Wanted to start a quick discussion around whether this concept is even useful outside of something the exchanges do themselves.. (which I believe they do...)

Given that I'm as close & fast & reactive as possible, is there even money to be made this way?

bmino commented 3 years ago

It's a sad reality that execution takes on the order of 10's of milliseconds. Perhaps this alone is too much to overcome consistently? I still hold out hope for parallel execution improving this.

But let's look at what happened in this example!

  1. BNBBTC shifted enough to require an additional 0.17600704% BTC within worst case 116 ms (58 + 58)
  2. We converted all the BNB as expected
  3. BNBETH shifted enough to get 0.17697917% less ETH within worst case 174 ms (58 + 58 + 62)
  4. Since we have less ETH than expected, we have dropped below a dust step and can only convert .172 instead of .173 ETH. This difference leads to a gain of 0.0008 ETH overall.
  5. Finally we convert less ETH than expected and of course get less BTC than originally expected.

Here is the crazy part though. If you assume that all three legs were equal values to each other (ie BTC ~ BNB ~ ETH) and you lost 0.4572% of A, netted 0% of B, and gained 0.4651% of C:

- 0.4572%
- 0.0000%
+ 0.4651%
---------
+ 0.0079%

This is still not what the bot predicted and doesn't account for fees, but the thing to note is that errors compound themselves. If the A-B conversion goes awry, then the B-C conversion and C-A conversion has different starting quantities.

If you turn on trace logging the depth cache used for calculations will be displayed and can be compared against your order history to determine exactly what shifted in the depth cache

bmino commented 3 years ago

I also have no doubt the exchange(s) have internal methods checking for the same relationships this bot looks for... and can execute this with 0 latency before information is even published to the public depth cache

dlasher commented 3 years ago

I also have no doubt the exchange(s) have internal methods checking for the same relationships this bot looks for... and can execute this with 0 latency before information is even published to the public depth cache

I believe you're exactly correct. would be cool if this bot was written to ccxt, then we could figure out which of the other exchanges did NOT do the same thing.. find a home for TriArb. 👍

bmino commented 3 years ago

I looked into ccxt, and the websocket support isn't great :( You also hit issues with things like dust quantities being unique

dlasher commented 3 years ago

I looked into ccxt, and the websocket support isn't great :( You also hit issues with things like dust quantities being unique

Yeah, they want $$$ for the "pro" version with good websocket support.

I've also looked at : https://github.com/altangent/ccxws - as an alternative.

ilyacherevkov commented 3 years ago

Guys, it’s impossible to perform active triangular arbitrage on centralized exchanges. I’ve been doing it for 2 years. Look at DEXes or tune algo to execute first leg with limit order for specific target return.

ilyacherevkov commented 3 years ago

Better to separate calculation and data storage logic from exchange connection logic. That way you can test many exchanges quickly.