Naciśnij ESC, aby zamknąć

Order Book vs AMM: Mikrostruktura Rynku i Arbitraż HFT

Jeśli nadal myślisz, że transakcja na giełdzie to po prostu kliknięcie przycisku „Buy”, po którym dzieje się magia, to mam dla Ciebie wiadomości. Na poziomie mikrosekund i milisekund rynek to bezwzględne pole bitwy, gdzie płynność przepływa z jednego stanu w drugi, a szybkość realizacji i anatomia puli decydują o tym, kto zgarnie profit, a kto zapłaci za poślizg cenowy (slippage) i toksyczny przepływ.

W tradycyjnym handlu zcentralizowanym (TradFi i CEX) rządzi Order Book. W DeFi standardem stał się AMM. Ale kiedy schodzimy na poziom handlu wysokich częstotliwości (HFT), różnica między nimi okazuje się nie tylko technologiczna — ona fundamentalnie zmienia mechanikę kształtowania cen, arbitrażu i realizacji zleceń.

Rozbierzmy na czynniki pierwsze, jak wygląda mechanika płynności pod maską obu systemów, gdzie kryją się ukryte koszty i jak wykorzystać tę wiedzę w praktyce.

1. Anatomia arkusza zlecenia L2/L3: Jak naprawdę wygląda płynność

Większość inwestorów detalicznych widzi arkusz zleceń L2: zagregowane wolumeny na każdym poziomie cenowym. Ale algorytmy HFT i instytucjonalni gracze pracują na L3 (Order-by-Order) — surowym strumieniu danych, gdzie każde zdarzenie ma swój unikalny identyfikator (order_id), dokładny znacznik czasu i pozycję w kolejce.

Market Data
 

Zasada Price-Time Priority (FIFO)

W klasycznym silniku dopasowującym (matching engine) zlecenia są realizowane ściśle według priorytetu:

  • Cena (najlepsza cena otrzymuje priorytet).
  • Czas (przy równej cenie pierwszy realizowany jest ten, kto wcześniej ustawił się w kolejce).

Z powodu kolejki czasowej powstają dwa kluczowe efekty mikrostrukturalne:

Adverse Selection (Negatywna selekcja): Jeśli Twoje zlecenie limit na zakup zostanie szybko zrealizowane, istnieje duże prawdopodobieństwo, że na rynek wszedł duży sprzedawca z agresywnym przepływem (toxic flow), a cena będzie dalej spadać.

Queue Position Value: Miejsce na początku kolejki danego poziomu cenowego ma swoją własną wartość. Boty HFT ciągle anulują i ponownie wystawiają zlecenia (mechanika Spoofing/Layering lub adaptacyjne zarządzanie płynnością), aby utrzymać priorytet bez brania na siebie zbędnego ryzyka magazynowego (inventory risk).

2. AMM: Od klasycznego Constant Product do skoncentrowanej płynności

AMM różni się od arkusza zleceń w sposób fundamentalny: nie ma tu kolejki zleceń. Cena jest określana przez funkcję matematyczną inwariantu.

Constant Product (v2): x · y = k

W klasycznym Uniswap v2 płynność jest rozłożona od zera do nieskończoności.

Przy zawieraniu transakcji o wolumenie Δx trader zabiera z puli Δy, wyliczane z uwzględnieniem prowizji γ = (1 - fee):

Δy = (y · Δx · γ) / (x + Δx · γ)

Cena realizacji nie jest stała, lecz „ześlizguje się” wzdłuż krzywej w momencie realizacji.

Concentrated Liquidity (v3 / Tick-based)

Uniswap v3 przekształcił AMM w coś na kształt arkusza zleceń, pozwalając dostawcom płynności (LP) definiować przedziały cenowe [Pa, Pb].

Cena jest podzielona na tyki (ticks), gdzie każdy tyk odpowiada zmianie ceny o 0.01% (1 bps):

