Erstellen eines Arbitrage-Bots: Finden von Arbitrage-Möglichkeiten
September 28th, 2023

Erstellen eines Arbitrage-Bots: Finden von Arbitrage-Möglichkeiten

Wenn Ihr MEV-Setup nicht so aussieht, sind Sie ngmi Dieser Artikel ist Teil einer Serie über den Aufbau eines Arbitrage-Bots. Ziel dieser Serie ist es, eine Schritt-für-Schritt-Anleitung zum Aufbau eines automatisierten MEV-Handelsroboters bereitzustellen, der Arbitragemöglichkeiten an beliebten dezentralen Börsen finden und ausführen kann. In diesem Artikel führen wir eine Vorauswahl der interessierenden Token-Paare durch. Anschließend leiten wir die mathematische Formel ab, um die optimale Arbitrage zwischen zwei Pools derselben Token-Paare zu finden. Schließlich implementieren wir die Formel im Code und geben eine Liste potenzieller Arbitragemöglichkeiten zurück. Auswahl der Token-Paare Präzisierungen zur Arbitrage-Strategie

Bevor wir mit der Suche nach Arbitrage-Möglichkeiten beginnen, müssen wir den Umfang unseres Arbitrage-Bots klar definieren. Konkret: Auf welche Art von Arbitrage wollen wir reagieren? Die sicherste Art der Arbitrage ist zwischen Pools, an denen die ETH beteiligt ist. Da die ETH der Vermögenswert ist, mit dem das Gas unserer Transaktionen bezahlt wird, ist es selbstverständlich, dass man nach einer Arbitrage immer bei der ETH landen möchte. Aber jeder ist versucht, so zu denken. Bedenken Sie, dass beim Trading pünktliche Gelegenheiten immer weniger profitabel werden, je mehr Menschen sie nutzen. Der Einfachheit halber konzentrieren wir uns auf Arbitragemöglichkeiten zwischen Pools, an denen die ETH beteiligt ist. Wir werden nur nach Möglichkeiten zwischen zwei Pools desselben Token-Paares suchen. Wir werden nicht bei Gelegenheiten handeln, an denen mehr als zwei Pools in der Handelsroute beteiligt sind (sogenannte Multi-Hop- Möglichkeiten). Beachten Sie, dass das Upgrade dieser Strategie auf eine riskantere Strategie der erste Schritt ist, den Sie unternehmen sollten, um die Rentabilität Ihres Bots zu verbessern. Um diese Strategie zu verbessern, könnten Sie beispielsweise einen gewissen Bestand an Stablecoins halten und Arbitragemöglichkeiten nutzen, die Stablecoins generieren. Das Gleiche könnte man auch für viel riskantere Vermögenswerte wie Shitcoins machen (mit den nötigen Vorsichtsmaßnahmen) und sein Portfolio regelmäßig in ETH umschichten, um Benzin zu bezahlen. Eine andere Richtung bestünde darin, die von uns implizite Annahme der Atomizität aufzugeben und statistische Überlegungen in unsere Strategie einzuführen.

Zum Beispiel durch den Kauf eines Tokens in einem Pool, wenn sich der Preis um mehr als eine bestimmte Standardabweichung positiv entwickelt hat, und durch den späteren Verkauf (Mean-Reversion-Strategie). Dies wäre ideal für Shitcoins, die nicht an viel effizienteren zentralen Börsen notiert sind oder deren Preis in der Kette nicht korrekt verfolgt wird. Dies beinhaltet viel mehr bewegliche Teile und ist nicht Gegenstand dieser Serie. Auswahl der Token-Paare Nachdem wir nun den Umfang unseres Arbitrage-Bots definiert haben, müssen wir die Token-Paare auswählen, mit denen wir handeln möchten. Hier sind die 2 Auswahlkriterien, die wir verwenden werden: Die ausgewählten Paare müssen ETH beinhalten. Die Paare müssen in mindestens zwei verschiedenen Pools gehandelt werden.

Unter Wiederverwendung des Codes aus Artikel 2: Effizientes Lesen von Poolpreisen haben wir den folgenden Code, der alle Token-Paare auflistet, die durch die bereitgestellten Fabrikverträge bereitgestellt wurden:

[...]

Laden Sie die Adressen der Fabrikverträge

mit open ( "FactoriesV2.json" , "r" ) als f: factorys = json.load(f)

[...]

Liste der Pools abrufen für jedes FabrikvertragspaarDataList

