← Makalelere geri dön
May 17, 2025
5 dakikalık okuma

Avellaneda-Stoikov Modelini Kullanarak Kripto Çiftleri için Piyasa Yapıcı Algoritması Oluşturma

Avellaneda-Stoikov Modelini Kullanarak Kripto Çiftleri için Piyasa Yapıcı Algoritması Oluşturma
#piyasa yapıcılık
#kripto para
#Avellaneda-Stoikov
#algoritmik ticaret
#pekiştirmeli öğrenme
#PPO
#DeFi

Merhaba, arkadaşlar! Bugün USD+/wETH ve USD+/cbbtc kripto çiftleri için nasıl piyasa yapıcı algoritması oluşturacağımızı göstereceğim. Avellaneda-Stoikov (A-S) modelini kullanacağız ve dinamik spread optimizasyonu için Pekiştirmeli Öğrenme (PPO) algoritmasıyla onu geliştireceğiz. Karmaşık mı geliyor? Endişelenme, başlangıç seviyesindeki bir geliştirici bile takip edebilsin diye her şeyi açık adımlara böleceğim.

Piyasa Yapıcılık Görselleştirmesi Piyasa yapıcılığın özünü görselleştirme: Optimal piyasa likiditesi sentezlemek için adil fiyat etrafında sürekli olarak alış ve satış emirlerini dengeleme.

Piyasa Yapıcılık Nedir ve Neden İhtiyacımız Var?

Piyasa yapıcılık, bir yatırımcının bir varlık için eş zamanlı olarak alış ve satış emirleri vererek spread'den (fiyatlar arasındaki fark) kazandığı bir stratejidir. DeFi alanında piyasa yapıcılar, diğer piyasa katılımcıları için likidite sağlayarak ve kayma (slippage) oranını azaltarak kilit bir rol oynar.

Bir pazarda her zaman bir ürünü piyasa fiyatının biraz altında satın almaya ve biraz üzerinde satmaya hazır bir satıcı olduğunuzu hayal edin. Kârınız, alış ve satış fiyatlarınız arasındaki farktır. Ancak bir tehlike var: fiyat aniden bir yöne hareket ederse, çok fazla envanter biriktirebilir veya tam tersine satacak hiçbir şey kalmayabilirsiniz.

Avellaneda-Stoikov Modeli: Ticaretin Hizmetinde Matematik

A-S modeli, piyasa yapıcılık için optimal fiyatları belirlemede matematiksel bir yaklaşımdır. Temel avantajı, yalnızca mevcut piyasa fiyatını değil, aynı zamanda pozisyon büyüklüğünüzü (envanter), piyasa oynaklığını ve risk iştahınızı da dikkate almasıdır.

Modelin temel formülleri:

δ_a = S_t + (1/γ) * ln(1 + γ/k) + q_t * σ² * T
δ_b = S_t - (1/γ) * ln(1 + γ/k) - q_t * σ² * T

burada:

  • δ_a ve δ_b sırasıyla alış (ask) ve satış (bid) fiyatlarıdır
  • S_t mevcut piyasa fiyatıdır
  • γ risk parametresidir (ne kadar yüksekse spread o kadar geniştir)
  • k emir gelme hızıdır
  • q_t mevcut envantedir
  • σ oynaklıktır
  • T zaman ufkudur

Zincir İçi Ticaret Özellikleri

Algoritmayı zincir içine taşıdığımızda ek zorluklar ortaya çıkar:

  1. Gecikme (Latency) – blok zincirindeki işlemler anlık değildir ve emir gerçekleşmeden önce fiyat değişebilir
  2. Gas maliyetleri – her işlem için ağ ücreti gerekir
  3. AMM/PMM özellikleri – likidite havuzu mekaniği geleneksel borsalardan farklıdır

Bu faktörleri algoritmamızda nasıl hesaba katabileceğimize bakalım.

Adım 1: Ortamı Kur ve Veri Topla

Öncelikle piyasa verisi almak için bir ortam kurulması gerekiyor. Güncel fiyatları ve emir defteri derinliğini almak için Binance API'sini kullanacağız.