P(i) = 1.0001i

Płynność L wewnątrz przedziału działa jak „wirtualny” inwariant, ale przy przekroczeniu granicy tyka aktywna płynność gwałtownie się zmienia. Dla arbitrażysty HFT oznacza to jedno: arkusz AMM v3 jest dyskretny, a jego głębokość zmienia się skokowo przy przebijaniu kolejnych tyków.

3. Analiza porównawcza: Microstructure Matrix

ParametrOrder Book (CEX/TradFi)AMM (Uniswap v2)Concentrated AMM (v3)
Priorytet realizacjiPrice-Time (FIFO) / Pro-RataGas Price / MEV (Priority Fee)Gas Price / MEV (Priority Fee)
Opóźnienie (Latency)Mikrosekundy / NanosekundyCzas bloku (lub slotted latency)Czas bloku / Mempool P2P
Kształtowanie cenyAukcja ciągła (Continuous Double Auction)Dynamicznie z wolumenu transakcji (x · y = k)Dynamicznie w ramach aktywnego tyka
Koszty płynnościBrak nietrwałej straty (ale występuje Inventory Risk)Impermanent Loss (IL)Loss-Versus-Rebalancing (LVR)
Przejrzystość przepływuL3 Data Feeds (Pitch, ITCH, FIX)Mempool (przed blokiem) / On-chain (po bloku)Mempool (przed blokiem) / On-chain (po bloku)

4. Ukryte mechaniki: MEV, LVR i Toxic Flow

W arkuszu CEX algorytm HFT walczy o nanosekundy fizycznego opóźnienia sieciowego (kolokacja w serwerowni giełdy, światłowody, karty FPGA).

W DeFi pojęcie czasu ulega zagięciu: fundamentalną rolę odgrywa tu strukturyzacja bloku.

MEV (Maximal Extractable Value)

W AMM kolejność transakcji w bloku jest układana przez tzw. Searcherów i Builderów bloków. Rodzi to specyficzne mechaniki HFT:

  • Front-running / Back-running: Przechwytywanie transakcji w mempoolu poprzez zaproponowanie wyższej prowizji (Priority Fee).
  • Ataki typu Sandwich: Zakup tuż przed dużą transakcją użytkownika w celu podbicia ceny i natychmiastowa sprzedaż zaraz po niej.

LVR (Loss-Versus-Rebalancing)

Wszyscy przyzwyczaili się przeliczać ryzyko LP przez Impermanent Loss (IL). Jednak na poziomie wysokich częstotliwości bardziej adekwatna jest metryka LVR, zaproponowana przez badaczy z Uniwersytetu Columbia oraz Paradigm.

LVR (Loss-Versus-Rebalancing) to systematyczna strata dostawcy płynności w AMM w porównaniu do tego samego portfela, który jest stale rebalansowany na giełdzie CEX z wykorzystaniem cen zewnętrznych.

Przyczyną LVR jest arbitraż zmienności. Kiedy cena na CEX odjeżdża, pula AMM zostaje z nieaktualną ceną (stale price). Arbitrażysta HFT widzi ten spread, zgarnia tanią płynność z AMM i zabezpiecza pozycję na CEX. Dostawca płynności w AMM jest zawsze realizowany po najgorszej cenie w starciu z poinformowanym przepływem (toxic flow).

LVR ≈ (σ² / 8) · ∫0T St · Lt dt

Gdzie σ oznacza zmienność aktywa, St cenę, a Lt aktywną płynność. Wniosek: Im wyższa zmienność rynku, tym więcej pieniędzy LP oddają w ręce arbitrażystów HFT.

5. Praktyka: Skrypt Python do wyliczania kwotowania AMM v3 vs L2 Depth

Przejdźmy do kodu. Napiszemy działające narzędzie do wyliczania realnej ceny realizacji (z uwzględnieniem poślizgu) dla przykładowego zlecenia, porównując głębokość arkusza L2 oraz pulę Constant Product AMM.