= [] für Fabrikname, Fabrikdaten in Fabriken.items(): events = getPairEvents(w3.eth.contract(address=factoryData[ 'factory' ], abi=factory_abi), 0 , w3.eth.block_number) print ( f'Found { len (events)} Pools für {factoryName} ' ) für e in Ereignissen: pairDataList.append({ "token0" : e[ "args" ][ "token0" ], "token1" : e[ "args" ][ "token1" ], "pair" : e[ "args " ][ "pair" ], "factory" : FactoryName }) Wir werden einfach pairDataListin ein Wörterbuch umwandeln, in dem die Schlüssel die Token-Paare sind und die Werte die Liste der Pools sind, die dieses Paar handeln. Beim Durchlaufen der Liste ignorieren wir die Paare, an denen ETH nicht beteiligt ist. Wenn die Schleife beendet ist, werden Paare mit mindestens 2 ausgewählten Pools in Listen mit mindestens 2 Elementen gespeichert:

[...]

WETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" pair_pool_dict = {} fürpair_object inpairDataList : #Überprüfen Sie, ob ETH (WETH) im Paar vorhanden ist . pair = (pair_object[ 'token0' ], pair_object[ 'token1' ]) wenn WETH nicht im Paar: fortfahren # Stellen Sie sicher, dass das Paar im Wörterbuch referenziert wird. Wenn das Paar nicht inpair_pool_dict : pair_pool_dict[pair] = [] ist, fügen Sie den Pool zur Liste der Pools hinzu, die dieses Paar handeln. pair_pool_dict[pair].append(pair_object)

Erstellen Sie das endgültige Wörterbuch der Pools, mit denen gehandelt werden soll.

pool_dict = {} für Paar, pool_list in pair_pool_dict.items(): if len (pool_list) >= 2 : pool_dict[pair] = pool_list Einige Statistiken sollten ausgedruckt werden, um einen besseren Überblick über die Daten zu haben, mit denen wir arbeiten:

Anzahl verschiedener Paare

print ( f'Wir haben { len (pool_dict)} verschiedene Paare.' )

Gesamtzahl der Pools

print ( f'Wir haben { sum ([ len (pool_list) für pool_list in pool_dict.values()] )} Pools insgesamt.' )

Paar mit den meisten Pools

print ( f'Das Paar mit den meisten Pools ist { max (pool_dict, key= lambda k: len (pool_dict[k]))} mit { len ( max(pool_dict.values(), key= len ))} Pools.' )

Verteilung der Anzahl der Pools pro Paar, Dezile

pool_count_list = [ len (pool_list) für pool_list in pool_dict.values()] pool_count_list.sort(reverse= True ) print ( f'Anzahl der Pools pro Paar, in Dezilen: { pool_count_list[:: int ( len (pool_count_list)/ 10 )]} ' )

Verteilung der Anzahl der Pools pro Paar, Perzentile (Dezile des ersten Dezils)

pool_count_list.sort(reverse= True ) drucken( f'Anzahl der Pools pro Paar, in Perzentilen: {pool_count_list[:: int ( len (pool_count_list)/ 100 )][: 10 ]} ' ) Zum Zeitpunkt des Schreibens wird Folgendes ausgegeben: Wir haben 1431 verschiedene Paare. Wir haben insgesamt 3081 Pools . Das Paar mit den meisten Pools ist ( '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' , '0xdAC17F958D2ee523a2206206994597C13D831ec7' ) mit 16 Pools. Anzahl der Pools pro Paar, in Dezilen: [ 16 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 ]

