بناء روبوت التحكيم: العثور على فرص التحكيم

في هذا المقال، نقوم بإجراء اختيار مسبق لأزواج الرموز ذات الاهتمام. ثم نستمد الصيغة الرياضية للعثور على التحكم الأمثل بين بركتين من نفس أزواج الرموز.

إذا لم يكن إعداد MEV الخاص بك يبدو مثل هذا، فأنت غير محظوظ

هذا المقال هو جزء من سلسلة حول بناء روبوت التحكيم. هدف هذه السلسلة هو توفير دليل خطوة بخطوة لبناء روبوت تداول MEV الآلي الذي يمكنه العثور على فرص التحكيم وتنفيذها على البورصات اللامركزية الشهيرة.

في هذه المقالة، نقوم بإجراء اختيار مسبق لأزواج الرموز ذات الاهتمام. ثم نستنتج الصيغة الرياضية لإيجاد الفرص الاستثمارية الأمثل بين بركين من نفس أزواج الرموز. وأخيرًا، نقوم بتنفيذ الصيغة في الكود ونعيد قائمة بالفرص الاستثمارية المحتملة.

اختيار أزواج الرموز

توضيحات حول استراتيجية التحكيم

قبل أن نبدأ في البحث عن فرص التحكيم، يجب علينا تحديد بشكل واضح نطاق بوت التحكيم لدينا. على وجه الخصوص، أي نوع من التحكيم نريد التصرف فيه. أمن نوع من التحكيم هو بين حمامات تشمل ETH. نظرًا لأن ETH هو الأصل الذي يتم دفع الغاز لمعاملاتنا به، فمن الطبيعي دائمًا أن نرغب في الانتهاء بـ ETH بعد عملية التحكيم. ولكن الجميع مغرور بالتفكير بهذه الطريقة. تذكر أنه في التداول، تقل الفرص الدقيقة وتصبح أقل ربحية كلما تصرف المزيد من الأشخاص فيها.

لأسباب بسيطة، سنركز على فرص التحكم بين حمامات السباحة التي تتضمن ETH. سنبحث فقط عن الفرص بين حمامين من نفس زوج الرموز. لن نتداول في الفرص التي تشمل أكثر من حمامين في طريق التداول (المعروفة بالفرص متعددة القفزات). يرجى ملاحظة أن ترقية هذه الاستراتيجية إلى واحدة أكثر خطورة هي الخطوة الأولى التي يجب عليك اتخاذها لتحسين ربحية الروبوت الخاص بك.

لتحسين هذه الاستراتيجية، يمكنك على سبيل المثال الاحتفاظ ببعض المخزون في العملات المستقرة والتصرف في فرص التحكيم التي تعود بالعملات المستقرة. يمكن القيام بالشيء نفسه لأصول أكثر مخاطرة مثل shitcoins (مع اتخاذ الاحتياطات اللازمة)، وإعادة توازن محفظتك دوريًا إلى ETH لدفع رسوم الغاز.

يمكن أن يكون الاتجاه الآخر التخلي عن الافتراض الضمني للذرية الذي قمنا به، وإدخال الاستدلال الإحصائي في استراتيجيتنا. على سبيل المثال، من خلال شراء رمز واحد في بركة عندما يتحرك السعر بشكل إيجابي أكثر من بعض مقدار الانحرافات القياسية، وبيعه لاحقًا (استراتيجية الانحدار نحو المتوسط). سيكون هذا مثاليًا للعملات المزرية التي لم يتم سردها على بورصات مركزية أكثر كفاءة بكثير، أو تلك التي تكونت ولكن لم يتم تتبع سعرها بشكل صحيح على السلسلة. يتضمن هذا العديد من العناصر المتحركة وخارج نطاق هذه السلسلة.

اختيار أزواج الرموز

الآن بعد أن حددنا محيط بوت التحكيم الخاص بنا، نحتاج إلى اختيار أزواج الرموز التي نرغب في التداول بها. إليك معايير الاختيار الاثنان التي سنستخدمها:

  • يجب أن تكون الأزواج المُختارة تتضمن ETH.
  • يجب تداول الأزواج على ما لا يقل عن حوضين مختلفين.

إعادة استخدام الكود من المادة 2: قراءة فعالة لأسعار حوض السباحة, لدينا الكود التالي الذي يقوم بسرد جميع أزواج الرموز التي تم نشرها بواسطة عقود المصنع المقدمة:

# [...]# تحميل عناوين عقود المصنعمع فتح("FactoriesV2.json", "r") كما فعلت:f:factories = json.load(f)# [...]# الحصول على قائمة من حمامات السباحة لكل عقد مصنعpairDataList = []for factoryName, factoryData in factories.items():events = getPairEvents(w3.eth.contract(address=factoryData['factory'], abi=factory_abi), 0, w3.eth.block_number)print(f'تم العثور على {len(events)} حمامات سباحة لـ {factoryName}')for e in events:   pairDataList.append({       "token0": e["args"]["token0"],       "token1": e["args"]["token1"],       "pair": e["args"]["pair"],       "factory": factoryName   })

سنقوم ببساطة بعكس pairDataList إلى قاموس حيث تكون المفاتيح هي ازواج الرموز، والقيم هي قائمة المسابح التي تتداول هذا الزوج. عند التكرار من خلال القائمة، نتجاهل الأزواج التي لا تشمل ETH. عندما ينتهي الحلقة، سيتم تخزين الأزواج ذات المسابح العلى الأقل 2 في قوائم تحتوي على على الأقل 2 عنصرًا:

# [...]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

يجب طباعة بعض الإحصائيات للحصول على قبضة أفضل مع البيانات التي نعمل عليها:

# عدد الأزواج المختلفة print(f'لدينا {len(pool_dict)} أزواج مختلفة.')# إجمالي عدد المسابح print(f'لدينا {sum([len(pool_list) for pool_list in pool_dict.values()])} مسبحًا بالمجموع.')# الزوج مع أكبر عدد من المسابح print(f'الزوج الذي يحتوي على أكبر عدد من المسابح هو {max(pool_dict، key=lambda k: len(pool_dict[k]))} بـ {len(max(pool_dict.values()، key=len))} مسبحًا.')# توزيع عدد المسابح لكل زوج، بالعشراتpool_count_list = [len(pool_list) for pool_list in pool_dict.values()]pool_count_list.sort(reverse=True)print(f'عدد المسابح لكل زوج، بالعشرات: {pool_count_list[::int(len(pool_count_list)/10)]}')# توزيع عدد المسابح لكل زوج، بالنسب المئوية (عشرات العشرة الأولى)pool_count_list.sort(reverse=True)print(f'عدد المسابح لكل زوج، بالنسب المئوية: {pool_count_list[::int(len(pool_count_list)/100)][:10]}')