Kod został napisany w czystym Pythonie, bez ciężkich zewnętrznych frameworków.

from __future__ import annotations
from dataclasses import dataclass
from enum import Enum
from typing import List
class FeeMode(Enum):
    QUOTE = "quote"  # prowizja pobierana z przychodzącego USDT
    BASE = "base"    # prowizja pobierana z otrzymanego ETH
@dataclass
class AskLevel:
    price: float
    volume: float
class OrderBookL2:
    """
    L2 arkusz zleceń (Strona Ask).
    Przykład pary ETH/USDT:
        price  = USDT za 1 ETH
        volume = ETH
    """
    def __init__(
        self,
        asks: List[tuple[float, float]],
        taker_fee: float = 0.001,
    ) -> None:
        if not (0 <= taker_fee < 1):
            raise ValueError("taker_fee musi być w przedziale [0, 1)")
        self.taker_fee = float(taker_fee)
        self.asks: List[AskLevel] = []
        for price, volume in asks:
            if price <= 0:
                raise ValueError("Cena musi być > 0")
            if volume <= 0:
                raise ValueError("Wolumen musi być > 0")
            self.asks.append(
                AskLevel(
                    price=float(price),
                    volume=float(volume),
                )
            )
        self.asks.sort(key=lambda x: x.price)
    def best_ask(self) -> float:
        if not self.asks:
            raise ValueError("Arkusz jest pusty")
        return self.asks[0].price
    def spot_price(self) -> float:
        return self.best_ask()
    def total_liquidity_quote(self) -> float:
        return sum(
            level.price * level.volume
            for level in self.asks
        )
    def total_liquidity_base(self) -> float:
        return sum(
            level.volume
            for level in self.asks
        )
    def simulate_buy(
        self,
        amount_in_quote: float,
        mutate: bool = True,
        fee_mode: FeeMode = FeeMode.QUOTE,
    ) -> tuple[float, float]:
        """
        Zakup aktywa bazowego za amount_in_quote.
        Zwraca:
            (
                otrzymane_aktywo_bazowe,
                srednia_cena_efektywna
            )
        """
        if amount_in_quote <= 0:
            raise ValueError(
                "amount_in_quote musi być > 0"
            )
        if fee_mode == FeeMode.QUOTE:
            quote_for_trade = (
                amount_in_quote *
                (1.0 - self.taker_fee)
            )
        else:
            quote_for_trade = amount_in_quote
        remaining_quote = quote_for_trade
        total_base_bought = 0.0
        new_levels: List[AskLevel] = []
        for level in self.asks:
            if remaining_quote <= 0:
                new_levels.append(level)
                continue
            level_cost = (
                level.price *
                level.volume
            )
            if remaining_quote >= level_cost:
                total_base_bought += level.volume
                remaining_quote -= level_cost
            else:
                base_from_level = (
                    remaining_quote /
                    level.price
                )
                total_base_bought += base_from_level
                remaining_volume = (
                    level.volume -
                    base_from_level
                )
                if remaining_volume > 1e-12:
                    new_levels.append(
                        AskLevel(
                            level.price,
                            remaining_volume,
                        )
                    )
                remaining_quote = 0.0
        if remaining_quote > 1e-9:
            raise ValueError(
                "Brak wystarczającej płynności w arkuszu"
            )
        if fee_mode == FeeMode.BASE:
            total_base_bought *= (
                1.0 - self.taker_fee
            )
        if total_base_bought <= 0:
            raise ValueError(
                "Otrzymano wolumen równy zeru"
            )
        avg_price = (
            amount_in_quote /
            total_base_bought
        )
        if mutate:
            self.asks = new_levels
        return total_base_bought, avg_price
