Triangular Arbitrage With Crypto DEX’s: Part One

Alex Ford
Coinmonks
5 min readApr 19, 2022

--

Building an arbitrage bot is harder than they told you

Photo by 愚木混株 cdd20 on Unsplash

Introduction — Does the money printer go brrr?

Arbitrage is the practice of taking advantage of the difference in asset prices in the market. Arbitrage has been used in Forex for a long time because of the fluctuating prices of currency. Investopedia has a good intro to this — https://www.investopedia.com/terms/a/arbitrage.asp

Arbitrage opportunities can exist within the crypto market as well. In fact, arbitrage, especially in decentralized exchanges is encouraged. Arbitrage is the market being inefficient with its pricing, arbitrage makes these prices “efficient” again by bringing the asset back to its intended level.

Types of Arbitrage

Exchange Arb

One example of Arbitrage is between exchanges. For example, I could buy BTC-GBP on Coinbase Pro, let’s say I buy 1 Bitcoin on Coinbase for 32,051.44 GBP I transfer my 1BTC to Binance and sell it there for 32,067.76 GBP. I’ve made 16.32 GBP profit. There are a lot of factors here like transfer fees, slippage, spread, etc but that’s the basic principle.

Triangular Arb

Example of Triangular Arbitrage (Image By Author)

Triangular arbitrage is the method of performing 3 or more swaps to generate a profit. The example above illustrates that, let’s say we start with 1 BTC, we swap that for 14 ETH. We sell 14 ETH for 45,000 USDC which we then use to buy 1.082 BTC. This generates a 0.82 BTC Profit.

The Plan

I really like ALGO — I am not a shill or anything, not saying to buy some but I just find it really easy to use, cheap and fast. My plan was to use Tinyman (A large DEX on Algorand) to see if I could find any triangle opportunities. The flow looks a little like this.

Flow of Tinyman Arb Bot

I didn’t want to keep having to get swap quotes for all the permutations of the assets available. There are roughly one million two hundred different combinations of assets (1,224,936 to be precise). If I just brute force each permutation, that’s over a million network calls which would be very slow. I wanted to compute all quotes for each swap and create a matrix looking like this.

Example Matrix (Image by Author)

Where the y-axis is the asset to be swapped and the x-axis is the asset to be received. As below, if you take ALGO as A1 and USDC as A2, you would get 0.751 USDC for 1 ALGO.

Matrix Quotes (Image by Author)

This fixes a couple of issues around having to get multiple quotes for the paths, and allows for a quick lookup in the matrix. I just multiply the swap rate by the stake, i.e 10 ALGOs to USDC gave me 10*0.751 = 7.51 USDC.

I actually did manage to get this working, the downside is, I ran it for 2 days with no possible arbitrage opportunities. Some came close, please have a minute of silence for the close swaps below — This was using 20 ALGO as the input.

Path (0, 31566704, 312769) Close to Profit!First Swap Quote: SwapQuote(swap_type='fixed-input', amount_in=ALGO('20'), amount_out=USDC('14.394919'), swap_fees=ALGO('0.06'), slippage=0.01)Second Swap Quote: SwapQuote(swap_type='fixed-input', amount_in=USDC('14.25097'), amount_out=USDt('14.260552'), swap_fees=USDC('0.042752'), slippage=0.01)Third Swap Quote: SwapQuote(swap_type='fixed-input', amount_in=USDt('14.117947'), amount_out=ALGO('19.402954'), swap_fees=USDt('0.042353'), slippage=0.01)Final Amount Of ALGO('19.208925')--------------------------------------------------------------------Path (0, 226701642, 404044168) Close to Profit!First Swap Quote: SwapQuote(swap_type='fixed-input', amount_in=ALGO('20'), amount_out=YLDY('6096.563343'), swap_fees=ALGO('0.06'), slippage=0.01)Second Swap Quote: SwapQuote(swap_type='fixed-input', amount_in=YLDY('6035.59771'), amount_out=Nekos('1242639.8739'), swap_fees=YLDY('18.106793'), slippage=0.01)Third Swap Quote: SwapQuote(swap_type='fixed-input', amount_in=Nekos('1230213.4752'), amount_out=ALGO('19.212889'), swap_fees=Nekos('3690.6404'), slippage=0.01)Final Amount Of ALGO('19.020761')

You might have noticed above, the paths are numbers, not ALGO — USDC etc. This is because most DEX’s use the ASA ID for their pool identifiers. These are just asset ids (https://developer.algorand.org/docs/get-details/asa/)

Issues

This proof of concept was riddled with issues, I sort of coded myself into a corner not realising how difficult this would be, and how many factors to take into account.

  • It was slow, iterating over millions of permutations and getting the quotes in the first place took time, not to mention matrix lookups happened multiple times for the same swaps
  • Liquidity would skew things. If I got a quote to swap 1 goBTC for USDC, there might not be enough liquidity in the pool to facilitate it because of the USD value difference. i.e 1 goBTC (Worth 40,000 USD) would swap for only 200 USDC (Worth 200 USD) because there wasn’t enough USDC in the pool to swap it all — this skews quotes in the matrix
  • Including other exchanges would mean having to use a 3D Matrix, this is fine but is adding more complexity and querying would be more difficult.
  • I was only doing permutations with a length of 3, increasing this would make performance even worse but I wanted to see what was possible with 5+ swaps — fees and slippage would affect this more but it’s all fun!

A New Approach

The code worked, but it couldn’t find any profitable trades and it was plagued with performance issues.

I had to do a complete refactor to support multiple exchanges and to be faster otherwise it would never be profitable.

I’ll continue this in part 2!

If you’re interested in the code, please appreciate I managed to start making some nice profit with the bot in the end. I am going to put myself first in this instance and not release the code, knowing this will make the opportunities harder to capitalise on.

Join Coinmonks Telegram Channel and Youtube Channel learn about crypto trading and investing

Also, Read

--

--