Anzahl der Pools pro Paar, in Perzentilen: [ 16 , 5 , 4 , 3 , 3 , 3 , 3 , 3 , 3 , 3 ] Das Abrufen von Reserven für 3000 Pools kann mit öffentlichen RPC-Knoten in weniger als 1 Sekunde erfolgen. Dies ist eine angemessene Zeitspanne. Da wir nun über alle benötigten Daten verfügen, müssen wir damit beginnen, Arbitragemöglichkeiten zu finden. Arbitrage-Möglichkeiten finden Grund Idee Eine Arbitragemöglichkeit besteht immer dann, wenn zwischen zwei Pools, die dasselbe Paar handeln, eine Preisdiskrepanz besteht. Allerdings sind nicht alle Preisunterschiede ausnutzbar: Die Gaskosten der Transaktion legen einen Mindestwert fest, der durch den Handel wieder hereingeholt werden muss, und die Liquidität in jedem Pool begrenzt den Wert, der aus einem bestimmten Preisunterschied gewonnen werden kann. Um die profitabelste Arbitragemöglichkeit zu finden, die uns zur Verfügung steht, müssen wir den potenziellen Wert berechnen, der sich aus jeder Preisdifferenz ziehen lässt, unter Berücksichtigung der Reserven/Liquidität in jedem Pool und die Gaskosten der Transaktion schätzen. Arbitrage-Formel für die optimale Handelsgröße Wenn eine Arbitragemöglichkeit genutzt wird, sinkt der Preis des Pools, der den Input-Token kauft, und der Preis des Pools, der verkauft. Die Preisbewegung wird durch eine konstante Produktformel beschrieben. Wir haben bereits in Artikel 1 gesehen , wie man den Output eines Swaps über einen Pool unter Berücksichtigung der Reserven dieses Pools und des Inputbetrags berechnet. Um die optimale Handelsgröße zu ermitteln, finden wir zunächst eine Formel für den Output zweier aufeinanderfolgender Swaps unter Berücksichtigung eines bestimmten Inputbetrags und der Reserven der beiden an den Swaps beteiligten Pools.

Wir gehen davon aus, dass der Input des ersten Swaps in ist token0und der Input des zweiten Swaps in ist token1, was schließlich einen Output in ergibt token0. Sei xder Eingabebetrag, (a1, b1)die Reserven des ersten Pools und (a2, b2)die Reserven des zweiten Pools. feeist die Gebühr, die von den Pools erhoben wird, und es wird davon ausgegangen, dass sie für beide Pools gleich ist (meistens 0,3 %). Wir definieren eine Funktion, die den Output eines Swaps bei gegebenem Input x und Reserven (a,b) berechnet: f(x, a, b) = b * (1 - a/(a + x* (1-Gebühr))) Wir wissen dann, dass die Ausgabe des ersten Austauschs ist: out1(x) = f(x, a1, b1) out1(x) = b1 * (1 - a1/(a1 + x* (1-Gebühr))) Die Ausgabe des zweiten Austauschs ist: (Beachten Sie die ausgetauschten Reservevariablen) 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-Gebühr))) Wir können diese Funktion mit desmos plotten . Indem wir die Reservewerte so wählen, dass wir den ersten Pool mit 1 ETH und 1750 USDC und den zweiten Pool mit 1340 USDC und 1 ETH simulieren, erhalten wir die folgende Grafik: Darstellung des Bruttogewinns des Handels als Funktion des Inputwerts Beachten Sie, dass wir tatsächlich aufgetragen haben out2(x) - x, d. h. den Gewinn des Handels abzüglich des Eingabebetrags. Grafisch können wir sehen, dass die optimale Handelsgröße bei 0.0607 ETHder Eingabe liegt, was zu einem Gewinn von führt 0.0085 ETH. 0.0607 ETHUm diese Chance nutzen zu können, muss der Vertrag mindestens über Liquidität in WETH verfügen . Dieser Gewinnwert von 0.0085 ETH(~16 $ beim Schreiben dieses Artikels) ist NICHT der endgültige Gewinn des Handels, da wir immer noch die Gaskosten der Transaktion berücksichtigen müssen. Dies wird in einem folgenden Artikel besprochen. Wir möchten diese optimale Handelsgröße für unseren MEV-Bot automatisch berechnen. Dies kann durch Elementarrechnung erfolgen. Wir haben eine Funktion einer Variablen x, die wir maximieren möchten. Die Funktion erreicht ihr Maximum bei einem Wert, bei xdem die Ableitung der Funktion liegt 0. Zur symbolischen Berechnung der Ableitung einer Funktion können verschiedene kostenlose und Online-Tools verwendet werden, beispielsweise Wolfram Alpha .

Finden der Ableitung unserer Bruttogewinnfunktion. Mit Wolfram Alpha ist es sehr einfach, eine solche Ableitung zu finden. Sie können es auch per Hand machen, wenn Sie unsicher sind, was Ihre mathematischen Fähigkeiten angeht. Wolfram Alpha ergibt die folgende Ableitung: dout2(x)/dx = (a1 b1 a2 b2 (1-Gebühr)^2)/(a1 b2 + (1-Gebühr) x (b1 (1-Gebühr)+b2)) ^2 Da wir den Wert ermitteln möchten, xder den Gewinn maximiert (also out2(x) - x), müssen wir den Wert ermitteln, xbei dem die Ableitung 1 (und nicht 0) ist. Wolfram Alpha liefert die folgende Lösung für xin der Gleichung dout2(x)/dx = 1: x = (sqrt(a1 b1 a2 b2 (1-Gebühr)^4 * (b1* (1-Gebühr)+b2)^2) - a1 b2 (1-Gebühr) (b1 ( 1-Gebühr)+b2)) / ((1-Gebühr) * (b1* (1-Gebühr) + b2))^2 Mit den Werten der Reserven, die wir in der obigen Grafik verwendet haben, erhalten wir x_optimal = 0.0607203782551, was unsere Formel bestätigt (im Vergleich zum Diagrammwert von 0.0607). Obwohl diese Formel nicht sehr gut lesbar ist, lässt sie sich leicht in Code implementieren. Hier ist eine Python-Implementierung der Formel zur Berechnung der Ausgabe der beiden Swaps und der optimalen Handelsgröße:

Hilfsfunktionen zur Berechnung der optimalen Handelsgröße

Ausgabe eines einzelnen Swaps

def swap_output ( x, a, b, fee= 0.003 ): return b * ( 1 - a/(a + x*( 1 -fee)))

Bruttogewinn von zwei aufeinanderfolgenden Swaps

def trade_profit ( x, Reserven1, Reserven2, Gebühr= 0,003 ): a1, b1 = Reserven1 a2, b2 = Reserven2 return swap_output(swap_output(x, a1, b1, fee), b2, a2, fee) - x

Optimaler Eingabebetrag

def optimal_trade_size ( Reserven1, Reserven2, Gebühr = 0,003 ): a1, b1 = Reserven1 a2, b2 = Reserven2 return (math.sqrt(a1b1a2b2( 1 -fee)** 4 * (b1*( 1 -fee)+b2)** 2 ) - a1 b2( 1 -fee)(b1( 1 -fee)+b2)) / (( 1 -fee) * (b1*( 1 -fee) + b2))** 2 Finder für Arbitragemöglichkeiten Da wir nun wissen, wie man den Bruttogewinn aus einer Arbitragemöglichkeit zwischen zwei beliebigen Pools desselben Token-Paares berechnet, müssen wir nur noch alle Token-Paare durchlaufen und alle Pools, die das haben, jeweils zwei mal zwei testen dasselbe Token-Paar. Dadurch erhalten wir den Bruttogewinn aller möglichen Arbitragemöglichkeiten, die im Rahmen unserer Strategie liegen. Um den Nettogewinn eines Handels abzuschätzen, müssen wir die Gaskosten für die Nutzung einer bestimmten Gelegenheit abschätzen. Dies kann genau durch die Simulation der Transaktion über einen eth_call an einen RPC-Knoten erfolgen, nimmt jedoch viel Zeit in Anspruch und kann nur für ein paar Dutzend Gelegenheiten pro Block durchgeführt werden. Wir werden zunächst eine grobe Schätzung der Gaskosten vornehmen, indem wir von festen Transaktionskosten für Gas ausgehen (eigentlich eine Untergrenze) und die Gelegenheiten aussortieren, die nicht rentabel genug sind, um die Gaskosten zu decken. Erst dann führen wir eine genaue Schätzung der Gaskosten für die verbleibenden Möglichkeiten durch. Hier ist der Code, der alle Paare und alle Pools durchgeht und die Chancen nach Gewinn sortiert:

[...]

Rufen Sie die Reserven jedes Pools in pool_dict ab

to_fetch = [] # Liste der Pooladressen, für die Reserven abgerufen werden müssen. für Paar, pool_list in pool_dict.items(): für paar_Objekt in pool_list: to_fetch.append(pair_object[ "pair" ]) # Fügen Sie die Adresse des Pools hinzu print ( f"Reserven von { len (to_fetch)} Pools abrufen.. ." )

getReservesParallel() stammt aus Artikel 2 in der MEV-Bot-Reihe

ReserveList = asyncio.get_event_loop().run_until_complete(getReservesParallel(to_fetch, ProviderAsync))

Liste der Handelsmöglichkeiten erstellen