class ConstantProductAMM:
    """
    AMM w stylu Uniswap V2
    x = ETH
    y = USDT
    spot = y / x
    """
    def __init__(
        self,
        reserve_x: float,
        reserve_y: float,
        fee: float = 0.003,
    ) -> None:
        if reserve_x <= 0:
            raise ValueError(
                "reserve_x musi być > 0"
            )
        if reserve_y <= 0:
            raise ValueError(
                "reserve_y musi być > 0"
            )
        if not (0 <= fee < 1):
            raise ValueError(
                "fee musi być w przedziale [0, 1)"
            )
        self.x = float(reserve_x)
        self.y = float(reserve_y)
        self.fee = float(fee)
    def spot_price(self) -> float:
        return self.y / self.x
    def invariant(self) -> float:
        return self.x * self.y
    def simulate_buy(
        self,
        amount_y_in: float,
        mutate: bool = True,
    ) -> tuple[float, float]:
        """
        Zakup ETH za USDT.
        Zwraca:
            (
                otrzymane_ETH,
                srednia_cena
            )
        """
        if amount_y_in <= 0:
            raise ValueError(
                "amount_y_in musi być > 0"
            )
        y_effective = (
            amount_y_in *
            (1.0 - self.fee)
        )
        x_out = (
            self.x *
            y_effective
        ) / (
            self.y +
            y_effective
        )
        if x_out <= 0:
            raise ValueError(
                "Otrzymano wolumen równy zeru"
            )
        if x_out >= self.x:
            raise ValueError(
                "Niewystarczająca płynność w puli"
            )
        avg_price = (
            amount_y_in /
            x_out
        )
        if mutate:
            self.x -= x_out
            self.y += amount_y_in
        return x_out, avg_price
def print_trade_result(
    title: str,
    received: float,
    avg_price: float,
    spot_price: float,
) -> None:
    slippage = (
        (avg_price - spot_price)
        / spot_price
    ) * 100
    print(
        f"{title:<12}"
        f" Otrzymano: {received:.6f}"
        f" | Średnia cena: {avg_price:,.4f}"
        f" | Poślizg (slippage): {slippage:.4f}%"
    )
def main() -> None:
    asks = [
        (3000.0, 1.5),
        (3001.0, 2.0),
        (3002.5, 5.0),
        (3005.0, 10.0),
        (3010.0, 25.0),
    ]
    orderbook = OrderBookL2(
        asks=asks,
        taker_fee=0.001,
    )
    amm = ConstantProductAMM(
        reserve_x=1000.0,
        reserve_y=3_000_000.0,
        fee=0.003,
    )
    trade_size = 15_000.0
    ob_spot = orderbook.spot_price()
    amm_spot = amm.spot_price()
    ob_received, ob_avg = orderbook.simulate_buy(
        amount_in_quote=trade_size,
        mutate=True,
        fee_mode=FeeMode.QUOTE,
    )
    amm_received, amm_avg = amm.simulate_buy(
        amount_y_in=trade_size,
        mutate=True,
    )
    print(
        f"\n=== Porównanie realizacji zlecenia "
        f"na {trade_size:,.2f} USDT ===\n"
    )
    print_trade_result(
        "ORDERBOOK",
        ob_received,
        ob_avg,
        ob_spot,
    )
    print_trade_result(
        "AMM V2",
        amm_received,
        amm_avg,
        amm_spot,
    )
    print("\n=== Stan po transakcji ===\n")
    if orderbook.asks:
        print(
            f"Best Ask: "
            f"{orderbook.best_ask():,.4f}"
        )
    else:
        print("Arkusz został całkowicie wykupiony")
    print(
        f"AMM Spot: "
        f"{amm.spot_price():,.4f}"
    )
    print(
        f"AMM Reserves: "
        f"{amm.x:.6f} ETH | "
        f"{amm.y:.2f} USDT"
    )
if __name__ == "__main__":
    main()

Jak interpretować wyniki

