AI-Powered DEX Arbitrage Bots
Since my time at Deutsche Bank I have been programming financial indicators, trading strategies and arbitrage bots. In the early days it was simple: indicators with alert systems that sent me a notification when some conditions were met, and I executed the trades by hand. For long-term investments, where speed was not critical, this worked. At least for a while.
Later in crypto my approach to algorithmic trading changed a lot. Using the market imbalances between centralized exchanges like Poloniex and Bitfinex, I ran a quite profitable arbitrage bot from a Raspberry Pi plugged into my home router. That was a different beast, for a few reasons:
- Live trading is much more complex than backtesting. Spotting the opportunity is one thing, you also have to manage liquidity and position sizes carefully.
- APIs are unreliable. They go down, answer slowly or return garbage data, and you have to be ready for all of it.
- Latency is everything. It was less about clever indicators and more about seeing the imbalance fast enough to act before it's gone.
It was the time of hardcoded rules, if-else statements and endless trial and error. Then decentralized exchanges
(DEXes) and liquidity pools came, and the game changed again.
I started to build a strategy with deterministic logic to find arbitrage opportunities across DEX pools. The idea was a mathematical model that detects imbalances, sometimes several hops away. My first logic was primitive, and brute force soon became impossible as the number and complexity of DEXes grew. I had to level up.
That's when I started with machine learning, using TensorFlow to detect arbitrage patterns in market data. Deep neural networks and reinforcement learning should find signals I would otherwise miss. And it changed everything. The model learned over time and found opportunities I would never have thought of. If you ignore problems like front-running, MEV or gas fees, it was a very promising direction.
My current research moved beyond simple DEX arbitrage, but I want to show one experiment here: a transformer-based setup (yes, the same architecture that powers today's LLMs) applied to V2 pools, and why the picture changes with V3 pools.
V2 pools
Before we get to transformers, a quick look at how V2-style DEX pools work, like the ones introduced by Uniswap V2. They are fully deterministic, and this is key to understand how arbitrage opportunities appear and why they were once relatively easy to model.
A V2 liquidity pool is a constant product market maker (CPMM). Two tokens, say token and token , are pooled together and the core invariant is:
Where:
- = reserve of token
- = reserve of token
- = constant invariant
Every trade keeps the product of reserves. If you swap in some token , you get back an amount of so that the new product . In practice fees shift the invariant a little bit.
A simple arbitrage
Imagine two DEXes, DEX A and DEX B, each with an ETH/USDC pool. Because trades happen asynchronously, ETH might cost $1,950 on DEX A and $2,000 on DEX B.
Classic arbitrage:
- Buy ETH on DEX A for $1,950 USDC.
- Sell the same ETH on DEX B for $2,000 USDC.
- Profit: $50 (minus gas fees and slippage).
Since the V2 math is fully transparent and deterministic, this kind of cross-exchange arbitrage is easy to simulate and reason about.
Flash loans (and why you might not need them)
Flash loans are a clever DeFi primitive. You borrow funds without collateral, as long as you pay them back within the same transaction. For arbitrage they are handy when you don't want to risk your own capital.
For circular arbitrage inside DEXes though (e.g. ETH → DAI → USDC → ETH), you often don't need a flash loan when the opportunity fits into one atomic transaction. Some initial capital and good execution is enough.
What made V2 special was its predictability. You could compute every quote off-chain and pre-simulate every route. Perfect ground for rule-based bots, early ML models and at the end transformer-based agents.
The transformer architecture
Simulating a multi-DEX, multi-pool environment is relatively easy. You can set token amounts, pool sizes, how dense the connections are, flash loan providers, and inject arbitrage opportunities with different frequencies. So you get an ideal environment to train transformer models on practically unlimited data.
My recent setup is different from what I did before. I wanted to test how a modern transformer architecture, inspired by LLMs, performs here.
The network is a Transformer Encoder followed by a Linear Output Layer, which is split into PPO-style heads (value and policy). The encoder has 4 stacked Transformer Blocks and ends with a final RMS Normalization Layer.
You will notice there is no token embedding layer. All encodings were handcrafted, I explain why in the I/O section.
GQA: Grouped-Query Attention
Every Transformer Block has a Grouped-Query Attention with 4 attention heads divided into 2 groups. 4 heads are not computationally heavy, honestly. I just wanted to play with this newer improvement.
MoE: Mixture of Experts
The expert layer uses a linear router and 16 SwiGLU feedforward "experts". For each token three experts are selected dynamically, plus a fourth generic expert that is always on.
All results go through RMS Normalization, get merged and are fed into the next block. This repeats through the 4 layers until the final output.
Input and output
AI is no magic bullet. It needs thoughtful planning and design, and whether the model works or not depends a lot on well structured inputs and outputs.
In LLM pretraining you often start with big datasets and random embeddings. Here I wanted clear embeddings from the start, so I designed my own encoding.
DEX pools can be seen as a graph: nodes are tokens and edges are liquidity pools. So I encoded each token as a normalised one-hot vector, and each pool as the sum of its two token vectors, weighted by their reserves. Like this the model can learn the relations between tokens and pools quite easily.
Take three tokens, ETH, USDC and DAI. Their one-hot encodings could look like this:
I chose a big enough vector size (e.g. 128 dimensions) so I can add new tokens later, even though my initial set was only a few dozen tokens and their pools. The encoding for an ETH/USDC pool with reserves and would be:
Where 100 is the amount of ETH and 400,000 the amount of USDC in the pool.
Then each pool vector got some extra features:
- 6 dimensions: DEX id (one-hot, supports up to 6 DEXes)
- 1 dimension: pool fee tier (percentage per swap)
- 2 × 2 dimensions: lending info (AAVE), available liquidity and supply rate for both tokens
So the final input vector for each pool has dimensions.
The nice thing about these manual embeddings, and the orthogonality of the one-hot vectors, is that the model doesn't need to learn embeddings from scratch to understand how tokens and pools relate.
The input matrix had a fixed size too, similar to the context length in LLMs. I set a maximum number of pools (e.g. 50), and when there were fewer pools, I padded the input with zero vectors. So the transformer always gets the same input dimensions.
Example matrix with pools, where :
No positional encodings
The order of pools in the input matrix is arbitrary, unlike words in a sentence. So I didn't use positional encodings, self-attention can learn the relationships between pools regardless of their order.
Output
The policy head returns a single vector with this structure:
Where:
- = investment amount of the starting token
- = starting token id (positional index of the one-hot vector)
- to = next token ids
The output was fixed to 10 dimensions, which allows up to 8 hops. To stop early, the network returns a negative value as token id, and all following hops are ignored in the simulation.
Training and results
With the simulator I generated DEXes with different numbers of pools and tokens and different connection densities. Arbitrage opportunities were injected at random intervals, with varying frequency and complexity. Gas fees, slippage and flash loan requirements were simulated like in the real world.
The model was trained with Proximal Policy Optimization (PPO), a reinforcement learning algorithm that suits continuous action spaces well. The reward was the profit from executed arbitrage trades, minus gas fees and slippage.
Training ran in episodes, each one a fixed number of simulation steps. In every step the model looked at the current state of the DEX pools, made a decision based on its policy and got a reward depending on the outcome.
After roughly 3-4 million episodes the model found and executed arbitrage opportunities with high accuracy. Compared to the baseline (brute force) the profit went up significantly, so PPO together with the transformer architecture clearly worked in this context.
The funny part: it found complex arbitrage paths that were sometimes different from the injected imbalance, and more profitable. Some kind of emerging behaviour that adapted to new market conditions.
Final success rate: 98.9% on the test set.
V3 pools
V3 pools brought a new level of complexity with concentrated liquidity and multiple fee tiers. In V2 the liquidity is spread evenly across the price curve. V3 lets liquidity providers concentrate it within specific price ranges, which changes how trades affect the pool reserves and, as a result, how arbitrage opportunities appear.
It also made simulation and prediction much harder. In the end I used a rule-based approach and got similar performance as with V2 pools, without training and without the computational overhead.
Which showed me once again that not everything should be solved with machine learning. Not everything is a nail. Sometimes a well crafted algorithm is more efficient and does the job better.
I will explain the V3 approach in a future article.
Where this goes
The transformer experiment in a simulated DEX environment gave promising results, especially with V2 pools. The model was really good at finding and exploiting arbitrage opportunities, with a high success rate.
It is also the basis of my current research: using transformers for more complex DeFi strategies with other primitives than DEX pools, like principal/yield splits, hedging yields and more, where the deterministic approach might not be enough.