std::tuple MarketMaker::get_binance_data(const std::string& pair) {
    // Gerçek kodda bu, Binance API'sine yapılan bir istek olacaktır
    // Döndürür: mid_price, bid, ask, bid_volume, ask_volume
    double mid_price = 2000.0;
    double bid = mid_price - 1.0;
    double ask = mid_price + 1.0;
    double bid_volume = 10.0;
    double ask_volume = 8.0;
    return {mid_price, bid, ask, bid_volume, ask_volume};
}

Ayrıca gas maliyeti ve ağ gecikmesi gibi zincir içi metriklere de ihtiyacımız olacak:

std::pair MarketMaker::get_onchain_metrics() {
    // Gerçek kodda bu, bir Ethereum düğümüne yapılan istek olacaktır
    // Döndürür: gas_price (wei), latency (saniye)
    return {50e9, 12.0};
}

Adım 2: Temel A-S Modelini Uygula

Şimdi A-S modelini kullanarak spread hesaplamasını uygulayalım:

std::pair MarketMaker::calculate_spreads(double S_t, double sigma, double k, double q_t) {
    // Avellaneda-Stoikov formülü
    double spread_term = (1.0 / gamma_) * log(1.0 + gamma_ / k);
    double inventory_term = q_t * sigma * sigma * T_;
    
    double delta_a = S_t + spread_term + inventory_term;  // Alış fiyatı
    double delta_b = S_t - spread_term - inventory_term;  // Satış fiyatı
    
    return {delta_a, delta_b};
}

inventory_term'e dikkat edin. Pozitif envantere (çok fazla varlık) sahipseniz, alış fiyatı düşer ve satışı teşvik edip alımı sınırlamak için satış fiyatı daha da düşer. Negatif envanter için ise tam tersi geçerlidir.

Adım 3: Modeli Zincir İçi Ticarete Uyarla

Şimdi blok zinciri özelliklerini hesaba katmamız gerekiyor. Gecikmeyle başlayalım:

double MarketMaker::adjust_price_with_latency(double S_t, double sigma, double latency) {
    // Gecikmeden kaynaklanan rastgele fiyat değişimini simüle et
    double latency_adjustment = utils::normal_dist(0.0, sigma * std::sqrt(latency));
    return S_t + latency_adjustment;
}

Burada rastgele yürüyüş modeli kullanıyoruz: oynaklık ne kadar yüksek ve gecikme ne kadar uzunsa, emir gerçekleşmeden önce fiyat o kadar fazla değişebilir.

Şimdi gas maliyetini hesaba katalım:

double MarketMaker::calculate_gas_cost(double gas_price, double trade_size) {
    const double GAS_LIMIT_PER_ORDER = 100000;  // Emir başına yaklaşık değer
    return (gas_price * GAS_LIMIT_PER_ORDER * trade_size) / 1e18;  // Wei'yi ETH'ye dönüştür
}

Son olarak, PMM havuz özelliklerine göre spread'leri uyarlayalım:

std::pair MarketMaker::adjust_spreads_for_pmm(double S_t, double delta_a, double delta_b, double pool_depth) {
    // Basitleştirilmiş PMM modeli: spread'leri havuz derinliğine göre ayarla
    const double MIN_POOL_DEPTH = 10.0;
    double depth_factor = std::max(pool_depth, MIN_POOL_DEPTH) / MIN_POOL_DEPTH;
    
    // Daha büyük havuz derinliğiyle spread'leri azalt
    double spread_reduction = 1.0 / std::sqrt(depth_factor);
    double mid_price = (delta_a + delta_b) / 2;
    double new_delta_a = mid_price + (delta_a - mid_price) * spread_reduction;
    double new_delta_b = mid_price - (mid_price - delta_b) * spread_reduction;
    
    return {new_delta_a, new_delta_b};
}

Adım 4: Envanter Yönetimi

Envanteri takip etmek ve yönetmek için basit bir sınıf oluşturalım:

class InventoryManager {
public:
    InventoryManager() : inventory_(0.0) {}
    