W głębokich pulach AMM małe zlecenia są realizowane z minimalnym poślizgiem, jednak wraz ze wzrostem wolumenu cena w AMM rośnie po wykładniczej krzywej. W arkuszu zleceń wszystko zależy natomiast od „ścianek” płynności (liquidity walls). Jeśli arkusz jest płytki, przebijesz kilka poziomów i zaliczysz rozjazd cenowy znacznie gorszy niż w AMM.

6. Modele hybrydowe: Jak DEX-y wdrażają Order Booki i dlaczego CEX-y spoglądają na AMM

Granica między arkuszami zleceń a modelami AMM powoli się zaciera. HFT i gracze instytucjonalni błyskawicznie zderzyli się ze ścianą możliwości klasycznego Uniswap v2: niska efektywność kapitałowa oraz brak obsługi zaawansowanych zleceń limit (Stop-loss, Take-profit, Iceberg) sprawiały, że DEX-y zupełnie nie nadawały się do profesjonalnego market makingu.

To wymusiło ewolucyjny skok i dało początek architekturom hybrydowym.

1. On-Chain oraz L2 Order Booki (dYdX, Hyperliquid, Vertex)

Wraz z nadejściem wysoce wydajnych sieci L1/L2 (Aptos, Sui, Arbitrum) oraz dedykowanych AppChainów, odpalenie pełnoprawnego order booka bezpośrednio na blockchainie stało się wreszcie realne.

Off-chain matching + On-chain settlement: Silniki kojarzenia zleceń śmigają off-chain na ultraszybkich matching engine'ach (aby zejść z opóźnieniami < 10 ms), natomiast same wykończenia transakcji i wymogi depozytowe rozliczane są w smart kontraktach.

Fully On-chain (Hyperliquid, Serum/Ellipsis): Cały order book żyje bezpośrednio w konsensusie chaina. Głównym wyzwaniem jest tu udźwignięcie potężnej przepustowości: operacje modyfikacji i anulowania zleceń (Cancel/Replace) w świecie HFT stanowią wręcz 95–98% całego ruchu.

2. Architektura Intent-Based oraz RFQ (Request for Quote)

Koncepcja „Intents” (Uniswap X, 1inch Fusion, CoW Protocol) to w gruncie rzeczy powrót do instytucjonalnego podejścia do egzekucji zleceń.

Trader nie podpisuje bezpośredniej transakcji wchodzącej w interakcję z konkretną pulą, lecz intencję (np. „Chcę wymienić 100 ETH na nie mniej niż 300 000 USDC”). Następnie sieć zewnętrznych egzekutorów (Fillers / Solvers) rywalizuje o zrealizowanie tego zlecenia, sięgając po dowolne źródła płynności — CEX-y, prywatne inventory market makerów czy DEX-y.

Architecture
 

Dla tradera oznacza to zerowy slippage i pełną ochronę przed atakami MEV (typu sandwich): całe ryzyko poślizgu i realizacji bierze na siebie Solver, zarabiając na arbitrażu międzyaktywowym.

7. Praktyka: Zaawansowany skrypt arbitrażowy między CEX L2 Order Bookiem a AMM v2

W praktyce boty HFT bezustannie polują na rozbieżności cenowe między giełdami CEX a AMM-ami. Jeśli na CEX-ie cena aktywa gwałtownie rośnie w wyniku rynkowego buy orders, pula AMM przez pewien czas pozostaje „niezaktualizowana” (stale). Arbitrażysta, kupując w AMM, dociąga jego cenę do poziomu CEX-a, a zakupiony wolumen natychmiast wyrzuca z powrotem na CEX.

Poniżej znajdziesz gotowy skrypt w Pythonie, który w czasie rzeczywistym wylicza optymalny rozmiar transakcji arbitrażowej (dx), uwzględniając prowizję AMM, głębokość order booka CEX oraz opłaty maker/taker.

