Membangun bot arbitrase: Menemukan peluang arbitrase

Menengah4/9/2024, 2:29:22 PM
Dalam artikel ini, kami melakukan pra-seleksi pasangan token yang menarik. Kami kemudian menurunkan rumus matematika untuk menemukan arbitrase optimal antara dua kelompok pasangan token yang sama.

Jika pengaturan MEV Anda tidak terlihat seperti ini, Anda ngmi

Artikel ini adalah bagian dari serangkaian tentang membangun bot arbitrase. Tujuan dari seri ini adalah untuk memberikan panduan langkah demi langkah dalam membangun robot perdagangan MEV otomatis yang dapat menemukan dan mengeksekusi peluang arbitrase di bursa terdesentralisasi populer.

Dalam artikel ini, kami melakukan pra-pemilihan pasangan token yang menarik. Kami kemudian menurunkan rumus matematika untuk menemukan arbitrase optimal antara dua kelompok pasangan token yang sama. Akhirnya, kami menerapkan rumus tersebut dalam kode dan mengembalikan daftar kesempatan arbitrase potensial.

Memilih pasangan token

Ketepatan tentang strategi arbitrase

Sebelum kita mulai mencari peluang arbitrase, kita harus dengan jelas mendefinisikan batas dari bot arbitrase kita. Secara khusus, jenis arbitrase apa yang ingin kita lakukan. Jenis arbitrase paling aman adalah antara pool yang melibatkan ETH. Karena ETH adalah aset dengan mana gas transaksi kita dibayar, adalah wajar untuk selalu ingin mendapatkan ETH setelah arbitrase. Tetapi semua orang tergoda untuk berpikir seperti ini. Ingatlah bahwa dalam perdagangan, peluang yang tepat waktu menjadi kurang menguntungkan seiring dengan bertambahnya orang yang bertindak atasnya.

Demi kesederhanaan, kami akan fokus pada peluang arbitrase antara kolam yang melibatkan ETH. Kami hanya akan mencari peluang antara dua kolam dari pasangan token yang sama. Kami tidak akan melakukan perdagangan pada peluang yang melibatkan lebih dari 2 kolam dalam rute perdagangan (disebut peluang multi-hop). Perhatikan bahwa meningkatkan strategi ini ke yang lebih berisiko adalah langkah pertama yang harus Anda ambil untuk meningkatkan profitabilitas bot Anda.

Untuk meningkatkan strategi ini, Anda misalnya dapat menyimpan sejumlah inventaris dalam stablecoins dan bertindak pada peluang arbitrase yang menghasilkan stablecoins. Hal yang sama dapat dilakukan untuk aset yang jauh lebih berisiko seperti shitcoins (dengan tindakan pencegahan yang diperlukan), dan secara berkala merekonsiliasi portofolio Anda ke ETH untuk membayar gas.

Salah satu arah lainnya adalah meninggalkan asumsi implisit tentang atomisitas yang kita buat, dan memperkenalkan penalaran statistik dalam strategi kita. Misalnya, dengan membeli satu token dalam sebuah pool ketika harga telah bergerak secara menguntungkan lebih dari beberapa jumlah deviasi standar, dan menjualnya kemudian (strategi reverensi rerata). Ini akan ideal untuk shitcoins yang tidak terdaftar di bursa terpusat yang jauh lebih efisien, atau yang sudah terdaftar tetapi harganya tidak terlacak dengan benar secara on-chain. Ini melibatkan banyak bagian yang bergerak dan berada di luar cakupan seri ini.

Memilih pasangan token

Sekarang bahwa kami telah mendefinisikan batas dari bot arbitrase kami, kami perlu memilih pasangan token yang ingin kami perdagangkan. Berikut adalah 2 kriteria pemilihan yang akan kami gunakan:

  • Pasangan yang akan dipilih harus melibatkan ETH.
  • Pasangan harus diperdagangkan di setidaknya 2 kolam yang berbeda.

Menggunakan ulang kode dari artikel 2: Membaca Harga Kolam Renang Secara Efisien, kami memiliki kode berikut yang mencantumkan semua pasangan token yang diterapkan oleh kontrak pabrik yang disediakan:

# [...]# Memuat alamat dari kontrak pabrikadengan open("FactoriesV2.json", "r") as f:pabrik = json.load(f)# [...]# Ambil daftar kolam untuk setiap kontrak pabrikpairDataList = []for namaPabrik, dataPabrik in pabrik.items():acara = getPairEvents(w3.eth.contract(address=dataPabrik['factory'], abi=factory_abi), 0, w3.eth.block_number)print(f'Ditemukan {len(acara)} kolam untuk {namaPabrik}')for e in acara:   pairDataList.append({       "token0": e["args"]["token0"],       "token1": e["args"]["token1"],       "pair": e["args"]["pair"],       "factory": namaPabrik   })

Kami akan dengan mudah membalikkan pairDataList ke dalam kamus di mana kunci-kunci adalah pasangan token, dan nilai-nilainya adalah daftar kolam yang melakukan perdagangan pasangan ini. Saat melintasi daftar, kami mengabaikan pasangan yang tidak melibatkan ETH. Setelah perulangan selesai, pasangan dengan setidaknya 2 kolam yang dipilih akan disimpan dalam daftar dengan setidaknya 2 elemen:

# [...]WETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"pair_pool_dict = {}for pair_object in pairDataList:# Check for ETH (WETH) in the pair.pair = (pair_object['token0'], pair_object['token1'])if WETH not in pair:   continue# Make sure the pair is referenced in the dictionary. if pair not in pair_pool_dict:   pair_pool_dict[pair] = []# Add the pool to the list of pools that trade this pair.pair_pool_dict[pair].append(pair_object)# Create the final dictionnary of pools that will be traded on.pool_dict = {}for pair, pool_list in pair_pool_dict.items():if len(pool_list) >= 2:   pool_dict[pair] = pool_list

Beberapa statistik harus dicetak untuk lebih memahami data yang sedang kita kerjakan:

# Jumlah pasangan yang berbedaprint(f'Kami memiliki {len(pool_dict)} pasangan yang berbeda.')# Total jumlah kolamrenangprint(f'Kami memiliki {sum([len(pool_list) for pool_list in pool_dict.values()])} kolamrenang secara total.')# Pasangan dengan kolamrenang terbanyak print(f'Pasangan dengan kolamrenang terbanyak adalah {max(pool_dict, key=lambda k: len(pool_dict[k]))} dengan {len(max(pool_dict.values(), key=len))} kolamrenang.')# Distribusi jumlah kolamrenang per pasangan, desilspool_count_list = [len(pool_list) for pool_list in pool_dict.values()]pool_count_list.sort(reverse=True)print(f'Jumlah kolamrenang per pasangan, dalam desil: {pool_count_list[::int(len(pool_count_list)/10)]}')# Distribusi jumlah kolamrenang per pasangan, persenil (desil dari desil pertama)pool_count_list.sort(reverse=True)print(f'Jumlah kolamrenang per pasangan, dalam persenil: {pool_count_list[::int(len(pool_count_list)/100)][:10]}')