index = 0 opps = [] für Paar, pool_list in pool_dict.items(): # Speichern Sie die Reserven in den Pool-Objekten zur späteren Verwendung für paar_Objekt in pool_list: paar_objekt[ "reserven" ] = ReserveList[index ] index += 1 # Iteriere über alle Pools des Paares für poolA in pool_list: für poolB in pool_list: # Überspringen, wenn es sich um denselben Pool handelt, if poolA[ "pair" ] == poolB[ "pair" ]: fortfahren # Überspringen, wenn eine der Reserven 0 ist (Division durch 0), wenn 0 in PoolA[ „reserves" ] oder 0 in poolB[ „reserves" ]: fortfahren # Die Reserven neu anordnen, sodass WETH immer der erste Token ist, wenn poolA [ „token0" ] == WETH: res_A = (poolA[ „reserves" ][ 0 ], poolA[ „reserves" ][ 1 ]) res_B = (poolB[ „reserves" ][ 0 ], poolB[ „reserves" ][ 1 ]) sonst : res_A = (poolA[ "reserves" ][ 1 ], poolA[ "reserves" ][ 0 ]) res_B = (poolB[ "reserves" ][ 1 ], poolB[ "reserves" ][ 0 ]) # Wert berechnen von optimale Eingabe durch die Formel x = optimale_trade_size(res_A, res_B) # Überspringen, wenn die optimale Eingabe negativ ist (die Reihenfolge der Pools ist umgekehrt), wenn x < 0 : fortfahren # Bruttogewinn in Wei (vor Gaskosten) berechnen profit = trade_profit( x, res_A, res_B) # Details der Verkaufschance speichern. Werte sind in ETH. (1e18 Wei = 1 ETH) opps.append({ "profit" : profit / 1e18 , "input" : x / 1e18 , "pair" : pair, "poolA" : poolA, "poolB" : poolB, }) print ( f"Es wurden { len (opps)} Möglichkeiten gefunden. ) Was die folgende Ausgabe erzeugt: Reserven von 3081 Pools abrufen. 1791 Möglichkeiten gefunden. Wir haben jetzt eine Liste aller Möglichkeiten. Wir müssen nur ihren Gewinn schätzen. Im Moment gehen wir einfach von konstanten Gaskosten für den Handel bei einer Gelegenheit aus. Wir müssen eine Untergrenze für die Gaskosten eines Swaps auf Uniswap V2 verwenden. Experimentell haben wir herausgefunden, dass dieser Wert nahe bei 43.000 Gas liegt. Die Nutzung einer Gelegenheit erfordert zwei Swaps, und die Durchführung einer Transaktion auf Ethereum kostet pauschal 21.000 Gas, also insgesamt 107.000 Gas pro Gelegenheit. Hier ist der Code, der den geschätzten Nettogewinn jeder Gelegenheit berechnet:

[...]

Verwenden Sie die fest codierten Gaskosten von 107.000 Gas pro Gelegenheit

gp = w3.eth.gas_price für opp in opps: opp[ "net_profit" ] = opp[ "profit" ] - 107000 * gp / 1e18

Sortieren nach geschätztem Nettogewinn

opps.sort(key= lambda x: x[ "net_profit" ], reverse= True )

Positive Chancen beibehalten

positive_opps = [opp für opp in opps if opp[ "net_profit" ] > 0 ]

# Statistiken drucken

Positive Chancen zählen