from __future__ import annotations
from dataclasses import dataclass
from typing import List, Dict, Any
@dataclass
class BidLevel:
    price: float
    volume: float
class OrderBookSide:
    """
    Bid strona stakanu.
    price  = cena zakupu
    volume = wolumen aktywa bazowego
    """
    def __init__(self, bids: List[tuple[float, float]]):
        self.bids: List[BidLevel] = []
        for price, volume in bids:
            if price <= 0:
                raise ValueError("Cena musi być > 0")
            if volume <= 0:
                raise ValueError("Wolumen musi być > 0")
            self.bids.append(
                BidLevel(
                    float(price),
                    float(volume)
                )
            )
        self.bids.sort(
            key=lambda x: x.price,
            reverse=True
        )
    def is_empty(self) -> bool:
        return len(self.bids) == 0
    def best_bid(self) -> float:
        if self.is_empty():
            raise ValueError("Order book jest pusty")
        return self.bids[0].price
    def cumulative_levels(self) -> List[tuple[float, float]]:
        """
        Zwraca punkty zmiany płynności.
        [
            (2 ETH, VWAP do 2 ETH),
            (7 ETH, VWAP do 7 ETH),
            ...
        ]
        """
        result = []
        cumulative_x = 0.0
        cumulative_y = 0.0
        for level in self.bids:
            cumulative_x += level.volume
            cumulative_y += level.volume * level.price
            result.append(
                (
                    cumulative_x,
                    cumulative_y
                )
            )
        return result
    def execute_sell(
        self,
        amount_x: float
    ) -> tuple[float, float]:
        """
        Sprzedaż amount_x w order book.
        Zwraca:
        (
            otrzymano_USDT,
            VWAP
        )
        """
        if amount_x <= 0:
            raise ValueError(
                "amount_x musi być > 0"
            )
        remaining_x = amount_x
        received_y = 0.0
        for level in self.bids:
            if remaining_x <= 0:
                break
            executed = min(
                remaining_x,
                level.volume
            )
            received_y += (
                executed *
                level.price
            )
            remaining_x -= executed
        if remaining_x > 1e-9:
            raise ValueError(
                "Niewystarczająca płynność w order booku"
            )
        vwap = received_y / amount_x
        return received_y, vwap
class AMMPool:
    """
    Constant Product AMM
    x = ETH
    y = USDT
    """
    def __init__(
        self,
        reserve_x: float,
        reserve_y: float,
        fee: float = 0.003
    ):
        if reserve_x <= 0:
            raise ValueError(
                "reserve_x musi być > 0"
            )
        if reserve_y <= 0:
            raise ValueError(
                "reserve_y musi być > 0"
            )
        if not (0 <= fee < 1):
            raise ValueError(
                "fee musi być w przedziale [0,1)"
            )
        self.x = float(reserve_x)
        self.y = float(reserve_y)
        self.fee = float(fee)
    def spot_price(self) -> float:
        return self.y / self.x
    def calculate_out_x(
        self,
        amount_y_in: float
    ) -> float:
        if amount_y_in <= 0:
            raise ValueError(
                "amount_y_in musi być > 0"
            )
        y_effective = (
            amount_y_in *
            (1.0 - self.fee)
        )
        x_out = (
            self.x *
            y_effective
        ) / (
            self.y +
            y_effective
        )
        return x_out
    def calculate_required_y_for_x(
        self,
        target_x_out: float
    ) -> float:
        """
        Odwrócenie wzoru AMM.
        Ile USDT trzeba wpłacić,
        aby otrzymać target_x_out.
        """
        if target_x_out <= 0:
            raise ValueError(
                "target_x_out musi być > 0"
            )
        if target_x_out >= self.x:
            raise ValueError(
                "Nie można wypłacić całego rezerwu"
            )
        y_effective = (
            target_x_out *
            self.y
        ) / (
            self.x -
            target_x_out
        )
        amount_y_in = (
            y_effective /
            (1.0 - self.fee)
        )
        return amount_y_in