في وقت الكتابة، يخرج ما يلي:

لدينا 1431 زوجًا مختلفًا.

لدينا 3081 بركة بإجمالي.

أكثر زوج يحتوي على أكبر عدد من المسابح هو ('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'، '0xdAC17F958D2ee523a2206206994597C13D831ec7') بعدد 16 مسبحًا.

عدد حمامات السباحة لكل زوج، بالأعشار: [16، 2، 2، 2، 2، 2، 2، 2، 2، 2، 2]

عدد حمامات السباحة لكل زوج، بالنسب المئوية: [16، 5، 4، 3، 3، 3، 3، 3، 3، 3]

يمكن الحصول على احتياطيات لـ 3000 بركة في أقل من ثانية واحدة باستخدام العقد الذكية العامة. هذه كمية معقولة من الوقت.

الآن، وبما أن لدينا جميع البيانات التي نحتاجها، نحتاج إلى البدء في البحث عن فرص التحكيم.

العثور على فرص التحكم

فكرة عامة

هناك فرصة للتحكيم كلما وجد فارق في السعر بين بركتي تداول تتداولان نفس الزوج. ومع ذلك، ليس كل الفروقات في الأسعار يمكن استغلالها: تكلفة الغاز للصفقة تحدد قيمة الحد الأدنى التي يجب استردادها من التجارة، وسيولة كل بركة تحد من القيمة التي يمكن استخراجها من فارق معين في السعر.

من أجل العثور على أكثر فرصة تحكم ربحية يمكن الوصول إليها، سنحتاج إلى حساب القيمة الناتجة المحتملة من كل فارق في الأسعار، مع النظر في الاحتياطيات/السيولة في كل بركة، وتقدير تكلفة الغاز للمعاملة.

صيغة حجم التداول الأمثل للتحكيم

عند استغلال فرصة التحكم في الأسعار، سينخفض سعر الحوض الذي يشتري رمز الإدخال، وسيرتفع سعر الحوض الذي يبيع. يتم وصف حركة الأسعار بواسطة صيغة المنتج الثابت.

لقد رأينا بالفعل في@emileamajar/بناء-بوت-التحكيم-الآلي-وصانعي-السوق-الآلي-و-يونيسواب-2d208215d8c2">المادة 1 كيفية حساب إخراج تبادل من خلال بركة، مع الاحتياطيات لتلك البركة وكمية الإدخال.

من أجل العثور على حجم التداول الأمثل، نجد أولاً صيغة لإخراج صفقتين متتاليتين، نظرًا لكمية معينة من الإدخال واحتياطيات البركتين المشاركتين في الصفقات.

نفترض أن إدخال التبديل الأول هو في رمز0، وإدخال التبديل الثاني هو في رمز1، الذي يؤدي في النهاية إلى إخراج في رمز0.

لنكن x هو المبلغ المدخل، (a1، b1) هما احتياطيات البركة الأولى، و (a2، b2) هما احتياطيات البركة الثانية. الرسم هو الرسم المأخوذ من البرك، ويفترض أنه نفسه لكلا البركتين (0.3% معظم الوقت).

نحدد وظيفة تحسب مخرج تبديل، بالإدخال x والاحتياطيات (أ،ب):

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

ثم نعلم أن إخراج التبادل الأول هو:

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

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

مخرج التبادل الثاني هو: (لاحظ متغيرات الاحتياطي المبادلة)

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)))

يمكننا رسم هذه الوظيفة باستخدامديسموس. عن طريق اختيار قيم الاحتياطي بحيث نحاكي أن يكون لدى المجمع الأول 1 إثريوم و 1750 دولار أمريكي، ولدى المجمع الثاني 1340 دولار أمريكي و 1 إثريوم، نحصل على الرسم البياني التالي:

مؤامرة الربح الإجمالي للتجارة كدالة لقيمة الإدخال

لاحظ أننا فعلاً رسمنا 2(x) - x، وهو الربح من التجارة، ناقص كمية الإدخال.

من الناحية الرسومية، يمكننا رؤية أن حجم التداول الأمثل هو 0.0607 إيثريوم من المدخلات، والذي ينتج ربحًا قدره 0.0085 إيثريوم. يجب أن يكون للعقد على الأقل 0.0607 إيثريوم من السيولة في WETH من أجل أن يكون بإمكانه استغلال هذه الفرصة.

قيمة الربح هذه بقيمة 0.0085 ETH (~$16 عند كتابة هذه المقالة) ليست الربح النهائي للصفقة، حيث نحتاج لاحقًا إلى أخذ تكلفة الغاز في العملية بعين الاعتبار. سيتم مناقشة هذا في مقالة قادمة.

نريد حساب حجم التداول الأمثل هذا تلقائيًا لروبوت MEV الخاص بنا. يمكن القيام بذلك من خلال الحساب الاستدلالي. لدينا وظيفة من متغير واحد x نريد أن نقصد. تصل الوظيفة إلى أقصى قيمة لها لقيمة x حيث تكون المشتقة من الوظيفة هي 0.

يمكن استخدام مجموعة متنوعة من الأدوات المجانية والمتاحة عبر الإنترنت لحساب تفاضل الدالة رمزيًا، مثل وولفرام ألفا.

العثور على المشتقة لوظيفة الربح الإجمالي الخاصة بنا.

العثور على مشتقة مثل هذا الأمر بسيط جدًا مع Wolfram Alpha. يمكنك أيضًا القيام بذلك يدويًا إذا كنت غير واثق من مهاراتك الرياضية.

Wolfram Alpha يعطي المشتقة التالية:

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

نظرًا لأننا نريد العثور على قيمة x التي تعظم الربح (وهو out2(x) - x) ، فإننا بحاجة إلى العثور على قيمة x حيث تكون المشتقة تساوي 1 (وليس 0).

تعطي وولفرام ألفا الحل التالي لـ x في المعادلة dout2(x)/dx = 1:

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

مع قيم الاحتياطيات التي استخدمناها في الرسم البياني أعلاه، نحصل على x_optimal = 0.0607203782551، مما يوضح صحة صيغتنا (مقارنة بقيمة الرسم البياني 0.0607).

على الرغم من أن هذه الصيغة ليست سهلة القراءة، إلا أنه من السهل تنفيذها في الشيفرة. إليك تنفيذ بيثون للصيغة لحساب إخراج التبادلات الثنائية، وحجم التداول الأمثل:

# الوظائف المساعدة لحساب حجم التداول الأمثل# إخراج تبديل واحدdef swap_output(x, a, b, fee=0.003):return b * (1 - a/(a + x*(1-fee)))# صافي الربح من صفقتي تبديل متتاليتينdef trade_profit(x, reserves1, reserves2, fee=0.003): a1, b1 = reserves1a2, b2 = reserves2return swap_output(swap_output(x, a1, b1, fee), b2, a2, fee) - x# كمية الإدخال الأمثلdef optimal_trade_size(reserves1, reserves2, fee=0.003):a1, b1 = reserves1a2, b2 = reserves2return (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

الباحث عن فرص التحكيم

الآن بعد أن نعرف كيفية حساب الربح الإجمالي من فرصة التحكيم بين أي حوضين معينين من نفس زوج الرمز، علينا ببساطة تكرار جميع أزواج الرموز، واختبار جميع الحمامات زوجين زوجين التي تحتوي على نفس زوج الرمز. سيمنحنا هذا الربح الإجمالي لجميع فرص التحكيم الممكنة التي تكون ضمن الحدود الخارجية لاستراتيجيتنا.

لتقدير صافي الربح من تجارة ما، نحتاج إلى تقدير تكلفة الغاز لاستغلال فرصة معينة. يمكن القيام بذلك بدقة عن طريق محاكاة الصفقة من خلال استدعاء eth_call إلى عقد RPC، ولكن يستغرق الأمر الكثير من الوقت ويمكن إجراؤه فقط لعدد قليل من الفرص في كل كتلة.

سنقوم أولاً بإجراء تقدير إجمالي لتكلفة الغاز عن طريق افتراض تكلفة ثابتة للمعاملة الغاز (حد أدنى، في الواقع)، ونخرج الفرص التي ليست مربحة بما يكفي لتغطية تكلفة الغاز. ثم سنقوم بإجراء تقدير دقيق لتكلفة الغاز للفرص المتبقية.

هنا هو الكود الذي يمر عبر جميع الأزواج وجميع المجمعات، ويقوم بفرز الفرص حسب الربح:

# [...] # جلب احتياطيات كل تجمع في pool_dictto_fetch = [] # قائمة عناوين التجمعات التي يجب جلب الاحتياطيات لها.بالنسبة للزوج ، pool_list في pool_dict.items (): for pair_object في pool_list: to_fetch.append(pair_object["pair"]) # أضف عنوان poolprint(f"جلب احتياطيات تجمعات {len(to_fetch)}...")# getReservesParallel() مأخوذ من المادة 2 في MEV bot seriesreserveList = asyncio.get_event_loop().run_until_complete(getReservesParallel(to_fetch,  providersAsync))# إنشاء قائمة بفرص التداول Index = 0opps = []للزوج ، pool_list في pool_dict.items ():# قم بتخزين الاحتياطيات في كائنات التجمع لاستخدامها لاحقا في pair_object في pool_list: pair_object["الاحتياطيات"] = reserveList [index] index += 1 # كرر على جميع تجمعات الزوج لتجمع A في pool_list: ل poolB في pool_list: # تخطي إذا كان نفس التجمع إذا كان poolA ["pair"] == poolB ["pair"]:            تابع # تخطي إذا كان أحد الاحتياطيات هو 0 (القسمة على 0) إذا كان 0 في poolA ["الاحتياطيات"] أو 0 في poolB ["الاحتياطيات"]: تابع # أعد ترتيب الاحتياطيات بحيث يكون WETH دائما هو الرمز المميز الأول إذا كان poolA ["token0"] == WETH: res_A = (poolA ["الاحتياطيات"] [0] ، poolA ["الاحتياطيات"] [1]) res_B = (poolB ["الاحتياطيات"] [0] ، poolB ["الاحتياطيات"] [1]) آخر: res_A = (poolA ["الاحتياطيات"] [1] ،  poolA["الاحتياطيات"][0]) res_B = (poolB["الاحتياطيات"][1]، poolB["الاحتياطيات"][0]) # حساب قيمة المدخلات المثلى من خلال الصيغة x = optimal_trade_size(res_A، res_B) # تخطي إذا كان الإدخال الأمثل سالبا (يتم عكس ترتيب التجمعات) إذا كان x < 0: متابعة # حساب الربح الإجمالي في Wei (قبل تكلفة الغاز) الربح = trade_profit (x ،  res_A ، res_B) # تخزين تفاصيل الفرصة. القيم في ETH. (1e18 Wei = 1 ETH) opps.append({ "الربح": الربح / 1e18، "الإدخال": x / 1e18، "الزوج": الزوج، "poolA": poolA، "poolB": poolB، })print(f"Found {len(opps)} الفرص.")

والتي تنتج المخرجات التالية:

جلب احتياطيات 3081 حوضًا.

تم العثور على 1791 فرصة.

لدينا الآن قائمة بجميع الفرص. نحن بحاجة فقط إلى تقدير ربحها. في الوقت الحالي، سنفترض ببساطة تكلفة ثابتة للغاز للتداول في فرصة معينة.

يجب علينا استخدام حد أدنى لتكلفة الغاز لعملية تبادل على Uniswap V2. من خلال التجارب، وجدنا أن هذه القيمة قريبة من 43 ألف وحدة غاز.

استغلال الفرصة يتطلب 2 تبادلات، وتنفيذ صفقة على الإيثيريوم يكلف 21 ألف غاز ثابت، مما يؤدي إلى مجموع 107 ألف غاز لكل فرصة.

هنا هو الكود الذي يحسب الربح الصافي المقدر لكل فرصة:

# [...]# استخدم تكلفة الغاز المشفرة بمقدار 107 ألف غاز لكل فرصة gp = w3.eth.gas_pricefor opp in opps:opp["net_profit"] = opp["profit"] - 107000 * gp / 1e18# فرز حسب صافي الربح المقدرopps.sort(key=lambda x: x["net_profit"], reverse=True)# الاحتفاظ بالفرص الإيجابيةpositive_opps = [opp for opp in opps if opp["net_profit"] > 0]

اطبع الإحصائيات

# فرص إيجابية تحسب(f"تم العثور على {len(positive_opps)} فرصة إيجابية.")# تفاصيل حول كل فرصة ETH_PRICE = 1900 # يجب أن تقوم بجلب سعر ETH ديناميكيًاللفرصة في الفرص الإيجابية:print(f"الربح: {opp['net_profit']} ETH (${opp['net_profit'] * ETH_PRICE})")print(f"المدخل: {opp['input']} ETH (${opp['input'] * ETH_PRICE})")print(f"البركة أ: {opp['poolA']['pair']}")print(f"البركة ب: {opp['poolB']['pair']}")print()

