Triangular Arbitrage: How It Works and Why It Rarely Nets Out

🌐 한국어

The idea behind triangular arbitrage fits in one sentence. Buy B with token A, buy C with B, buy A back with C — and if you end up with more A than you started with, that's profit. You're hunting the moment three pairs on a single exchange (or a single chain) fall out of alignment with each other. The principle is grade-school arithmetic. Actually clearing a net profit is an entirely different story.

Compute the Loop as a Product

Say the route is WBNB → USDT → CAKE → WBNB. At each hop you multiply by the exchange rate — "how many units come out per unit in." If the final figure exceeds your starting amount, you have a theoretical profit.

// Multiply the effective rate at each hop to get the loop result

// rateAB = effective price of B in terms of A (after fees)

func cycleReturn(amountIn float64, rates []float64) float64 {

    out := amountIn

    for _, r := range rates {

        out = out * r   // multiply by the rate at every hop

    }

    return out // out > amountIn means an (apparent) profit

}

Real bots register these routes up front. The code below turns a cycle into a human-readable label — when you're debugging, WBNB→USDT→CAKE→WBNB beats cycle#7 every time.

// Render a registered cycle as "WBNB→USDT→CAKE→WBNB"

func cycleLabel(hops []Hop) string {

    if len(hops) == 0 {

        return "cycle(empty)"

    }

    parts := make([]string, 0, len(hops)+1)

    parts = append(parts, symbol(hops[0].TokenIn))

    for _, h := range hops {

        parts = append(parts, symbol(h.TokenOut))

    }

    return strings.Join(parts, "→")

}

Pitfall 1 — Fees Compound Three Times

The first thing that trips you up is fees. Every hop charges a swap fee (0.25–0.3%, typically), and a triangular route has three hops, so you pay three times. Each one looks small; compounded, they aren't.

// Three hops at 0.3% each...

// Even with prices in perfect balance (rate 1.0), the loop loses ~0.9%

gross := 1.0 * 1.0 * 1.0

net := gross * 0.997 * 0.997 * 0.997 // ~0.991

// So you need to beat ~0.9% just to break even. Anything above that is real profit

Put differently: the mispricing across those three pairs has to exceed the cumulative fee (about 0.9% here) before you're even at break-even. Opportunities that clear that bar aren't common.

Pitfall 2 — Gas and Slippage

Suppose the apparent profit does clear the fees. Now gas is waiting. Three swaps consume real execution cost, even bundled into a single on-chain transaction. Then add slippage — as size grows, each hop fills at a worse price, so the rates you computed turn out optimistic.

func netProfit(amountIn, cycleOut, gasCost float64) float64 {

    grossProfit := cycleOut - amountIn

    return grossProfit - gasCost // must stay positive after gas to be worth executing

}

// Execution guard: only send when net profit clears the minimum threshold

if netProfit(amountIn, out, gasCost) < minProfitThreshold {

    return // skip — executing would itself be a loss

}

Pitfall 3 — Competition and Timing

The cruelest one. You are not the only one seeing this. Dozens of bots are looking at the same edge on their screens, and only the one that fills first takes it. On-chain, that turns into a race to get ahead in the mempool — front-running. By the time your transaction makes it into a block, the mispricing has most likely already closed.

So in Practice

  • Judge on net profit only. Not the apparent edge — execute only when the figure clears the threshold after fees, gas, and expected slippage have all been subtracted.
  • Size to the liquidity. The thinnest of the three pools caps your entire size. Push hard into a thin pool and slippage eats the whole edge.
  • Scan fast, execute carefully. Sweep broadly off-chain with closed-form math, then verify only the promising candidates precisely before you execute.
  • Accept that opportunities are rare. Most scans ending in "no profit" is the normal state. Lowering the threshold to force trades only produces losing ones.

Triangular arbitrage is appealing because the principle is simple, and that simplicity is the trap. Real skill isn't "multiplying along a route" — it's picking out the tiny minority of opportunities that still have something left after fees, gas, slippage, and competition. Knowing that most triangular opportunities don't actually survive is step one.

This article is for educational and informational purposes and is not investment advice. All automated trading, arbitrage included, carries a risk of principal loss and does not guarantee any actual net profit. The outcomes are your own responsibility.

댓글

이 블로그의 인기 게시물

한국투자증권 KIS API로 실시간 시세 받기 (WebSocket 실전)

파이썬으로 업비트 API 연동하기 — 시세 조회부터 주문까지 기초

Go로 자동매매 신호봇 프레임워크 설계하기