def find_optimal_arbitrage(
    amm: AMMPool,
    cex_bids: OrderBookSide,
    cex_fee: float = 0.001
) -> Dict[str, Any]:
    if not (0 <= cex_fee < 1):
        raise ValueError(
            "cex_fee musi być w przedziale [0,1)"
        )
    if cex_bids.is_empty():
        return {
            "opportunity": False,
            "reason": "Pusty order book CEX"
        }
    best_bid = cex_bids.best_bid()
    if (
        best_bid *
        (1.0 - cex_fee)
        <=
        amm.spot_price()
    ):
        return {
            "opportunity": False,
            "reason": "Brak spreadu"
        }
    best_result = None
    best_profit = float("-inf")
    cumulative = cex_bids.cumulative_levels()
    for cumulative_x, cumulative_y in cumulative:
        try:
            required_usdt = (
                amm.calculate_required_y_for_x(
                    cumulative_x
                )
            )
            gross_usdt = cumulative_y
            net_usdt = (
                gross_usdt *
                (1.0 - cex_fee)
            )
            profit = (
                net_usdt -
                required_usdt
            )
            if profit > best_profit:
                avg_buy_price = (
                    required_usdt /
                    cumulative_x
                )
                avg_sell_price = (
                    gross_usdt /
                    cumulative_x
                )
                amm_spot = (
                    amm.spot_price()
                )
                impact_pct = (
                    (
                        avg_buy_price -
                        amm_spot
                    )
                    /
                    amm_spot
                ) * 100
                roi_pct = (
                    profit /
                    required_usdt
                ) * 100
                best_profit = profit
                best_result = {
                    "opportunity": True,
                    "input_usdt_amm": required_usdt,
                    "bought_x": cumulative_x,
                    "gross_usdt_cex": gross_usdt,
                    "net_usdt_cex": net_usdt,
                    "net_profit_usdt": profit,
                    "roi_pct": roi_pct,
                    "amm_spot_price": amm_spot,
                    "amm_avg_buy_price": avg_buy_price,
                    "amm_price_impact_pct": impact_pct,
                    "cex_vwap": avg_sell_price,
                }
        except ValueError:
            continue
    if best_result is None:
        return {
            "opportunity": False,
            "reason": "Niewystarczająca płynność"
        }
    if best_result["net_profit_usdt"] <= 0:
        return {
            "opportunity": False,
            "reason": "Slippage zjada cały zysk"
        }
    return best_result
def main():
    amm = AMMPool(
        reserve_x=1000.0,
        reserve_y=3_000_000.0,
        fee=0.003
    )
    cex = OrderBookSide([
        (3050.0, 2.0),
        (3048.0, 5.0),
        (3045.0, 10.0),
        (3040.0, 20.0),
        (3030.0, 50.0),
    ])
    result = find_optimal_arbitrage(
        amm,
        cex,
        cex_fee=0.0005
    )
    print(
        "\n=== Wynik wyszukiwania arbitrażu ===\n"
    )
    if not result["opportunity"]:
        print(
            f"Status: ANULOWANO\n"
            f"Powód: {result['reason']}"
        )
        return
    print("Status: ZNALEZIONO OKAZJĘ")
    print()
    print(
        f"Wkład AMM: "
        f"${result['input_usdt_amm']:,.2f}"
    )
    print(
        f"Kupiono ETH: "
        f"{result['bought_x']:.6f}"
    )
    print(
        f"Przychód CEX: "
        f"${result['gross_usdt_cex']:,.2f}"
    )
    print(
        f"Przychód netto CEX: "
        f"${result['net_usdt_cex']:,.2f}"
    )
    print(
        f"Zysk netto: "
        f"${result['net_profit_usdt']:,.2f}"
    )
    print(
        f"ROI: "
        f"{result['roi_pct']:.4f}%"
    )
    print(
        f"AMM Spot: "
        f"{result['amm_spot_price']:.4f}"
    )
    print(
        f"AMM Avg Buy: "
        f"{result['amm_avg_buy_price']:.4f}"
    )
    print(
        f"AMM Impact: "
        f"{result['amm_price_impact_pct']:.4f}%"
    )
    print(
        f"CEX VWAP: "
        f"{result['cex_vwap']:.4f}"
    )