    void update_inventory(double size, bool is_buy) {
        inventory_ += is_buy ? size : -size;
    }
    
    double get_inventory() const {
        return inventory_;
    }
    
private:
    double inventory_;
};

Envanter yönetimi ve risk görselleştirmesi Envanter Riski Görselleştirmesi: Tek yönlü piyasa hareketlerine aşırı maruz kalmayı (uzun veya kısa) önlemek için pozisyon büyüklüklerinin izlenmesi.

Adım 5: Her Şeyi Tek Bir Algoritmada Birleştir

Şimdi tüm bileşenleri tek bir piyasa yapıcı algoritmasında birleştirelim:

void MarketMaker::step(double S_t, double sigma, double k, double latency, double gas_cost, double trade_size) {
    // Mevcut envanteri al
    double current_inventory = inventory_.get_inventory();
    
    // Mevcut piyasa koşullarına ve envantere göre spread'leri hesapla
    auto [delta_a, delta_b] = calculate_spreads(S_t, sigma, k, current_inventory);
    auto [adjusted_delta_a, adjusted_delta_b] = adjust_spreads_for_onchain(S_t, delta_a, delta_b, latency, sigma, gas_cost, trade_size);
    
    // Bağımsız piyasa fiyatı oluştur
    double market_price = S_t + utils::normal_dist(0.0, sigma);
    
    // Piyasa fiyatına ve spread'lere göre işlem yapılıp yapılmayacağını belirle
    bool is_buy = (market_price = adjusted_delta_a);
    
    // İşlemleri gerçekleştir ve envanteri güncelle
    if (is_buy) {
        inventory_.update_inventory(trade_size, true);
        std::cout  reset();
    
    // Aksiyon al ve yeni durum, ödül ve bitiş bayrağını al
    std::tuple, double, bool> step(const std::array& action);
    
private:
    // Mevcut ortam durumunu al
    std::vector get_state() const;
    
    MarketMaker& mm_;
    double current_inventory_;
    double current_profit_;
    int current_step_;
    int max_steps_;
    
    // Mevcut piyasa parametreleri
    double mid_price_;
    double sigma_;
    double latency_;
    double pool_depth_;
    
    std::mt19937 rng_;
};

Ortam durumumuz mevcut fiyat, envanter, oynaklık, ağ gecikmesi ve havuz derinliğinden oluşan bir vektördür. Aksiyon ise spread'ler ve alış/satış boyutlarından oluşan bir vektördür.

Şimdi ödül fonksiyonunu uygulayalım:

double reward = profit_term - inventory_risk - gas_cost;

Burada:

  • profit_term işlemlerden elde edilen kârdır
  • inventory_risk büyük envanter için bir cezadır (risk)
  • gas_cost harcanan gas miktarıdır

Son olarak PPO ajanını eğitelim:

void PPOTrainer::train(int episodes) {
    for (int ep = 0; ep  states;
        std::vector actions;
        std::vector rewards;
        
        while (true) {
            // Politikadan aksiyon al
            auto action_probs = policy_net_->forward(torch::tensor(state));
            auto action = action_probs.multinomial(1);
            
            // Ortamda bir adım at
            auto [next_state, reward, done] = env_.step(action);
            
            // Geçişi kaydet
            states.push_back(torch::tensor(state));
            actions.push_back(action);
            rewards.push_back(reward);
            
            if (done) break;
            state = next_state;
        }
        
        // PPO politikasını güncelle
        update_policy(states, actions, rewards);
    }
}

Spread optimizasyonu için PPO Pekiştirmeli Öğrenme ajanı Pekiştirmeli Öğrenme pratikte: PPO ajanı maksimum beklenen ödül için alış/satış spread'lerini dinamik olarak optimize etmek amacıyla karmaşık piyasa durumlarını işliyor.

Adım 7: Test ve Görselleştirme

Algoritmamızı test etmek için basit bir simülasyon oluşturalım:

int main() {
    // Görevde belirtildiği gibi T = 300 saniye kullan
    MarketMaker mm(0.1, 300.0);

    // Oynaklık için geçmiş veri simüle et
    std::vector prices = {2000.0};
    double S_t = 2000.0;
    double trade_size = 1.0;
    double initial_sigma = 0.05;  // %5 oynaklık

    for (int i = 0; i < 300; ++i) {
        std::cout << "Adım " << i + 1 << ": ";

        // Veri al (taslaklar)
        auto [mid_price, bid_ask] = mm.get_binance_data("USD+/wETH");
        auto [gas_cost, latency] = mm.get_onchain_metrics();
        
        // Gerçek bir piyasayı simüle etmek için rastgele fiyat hareketi ekle
        S_t = mid_price + utils::normal_dist(0.0, mid_price * 0.01);

        // Oynaklığı hesapla
        double sigma = mm.calculate_volatility(prices, 5);
        if (sigma < 0.01) sigma = initial_sigma;

        // Emir gelme hızı (taslak)
        double k = 5.0;

        mm.step(S_t, sigma, k, latency, gas_cost, trade_size);

        // Bir sonraki adım için fiyatı güncelle
        S_t += utils::normal_dist(0.0, S_t * 0.02);
        prices.push_back(S_t);
    }

    return 0;
}

Sırada Ne Var?

Piyasa yapıcı algoritmamız hazır, ancak onu geliştirmenin birçok yolu var:

  1. Gerçek API'lere bağlan: taslakları Binance API ve Ethereum düğümüne gerçek isteklerle değiştir
  2. Oynaklık modelini geliştir: GARCH veya diğer gelişmiş modelleri kullan
  3. PPO'yu genişlet: duruma ve aksiyona daha fazla parametre ekle
  4. Gas'ı optimize et: gas maliyetlerini en aza indirme stratejileri
  5. Çok varlıklı strateji: aynı anda birden fazla çifte genişlet

Sonuç

Zincir içi ticaret özelliklerini dikkate alan ve hem klasik A-S modelini hem de modern RL yöntemlerini kullanan bir piyasa yapıcı algoritması inşa ettik. Bu yaklaşım, değişen piyasa koşullarına uyum sağlamanıza ve riski kontrol ederken kârı maksimize etmenize olanak tanır.

Elbette gerçek ticarette dikkate alınması gereken pek çok ek faktör var, ancak algoritmamız daha ileri geliştirme için sağlam bir temel sağlıyor. Unutma: algoritmik ticarette yalnızca matematik değil, kapsamlı test, izleme ve sürekli optimizasyon da önemlidir.

Umarım bu makale, piyasa yapıcılık ilkelerini daha iyi anlamanıza yardımcı olmuş ve kendi algoritmalarınızı oluşturmanız için ilham vermiştir. İyi işlemler!

Atıf

@software{soloviov2025marketmakingavellanedastoikov,
  author = {Soloviov, Eugen},
  title = {Building a Market Making Algorithm for Crypto Pairs Using the Avellaneda-Stoikov Model},
  year = {2025},
  url = {https://marketmaker.cc/tr/blog/post/market-making-avellaneda-stoikov},
  version = {0.1.0},
  description = {Avellaneda-Stoikov modeli ve PPO kullanarak USD+/wETH ve USD+/cbbtc çiftleri için piyasa yapıcı algoritması oluşturmaya yönelik adım adım rehber. Zincir içi ticaret özellikleri, envanter yönetimi, RL eğitimi.}
}
Sorumluluk Reddi: Bu makalede sağlanan bilgiler yalnızca eğitim ve bilgilendirme amaçlıdır ve finansal, yatırım veya ticaret tavsiyesi niteliği taşımaz. Kripto para ticareti önemli bir kayıp riski içerir.

Yazarlar

Eugen Soloviov
Eugen Soloviov

Trading-systems engineer

Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.

Newsletter

Piyasanın Önünde Olun

Özel yapay zeka ticaret içgörüleri, piyasa analizi ve platform güncellemeleri için bültenimize abone olun.

Gizliliğinize saygı duyuyoruz. İstediğiniz zaman abonelikten çıkabilirsiniz.