Saat ini, ini menghasilkan yang berikut ini:

Kami memiliki 1431 pasangan yang berbeda.

Kami memiliki total 3081 kolam renang.

Pasangan dengan jumlah kolam terbanyak adalah ('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', '0xdAC17F958D2ee523a2206206994597C13D831ec7') dengan 16 kolam.

Jumlah kolam per pasangan, dalam desil: [16, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

Jumlah kolam per pasang, dalam persentil: [16, 5, 4, 3, 3, 3, 3, 3, 3, 3]

Mengambil cadangan untuk 3000 kolam dapat dilakukan dalam waktu kurang dari 1 detik dengan node RPC publik. Ini adalah jumlah waktu yang wajar.

Sekarang, kami memiliki semua data yang kami butuhkan, kami perlu mulai mencari peluang arbitrase.

Mencari peluang arbitrase

Idea umum

Ada peluang arbitrase setiap kali ada perbedaan harga antara dua pool yang melakukan perdagangan pasangan yang sama. Namun, tidak semua perbedaan harga dapat dieksploitasi: biaya gas transaksi menetapkan nilai minimum yang harus dikembalikan oleh perdagangan, dan likuiditas di setiap pool membatasi nilai yang dapat diekstraksi dari perbedaan harga yang diberikan.

Untuk menemukan peluang arbitrase paling menguntungkan yang dapat diakses oleh kita, kita perlu menghitung nilai potensial yang dapat diekstraksi dari setiap perbedaan harga, mempertimbangkan cadangan/likuiditas di setiap pool, dan memperkirakan biaya gas transaksi.

Rumus Ukuran Perdagangan Optimal Arbitrase

Ketika peluang arbitrase dieksploitasi, harga dari pool yang membeli token input akan turun, dan harga dari pool yang menjual akan naik. Pergerakan harga dideskripsikan oleh rumus produk konstan.

Kita sudah melihat di @emileamajar/membangun-bot-arbitrase-pembuat-pasar-otomatis-dan-uniswap-2d208215d8c2"> artikel 1 cara menghitung output dari swap melalui kolam, diberikan cadangan kolam tersebut dan jumlah masukan.

Untuk menemukan ukuran perdagangan optimal, pertama-tama kita menemukan formula untuk output dari dua pertukaran berturut-turut, dengan jumlah input tertentu, dan cadangan dari dua kolam yang terlibat dalam pertukaran tersebut.

Kami mengasumsikan bahwa input pertukaran pertama berada di token0, dan input pertukaran kedua berada di token1, yang akhirnya menghasilkan output di token0.

Biarkan x menjadi jumlah masukan, (a1, b1) cadangan dari kolam pertama, dan (a2, b2) cadangan dari kolam kedua. biaya adalah biaya yang diambil oleh kolam, dan diasumsikan sama untuk kedua kolam (0.3% sebagian besar waktu).

Kami mendefinisikan sebuah fungsi yang menghitung output dari pertukaran, dengan input x dan cadangan (a,b):

f(x, a, b) = b (1 - a/(a + x(1-fee)))

Kami kemudian tahu bahwa output swap pertama adalah:

out1(x) = f(x, a1, b1)

out1(x) = b1(1 - a1/(a1 + x(1-fee)))

Output dari swap kedua adalah: (perhatikan variabel cadangan yang ditukar)

out2(x) = f(out1(x), b2, a2)

out2(x) = f(f(x, a1, b1), b2, a2)

out2(x) = a2(1 - b2/(b2 + f(x, a1, b1)(1-fee)))

out2(x) = a2 (1 - b2/(b2 + b1) (1 - a1/(a1 + x (1-fee))) (1-fee)))

Kita dapat memplot fungsi ini menggunakan desmosDengan memilih nilai cadangan sehingga kita mensimulasikan kolam pertama memiliki 1 ETH dan 1750 USDC, dan kolam kedua memiliki 1340 USDC dan 1 ETH, kita mendapatkan grafik berikut:

Plot dari keuntungan kotor perdagangan sebagai fungsi dari nilai input

Perhatikan bahwa kami sebenarnya telah merencanakan out2(x) - x, yang merupakan keuntungan dari perdagangan, dikurangi jumlah input.

Secara grafis, kita dapat melihat bahwa ukuran perdagangan optimal berada di 0.0607 ETH input, yang menghasilkan keuntungan sebesar 0.0085 ETH. Kontrak harus memiliki setidaknya 0.0607 ETH likuiditas dalam WETH agar dapat memanfaatkan peluang ini.

Nilai keuntungan sebesar 0.0085 ETH (~$16 saat menulis artikel ini) BUKAN keuntungan akhir dari perdagangan, karena kita masih perlu memperhitungkan biaya gas transaksi. Ini akan dibahas dalam artikel berikutnya.

Kami ingin menghitung ukuran perdagangan optimal ini secara otomatis untuk bot MEV kami. Ini dapat dilakukan melalui kalkulus elementer. Kami memiliki fungsi satu variabel x yang ingin kita maksimalkan. Fungsi mencapai maksimumnya untuk nilai x di mana turunan fungsi adalah 0.

Berbagai alat gratis dan online dapat digunakan untuk menghitung turunan secara simbolis dari suatu fungsi, seperti wolfram alpha.

Mencari turunan fungsi laba kotor kami.

Mencari turunan seperti itu sangat mudah dengan Wolfram Alpha. Anda juga dapat melakukannya secara manual jika Anda meragukan kemampuan matematika Anda.

Wolfram Alpha menghasilkan turunan berikut:

dout2(x)/dx = (a1b1a2b2(1-biaya)^2)/(a1b2 + (1-biaya)x(b1(1-biaya)+b2))^2

Karena kita ingin menemukan nilai x yang memaksimalkan keuntungan (yaitu out2(x) - x), kita perlu menemukan nilai x di mana turunan adalah 1 (dan bukan 0).

Wolfram Alpha memberikan solusi berikut untuk x dalam persamaan dout2(x)/dx = 1:

x = (sqrt(a1b1a2b2(1-fee)^4 (b1(1-biaya)+b2)^2) - a1b2(1-fee)(b1(1-fee)+b2)) / ((1-fee) (b1(1-fee) + b2))^2