if __name__ == "__main__":
    main()

8. Wnioski praktyczne dla tradera: Jak nie płacić „podatku od nieświadomości”

Zrozumienie mikrostruktury rynku to nie sucha teoria z akademickiego podręcznika. To narzędzie, które realnie chroni Twój depozyt przed cichym przeciekiem kapitału.

  • Dobieraj typ zlecenia do sytuacji na rynku: Na CEX-ach zagranie rynkowe (Market Order) przy dużym wolumenie gwarantuje, że zlecenie przebije się przez kilka poziomów w order booku, generując spore ujemne poślizgi. Jeśli zależy Ci na czasie, sięgaj po zlecenia IOC (Immediate-or-Cancel) lub FOK (Fill-or-Kill) z sztywno ustawionym limitem najgorszej akceptowalnej ceny.
  • Licz efektywną głębokość, a nie sam spread: Ciasny spread na poziomie L2 ($0.01) bywa złudny. Jeśli na najlepszym Bid/Ask wisi zaledwie $100 płynności, Twoje zlecenie na $50 000 przemiecie arkusz aż do poziomów z zupełnie inną wyceną.
  • Pamiętaj o toksyczności przepływu w AMM: Jeśli dostarczasz płynność do Uniswap v3 w ciasnym przedziale cenowym w trakcie publikacji ważnych danych czy wysokiej zmienności, stajesz się łatwym celem dla botów HFT. Wskaźnik LVR potrafi zjeść cały Twój zysk z prowizji w zaledwie parę minut.
  • Chroń się przed MEV na DEX-ach: Przy swapach na AMM-ach zawsze utwardzaj tolerancję na poślizg (Slippage Tolerance ustawo maksymalnie na 0.1–0.3%) albo korzystaj z prywatnych węzłów RPC (np. Flashbots Protect / MEV-Blocker), aby Twoje transakcje nie lądowały w publicznym mempoolu i nie wystawiały Cię na ataki sandwichingowe.

Dajcie znać w komentarzach, z jak dużym slippage'em najczęściej zmagacie się przy większych zleceniach i który model (CEX Order Book czy DEX AMM) sprawdza się u Was najlepiej na co dzień!


FAQ

Order Book realizuje zlecenia na podstawie ciągłego aukcyjnego dopasowania cenowo-czasowego (FIFO), podczas gdy AMM rozlicza transakcje algorytmicznie poprzez pule płynności sterowane niezmiennikiem matematycznym.

Impermanent Loss mierzy względną zmianę wartości portfela względem prostego HODL, natomiast Loss-Versus-Rebalancing oblicza realny koszt selekcji negatywnej ponoszony przez arbitrażystów HFT wykorzystujących opóźnienia cenowe AMM względem giełd centralizowanych.

Boty monitorują publiczny mempool, wstrzykując transakcję wyprzedzającą (front-running) przed zleceniem użytkownika w celu sztucznego podbicia ceny, a następnie realizują natychmiastową transakcję następczą (back-running) w tym samym bloku, przechwytując marżę wynikającą z tolerancji poślizgu cenowego.
Martyn Borkowski

I am a crypto trader specializing in digital assets and blockchain markets.

My focus is on identifying opportunities, managing risk, and optimizing strategies to achieve consistent growth in the fast-evolving world of cryptocurrency.

Verification & Professional Profiles: X Profile

...

Dodaj opinię

Twój adres e-mail nie zostanie opublikowany. Obowiązkowe pola są oznaczone*