print ( f"Gefunden { len (positive_opps)} positive Gelegenheiten. )

Details zu jeder Gelegenheit

ETH_PRICE = 1900 # Sie sollten den Preis von ETH für Opportunity in positive_opps dynamisch abrufen: print ( f"Gewinn: {opp[ 'net_profit' ]} ETH ($ {opp[ 'net_profit' ] * ETH_PRICE} )" ) print ( f"Eingabe:{opp[ 'input' ]} ETH ($ {opp[ 'input' ] * ETH_PRICE} )" ) drucken( f"Pool A: {opp[ 'poolA' ][ 'pair' ]} " ) print ( f"Pool B: {opp[ 'poolB' ][ 'pair' ]} " ) print () Hier ist die Ausgabe des Skripts: 57 positive Möglichkeiten gefunden. Profit: 4.936025725859028 ETH ($9378.448879132153) Input: 1.7958289984719014 ETH ($3412.075097096613) Pool A: 0x1498bd576454159Bb81B5Ce532692a8752D163e8 Pool B: 0x7D7E813082eF6c143277c71786e5bE626ec77b20 {'profit': 4.9374642090282865, 'input': 1.7958(...) Profit: 4.756587769768892 ETH ($9037.516762560894) Input: 0.32908348765283796 ETH (625,2586265403921) Pool A: 0x486c1609f9605fA14C28E311b7D708B0541cd2f5 Pool B: 0x5e81b946b61F3C7F73Bf84dd961dE3A0A78E8c33 {'Gewinn': 4,758 0262529381505, 'Eingabe': 0,329(...) Gewinn: 0,8147203063054365 ETH (1547,9685819803292) Eingabe: 0,6715171730669338 ETH (1275,8826288271744 ) Pool A: 0x1f1B4836Dde1859e2edE1C6155140318EF5931C2 Pool B: 0x1f7efDcD748F43Fc4BeAe6897e5a6DDd865DcceA {'profit': 0.8161587894746954, 'input': 0.671( ...) (...)

Das sind verdächtig hohe Gewinne. Der erste Schritt, der unternommen werden sollte, besteht darin, zu überprüfen, ob der Code korrekt ist. Nach sorgfältiger Überprüfung des Codes haben wir festgestellt, dass der Code korrekt ist. Sind diese Gewinne real? Wie sich herausstellt, nein. Bei der Auswahl der Pools, die wir in unserer Strategie berücksichtigen möchten, haben wir unser Netz zu weit geworfen und sind in die Hände von Pools mit toxischen Token geraten. Der ERC20-Token-Standard beschreibt lediglich eine Schnittstelle für Interoperabilität. Jeder kann einen Token bereitstellen, der diese Schnittstelle implementiert, und sich für die Implementierung unorthodoxen Verhaltens entscheiden, und genau darum geht es hier. Einige Token-Ersteller gestalten ihren ERC20 so, dass die Pools, in denen sie gehandelt werden, den Token nicht verkaufen, sondern nur kaufen können. Einige Token-Verträge verfügen sogar über Kill-Switches-Mechanismen, die es dem Ersteller ermöglichen, alle seine Benutzer abzuwerben. In unserem MEV-Bot müssen diese toxischen Token herausgefiltert werden. Dies wird in einem zukünftigen Artikel behandelt. Wenn wir die offensichtlich giftigen Token manuell herausfiltern, bleiben uns die folgenden 42 Möglichkeiten: Profit: 0.004126583158496902 ETH ($7.840508001144114) Input: 0.008369804833786892 ETH ($15.902629184195094) Pool A: 0xdF42388059692150d0A9De836E4171c7B9c09CBf Pool B: 0xf98fCEB2DC0Fa2B3f32ABccc5e8495E961370B23 { 'profit': 0.005565066327755902 , (...) Profit: 0.004092580415474992 ETH ($7.775902789402485) Input: 0.014696360216108083 ETH ($27.92308441060536) Pool A : 0xfDBFb4239935A15C2C348400570E34De3b044c5F Pool B: 0x0F15d69a7E5998252ccC39Ad239Cef67fa2a9369 { 'Gewinn': 0.005531063584733992 , (...) Profit: 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 { 'Gewinn': 0.005112612088086048 , (...) (...)

Beachten Sie, dass die Gewinne im Allgemeinen geringer sind als der zur Ausführung der Transaktion erforderliche Eingabebetrag. Diese Gewinne sind viel vernünftiger. Denken Sie jedoch daran, dass es sich immer noch um Gewinne im besten Fall handelt, da wir eine sehr grobe Schätzung der Gaskosten für jede Gelegenheit verwendet haben. In einem zukünftigen Artikel werden wir die Ausführung unseres Handels simulieren, um einen genauen Wert der Gaskosten für jede Gelegenheit zu erhalten. Um die Ausführung zu simulieren, müssen wir zunächst den Smart Contract entwickeln, der den Handel ausführt. Dies ist das Thema des nächsten Artikels. Abschluss Wir haben jetzt eine klare Definition des Umfangs unseres MEV-Arbitrage-Bots. Wir haben die mathematische Theorie hinter der Arbitrage-Strategie untersucht und sie in Python implementiert. Wir haben jetzt eine Liste potenzieller Arbitragemöglichkeiten und müssen deren Ausführung simulieren, um einen endgültigen Gewinnwert zu erhalten. Dazu müssen wir unseren Trading-Smart-Vertrag bereithalten. Im nächsten Artikel werden wir einen solchen Smart Contract in Solidity entwickeln und unseren ersten Arbitrage-Handel simulieren. Den vollständigen Code finden Sie im Github-Repo, das diesem Artikel zugeordnet ist . Das Skript lässt sich am besten in einem Jupyter-Notebook ausführen.

🌟 Eine Initiative, um die Web3-Bildung für die nächste Generation zugänglicher zu machen. 🌟

🌟 Feel free to check out: my.bio/blockliv3

Social Media: @blockliv3 E-Mail: blockliv3.nft@ud.me

Subscribe to blockliv3 | (GER)
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.
More from blockliv3 | (GER)

Skeleton

Skeleton

Skeleton