Dengan nilai cadangan yang kami gunakan dalam grafik di atas, kita mendapatkan x_optimal = 0.0607203782551, yang memvalidasi rumus kami (dibandingkan dengan nilai grafik sebesar 0.0607).

Meskipun rumus ini tidak terlalu mudah dibaca, namun mudah untuk diimplementasikan dalam kode. Berikut adalah implementasi python dari rumus untuk menghitung output dari 2 swap, dan ukuran perdagangan optimal:

# Fungsi pembantu untuk menghitung ukuran perdagangan optimal# Output dari satu pertukaran tunggaldef swap_output(x, a, b, fee=0.003):return b * (1 - a/(a + x*(1-fee)))# Keuntungan kotor dari dua pertukaran berturut-turutdef trade_profit(x, cadangan1, cadangan2, fee=0.003): a1, b1 = cadangan1a2, b2 = cadangan2return swap_output(swap_output(x, a1, b1, fee), b2, a2, fee) - x# Jumlah input optimaldef optimal_trade_size(cadangan1, cadangan2, fee=0.003):a1, b1 = cadangan1a2, b2 = cadangan2return (math.sqrt(a1*b1*a2*b2*(1-fee)**4 * (b1*(1-fee)+b2)**2) - a1*b2*(1-fee)*(b1*(1-fee)+b2)) / ((1-fee) * (b1*(1-fee) + b2))**2

Penemuan peluang arbitrase

Sekarang bahwa kita tahu bagaimana menghitung keuntungan kotor dari peluang arbitrase antara dua kolam yang diberikan dari pasangan token yang sama, kita hanya perlu mengulang semua pasangan token, dan menguji dua per dua semua kolam yang memiliki pasangan token yang sama. Ini akan memberikan kita keuntungan kotor dari semua peluang arbitrase yang mungkin yang berada dalam batas strategi kita.

Untuk memperkirakan keuntungan bersih dari perdagangan, kita perlu memperkirakan biaya gas untuk memanfaatkan peluang yang diberikan. Ini bisa dilakukan secara tepat dengan mensimulasikan transaksi melalui eth_call ke node RPC, tetapi membutuhkan banyak waktu dan hanya dapat dilakukan untuk beberapa puluh peluang per blok.

Kami akan pertama-tama membuat estimasi kasar dari biaya gas dengan mengasumsikan biaya gas transaksi tetap (sebenarnya merupakan batas bawah), dan menyingkirkan peluang-peluang yang tidak cukup menguntungkan untuk menutupi biaya gas. Hanya setelah itu kami akan melakukan estimasi yang tepat dari biaya gas untuk peluang-peluang yang tersisa.

Berikut adalah kode yang melalui semua pasangan dan semua kolam, dan menyortir peluang berdasarkan keuntungan:

# [...] # Ambil cadangan setiap pool di pool_dictto_fetch = [] # Daftar alamat pool yang cadangannya perlu diambil.untuk pasangan, pool_list di pool_dict.items():untuk pair_object di pool_list: to_fetch.append(pair_object["pair"]) # Tambahkan alamat poolprint(f"Fetching reserves of {len(to_fetch)} pools...")# getReservesParallel() berasal dari artikel 2 di bot MEV seriesreserveList = asyncio.get_event_loop().run_until_complete(getReservesParallel(to_fetch,  providersAsync))# Buat daftar peluang perdaganganindeks = 0opps = []untuk pasangan, pool_list di pool_dict.items():# Simpan cadangan di objek kumpulan untuk digunakan nantiuntuk pair_object di pool_list: pair_object["reserves"] = reserveList[index] index += 1# Iterasi di semua kumpulan pasanganuntuk poolA di pool_list: untuk poolB di pool_list: # Lewati jika kumpulannya sama jika poolA["pair"] == poolB["pair"]:            lanjutkan # Lewati jika salah satu cadangan adalah 0 (dibagi dengan 0) jika 0 di poolA["cadangan"] atau 0 di poolB["cadangan"]: lanjutkan # Susun ulang cadangan sehingga WETH selalu menjadi token pertama jika poolA["token0"] == WETH: res_A = (poolA["reserves"][0], poolA["reserves"][1]) res_B = (poolB["reserves"][0], poolB["reserves"][1]) else: res_A = (poolA["reserves"][1],  poolA["reserves"][0]) res_B = (poolB["reserves"][1], poolB["reserves"][0]) # Hitung nilai input optimal melalui rumus x = optimal_trade_size(res_A, res_B) # Lewati jika input optimal negatif (urutan pool terbalik) jika x < 0: lanjutkan # Hitung laba kotor di Wei (sebelum biaya gas) laba = trade_profit (x,  res_A, res_B) # Simpan detail peluang. Nilai dalam ETH. (1e18 Wei = 1 ETH) opps.append({ "profit": profit / 1e18, "input": x / 1e18, "pair": pair, "poolA": poolA, "poolB": poolB, })print(f"Found {len(opps)} opportunities.")

Yang menghasilkan output berikut:

Mengambil cadangan dari 3081 kolam renang.

Ditemukan 1791 kesempatan.

Kami sekarang memiliki daftar semua peluang. Kami hanya perlu memperkirakan keuntungan mereka. Saat ini, kami akan berasumsi biaya gas konstan untuk berdagang pada peluang.

Kita harus menggunakan batas bawah untuk biaya gas dari swap di Uniswap V2. Secara eksperimental, kami menemukan bahwa nilai ini mendekati 43k gas.

Memanfaatkan peluang memerlukan 2 swap, dan mengeksekusi transaksi di Ethereum biaya tetap 21k gas, untuk total 107k gas per peluang.

Berikut adalah kode yang menghitung keuntungan bersih yang diperkirakan dari setiap peluang:

# [...]# Gunakan biaya gas yang telah diprogram sebesar 107k gas per kesempatan gp = w3.eth.gas_pricefor opp in opps:opp["net_profit"] = opp["profit"] - 107000 * gp / 1e18# Urutkan berdasarkan perkiraan keuntungan bersihopps.sort(key=lambda x: x["net_profit"], reverse=True)# Simpan kesempatan positifpositive_opps = [opp for opp in opps if opp["net_profit"] > 0]

Cetak statistik

# Kesempatan positif hitungprint(f"Ditemukan {len(positive_opps)} kesempatan positif.")# Rincian setiap kesempatan ETH_PRICE = 1900 # Anda harus mengambil harga ETH secara dinamisuntuk opp in positive_opps:print(f"Keuntungan: {opp['net_profit']} ETH (${opp['net_profit'] * ETH_PRICE})")print(f"Input: {opp['input']} ETH (${opp['input'] * ETH_PRICE})")print(f"Pool A: {opp['poolA']['pair']}")print(f"Pool B: {opp['poolB']['pair']}")print()