هنا هو إخراج البرنامج النصي:

وجدت 57 فرصة إيجابية.

الربح: 4.936025725859028 ETH ($9378.448879132153)

الإدخال: 1.7958289984719014 ETH ($3412.075097096613)

مجموعة A: 0x1498bd576454159Bb81B5Ce532692a8752D163e8

Pool B: 0x7D7E813082eF6c143277c71786e5bE626ec77b20

{‘profit’: 4.9374642090282865, ‘input’: 1.7958(…)

الربح: 4.756587769768892 ETH ($9037.516762560894)

الإدخال: 0.32908348765283796 ETH ($625.2586265403921)

Pool A: 0x486c1609f9605fA14C28E311b7D708B0541cd2f5

Pool B: 0x5e81b946b61F3C7F73Bf84dd961dE3A0A78E8c33

{‘profit’: 4.7580262529381505, ‘input’: 0.329(…)

ربح: 0.8147203063054365 ETH ($1547.9685819803292)

المدخلات: 0.6715171730669338 ETH ($1275.8826288271744)

Pool A: 0x1f1B4836Dde1859e2edE1C6155140318EF5931C2

Pool B: 0x1f7efDcD748F43Fc4BeAe6897e5a6DDd865DcceA

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

(…)

والتي تبدو ربحية مرتفعة بشكل مشبوه. الخطوة الأولى التي يجب اتخاذها هي التحقق من صحة الكود. بعد التحقق بحذر من الكود، وجدنا أن الكود صحيح.

هل هذه الأرباح حقيقية؟ كما يبدو، لا. لقد قمنا برمي شبكتنا بشكل واسع عند اختيار البرك للاعتبار في استراتيجيتنا، وحصلنا في أيدينا على برك من الرموز السامة.

معيار الرمز المميز ERC20 يصف واجهة للتوافق فقط. يمكن لأي شخص نشر رمز مميز ينفذ هذه الواجهة، واختيار تنفيذ سلوك غير تقليدي، وهذا بالضبط ما يحدث هنا.

بعض مبتكري الرموز المميزة الخاصة بهم ERC20 بحيث لا يمكن للمسابح التي يتم تداولها فيها بيع الرمز المميز، ولكن يمكن فقط شراء الرمز المميز. بعض عقود الرموز المميزة حتى تحتوي على آليات مفاتيح الإيقاف التي تسمح للمبتكر بسحب جميع مستخدميها.

في برنامجنا MEV bot، يجب تصفية هذه الرموز السامة. سيتم التعامل مع هذا في مقال مستقبلي.

إذا قمنا بتصفية الرموز السامة بشكل يدوي، سنترك مع الفرص التالية 42:

ربح: 0.004126583158496902 ETH ($7.840508001144114)

Input: 0.008369804833786892 ETH ($15.902629184195094)

Pool A: 0xdF42388059692150d0A9De836E4171c7B9c09CBf

Pool B: 0xf98fCEB2DC0Fa2B3f32ABccc5e8495E961370B23

{‘profit’: 0.005565066327755902, (...)

ربح: 0.004092580415474992 ETH ($7.775902789402485)

Input: 0.014696360216108083 ETH ($27.92308441060536)

Pool A: 0xfDBFb4239935A15C2C348400570E34De3b044c5F

Pool B: 0x0F15d69a7E5998252ccC39Ad239Cef67fa2a9369

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

ربح: 0.003693235163284344 ETH ($7.017146810240254)

الإدخال: 0.1392339178514088 ETH ($264.5444439176767)

Pool A: 0x2957215d0473d2c811A075725Da3C31D2af075F1

Pool B: 0xF110783EbD020DCFBA91Cd1976b79a6E510846AA

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

الربح: 0.003674128918827048 ETH ($6.980844945771391)

الإدخال: 0.2719041848570484 ETH ($516.617951228392)

Pool A: 0xBa19343ff3E9f496F17C7333cdeeD212D65A8425

Pool B: 0xD30567f1d084f411572f202ebb13261CE9F46325

{‘profit’: 0.005112612088086048, (...)

(…)

لاحظ أن الأرباح عمومًا أقل من المبلغ اللازم لتنفيذ الصفقة.

هذه الأرباح أكثر معقولية بكثير. ولكن تذكر أنها لا تزال أفضل حالة سيناريو للأرباح، حيث استخدمنا تقديراً خاماً لتكلفة الغاز لكل فرصة.

في مقالة مستقبلية، سنقوم بمحاكاة تنفيذ تجارتنا من أجل الحصول على قيمة دقيقة لتكلفة الغاز لكل فرصة.

من أجل محاكاة التنفيذ، نحتاج أولاً إلى تطوير العقد الذكي الذي سينفذ التجارة. هذا هو موضوع المقالة التالية.

استنتاج

لدينا الآن تعريف واضح لمحيط بوت التحكيم MEV الخاص بنا.

لقد استكشفنا النظرية الرياضية وراء استراتيجية التحكم، وقمنا بتنفيذها باستخدام Python.

لدينا الآن قائمة من الفرص المحتملة للتحكيم، ونحتاج إلى محاكاة تنفيذها من أجل الحصول على قيمة ربح نهائية. للقيام بذلك، نحتاج إلى أن يكون عقد التداول الذكي الخاص بنا جاهزًا.

في المقالة القادمة، سنقوم بتطوير عقد ذكي من هذا النوع في Solidity، ونحاكي التجارة التحكيمية الأولى لدينا.

يمكنك العثور على الشفرة الكاملة في المستودع جيتهاب المرتبط بهذه المقالة. النص البرمجي يعمل بشكل أفضل في دفتر ملاحظات جوبيتر.

إخلاء المسؤولية:

  1. تم نقل هذه المقالة من [Gateمتوسط], كل حقوق الطبع والنشر تنتمي إلى الكاتب الأصلي [إيميل أماجار]. عنوان المقال الأصلي” بناء روبوت التحكيم: العثور على فرص التحكيم (المقال 3/ن)، إذا كانت هناك اعتراضات على هذا النشر، يرجى الاتصال بالبوابة التعلمالفريق، وسيتولون عليه على الفور.
  2. تنصل المسؤولية: الآراء والآراء الواردة في هذه المقالة هي فقط تلك التي يعبر عنها المؤلف ولا تشكل أي نصيحة استثمارية.
  3. تتم ترجمة المقالة إلى لغات أخرى عن طريق فريق Gate Learn. ما لم يذكر غير ذلك، يُحظر نسخ أو توزيع أو ارتكاب الانتحال للمقالات المُترجمة.

بناء روبوت التحكيم: العثور على فرص التحكيم

متوسط4/9/2024, 2:29:22 PM
في هذا المقال، نقوم بإجراء اختيار مسبق لأزواج الرموز ذات الاهتمام. ثم نستمد الصيغة الرياضية للعثور على التحكم الأمثل بين بركتين من نفس أزواج الرموز.

إذا لم يكن إعداد MEV الخاص بك يبدو مثل هذا، فأنت غير محظوظ

هذا المقال هو جزء من سلسلة حول بناء روبوت التحكيم. هدف هذه السلسلة هو توفير دليل خطوة بخطوة لبناء روبوت تداول MEV الآلي الذي يمكنه العثور على فرص التحكيم وتنفيذها على البورصات اللامركزية الشهيرة.

في هذه المقالة، نقوم بإجراء اختيار مسبق لأزواج الرموز ذات الاهتمام. ثم نستنتج الصيغة الرياضية لإيجاد الفرص الاستثمارية الأمثل بين بركين من نفس أزواج الرموز. وأخيرًا، نقوم بتنفيذ الصيغة في الكود ونعيد قائمة بالفرص الاستثمارية المحتملة.

اختيار أزواج الرموز

توضيحات حول استراتيجية التحكيم

قبل أن نبدأ في البحث عن فرص التحكيم، يجب علينا تحديد بشكل واضح نطاق بوت التحكيم لدينا. على وجه الخصوص، أي نوع من التحكيم نريد التصرف فيه. أمن نوع من التحكيم هو بين حمامات تشمل ETH. نظرًا لأن ETH هو الأصل الذي يتم دفع الغاز لمعاملاتنا به، فمن الطبيعي دائمًا أن نرغب في الانتهاء بـ ETH بعد عملية التحكيم. ولكن الجميع مغرور بالتفكير بهذه الطريقة. تذكر أنه في التداول، تقل الفرص الدقيقة وتصبح أقل ربحية كلما تصرف المزيد من الأشخاص فيها.

لأسباب بسيطة، سنركز على فرص التحكم بين حمامات السباحة التي تتضمن ETH. سنبحث فقط عن الفرص بين حمامين من نفس زوج الرموز. لن نتداول في الفرص التي تشمل أكثر من حمامين في طريق التداول (المعروفة بالفرص متعددة القفزات). يرجى ملاحظة أن ترقية هذه الاستراتيجية إلى واحدة أكثر خطورة هي الخطوة الأولى التي يجب عليك اتخاذها لتحسين ربحية الروبوت الخاص بك.

لتحسين هذه الاستراتيجية، يمكنك على سبيل المثال الاحتفاظ ببعض المخزون في العملات المستقرة والتصرف في فرص التحكيم التي تعود بالعملات المستقرة. يمكن القيام بالشيء نفسه لأصول أكثر مخاطرة مثل shitcoins (مع اتخاذ الاحتياطات اللازمة)، وإعادة توازن محفظتك دوريًا إلى ETH لدفع رسوم الغاز.

يمكن أن يكون الاتجاه الآخر التخلي عن الافتراض الضمني للذرية الذي قمنا به، وإدخال الاستدلال الإحصائي في استراتيجيتنا. على سبيل المثال، من خلال شراء رمز واحد في بركة عندما يتحرك السعر بشكل إيجابي أكثر من بعض مقدار الانحرافات القياسية، وبيعه لاحقًا (استراتيجية الانحدار نحو المتوسط). سيكون هذا مثاليًا للعملات المزرية التي لم يتم سردها على بورصات مركزية أكثر كفاءة بكثير، أو تلك التي تكونت ولكن لم يتم تتبع سعرها بشكل صحيح على السلسلة. يتضمن هذا العديد من العناصر المتحركة وخارج نطاق هذه السلسلة.

اختيار أزواج الرموز

الآن بعد أن حددنا محيط بوت التحكيم الخاص بنا، نحتاج إلى اختيار أزواج الرموز التي نرغب في التداول بها. إليك معايير الاختيار الاثنان التي سنستخدمها:

  • يجب أن تكون الأزواج المُختارة تتضمن ETH.
  • يجب تداول الأزواج على ما لا يقل عن حوضين مختلفين.

إعادة استخدام الكود من المادة 2: قراءة فعالة لأسعار حوض السباحة, لدينا الكود التالي الذي يقوم بسرد جميع أزواج الرموز التي تم نشرها بواسطة عقود المصنع المقدمة:

# [...]# تحميل عناوين عقود المصنعمع فتح("FactoriesV2.json", "r") كما فعلت:f:factories = json.load(f)# [...]# الحصول على قائمة من حمامات السباحة لكل عقد مصنعpairDataList = []for factoryName, factoryData in factories.items():events = getPairEvents(w3.eth.contract(address=factoryData['factory'], abi=factory_abi), 0, w3.eth.block_number)print(f'تم العثور على {len(events)} حمامات سباحة لـ {factoryName}')for e in events:   pairDataList.append({       "token0": e["args"]["token0"],       "token1": e["args"]["token1"],       "pair": e["args"]["pair"],       "factory": factoryName   })

سنقوم ببساطة بعكس pairDataList إلى قاموس حيث تكون المفاتيح هي ازواج الرموز، والقيم هي قائمة المسابح التي تتداول هذا الزوج. عند التكرار من خلال القائمة، نتجاهل الأزواج التي لا تشمل ETH. عندما ينتهي الحلقة، سيتم تخزين الأزواج ذات المسابح العلى الأقل 2 في قوائم تحتوي على على الأقل 2 عنصرًا:

# [...]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

يجب طباعة بعض الإحصائيات للحصول على قبضة أفضل مع البيانات التي نعمل عليها:

# عدد الأزواج المختلفة print(f'لدينا {len(pool_dict)} أزواج مختلفة.')# إجمالي عدد المسابح print(f'لدينا {sum([len(pool_list) for pool_list in pool_dict.values()])} مسبحًا بالمجموع.')# الزوج مع أكبر عدد من المسابح print(f'الزوج الذي يحتوي على أكبر عدد من المسابح هو {max(pool_dict، key=lambda k: len(pool_dict[k]))} بـ {len(max(pool_dict.values()، key=len))} مسبحًا.')# توزيع عدد المسابح لكل زوج، بالعشراتpool_count_list = [len(pool_list) for pool_list in pool_dict.values()]pool_count_list.sort(reverse=True)print(f'عدد المسابح لكل زوج، بالعشرات: {pool_count_list[::int(len(pool_count_list)/10)]}')# توزيع عدد المسابح لكل زوج، بالنسب المئوية (عشرات العشرة الأولى)pool_count_list.sort(reverse=True)print(f'عدد المسابح لكل زوج، بالنسب المئوية: {pool_count_list[::int(len(pool_count_list)/100)][:10]}')

في وقت الكتابة، يخرج ما يلي:

لدينا 1431 زوجًا مختلفًا.

لدينا 3081 بركة بإجمالي.

أكثر زوج يحتوي على أكبر عدد من المسابح هو ('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'، '0xdAC17F958D2ee523a2206206994597C13D831ec7') بعدد 16 مسبحًا.

عدد حمامات السباحة لكل زوج، بالأعشار: [16، 2، 2، 2، 2، 2، 2، 2، 2، 2، 2]

عدد حمامات السباحة لكل زوج، بالنسب المئوية: [16، 5، 4، 3، 3، 3، 3، 3، 3، 3]

يمكن الحصول على احتياطيات لـ 3000 بركة في أقل من ثانية واحدة باستخدام العقد الذكية العامة. هذه كمية معقولة من الوقت.

الآن، وبما أن لدينا جميع البيانات التي نحتاجها، نحتاج إلى البدء في البحث عن فرص التحكيم.

العثور على فرص التحكم

فكرة عامة

هناك فرصة للتحكيم كلما وجد فارق في السعر بين بركتي تداول تتداولان نفس الزوج. ومع ذلك، ليس كل الفروقات في الأسعار يمكن استغلالها: تكلفة الغاز للصفقة تحدد قيمة الحد الأدنى التي يجب استردادها من التجارة، وسيولة كل بركة تحد من القيمة التي يمكن استخراجها من فارق معين في السعر.

من أجل العثور على أكثر فرصة تحكم ربحية يمكن الوصول إليها، سنحتاج إلى حساب القيمة الناتجة المحتملة من كل فارق في الأسعار، مع النظر في الاحتياطيات/السيولة في كل بركة، وتقدير تكلفة الغاز للمعاملة.

صيغة حجم التداول الأمثل للتحكيم

عند استغلال فرصة التحكم في الأسعار، سينخفض سعر الحوض الذي يشتري رمز الإدخال، وسيرتفع سعر الحوض الذي يبيع. يتم وصف حركة الأسعار بواسطة صيغة المنتج الثابت.

لقد رأينا بالفعل في@emileamajar/بناء-بوت-التحكيم-الآلي-وصانعي-السوق-الآلي-و-يونيسواب-2d208215d8c2">المادة 1 كيفية حساب إخراج تبادل من خلال بركة، مع الاحتياطيات لتلك البركة وكمية الإدخال.

من أجل العثور على حجم التداول الأمثل، نجد أولاً صيغة لإخراج صفقتين متتاليتين، نظرًا لكمية معينة من الإدخال واحتياطيات البركتين المشاركتين في الصفقات.

نفترض أن إدخال التبديل الأول هو في رمز0، وإدخال التبديل الثاني هو في رمز1، الذي يؤدي في النهاية إلى إخراج في رمز0.

لنكن x هو المبلغ المدخل، (a1، b1) هما احتياطيات البركة الأولى، و (a2، b2) هما احتياطيات البركة الثانية. الرسم هو الرسم المأخوذ من البرك، ويفترض أنه نفسه لكلا البركتين (0.3% معظم الوقت).

نحدد وظيفة تحسب مخرج تبديل، بالإدخال x والاحتياطيات (أ،ب):

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

ثم نعلم أن إخراج التبادل الأول هو:

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

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

مخرج التبادل الثاني هو: (لاحظ متغيرات الاحتياطي المبادلة)

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)))

يمكننا رسم هذه الوظيفة باستخدامديسموس. عن طريق اختيار قيم الاحتياطي بحيث نحاكي أن يكون لدى المجمع الأول 1 إثريوم و 1750 دولار أمريكي، ولدى المجمع الثاني 1340 دولار أمريكي و 1 إثريوم، نحصل على الرسم البياني التالي:

مؤامرة الربح الإجمالي للتجارة كدالة لقيمة الإدخال

لاحظ أننا فعلاً رسمنا 2(x) - x، وهو الربح من التجارة، ناقص كمية الإدخال.

من الناحية الرسومية، يمكننا رؤية أن حجم التداول الأمثل هو 0.0607 إيثريوم من المدخلات، والذي ينتج ربحًا قدره 0.0085 إيثريوم. يجب أن يكون للعقد على الأقل 0.0607 إيثريوم من السيولة في WETH من أجل أن يكون بإمكانه استغلال هذه الفرصة.

قيمة الربح هذه بقيمة 0.0085 ETH (~$16 عند كتابة هذه المقالة) ليست الربح النهائي للصفقة، حيث نحتاج لاحقًا إلى أخذ تكلفة الغاز في العملية بعين الاعتبار. سيتم مناقشة هذا في مقالة قادمة.

نريد حساب حجم التداول الأمثل هذا تلقائيًا لروبوت MEV الخاص بنا. يمكن القيام بذلك من خلال الحساب الاستدلالي. لدينا وظيفة من متغير واحد x نريد أن نقصد. تصل الوظيفة إلى أقصى قيمة لها لقيمة x حيث تكون المشتقة من الوظيفة هي 0.

يمكن استخدام مجموعة متنوعة من الأدوات المجانية والمتاحة عبر الإنترنت لحساب تفاضل الدالة رمزيًا، مثل وولفرام ألفا.

العثور على المشتقة لوظيفة الربح الإجمالي الخاصة بنا.

العثور على مشتقة مثل هذا الأمر بسيط جدًا مع Wolfram Alpha. يمكنك أيضًا القيام بذلك يدويًا إذا كنت غير واثق من مهاراتك الرياضية.

Wolfram Alpha يعطي المشتقة التالية:

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

نظرًا لأننا نريد العثور على قيمة x التي تعظم الربح (وهو out2(x) - x) ، فإننا بحاجة إلى العثور على قيمة x حيث تكون المشتقة تساوي 1 (وليس 0).

تعطي وولفرام ألفا الحل التالي لـ x في المعادلة dout2(x)/dx = 1:

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

مع قيم الاحتياطيات التي استخدمناها في الرسم البياني أعلاه، نحصل على x_optimal = 0.0607203782551، مما يوضح صحة صيغتنا (مقارنة بقيمة الرسم البياني 0.0607).

على الرغم من أن هذه الصيغة ليست سهلة القراءة، إلا أنه من السهل تنفيذها في الشيفرة. إليك تنفيذ بيثون للصيغة لحساب إخراج التبادلات الثنائية، وحجم التداول الأمثل:

# الوظائف المساعدة لحساب حجم التداول الأمثل# إخراج تبديل واحدdef swap_output(x, a, b, fee=0.003):return b * (1 - a/(a + x*(1-fee)))# صافي الربح من صفقتي تبديل متتاليتينdef trade_profit(x, reserves1, reserves2, fee=0.003): a1, b1 = reserves1a2, b2 = reserves2return swap_output(swap_output(x, a1, b1, fee), b2, a2, fee) - x# كمية الإدخال الأمثلdef optimal_trade_size(reserves1, reserves2, fee=0.003):a1, b1 = reserves1a2, b2 = reserves2return (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

الباحث عن فرص التحكيم

الآن بعد أن نعرف كيفية حساب الربح الإجمالي من فرصة التحكيم بين أي حوضين معينين من نفس زوج الرمز، علينا ببساطة تكرار جميع أزواج الرموز، واختبار جميع الحمامات زوجين زوجين التي تحتوي على نفس زوج الرمز. سيمنحنا هذا الربح الإجمالي لجميع فرص التحكيم الممكنة التي تكون ضمن الحدود الخارجية لاستراتيجيتنا.

لتقدير صافي الربح من تجارة ما، نحتاج إلى تقدير تكلفة الغاز لاستغلال فرصة معينة. يمكن القيام بذلك بدقة عن طريق محاكاة الصفقة من خلال استدعاء eth_call إلى عقد RPC، ولكن يستغرق الأمر الكثير من الوقت ويمكن إجراؤه فقط لعدد قليل من الفرص في كل كتلة.

سنقوم أولاً بإجراء تقدير إجمالي لتكلفة الغاز عن طريق افتراض تكلفة ثابتة للمعاملة الغاز (حد أدنى، في الواقع)، ونخرج الفرص التي ليست مربحة بما يكفي لتغطية تكلفة الغاز. ثم سنقوم بإجراء تقدير دقيق لتكلفة الغاز للفرص المتبقية.

هنا هو الكود الذي يمر عبر جميع الأزواج وجميع المجمعات، ويقوم بفرز الفرص حسب الربح:

# [...] # جلب احتياطيات كل تجمع في pool_dictto_fetch = [] # قائمة عناوين التجمعات التي يجب جلب الاحتياطيات لها.بالنسبة للزوج ، pool_list في pool_dict.items (): for pair_object في pool_list: to_fetch.append(pair_object["pair"]) # أضف عنوان poolprint(f"جلب احتياطيات تجمعات {len(to_fetch)}...")# getReservesParallel() مأخوذ من المادة 2 في MEV bot seriesreserveList = asyncio.get_event_loop().run_until_complete(getReservesParallel(to_fetch,  providersAsync))# إنشاء قائمة بفرص التداول Index = 0opps = []للزوج ، pool_list في pool_dict.items ():# قم بتخزين الاحتياطيات في كائنات التجمع لاستخدامها لاحقا في pair_object في pool_list: pair_object["الاحتياطيات"] = reserveList [index] index += 1 # كرر على جميع تجمعات الزوج لتجمع A في pool_list: ل poolB في pool_list: # تخطي إذا كان نفس التجمع إذا كان poolA ["pair"] == poolB ["pair"]:            تابع # تخطي إذا كان أحد الاحتياطيات هو 0 (القسمة على 0) إذا كان 0 في poolA ["الاحتياطيات"] أو 0 في poolB ["الاحتياطيات"]: تابع # أعد ترتيب الاحتياطيات بحيث يكون WETH دائما هو الرمز المميز الأول إذا كان poolA ["token0"] == WETH: res_A = (poolA ["الاحتياطيات"] [0] ، poolA ["الاحتياطيات"] [1]) res_B = (poolB ["الاحتياطيات"] [0] ، poolB ["الاحتياطيات"] [1]) آخر: res_A = (poolA ["الاحتياطيات"] [1] ،  poolA["الاحتياطيات"][0]) res_B = (poolB["الاحتياطيات"][1]، poolB["الاحتياطيات"][0]) # حساب قيمة المدخلات المثلى من خلال الصيغة x = optimal_trade_size(res_A، res_B) # تخطي إذا كان الإدخال الأمثل سالبا (يتم عكس ترتيب التجمعات) إذا كان x < 0: متابعة # حساب الربح الإجمالي في Wei (قبل تكلفة الغاز) الربح = trade_profit (x ،  res_A ، res_B) # تخزين تفاصيل الفرصة. القيم في ETH. (1e18 Wei = 1 ETH) opps.append({ "الربح": الربح / 1e18، "الإدخال": x / 1e18، "الزوج": الزوج، "poolA": poolA، "poolB": poolB، })print(f"Found {len(opps)} الفرص.")

والتي تنتج المخرجات التالية:

جلب احتياطيات 3081 حوضًا.

تم العثور على 1791 فرصة.

لدينا الآن قائمة بجميع الفرص. نحن بحاجة فقط إلى تقدير ربحها. في الوقت الحالي، سنفترض ببساطة تكلفة ثابتة للغاز للتداول في فرصة معينة.

يجب علينا استخدام حد أدنى لتكلفة الغاز لعملية تبادل على Uniswap V2. من خلال التجارب، وجدنا أن هذه القيمة قريبة من 43 ألف وحدة غاز.

استغلال الفرصة يتطلب 2 تبادلات، وتنفيذ صفقة على الإيثيريوم يكلف 21 ألف غاز ثابت، مما يؤدي إلى مجموع 107 ألف غاز لكل فرصة.

هنا هو الكود الذي يحسب الربح الصافي المقدر لكل فرصة:

# [...]# استخدم تكلفة الغاز المشفرة بمقدار 107 ألف غاز لكل فرصة gp = w3.eth.gas_pricefor opp in opps:opp["net_profit"] = opp["profit"] - 107000 * gp / 1e18# فرز حسب صافي الربح المقدرopps.sort(key=lambda x: x["net_profit"], reverse=True)# الاحتفاظ بالفرص الإيجابيةpositive_opps = [opp for opp in opps if opp["net_profit"] > 0]

اطبع الإحصائيات

# فرص إيجابية تحسب(f"تم العثور على {len(positive_opps)} فرصة إيجابية.")# تفاصيل حول كل فرصة ETH_PRICE = 1900 # يجب أن تقوم بجلب سعر ETH ديناميكيًاللفرصة في الفرص الإيجابية:print(f"الربح: {opp['net_profit']} ETH (${opp['net_profit'] * ETH_PRICE})")print(f"المدخل: {opp['input']} ETH (${opp['input'] * ETH_PRICE})")print(f"البركة أ: {opp['poolA']['pair']}")print(f"البركة ب: {opp['poolB']['pair']}")print()

هنا هو إخراج البرنامج النصي:

وجدت 57 فرصة إيجابية.

الربح: 4.936025725859028 ETH ($9378.448879132153)

الإدخال: 1.7958289984719014 ETH ($3412.075097096613)

مجموعة A: 0x1498bd576454159Bb81B5Ce532692a8752D163e8

Pool B: 0x7D7E813082eF6c143277c71786e5bE626ec77b20

{‘profit’: 4.9374642090282865, ‘input’: 1.7958(…)

الربح: 4.756587769768892 ETH ($9037.516762560894)

الإدخال: 0.32908348765283796 ETH ($625.2586265403921)

Pool A: 0x486c1609f9605fA14C28E311b7D708B0541cd2f5

Pool B: 0x5e81b946b61F3C7F73Bf84dd961dE3A0A78E8c33

{‘profit’: 4.7580262529381505, ‘input’: 0.329(…)

ربح: 0.8147203063054365 ETH ($1547.9685819803292)

المدخلات: 0.6715171730669338 ETH ($1275.8826288271744)

Pool A: 0x1f1B4836Dde1859e2edE1C6155140318EF5931C2

Pool B: 0x1f7efDcD748F43Fc4BeAe6897e5a6DDd865DcceA

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

(…)

والتي تبدو ربحية مرتفعة بشكل مشبوه. الخطوة الأولى التي يجب اتخاذها هي التحقق من صحة الكود. بعد التحقق بحذر من الكود، وجدنا أن الكود صحيح.

هل هذه الأرباح حقيقية؟ كما يبدو، لا. لقد قمنا برمي شبكتنا بشكل واسع عند اختيار البرك للاعتبار في استراتيجيتنا، وحصلنا في أيدينا على برك من الرموز السامة.

معيار الرمز المميز ERC20 يصف واجهة للتوافق فقط. يمكن لأي شخص نشر رمز مميز ينفذ هذه الواجهة، واختيار تنفيذ سلوك غير تقليدي، وهذا بالضبط ما يحدث هنا.

بعض مبتكري الرموز المميزة الخاصة بهم ERC20 بحيث لا يمكن للمسابح التي يتم تداولها فيها بيع الرمز المميز، ولكن يمكن فقط شراء الرمز المميز. بعض عقود الرموز المميزة حتى تحتوي على آليات مفاتيح الإيقاف التي تسمح للمبتكر بسحب جميع مستخدميها.

في برنامجنا MEV bot، يجب تصفية هذه الرموز السامة. سيتم التعامل مع هذا في مقال مستقبلي.

إذا قمنا بتصفية الرموز السامة بشكل يدوي، سنترك مع الفرص التالية 42:

ربح: 0.004126583158496902 ETH ($7.840508001144114)

Input: 0.008369804833786892 ETH ($15.902629184195094)

Pool A: 0xdF42388059692150d0A9De836E4171c7B9c09CBf

Pool B: 0xf98fCEB2DC0Fa2B3f32ABccc5e8495E961370B23

{‘profit’: 0.005565066327755902, (...)

ربح: 0.004092580415474992 ETH ($7.775902789402485)

Input: 0.014696360216108083 ETH ($27.92308441060536)

Pool A: 0xfDBFb4239935A15C2C348400570E34De3b044c5F

Pool B: 0x0F15d69a7E5998252ccC39Ad239Cef67fa2a9369

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

ربح: 0.003693235163284344 ETH ($7.017146810240254)

الإدخال: 0.1392339178514088 ETH ($264.5444439176767)

Pool A: 0x2957215d0473d2c811A075725Da3C31D2af075F1

Pool B: 0xF110783EbD020DCFBA91Cd1976b79a6E510846AA

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

الربح: 0.003674128918827048 ETH ($6.980844945771391)

الإدخال: 0.2719041848570484 ETH ($516.617951228392)

Pool A: 0xBa19343ff3E9f496F17C7333cdeeD212D65A8425

Pool B: 0xD30567f1d084f411572f202ebb13261CE9F46325

{‘profit’: 0.005112612088086048, (...)

(…)

لاحظ أن الأرباح عمومًا أقل من المبلغ اللازم لتنفيذ الصفقة.

هذه الأرباح أكثر معقولية بكثير. ولكن تذكر أنها لا تزال أفضل حالة سيناريو للأرباح، حيث استخدمنا تقديراً خاماً لتكلفة الغاز لكل فرصة.

في مقالة مستقبلية، سنقوم بمحاكاة تنفيذ تجارتنا من أجل الحصول على قيمة دقيقة لتكلفة الغاز لكل فرصة.

من أجل محاكاة التنفيذ، نحتاج أولاً إلى تطوير العقد الذكي الذي سينفذ التجارة. هذا هو موضوع المقالة التالية.

استنتاج

لدينا الآن تعريف واضح لمحيط بوت التحكيم MEV الخاص بنا.

لقد استكشفنا النظرية الرياضية وراء استراتيجية التحكم، وقمنا بتنفيذها باستخدام Python.

لدينا الآن قائمة من الفرص المحتملة للتحكيم، ونحتاج إلى محاكاة تنفيذها من أجل الحصول على قيمة ربح نهائية. للقيام بذلك، نحتاج إلى أن يكون عقد التداول الذكي الخاص بنا جاهزًا.

في المقالة القادمة، سنقوم بتطوير عقد ذكي من هذا النوع في Solidity، ونحاكي التجارة التحكيمية الأولى لدينا.

يمكنك العثور على الشفرة الكاملة في المستودع جيتهاب المرتبط بهذه المقالة. النص البرمجي يعمل بشكل أفضل في دفتر ملاحظات جوبيتر.

إخلاء المسؤولية:

  1. تم نقل هذه المقالة من [Gateمتوسط], كل حقوق الطبع والنشر تنتمي إلى الكاتب الأصلي [إيميل أماجار]. عنوان المقال الأصلي” بناء روبوت التحكيم: العثور على فرص التحكيم (المقال 3/ن)، إذا كانت هناك اعتراضات على هذا النشر، يرجى الاتصال بالبوابة التعلمالفريق، وسيتولون عليه على الفور.
  2. تنصل المسؤولية: الآراء والآراء الواردة في هذه المقالة هي فقط تلك التي يعبر عنها المؤلف ولا تشكل أي نصيحة استثمارية.
  3. تتم ترجمة المقالة إلى لغات أخرى عن طريق فريق Gate Learn. ما لم يذكر غير ذلك، يُحظر نسخ أو توزيع أو ارتكاب الانتحال للمقالات المُترجمة.
Start Now
Sign up and get a
$100
Voucher!