Berikut adalah output dari skrip:

Ditemukan 57 peluang positif.

Keuntungan: 4.936025725859028 ETH ($9378.448879132153)

Input: 1.7958289984719014 ETH ($3412.075097096613)

Pool A: 0x1498bd576454159Bb81B5Ce532692a8752D163e8

Pool B: 0x7D7E813082eF6c143277c71786e5bE626ec77b20

{'profit': 4.9374642090282865, 'input': 1.7958(…)

Keuntungan: 4.756587769768892 ETH ($9037.516762560894)

Input: 0.32908348765283796 ETH ($625.2586265403921)

Pool A: 0x486c1609f9605fA14C28E311b7D708B0541cd2f5

Pool B: 0x5e81b946b61F3C7F73Bf84dd961dE3A0A78E8c33

{'profit': 4.7580262529381505, 'input': 0.329(…)

Keuntungan: 0.8147203063054365 ETH ($1547.9685819803292)

Input: 0.6715171730669338 ETH ($1275.8826288271744)

Pool A: 0x1f1B4836Dde1859e2edE1C6155140318EF5931C2

Pool B: 0x1f7efDcD748F43Fc4BeAe6897e5a6DDd865DcceA

{‘profit’: 0.8161587894746954, ‘input’: 0.671(…)

(...)

Yang keuntungannya mencurigakan tinggi. Langkah pertama yang harus diambil adalah memverifikasi bahwa kode tersebut benar. Setelah memeriksa kode dengan hati-hati, kami menemukan bahwa kode tersebut benar.

Apakah keuntungan ini nyata? Ternyata tidak. Kami telah melempar jaring terlalu luas saat memilih kolam renang mana yang akan dipertimbangkan dalam strategi kami, dan telah mendapatkan di tangan kami kolam renang token beracun.

Standar token ERC20 hanya menggambarkan antarmuka untuk interoperabilitas. Siapa pun dapat mendeploy token yang mengimplementasikan antarmuka ini, dan memilih untuk mengimplementasikan perilaku tidak ortodoks, yang tepatnya sedang berlangsung di sini.

Beberapa pencipta token membuat ERC20 mereka sehingga kolam di mana mereka diperdagangkan tidak dapat menjual, tetapi hanya membeli token. Beberapa kontrak token bahkan memiliki mekanisme kill-switch yang memungkinkan pencipta untuk menarik semua penggunanya.

Dalam bot MEV kami, token-token beracun ini harus disaring. Ini akan dibahas dalam artikel mendatang.

Jika kita menyaring token toksik secara manual, kita akan mendapatkan 42 peluang berikut:

Keuntungan: 0.004126583158496902 ETH ($7.840508001144114)

Input: 0.008369804833786892 ETH ($15.902629184195094)

Pool A: 0xdF42388059692150d0A9De836E4171c7B9c09CBf

Pool B: 0xf98fCEB2DC0Fa2B3f32ABccc5e8495E961370B23

{‘profit’: 0.005565066327755902, (…)

Keuntungan: 0.004092580415474992 ETH ($7.775902789402485)

Input: 0.014696360216108083 ETH ($27.92308441060536)

Pool A: 0xfDBFb4239935A15C2C348400570E34De3b044c5F

Pool B: 0x0F15d69a7E5998252ccC39Ad239Cef67fa2a9369

{‘profit’: 0.005531063584733992, (...)}

Keuntungan: 0.003693235163284344 ETH ($7.017146810240254)

Input: 0.1392339178514088 ETH ($264.5444439176767)

Pool A: 0x2957215d0473d2c811A075725Da3C31D2af075F1

Pool B: 0xF110783EbD020DCFBA91Cd1976b79a6E510846AA

{‘profit’: 0.005131718332543344, (…)

Profit: 0.003674128918827048 ETH ($6.980844945771391)

Input: 0.2719041848570484 ETH ($516.617951228392)

Pool A: 0xBa19343ff3E9f496F17C7333cdeeD212D65A8425

Pool B: 0xD30567f1d084f411572f202ebb13261CE9F46325

{‘profit’: 0.005112612088086048, (…)

(…)

Perhatikan bahwa secara umum keuntungan lebih rendah daripada jumlah input yang diperlukan untuk mengeksekusi transaksi.

Keuntungan ini jauh lebih masuk akal. Tapi ingatlah bahwa mereka masih merupakan keuntungan skenario terbaik, karena kami telah menggunakan estimasi biaya gas yang sangat kasar dari setiap kesempatan.

Dalam artikel mendatang, kami akan mensimulasikan eksekusi perdagangan kami untuk mendapatkan nilai tepat dari biaya gas setiap kesempatan.

Untuk mensimulasikan eksekusi, kita perlu pertama-tama mengembangkan kontrak pintar yang akan mengeksekusi perdagangan. Ini adalah topik dari artikel berikutnya.

Kesimpulan

Kami sekarang memiliki definisi yang jelas tentang batas lingkaran bot arbitrase MEV kami.

Kami telah menjelajahi teori matematika di balik strategi arbitrase, dan telah mengimplementasikannya dalam Python.

Kami sekarang memiliki daftar peluang arbitrase potensial, dan kami perlu mensimulasikan eksekusi mereka untuk mendapatkan nilai keuntungan akhir. Untuk melakukannya, kami perlu memiliki kontrak pintar perdagangan kami siap.

Pada artikel berikutnya, kami akan mengembangkan kontrak pintar seperti itu dalam Solidity, dan mensimulasikan perdagangan arbitrase pertama kami.

Anda dapat menemukan kode lengkap di repo GitHub yang terkait dengan artikel iniSkrip terbaik dijalankan di notebook Jupyter.

Disclaimer:

  1. Artikel ini dicetak ulang dari [Gatemedium], Semua hak cipta milik penulis asli [Emile Amajar]. Judul artikel asli "Membangun bot arbitrase: Menemukan peluang arbitrase (artikel 3 / n)", Jika ada keberatan dengan cetak ulang ini, silakan hubungi Gate Learntim, dan mereka akan menanganinya dengan segera.
  2. Penolakan Tanggung Jawab: Pandangan dan opini yang terdapat dalam artikel ini semata-mata milik penulis dan tidak merupakan saran investasi apa pun.
  3. Terjemahan artikel ke dalam bahasa lain dilakukan oleh tim Gate Learn. Kecuali disebutkan, menyalin, mendistribusikan, atau menjiplak artikel yang diterjemahkan dilarang.

Membangun bot arbitrase: Menemukan peluang arbitrase

Menengah4/9/2024, 2:29:22 PM
Dalam artikel ini, kami melakukan pra-seleksi pasangan token yang menarik. Kami kemudian menurunkan rumus matematika untuk menemukan arbitrase optimal antara dua kelompok pasangan token yang sama.

Jika pengaturan MEV Anda tidak terlihat seperti ini, Anda ngmi

Artikel ini adalah bagian dari serangkaian tentang membangun bot arbitrase. Tujuan dari seri ini adalah untuk memberikan panduan langkah demi langkah dalam membangun robot perdagangan MEV otomatis yang dapat menemukan dan mengeksekusi peluang arbitrase di bursa terdesentralisasi populer.

Dalam artikel ini, kami melakukan pra-pemilihan pasangan token yang menarik. Kami kemudian menurunkan rumus matematika untuk menemukan arbitrase optimal antara dua kelompok pasangan token yang sama. Akhirnya, kami menerapkan rumus tersebut dalam kode dan mengembalikan daftar kesempatan arbitrase potensial.

Memilih pasangan token

Ketepatan tentang strategi arbitrase

Sebelum kita mulai mencari peluang arbitrase, kita harus dengan jelas mendefinisikan batas dari bot arbitrase kita. Secara khusus, jenis arbitrase apa yang ingin kita lakukan. Jenis arbitrase paling aman adalah antara pool yang melibatkan ETH. Karena ETH adalah aset dengan mana gas transaksi kita dibayar, adalah wajar untuk selalu ingin mendapatkan ETH setelah arbitrase. Tetapi semua orang tergoda untuk berpikir seperti ini. Ingatlah bahwa dalam perdagangan, peluang yang tepat waktu menjadi kurang menguntungkan seiring dengan bertambahnya orang yang bertindak atasnya.

Demi kesederhanaan, kami akan fokus pada peluang arbitrase antara kolam yang melibatkan ETH. Kami hanya akan mencari peluang antara dua kolam dari pasangan token yang sama. Kami tidak akan melakukan perdagangan pada peluang yang melibatkan lebih dari 2 kolam dalam rute perdagangan (disebut peluang multi-hop). Perhatikan bahwa meningkatkan strategi ini ke yang lebih berisiko adalah langkah pertama yang harus Anda ambil untuk meningkatkan profitabilitas bot Anda.

Untuk meningkatkan strategi ini, Anda misalnya dapat menyimpan sejumlah inventaris dalam stablecoins dan bertindak pada peluang arbitrase yang menghasilkan stablecoins. Hal yang sama dapat dilakukan untuk aset yang jauh lebih berisiko seperti shitcoins (dengan tindakan pencegahan yang diperlukan), dan secara berkala merekonsiliasi portofolio Anda ke ETH untuk membayar gas.

Salah satu arah lainnya adalah meninggalkan asumsi implisit tentang atomisitas yang kita buat, dan memperkenalkan penalaran statistik dalam strategi kita. Misalnya, dengan membeli satu token dalam sebuah pool ketika harga telah bergerak secara menguntungkan lebih dari beberapa jumlah deviasi standar, dan menjualnya kemudian (strategi reverensi rerata). Ini akan ideal untuk shitcoins yang tidak terdaftar di bursa terpusat yang jauh lebih efisien, atau yang sudah terdaftar tetapi harganya tidak terlacak dengan benar secara on-chain. Ini melibatkan banyak bagian yang bergerak dan berada di luar cakupan seri ini.

Memilih pasangan token

Sekarang bahwa kami telah mendefinisikan batas dari bot arbitrase kami, kami perlu memilih pasangan token yang ingin kami perdagangkan. Berikut adalah 2 kriteria pemilihan yang akan kami gunakan:

  • Pasangan yang akan dipilih harus melibatkan ETH.
  • Pasangan harus diperdagangkan di setidaknya 2 kolam yang berbeda.

Menggunakan ulang kode dari artikel 2: Membaca Harga Kolam Renang Secara Efisien, kami memiliki kode berikut yang mencantumkan semua pasangan token yang diterapkan oleh kontrak pabrik yang disediakan:

# [...]# Memuat alamat dari kontrak pabrikadengan open("FactoriesV2.json", "r") as f:pabrik = json.load(f)# [...]# Ambil daftar kolam untuk setiap kontrak pabrikpairDataList = []for namaPabrik, dataPabrik in pabrik.items():acara = getPairEvents(w3.eth.contract(address=dataPabrik['factory'], abi=factory_abi), 0, w3.eth.block_number)print(f'Ditemukan {len(acara)} kolam untuk {namaPabrik}')for e in acara:   pairDataList.append({       "token0": e["args"]["token0"],       "token1": e["args"]["token1"],       "pair": e["args"]["pair"],       "factory": namaPabrik   })

Kami akan dengan mudah membalikkan pairDataList ke dalam kamus di mana kunci-kunci adalah pasangan token, dan nilai-nilainya adalah daftar kolam yang melakukan perdagangan pasangan ini. Saat melintasi daftar, kami mengabaikan pasangan yang tidak melibatkan ETH. Setelah perulangan selesai, pasangan dengan setidaknya 2 kolam yang dipilih akan disimpan dalam daftar dengan setidaknya 2 elemen:

# [...]WETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"pair_pool_dict = {}for pair_object in pairDataList:# Check for ETH (WETH) in the pair.pair = (pair_object['token0'], pair_object['token1'])if WETH not in pair:   continue# Make sure the pair is referenced in the dictionary. if pair not in pair_pool_dict:   pair_pool_dict[pair] = []# Add the pool to the list of pools that trade this pair.pair_pool_dict[pair].append(pair_object)# Create the final dictionnary of pools that will be traded on.pool_dict = {}for pair, pool_list in pair_pool_dict.items():if len(pool_list) >= 2:   pool_dict[pair] = pool_list

Beberapa statistik harus dicetak untuk lebih memahami data yang sedang kita kerjakan:

# Jumlah pasangan yang berbedaprint(f'Kami memiliki {len(pool_dict)} pasangan yang berbeda.')# Total jumlah kolamrenangprint(f'Kami memiliki {sum([len(pool_list) for pool_list in pool_dict.values()])} kolamrenang secara total.')# Pasangan dengan kolamrenang terbanyak print(f'Pasangan dengan kolamrenang terbanyak adalah {max(pool_dict, key=lambda k: len(pool_dict[k]))} dengan {len(max(pool_dict.values(), key=len))} kolamrenang.')# Distribusi jumlah kolamrenang per pasangan, desilspool_count_list = [len(pool_list) for pool_list in pool_dict.values()]pool_count_list.sort(reverse=True)print(f'Jumlah kolamrenang per pasangan, dalam desil: {pool_count_list[::int(len(pool_count_list)/10)]}')# Distribusi jumlah kolamrenang per pasangan, persenil (desil dari desil pertama)pool_count_list.sort(reverse=True)print(f'Jumlah kolamrenang per pasangan, dalam persenil: {pool_count_list[::int(len(pool_count_list)/100)][:10]}')

Saat ini, ini menghasilkan yang berikut ini:

Kami memiliki 1431 pasangan yang berbeda.

Kami memiliki total 3081 kolam renang.

Pasangan dengan jumlah kolam terbanyak adalah ('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', '0xdAC17F958D2ee523a2206206994597C13D831ec7') dengan 16 kolam.

Jumlah kolam per pasangan, dalam desil: [16, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

Jumlah kolam per pasang, dalam persentil: [16, 5, 4, 3, 3, 3, 3, 3, 3, 3]

Mengambil cadangan untuk 3000 kolam dapat dilakukan dalam waktu kurang dari 1 detik dengan node RPC publik. Ini adalah jumlah waktu yang wajar.

Sekarang, kami memiliki semua data yang kami butuhkan, kami perlu mulai mencari peluang arbitrase.

Mencari peluang arbitrase

Idea umum

Ada peluang arbitrase setiap kali ada perbedaan harga antara dua pool yang melakukan perdagangan pasangan yang sama. Namun, tidak semua perbedaan harga dapat dieksploitasi: biaya gas transaksi menetapkan nilai minimum yang harus dikembalikan oleh perdagangan, dan likuiditas di setiap pool membatasi nilai yang dapat diekstraksi dari perbedaan harga yang diberikan.

Untuk menemukan peluang arbitrase paling menguntungkan yang dapat diakses oleh kita, kita perlu menghitung nilai potensial yang dapat diekstraksi dari setiap perbedaan harga, mempertimbangkan cadangan/likuiditas di setiap pool, dan memperkirakan biaya gas transaksi.

Rumus Ukuran Perdagangan Optimal Arbitrase

Ketika peluang arbitrase dieksploitasi, harga dari pool yang membeli token input akan turun, dan harga dari pool yang menjual akan naik. Pergerakan harga dideskripsikan oleh rumus produk konstan.

Kita sudah melihat di @emileamajar/membangun-bot-arbitrase-pembuat-pasar-otomatis-dan-uniswap-2d208215d8c2"> artikel 1 cara menghitung output dari swap melalui kolam, diberikan cadangan kolam tersebut dan jumlah masukan.

Untuk menemukan ukuran perdagangan optimal, pertama-tama kita menemukan formula untuk output dari dua pertukaran berturut-turut, dengan jumlah input tertentu, dan cadangan dari dua kolam yang terlibat dalam pertukaran tersebut.

Kami mengasumsikan bahwa input pertukaran pertama berada di token0, dan input pertukaran kedua berada di token1, yang akhirnya menghasilkan output di token0.

Biarkan x menjadi jumlah masukan, (a1, b1) cadangan dari kolam pertama, dan (a2, b2) cadangan dari kolam kedua. biaya adalah biaya yang diambil oleh kolam, dan diasumsikan sama untuk kedua kolam (0.3% sebagian besar waktu).

Kami mendefinisikan sebuah fungsi yang menghitung output dari pertukaran, dengan input x dan cadangan (a,b):

f(x, a, b) = b (1 - a/(a + x(1-fee)))

Kami kemudian tahu bahwa output swap pertama adalah:

out1(x) = f(x, a1, b1)

out1(x) = b1(1 - a1/(a1 + x(1-fee)))

Output dari swap kedua adalah: (perhatikan variabel cadangan yang ditukar)

out2(x) = f(out1(x), b2, a2)

out2(x) = f(f(x, a1, b1), b2, a2)

out2(x) = a2(1 - b2/(b2 + f(x, a1, b1)(1-fee)))

out2(x) = a2 (1 - b2/(b2 + b1) (1 - a1/(a1 + x (1-fee))) (1-fee)))

Kita dapat memplot fungsi ini menggunakan desmosDengan memilih nilai cadangan sehingga kita mensimulasikan kolam pertama memiliki 1 ETH dan 1750 USDC, dan kolam kedua memiliki 1340 USDC dan 1 ETH, kita mendapatkan grafik berikut:

Plot dari keuntungan kotor perdagangan sebagai fungsi dari nilai input

Perhatikan bahwa kami sebenarnya telah merencanakan out2(x) - x, yang merupakan keuntungan dari perdagangan, dikurangi jumlah input.

Secara grafis, kita dapat melihat bahwa ukuran perdagangan optimal berada di 0.0607 ETH input, yang menghasilkan keuntungan sebesar 0.0085 ETH. Kontrak harus memiliki setidaknya 0.0607 ETH likuiditas dalam WETH agar dapat memanfaatkan peluang ini.

Nilai keuntungan sebesar 0.0085 ETH (~$16 saat menulis artikel ini) BUKAN keuntungan akhir dari perdagangan, karena kita masih perlu memperhitungkan biaya gas transaksi. Ini akan dibahas dalam artikel berikutnya.

Kami ingin menghitung ukuran perdagangan optimal ini secara otomatis untuk bot MEV kami. Ini dapat dilakukan melalui kalkulus elementer. Kami memiliki fungsi satu variabel x yang ingin kita maksimalkan. Fungsi mencapai maksimumnya untuk nilai x di mana turunan fungsi adalah 0.

Berbagai alat gratis dan online dapat digunakan untuk menghitung turunan secara simbolis dari suatu fungsi, seperti wolfram alpha.

Mencari turunan fungsi laba kotor kami.

Mencari turunan seperti itu sangat mudah dengan Wolfram Alpha. Anda juga dapat melakukannya secara manual jika Anda meragukan kemampuan matematika Anda.

Wolfram Alpha menghasilkan turunan berikut:

dout2(x)/dx = (a1b1a2b2(1-biaya)^2)/(a1b2 + (1-biaya)x(b1(1-biaya)+b2))^2

Karena kita ingin menemukan nilai x yang memaksimalkan keuntungan (yaitu out2(x) - x), kita perlu menemukan nilai x di mana turunan adalah 1 (dan bukan 0).

Wolfram Alpha memberikan solusi berikut untuk x dalam persamaan dout2(x)/dx = 1:

x = (sqrt(a1b1a2b2(1-fee)^4 (b1(1-biaya)+b2)^2) - a1b2(1-fee)(b1(1-fee)+b2)) / ((1-fee) (b1(1-fee) + b2))^2

Dengan nilai cadangan yang kami gunakan dalam grafik di atas, kita mendapatkan x_optimal = 0.0607203782551, yang memvalidasi rumus kami (dibandingkan dengan nilai grafik sebesar 0.0607).

Meskipun rumus ini tidak terlalu mudah dibaca, namun mudah untuk diimplementasikan dalam kode. Berikut adalah implementasi python dari rumus untuk menghitung output dari 2 swap, dan ukuran perdagangan optimal:

# Fungsi pembantu untuk menghitung ukuran perdagangan optimal# Output dari satu pertukaran tunggaldef swap_output(x, a, b, fee=0.003):return b * (1 - a/(a + x*(1-fee)))# Keuntungan kotor dari dua pertukaran berturut-turutdef trade_profit(x, cadangan1, cadangan2, fee=0.003): a1, b1 = cadangan1a2, b2 = cadangan2return swap_output(swap_output(x, a1, b1, fee), b2, a2, fee) - x# Jumlah input optimaldef optimal_trade_size(cadangan1, cadangan2, fee=0.003):a1, b1 = cadangan1a2, b2 = cadangan2return (math.sqrt(a1*b1*a2*b2*(1-fee)**4 * (b1*(1-fee)+b2)**2) - a1*b2*(1-fee)*(b1*(1-fee)+b2)) / ((1-fee) * (b1*(1-fee) + b2))**2

Penemuan peluang arbitrase

Sekarang bahwa kita tahu bagaimana menghitung keuntungan kotor dari peluang arbitrase antara dua kolam yang diberikan dari pasangan token yang sama, kita hanya perlu mengulang semua pasangan token, dan menguji dua per dua semua kolam yang memiliki pasangan token yang sama. Ini akan memberikan kita keuntungan kotor dari semua peluang arbitrase yang mungkin yang berada dalam batas strategi kita.

Untuk memperkirakan keuntungan bersih dari perdagangan, kita perlu memperkirakan biaya gas untuk memanfaatkan peluang yang diberikan. Ini bisa dilakukan secara tepat dengan mensimulasikan transaksi melalui eth_call ke node RPC, tetapi membutuhkan banyak waktu dan hanya dapat dilakukan untuk beberapa puluh peluang per blok.

Kami akan pertama-tama membuat estimasi kasar dari biaya gas dengan mengasumsikan biaya gas transaksi tetap (sebenarnya merupakan batas bawah), dan menyingkirkan peluang-peluang yang tidak cukup menguntungkan untuk menutupi biaya gas. Hanya setelah itu kami akan melakukan estimasi yang tepat dari biaya gas untuk peluang-peluang yang tersisa.

Berikut adalah kode yang melalui semua pasangan dan semua kolam, dan menyortir peluang berdasarkan keuntungan:

# [...] # Ambil cadangan setiap pool di pool_dictto_fetch = [] # Daftar alamat pool yang cadangannya perlu diambil.untuk pasangan, pool_list di pool_dict.items():untuk pair_object di pool_list: to_fetch.append(pair_object["pair"]) # Tambahkan alamat poolprint(f"Fetching reserves of {len(to_fetch)} pools...")# getReservesParallel() berasal dari artikel 2 di bot MEV seriesreserveList = asyncio.get_event_loop().run_until_complete(getReservesParallel(to_fetch,  providersAsync))# Buat daftar peluang perdaganganindeks = 0opps = []untuk pasangan, pool_list di pool_dict.items():# Simpan cadangan di objek kumpulan untuk digunakan nantiuntuk pair_object di pool_list: pair_object["reserves"] = reserveList[index] index += 1# Iterasi di semua kumpulan pasanganuntuk poolA di pool_list: untuk poolB di pool_list: # Lewati jika kumpulannya sama jika poolA["pair"] == poolB["pair"]:            lanjutkan # Lewati jika salah satu cadangan adalah 0 (dibagi dengan 0) jika 0 di poolA["cadangan"] atau 0 di poolB["cadangan"]: lanjutkan # Susun ulang cadangan sehingga WETH selalu menjadi token pertama jika poolA["token0"] == WETH: res_A = (poolA["reserves"][0], poolA["reserves"][1]) res_B = (poolB["reserves"][0], poolB["reserves"][1]) else: res_A = (poolA["reserves"][1],  poolA["reserves"][0]) res_B = (poolB["reserves"][1], poolB["reserves"][0]) # Hitung nilai input optimal melalui rumus x = optimal_trade_size(res_A, res_B) # Lewati jika input optimal negatif (urutan pool terbalik) jika x < 0: lanjutkan # Hitung laba kotor di Wei (sebelum biaya gas) laba = trade_profit (x,  res_A, res_B) # Simpan detail peluang. Nilai dalam ETH. (1e18 Wei = 1 ETH) opps.append({ "profit": profit / 1e18, "input": x / 1e18, "pair": pair, "poolA": poolA, "poolB": poolB, })print(f"Found {len(opps)} opportunities.")

Yang menghasilkan output berikut:

Mengambil cadangan dari 3081 kolam renang.

Ditemukan 1791 kesempatan.

Kami sekarang memiliki daftar semua peluang. Kami hanya perlu memperkirakan keuntungan mereka. Saat ini, kami akan berasumsi biaya gas konstan untuk berdagang pada peluang.

Kita harus menggunakan batas bawah untuk biaya gas dari swap di Uniswap V2. Secara eksperimental, kami menemukan bahwa nilai ini mendekati 43k gas.

Memanfaatkan peluang memerlukan 2 swap, dan mengeksekusi transaksi di Ethereum biaya tetap 21k gas, untuk total 107k gas per peluang.

Berikut adalah kode yang menghitung keuntungan bersih yang diperkirakan dari setiap peluang:

# [...]# Gunakan biaya gas yang telah diprogram sebesar 107k gas per kesempatan gp = w3.eth.gas_pricefor opp in opps:opp["net_profit"] = opp["profit"] - 107000 * gp / 1e18# Urutkan berdasarkan perkiraan keuntungan bersihopps.sort(key=lambda x: x["net_profit"], reverse=True)# Simpan kesempatan positifpositive_opps = [opp for opp in opps if opp["net_profit"] > 0]

Cetak statistik

# Kesempatan positif hitungprint(f"Ditemukan {len(positive_opps)} kesempatan positif.")# Rincian setiap kesempatan ETH_PRICE = 1900 # Anda harus mengambil harga ETH secara dinamisuntuk opp in positive_opps:print(f"Keuntungan: {opp['net_profit']} ETH (${opp['net_profit'] * ETH_PRICE})")print(f"Input: {opp['input']} ETH (${opp['input'] * ETH_PRICE})")print(f"Pool A: {opp['poolA']['pair']}")print(f"Pool B: {opp['poolB']['pair']}")print()

Berikut adalah output dari skrip:

Ditemukan 57 peluang positif.

Keuntungan: 4.936025725859028 ETH ($9378.448879132153)

Input: 1.7958289984719014 ETH ($3412.075097096613)

Pool A: 0x1498bd576454159Bb81B5Ce532692a8752D163e8

Pool B: 0x7D7E813082eF6c143277c71786e5bE626ec77b20

{'profit': 4.9374642090282865, 'input': 1.7958(…)

Keuntungan: 4.756587769768892 ETH ($9037.516762560894)

Input: 0.32908348765283796 ETH ($625.2586265403921)

Pool A: 0x486c1609f9605fA14C28E311b7D708B0541cd2f5

Pool B: 0x5e81b946b61F3C7F73Bf84dd961dE3A0A78E8c33

{'profit': 4.7580262529381505, 'input': 0.329(…)

Keuntungan: 0.8147203063054365 ETH ($1547.9685819803292)

Input: 0.6715171730669338 ETH ($1275.8826288271744)

Pool A: 0x1f1B4836Dde1859e2edE1C6155140318EF5931C2

Pool B: 0x1f7efDcD748F43Fc4BeAe6897e5a6DDd865DcceA

{‘profit’: 0.8161587894746954, ‘input’: 0.671(…)

(...)

Yang keuntungannya mencurigakan tinggi. Langkah pertama yang harus diambil adalah memverifikasi bahwa kode tersebut benar. Setelah memeriksa kode dengan hati-hati, kami menemukan bahwa kode tersebut benar.

Apakah keuntungan ini nyata? Ternyata tidak. Kami telah melempar jaring terlalu luas saat memilih kolam renang mana yang akan dipertimbangkan dalam strategi kami, dan telah mendapatkan di tangan kami kolam renang token beracun.

Standar token ERC20 hanya menggambarkan antarmuka untuk interoperabilitas. Siapa pun dapat mendeploy token yang mengimplementasikan antarmuka ini, dan memilih untuk mengimplementasikan perilaku tidak ortodoks, yang tepatnya sedang berlangsung di sini.

Beberapa pencipta token membuat ERC20 mereka sehingga kolam di mana mereka diperdagangkan tidak dapat menjual, tetapi hanya membeli token. Beberapa kontrak token bahkan memiliki mekanisme kill-switch yang memungkinkan pencipta untuk menarik semua penggunanya.

Dalam bot MEV kami, token-token beracun ini harus disaring. Ini akan dibahas dalam artikel mendatang.

Jika kita menyaring token toksik secara manual, kita akan mendapatkan 42 peluang berikut:

Keuntungan: 0.004126583158496902 ETH ($7.840508001144114)

Input: 0.008369804833786892 ETH ($15.902629184195094)

Pool A: 0xdF42388059692150d0A9De836E4171c7B9c09CBf

Pool B: 0xf98fCEB2DC0Fa2B3f32ABccc5e8495E961370B23

{‘profit’: 0.005565066327755902, (…)

Keuntungan: 0.004092580415474992 ETH ($7.775902789402485)

Input: 0.014696360216108083 ETH ($27.92308441060536)

Pool A: 0xfDBFb4239935A15C2C348400570E34De3b044c5F

Pool B: 0x0F15d69a7E5998252ccC39Ad239Cef67fa2a9369

{‘profit’: 0.005531063584733992, (...)}

Keuntungan: 0.003693235163284344 ETH ($7.017146810240254)

Input: 0.1392339178514088 ETH ($264.5444439176767)

Pool A: 0x2957215d0473d2c811A075725Da3C31D2af075F1

Pool B: 0xF110783EbD020DCFBA91Cd1976b79a6E510846AA

{‘profit’: 0.005131718332543344, (…)

Profit: 0.003674128918827048 ETH ($6.980844945771391)

Input: 0.2719041848570484 ETH ($516.617951228392)

Pool A: 0xBa19343ff3E9f496F17C7333cdeeD212D65A8425

Pool B: 0xD30567f1d084f411572f202ebb13261CE9F46325

{‘profit’: 0.005112612088086048, (…)

(…)

Perhatikan bahwa secara umum keuntungan lebih rendah daripada jumlah input yang diperlukan untuk mengeksekusi transaksi.

Keuntungan ini jauh lebih masuk akal. Tapi ingatlah bahwa mereka masih merupakan keuntungan skenario terbaik, karena kami telah menggunakan estimasi biaya gas yang sangat kasar dari setiap kesempatan.

Dalam artikel mendatang, kami akan mensimulasikan eksekusi perdagangan kami untuk mendapatkan nilai tepat dari biaya gas setiap kesempatan.

Untuk mensimulasikan eksekusi, kita perlu pertama-tama mengembangkan kontrak pintar yang akan mengeksekusi perdagangan. Ini adalah topik dari artikel berikutnya.

Kesimpulan

Kami sekarang memiliki definisi yang jelas tentang batas lingkaran bot arbitrase MEV kami.

Kami telah menjelajahi teori matematika di balik strategi arbitrase, dan telah mengimplementasikannya dalam Python.

Kami sekarang memiliki daftar peluang arbitrase potensial, dan kami perlu mensimulasikan eksekusi mereka untuk mendapatkan nilai keuntungan akhir. Untuk melakukannya, kami perlu memiliki kontrak pintar perdagangan kami siap.

Pada artikel berikutnya, kami akan mengembangkan kontrak pintar seperti itu dalam Solidity, dan mensimulasikan perdagangan arbitrase pertama kami.

Anda dapat menemukan kode lengkap di repo GitHub yang terkait dengan artikel iniSkrip terbaik dijalankan di notebook Jupyter.

Disclaimer:

  1. Artikel ini dicetak ulang dari [Gatemedium], Semua hak cipta milik penulis asli [Emile Amajar]. Judul artikel asli "Membangun bot arbitrase: Menemukan peluang arbitrase (artikel 3 / n)", Jika ada keberatan dengan cetak ulang ini, silakan hubungi Gate Learntim, dan mereka akan menanganinya dengan segera.
  2. Penolakan Tanggung Jawab: Pandangan dan opini yang terdapat dalam artikel ini semata-mata milik penulis dan tidak merupakan saran investasi apa pun.
  3. Terjemahan artikel ke dalam bahasa lain dilakukan oleh tim Gate Learn. Kecuali disebutkan, menyalin, mendistribusikan, atau menjiplak artikel yang diterjemahkan dilarang.
Bắt đầu giao dịch
Đăng ký và giao dịch để nhận phần thưởng USDTEST trị giá
$100
$5500