مرکزی مواد پر جائیں

ایتھریم پر اپنا AI ٹریڈنگ ایجنٹ بنائیں

مصنوعی ذہانت
ٹریڈنگ
ایجنٹ
Python
درمیانی
اوری پومرانٹز
۱۳ فروری، ۲۰۲۶
28 منٹ کی پڑھائی

اس ٹیوٹوریل میں آپ ایک سادہ AI ٹریڈنگ ایجنٹ بنانا سیکھیں گے۔ یہ ایجنٹ ان اقدامات کا استعمال کرتے ہوئے کام کرتا ہے:

  1. ٹوکن کی موجودہ اور ماضی کی قیمتیں پڑھیں، نیز دیگر ممکنہ متعلقہ معلومات
  2. اس معلومات کے ساتھ ایک استفسار (query) بنائیں، اور ساتھ ہی پس منظر کی معلومات بھی شامل کریں تاکہ یہ واضح ہو سکے کہ یہ کیسے متعلقہ ہو سکتی ہے
  3. استفسار جمع کروائیں اور متوقع قیمت واپس حاصل کریں
  4. سفارش کی بنیاد پر ٹریڈ کریں
  5. انتظار کریں اور دہرائیں

یہ ایجنٹ ظاہر کرتا ہے کہ معلومات کو کیسے پڑھا جائے، اسے ایک ایسے استفسار میں کیسے تبدیل کیا جائے جو قابل استعمال جواب دے، اور اس جواب کو کیسے استعمال کیا جائے۔ یہ تمام اقدامات ایک AI ایجنٹ کے لیے ضروری ہیں۔ یہ ایجنٹ Python میں لاگو کیا گیا ہے کیونکہ یہ AI میں استعمال ہونے والی سب سے عام زبان ہے۔

ایسا کیوں کریں؟

خودکار ٹریڈنگ ایجنٹس ڈیولپرز کو ٹریڈنگ کی حکمت عملی منتخب کرنے اور اس پر عمل کرنے کی اجازت دیتے ہیں۔ AI ایجنٹس زیادہ پیچیدہ اور متحرک ٹریڈنگ حکمت عملیوں کی اجازت دیتے ہیں، ممکنہ طور پر ایسی معلومات اور الگورتھم استعمال کرتے ہوئے جن کے استعمال پر ڈیولپر نے غور بھی نہ کیا ہو۔

ٹولز

یہ ٹیوٹوریل کوٹس (quotes) اور ٹریڈنگ کے لیے Python (opens in a new tab)، Web3 لائبریری (opens in a new tab)، اور Uniswap v3 (opens in a new tab) کا استعمال کرتا ہے۔

Python کیوں؟

AI کے لیے سب سے زیادہ استعمال ہونے والی زبان Python (opens in a new tab) ہے، اس لیے ہم اسے یہاں استعمال کرتے ہیں۔ اگر آپ Python نہیں جانتے تو پریشان نہ ہوں۔ یہ زبان بہت واضح ہے، اور میں بالکل سمجھاؤں گا کہ یہ کیا کرتی ہے۔

Web3 لائبریری (opens in a new tab) سب سے عام Python ایتھریم API ہے۔ اسے استعمال کرنا کافی آسان ہے۔

بلاک چین پر ٹریڈنگ

ایسی بہت سی ڈسٹری بیوٹڈ ایکسچینجز (DEX) ہیں جو آپ کو ایتھریم پر ٹوکنز کی ٹریڈ کرنے دیتی ہیں۔ تاہم، آربٹراج (arbitrage) کی وجہ سے ان کے ایکسچینج ریٹس عموماً ایک جیسے ہوتے ہیں۔

Uniswap (opens in a new tab) ایک وسیع پیمانے پر استعمال ہونے والی DEX ہے جسے ہم کوٹس (ٹوکن کی متعلقہ قدریں دیکھنے کے لیے) اور ٹریڈز دونوں کے لیے استعمال کر سکتے ہیں۔

OpenAI

ایک بڑے لینگویج ماڈل (LLM) کے لیے، میں نے OpenAI (opens in a new tab) کے ساتھ شروعات کرنے کا انتخاب کیا۔ اس ٹیوٹوریل میں ایپلیکیشن چلانے کے لیے آپ کو API تک رسائی کے لیے ادائیگی کرنی ہوگی۔ کم از کم $5 کی ادائیگی کافی سے زیادہ ہے۔

ڈیولپمنٹ، مرحلہ وار

ڈیولپمنٹ کو آسان بنانے کے لیے، ہم مراحل میں آگے بڑھتے ہیں۔ ہر مرحلہ GitHub میں ایک برانچ ہے۔

شروعات کرنا

UNIX یا Linux (بشمول WSL (opens in a new tab)) کے تحت شروعات کرنے کے اقدامات یہ ہیں:

  1. اگر آپ کے پاس پہلے سے نہیں ہے، تو Python (opens in a new tab) ڈاؤن لوڈ اور انسٹال کریں۔

  2. GitHub ریپوزٹری کو کلون کریں۔

    1git clone https://github.com/qbzzt/260215-ai-agent.git -b 01-getting-started
    2cd 260215-ai-agent
  3. uv (opens in a new tab) انسٹال کریں۔ آپ کے سسٹم پر کمانڈ مختلف ہو سکتی ہے۔

    1pipx install uv
  4. لائبریریاں ڈاؤن لوڈ کریں۔

    1uv sync
  5. ورچوئل انوائرنمنٹ کو فعال کریں۔

    1source .venv/bin/activate
  6. یہ تصدیق کرنے کے لیے کہ Python اور Web3 درست طریقے سے کام کر رہے ہیں، python3 چلائیں اور اسے یہ پروگرام فراہم کریں۔ آپ اسے >>> پرامپٹ پر درج کر سکتے ہیں؛ کوئی فائل بنانے کی ضرورت نہیں ہے۔

    1from web3 import Web3
    2MAINNET_URL = "https://eth.drpc.org"
    3w3 = Web3(Web3.HTTPProvider(MAINNET_URL))
    4w3.eth.block_number
    5quit()

بلاک چین سے پڑھنا

اگلا قدم بلاک چین سے پڑھنا ہے۔ ایسا کرنے کے لیے، آپ کو 02-read-quote برانچ میں تبدیل ہونا ہوگا اور پھر پروگرام چلانے کے لیے uv کا استعمال کرنا ہوگا۔

1git checkout 02-read-quote
2uv run agent.py

آپ کو Quote آبجیکٹس کی ایک فہرست ملنی چاہیے، جن میں سے ہر ایک میں ٹائم اسٹیمپ، قیمت، اور اثاثہ (فی الحال ہمیشہ WETH/USDC) شامل ہو۔

یہاں لائن بہ لائن وضاحت دی گئی ہے۔

1from web3 import Web3
2from web3.contract import Contract
3from decimal import Decimal, ROUND_HALF_UP
4from dataclasses import dataclass
5from datetime import datetime, timezone
6from pprint import pprint
7import time
8import functools
9import sys

ہمیں درکار لائبریریاں امپورٹ کریں۔ جب انہیں استعمال کیا جائے گا تو ان کی وضاحت نیچے دی گئی ہے۔

1print = functools.partial(print, flush=True)

Python کے print کو ایک ایسے ورژن سے بدل دیتا ہے جو ہمیشہ آؤٹ پٹ کو فوری طور پر فلش (flush) کرتا ہے۔ یہ ایک طویل عرصے تک چلنے والے اسکرپٹ میں مفید ہے کیونکہ ہم اسٹیٹس اپ ڈیٹس یا ڈیبگنگ آؤٹ پٹ کا انتظار نہیں کرنا چاہتے۔

1MAINNET_URL = "https://eth.drpc.org"

مین نیٹ تک پہنچنے کے لیے ایک URL۔ آپ اسے نوڈ بطور سروس سے حاصل کر سکتے ہیں یا Chainlist (opens in a new tab) میں مشتہر کردہ میں سے کوئی ایک استعمال کر سکتے ہیں۔

1BLOCK_TIME_SECONDS = 12
2MINUTE_BLOCKS = int(60 / BLOCK_TIME_SECONDS)
3HOUR_BLOCKS = MINUTE_BLOCKS * 60
4DAY_BLOCKS = HOUR_BLOCKS * 24

ایتھریم مین نیٹ کا بلاک عام طور پر ہر بارہ سیکنڈ میں بنتا ہے، لہذا یہ ان بلاکس کی تعداد ہے جن کی ہم ایک مخصوص وقت میں توقع کریں گے۔ نوٹ کریں کہ یہ کوئی درست ہندسہ نہیں ہے۔ جب بلاک پروپوزر ڈاؤن ہوتا ہے، تو وہ بلاک چھوڑ دیا جاتا ہے، اور اگلے بلاک کا وقت 24 سیکنڈ ہوتا ہے۔ اگر ہم کسی ٹائم اسٹیمپ کے لیے بالکل درست بلاک حاصل کرنا چاہتے ہیں، تو ہم بائنری سرچ (opens in a new tab) استعمال کریں گے۔ تاہم، یہ ہمارے مقاصد کے لیے کافی قریب ہے۔ مستقبل کی پیشین گوئی کرنا کوئی قطعی سائنس نہیں ہے۔

1CYCLE_BLOCKS = DAY_BLOCKS

سائیکل کا سائز۔ ہم فی سائیکل ایک بار کوٹس کا جائزہ لیتے ہیں اور اگلے سائیکل کے اختتام پر قدر کا اندازہ لگانے کی کوشش کرتے ہیں۔

1# اس پول کا ایڈریس جسے ہم پڑھ رہے ہیں
2WETHUSDC_ADDRESS = Web3.to_checksum_address("0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640")

کوٹ کی قدریں Uniswap 3 USDC/WETH پول سے ایڈریس 0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640 (opens in a new tab) پر لی گئی ہیں۔ یہ ایڈریس پہلے ہی چیک سم (checksum) کی شکل میں ہے، لیکن کوڈ کو دوبارہ قابل استعمال بنانے کے لیے Web3.to_checksum_address (opens in a new tab) کا استعمال کرنا بہتر ہے۔

1POOL_ABI = [
2 { "name": "slot0", ... },
3 { "name": "token0", ... },
4 { "name": "token1", ... },
5]
6
7ERC20_ABI = [
8 { "name": "symbol", ... },
9 { "name": "decimals", ... }
10]

یہ ان دو کنٹریکٹس کے لیے ABIs (opens in a new tab) ہیں جن سے ہمیں رابطہ کرنے کی ضرورت ہے۔ کوڈ کو مختصر رکھنے کے لیے، ہم صرف وہی فنکشنز شامل کرتے ہیں جنہیں ہمیں کال کرنے کی ضرورت ہے۔

1w3 = Web3(Web3.HTTPProvider(MAINNET_URL))

Web3 (opens in a new tab) لائبریری شروع کریں اور ایتھریم نوڈ سے جڑیں۔

1@dataclass(frozen=True)
2class ERC20Token:
3 address: str
4 symbol: str
5 decimals: int
6 contract: Contract

Python میں ڈیٹا کلاس بنانے کا یہ ایک طریقہ ہے۔ Contract (opens in a new tab) ڈیٹا ٹائپ کا استعمال کنٹریکٹ سے جڑنے کے لیے کیا جاتا ہے۔ (frozen=True) کو نوٹ کریں۔ Python میں بولینز (booleans) (opens in a new tab) کو True یا False کے طور پر بیان کیا جاتا ہے، جن کا پہلا حرف بڑا ہوتا ہے۔ یہ ڈیٹا کلاس frozen ہے، جس کا مطلب ہے کہ فیلڈز میں ترمیم نہیں کی جا سکتی۔

انڈینٹیشن (indentation) کو نوٹ کریں۔ C سے ماخوذ زبانوں (opens in a new tab) کے برعکس، Python بلاکس کو ظاہر کرنے کے لیے انڈینٹیشن کا استعمال کرتا ہے۔ Python انٹرپریٹر جانتا ہے کہ درج ذیل تعریف اس ڈیٹا کلاس کا حصہ نہیں ہے کیونکہ یہ ڈیٹا کلاس فیلڈز جیسی انڈینٹیشن سے شروع نہیں ہوتی ہے۔

1@dataclass(frozen=True)
2class PoolInfo:
3 address: str
4 token0: ERC20Token
5 token1: ERC20Token
6 contract: Contract
7 asset: str
8 decimal_factor: Decimal = 1

Decimal (opens in a new tab) ٹائپ کا استعمال اعشاریہ کسروں کو درست طریقے سے سنبھالنے کے لیے کیا جاتا ہے۔

1 def get_price(self, block: int) -> Decimal:

Python میں فنکشن کی تعریف کرنے کا یہ طریقہ ہے۔ تعریف کو انڈینٹ کیا گیا ہے تاکہ یہ ظاہر ہو سکے کہ یہ اب بھی PoolInfo کا حصہ ہے۔

ایک فنکشن میں جو ڈیٹا کلاس کا حصہ ہے، پہلا پیرامیٹر ہمیشہ self ہوتا ہے، جو ڈیٹا کلاس کا وہ انسٹینس (instance) ہے جس نے یہاں کال کی ہے۔ یہاں ایک اور پیرامیٹر ہے، بلاک نمبر۔

1 assert block <= w3.eth.block_number, "Block is in the future"

اگر ہم مستقبل پڑھ سکتے، تو ہمیں ٹریڈنگ کے لیے AI کی ضرورت نہ ہوتی۔

1 sqrt_price_x96 = Decimal(self.contract.functions.slot0().call(block_identifier=block)[0])

Web3 سے EVM پر فنکشن کال کرنے کا سنٹیکس یہ ہے: <contract object>.functions.<function name>().call(<parameters>)۔ پیرامیٹرز EVM فنکشن کے پیرامیٹرز (اگر کوئی ہوں؛ یہاں نہیں ہیں) یا بلاک چین کے رویے میں ترمیم کرنے کے لیے نامزد پیرامیٹرز (named parameters) (opens in a new tab) ہو سکتے ہیں۔ یہاں ہم ایک، block_identifier کا استعمال کرتے ہیں، تاکہ بلاک نمبر کی وضاحت کی جا سکے جس میں ہم چلانا چاہتے ہیں۔

نتیجہ یہ اسٹرکٹ (struct) ہے، جو سرنی (array) کی شکل میں ہے (opens in a new tab)۔ پہلی قدر دونوں ٹوکنز کے درمیان ایکسچینج ریٹ کا ایک فنکشن ہے۔

1 raw_price = (sqrt_price_x96 / Decimal(2**96)) ** 2

آن چین حسابات کو کم کرنے کے لیے، Uniswap v3 اصل ایکسچینج فیکٹر کو اسٹور نہیں کرتا بلکہ اس کا مربع جزر (square root) اسٹور کرتا ہے۔ چونکہ EVM فلوٹنگ پوائنٹ ریاضی یا کسروں کو سپورٹ نہیں کرتا، اس لیے اصل قدر کے بجائے، جواب price296 ہوتا ہے۔

1 # (ٹوکن 1 فی ٹوکن 0)
2 return 1/(raw_price * self.decimal_factor)

ہمیں جو خام قیمت ملتی ہے وہ token0 کی وہ تعداد ہے جو ہمیں ہر token1 کے لیے ملتی ہے۔ ہمارے پول میں token0 USDC (ایک اسٹیبل کوائن جس کی قدر امریکی ڈالر کے برابر ہے) ہے اور token1 WETH (opens in a new tab) ہے۔ وہ قدر جو ہم واقعی چاہتے ہیں وہ فی WETH ڈالرز کی تعداد ہے، نہ کہ اس کا الٹ۔

ڈیسیمل فیکٹر دونوں ٹوکنز کے لیے ڈیسیمل فیکٹرز (opens in a new tab) کے درمیان کا تناسب ہے۔

1@dataclass(frozen=True)
2class Quote:
3 timestamp: str
4 price: Decimal
5 asset: str

یہ ڈیٹا کلاس ایک کوٹ کی نمائندگی کرتی ہے: کسی دیے گئے وقت پر کسی مخصوص اثاثے کی قیمت۔ اس مقام پر، asset فیلڈ غیر متعلقہ ہے کیونکہ ہم ایک ہی پول استعمال کرتے ہیں اور اس لیے ہمارے پاس ایک ہی اثاثہ ہے۔ تاہم، ہم بعد میں مزید اثاثے شامل کریں گے۔

1def read_token(address: str) -> ERC20Token:
2 token = w3.eth.contract(address=address, abi=ERC20_ABI)
3 symbol = token.functions.symbol().call()
4 decimals = token.functions.decimals().call()
5
6 return ERC20Token(
7 address=address,
8 symbol=symbol,
9 decimals=decimals,
10 contract=token
11 )

یہ فنکشن ایک ایڈریس لیتا ہے اور اس ایڈریس پر ٹوکن کنٹریکٹ کے بارے میں معلومات واپس کرتا ہے۔ ایک نیا Web3 Contract (opens in a new tab) بنانے کے لیے، ہم w3.eth.contract کو ایڈریس اور ABI فراہم کرتے ہیں۔

1def read_pool(address: str) -> PoolInfo:
2 pool_contract = w3.eth.contract(address=address, abi=POOL_ABI)
3 token0Address = pool_contract.functions.token0().call()
4 token1Address = pool_contract.functions.token1().call()
5 token0 = read_token(token0Address)
6 token1 = read_token(token1Address)
7
8 return PoolInfo(
9 address=address,
10 asset=f"{token1.symbol}/{token0.symbol}",
11 token0=token0,
12 token1=token1,
13 contract=pool_contract,
14 decimal_factor=Decimal(10) ** Decimal(token0.decimals - token1.decimals)
15 )

یہ فنکشن ہمیں ایک مخصوص پول (opens in a new tab) کے بارے میں درکار ہر چیز واپس کرتا ہے۔ سنٹیکس f"<string>" ایک فارمیٹڈ اسٹرنگ (opens in a new tab) ہے۔

1def get_quote(pool: PoolInfo, block_number: int = None) -> Quote:

ایک Quote آبجیکٹ حاصل کریں۔ block_number کی ڈیفالٹ قدر None (کوئی قدر نہیں) ہے۔

1 if block_number is None:
2 block_number = w3.eth.block_number

اگر بلاک نمبر کی وضاحت نہیں کی گئی تھی، تو w3.eth.block_number استعمال کریں، جو کہ تازہ ترین بلاک نمبر ہے۔ یہ ایک if اسٹیٹمنٹ (opens in a new tab) کا سنٹیکس ہے۔

ایسا لگ سکتا ہے کہ ڈیفالٹ کو صرف w3.eth.block_number پر سیٹ کرنا بہتر ہوتا، لیکن یہ اچھی طرح کام نہیں کرتا کیونکہ یہ اس وقت کا بلاک نمبر ہوگا جب فنکشن کی تعریف کی گئی تھی۔ ایک طویل عرصے تک چلنے والے ایجنٹ میں، یہ ایک مسئلہ ہوگا۔

1 block = w3.eth.get_block(block_number)
2 price = pool.get_price(block_number)
3 return Quote(
4 timestamp=datetime.fromtimestamp(block.timestamp, timezone.utc).isoformat(),
5 price=price.quantize(Decimal("0.01")),
6 asset=pool.asset
7 )

اسے انسانوں اور بڑے لینگویج ماڈلز (LLMs) کے لیے قابل مطالعہ فارمیٹ میں فارمیٹ کرنے کے لیے datetime لائبریری (opens in a new tab) کا استعمال کریں۔ قدر کو دو اعشاریہ مقامات تک راؤنڈ کرنے کے لیے Decimal.quantize (opens in a new tab) کا استعمال کریں۔

1def get_quotes(pool: PoolInfo, start_block: int, end_block: int, step: int) -> list[Quote]:

Python میں آپ ایک فہرست (list) (opens in a new tab) کی تعریف کرتے ہیں جس میں list[<type>] کا استعمال کرتے ہوئے صرف ایک مخصوص ٹائپ شامل ہو سکتی ہے۔

1 quotes = []
2 for block in range(start_block, end_block + 1, step):

Python میں ایک for لوپ (opens in a new tab) عام طور پر ایک فہرست پر اعادہ (iterate) کرتا ہے۔ کوٹس تلاش کرنے کے لیے بلاک نمبرز کی فہرست range (opens in a new tab) سے آتی ہے۔

1 quote = get_quote(pool, block)
2 quotes.append(quote)
3 return quotes

ہر بلاک نمبر کے لیے، ایک Quote آبجیکٹ حاصل کریں اور اسے quotes فہرست میں شامل کریں۔ پھر وہ فہرست واپس کریں۔

1pool = read_pool(WETHUSDC_ADDRESS)
2quotes = get_quotes(
3 pool,
4 w3.eth.block_number - 12*CYCLE_BLOCKS,
5 w3.eth.block_number,
6 CYCLE_BLOCKS
7)
8
9pprint(quotes)

یہ اسکرپٹ کا مرکزی کوڈ ہے۔ پول کی معلومات پڑھیں، بارہ کوٹس حاصل کریں، اور انہیں pprint (opens in a new tab) کریں۔

ایک پرامپٹ بنانا

اس کے بعد، ہمیں کوٹس کی اس فہرست کو LLM کے لیے ایک پرامپٹ میں تبدیل کرنے اور متوقع مستقبل کی قدر حاصل کرنے کی ضرورت ہے۔

1git checkout 03-create-prompt
2uv run agent.py

آؤٹ پٹ اب LLM کے لیے ایک پرامپٹ ہونے جا رہا ہے، جو اس سے ملتا جلتا ہے:

1Given these quotes:
2Asset: WETH/USDC
3 2026-01-20T16:34 3016.21
4 .
5 .
6 .
7 2026-02-01T17:49 2299.10
8
9Asset: WBTC/WETH
10 2026-01-20T16:34 29.84
11 .
12 .
13 .
14 2026-02-01T17:50 33.46
15
16
17What would you expect the value for WETH/USDC to be at time 2026-02-02T17:56?
18
19Provide your answer as a single number rounded to two decimal places,
20without any other text.

غور کریں کہ یہاں دو اثاثوں، WETH/USDC اور WBTC/WETH کے لیے کوٹس موجود ہیں۔ کسی دوسرے اثاثے سے کوٹس شامل کرنے سے پیشین گوئی کی درستگی بہتر ہو سکتی ہے۔

پرامپٹ کیسا لگتا ہے

اس پرامپٹ میں تین حصے شامل ہیں، جو LLM پرامپٹس میں کافی عام ہیں۔

  1. معلومات۔ LLMs کے پاس اپنی ٹریننگ سے بہت سی معلومات ہوتی ہیں، لیکن ان کے پاس عام طور پر تازہ ترین معلومات نہیں ہوتیں۔ یہی وجہ ہے کہ ہمیں یہاں تازہ ترین کوٹس بازیافت کرنے کی ضرورت ہے۔ پرامپٹ میں معلومات شامل کرنے کو retrieval augmented generation (RAG) (opens in a new tab) کہا جاتا ہے۔

  2. اصل سوال۔ یہ وہ ہے جو ہم جاننا چاہتے ہیں۔

  3. آؤٹ پٹ فارمیٹنگ کی ہدایات۔ عام طور پر، ایک LLM ہمیں ایک تخمینہ دے گا جس کی وضاحت ہوگی کہ وہ اس تک کیسے پہنچا۔ یہ انسانوں کے لیے بہتر ہے، لیکن کمپیوٹر پروگرام کو صرف حتمی نتیجے کی ضرورت ہوتی ہے۔

کوڈ کی وضاحت

یہاں نیا کوڈ ہے۔

1from datetime import datetime, timezone, timedelta

ہمیں LLM کو وہ وقت فراہم کرنے کی ضرورت ہے جس کے لیے ہم تخمینہ چاہتے ہیں۔ مستقبل میں "n منٹ/گھنٹے/دن" کا وقت حاصل کرنے کے لیے، ہم timedelta کلاس (opens in a new tab) کا استعمال کرتے ہیں۔

1# ان پولز کے ایڈریسز جنہیں ہم پڑھ رہے ہیں
2WETHUSDC_ADDRESS = Web3.to_checksum_address("0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640")
3WETHWBTC_ADDRESS = Web3.to_checksum_address("0xCBCdF9626bC03E24f779434178A73a0B4bad62eD")

ہمارے پاس دو پولز ہیں جنہیں ہمیں پڑھنے کی ضرورت ہے۔

1@dataclass(frozen=True)
2class PoolInfo:
3 .
4 .
5 .
6 reverse: bool = False
7
8 def get_price(self, block: int) -> Decimal:
9 assert block <= w3.eth.block_number, "Block is in the future"
10 sqrt_price_x96 = Decimal(self.contract.functions.slot0().call(block_identifier=block)[0])
11 raw_price = (sqrt_price_x96 / Decimal(2**96)) ** 2 # (ٹوکن 1 فی ٹوکن 0)
12 if self.reverse:
13 return 1/(raw_price * self.decimal_factor)
14 else:
15 return raw_price * self.decimal_factor

WETH/USDC پول میں، ہم جاننا چاہتے ہیں کہ ہمیں ایک token1 (WETH) خریدنے کے لیے کتنے token0 (USDC) کی ضرورت ہے۔ WETH/WBTC پول میں، ہم جاننا چاہتے ہیں کہ ہمیں ایک token0 (WBTC، جو کہ ریپڈ بٹ کوائن ہے) خریدنے کے لیے کتنے token1 (WETH) کی ضرورت ہے۔ ہمیں یہ ٹریک کرنے کی ضرورت ہے کہ آیا پول کے تناسب کو الٹنے کی ضرورت ہے۔

1def read_pool(address: str, reverse: bool = False) -> PoolInfo:
2 .
3 .
4 .
5
6 return PoolInfo(
7 .
8 .
9 .
10
11 asset= f"{token1.symbol}/{token0.symbol}" if reverse else f"{token0.symbol}/{token1.symbol}",
12 reverse=reverse
13 )

یہ جاننے کے لیے کہ آیا کسی پول کو الٹنے کی ضرورت ہے، ہم اسے read_pool کے ان پٹ کے طور پر حاصل کرتے ہیں۔ اس کے علاوہ، اثاثے کی علامت کو درست طریقے سے سیٹ کرنے کی ضرورت ہے۔

سنٹیکس <a> if <b> else <c> ٹرنری کنڈیشنل آپریٹر (ternary conditional operator) (opens in a new tab) کا Python متبادل ہے، جو C سے ماخوذ زبان میں <b> ? <a> : <c> ہوگا۔

1def format_quotes(quotes: list[Quote]) -> str:
2 result = f"Asset: {quotes[0].asset}\n"
3 for quote in quotes:
4 result += f"\t{quote.timestamp[0:16]} {quote.price.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)}\n"
5 return result

یہ فنکشن ایک اسٹرنگ بناتا ہے جو Quote آبجیکٹس کی فہرست کو فارمیٹ کرتا ہے، یہ فرض کرتے ہوئے کہ وہ سب ایک ہی اثاثے پر لاگو ہوتے ہیں۔

1def make_prompt(quotes: list[list[Quote]], expected_time: str, asset: str) -> str:
2 return f"""

Python میں ملٹی لائن اسٹرنگ لٹرلز (multi-line string literals) (opens in a new tab) کو """ .... """ کے طور پر لکھا جاتا ہے۔

1Given these quotes:
2{
3 functools.reduce(lambda acc, q: acc + '\n' + q,
4 map(lambda q: format_quotes(q), quotes))
5}

یہاں، ہم format_quotes کے ساتھ ہر کوٹ لسٹ کے لیے ایک اسٹرنگ بنانے کے لیے MapReduce (opens in a new tab) پیٹرن کا استعمال کرتے ہیں، پھر انہیں پرامپٹ میں استعمال کے لیے ایک ہی اسٹرنگ میں کم (reduce) کرتے ہیں۔

1What would you expect the value for {asset} to be at time {expected_time}?
2
3Provide your answer as a single number rounded to two decimal places,
4without any other text.
5 """

باقی پرامپٹ توقع کے مطابق ہے۔

1wethusdc_pool = read_pool(WETHUSDC_ADDRESS, True)
2wethusdc_quotes = get_quotes(
3 wethusdc_pool,
4 w3.eth.block_number - 12*CYCLE_BLOCKS,
5 w3.eth.block_number,
6 CYCLE_BLOCKS,
7)
8
9wethwbtc_pool = read_pool(WETHWBTC_ADDRESS)
10wethwbtc_quotes = get_quotes(
11 wethwbtc_pool,
12 w3.eth.block_number - 12*CYCLE_BLOCKS,
13 w3.eth.block_number,
14 CYCLE_BLOCKS
15)

دونوں پولز کا جائزہ لیں اور دونوں سے کوٹس حاصل کریں۔

1future_time = (datetime.now(timezone.utc) + timedelta(days=1)).isoformat()[0:16]
2
3print(make_prompt(wethusdc_quotes + wethwbtc_quotes, future_time, wethusdc_pool.asset))

مستقبل کے اس وقت کا تعین کریں جس کے لیے ہم تخمینہ چاہتے ہیں، اور پرامپٹ بنائیں۔

LLM کے ساتھ انٹرفیسنگ

اس کے بعد، ہم ایک حقیقی LLM کو پرامپٹ کرتے ہیں اور متوقع مستقبل کی قدر حاصل کرتے ہیں۔ میں نے یہ پروگرام OpenAI کا استعمال کرتے ہوئے لکھا ہے، لہذا اگر آپ کوئی مختلف پرووائیڈر استعمال کرنا چاہتے ہیں، تو آپ کو اسے ایڈجسٹ کرنا ہوگا۔

  1. ایک OpenAI اکاؤنٹ (opens in a new tab) حاصل کریں

  2. اکاؤنٹ میں فنڈز ڈالیں (opens in a new tab)—لکھتے وقت کم از کم رقم $5 ہے

  3. ایک API کلید بنائیں (opens in a new tab)

  4. کمانڈ لائن میں، API کلید کو ایکسپورٹ کریں تاکہ آپ کا پروگرام اسے استعمال کر سکے

    1export OPENAI_API_KEY=sk-<the rest of the key goes here>
  5. ایجنٹ کو چیک آؤٹ کریں اور چلائیں

    1git checkout 04-interface-llm
    2uv run agent.py

یہاں نیا کوڈ ہے۔

1from openai import OpenAI
2
3open_ai = OpenAI() # کلائنٹ OPENAI_API_KEY انوائرنمنٹ ویری ایبل کو پڑھتا ہے

OpenAI API کو امپورٹ کریں اور انسٹینشیٹ (instantiate) کریں۔

1response = open_ai.chat.completions.create(
2 model="gpt-4-turbo",
3 messages=[
4 {"role": "user", "content": prompt}
5 ],
6 temperature=0.0,
7 max_tokens=16,
8)

جواب بنانے کے لیے OpenAI API (open_ai.chat.completions.create) کو کال کریں۔

1expected_price = Decimal(response.choices[0].message.content.strip())
2current_price = wethusdc_quotes[-1].price
3
4print ("Current price:", wethusdc_quotes[-1].price)
5print(f"In {future_time}, expected price: {expected_price} USD")
6
7if (expected_price > current_price):
8 print(f"Buy, I expect the price to go up by {expected_price - current_price} USD")
9else:
10 print(f"Sell, I expect the price to go down by {current_price - expected_price} USD")

قیمت آؤٹ پٹ کریں اور خریدنے یا بیچنے کی سفارش فراہم کریں۔

پیشین گوئیوں کی جانچ کرنا

اب جب کہ ہم پیشین گوئیاں تیار کر سکتے ہیں، ہم تاریخی ڈیٹا کا استعمال بھی کر سکتے ہیں تاکہ یہ اندازہ لگایا جا سکے کہ آیا ہم مفید پیشین گوئیاں تیار کرتے ہیں۔

1uv run test-predictor.py

متوقع نتیجہ اس سے ملتا جلتا ہے:

1Prediction for 2026-01-05T19:50: predicted 3138.93 USD, real 3218.92 USD, error 79.99 USD
2Prediction for 2026-01-06T19:56: predicted 3243.39 USD, real 3221.08 USD, error 22.31 USD
3Prediction for 2026-01-07T20:02: predicted 3223.24 USD, real 3146.89 USD, error 76.35 USD
4Prediction for 2026-01-08T20:11: predicted 3150.47 USD, real 3092.04 USD, error 58.43 USD
5.
6.
7.
8Prediction for 2026-01-31T22:33: predicted 2637.73 USD, real 2417.77 USD, error 219.96 USD
9Prediction for 2026-02-01T22:41: predicted 2381.70 USD, real 2318.84 USD, error 62.86 USD
10Prediction for 2026-02-02T22:49: predicted 2234.91 USD, real 2349.28 USD, error 114.37 USD
11Mean prediction error over 29 predictions: 83.87103448275862068965517241 USD
12Mean change per recommendation: 4.787931034482758620689655172 USD
13Standard variance of changes: 104.42 USD
14Profitable days: 51.72%
15Losing days: 48.28%

ٹیسٹر کا زیادہ تر حصہ ایجنٹ جیسا ہی ہے، لیکن یہاں وہ حصے ہیں جو نئے ہیں یا جن میں ترمیم کی گئی ہے۔

1CYCLES_FOR_TEST = 40 # بیک ٹیسٹ کے لیے، ہم کتنے سائیکلز پر ٹیسٹ کرتے ہیں
2
3# بہت سارے کوٹس حاصل کریں
4wethusdc_pool = read_pool(WETHUSDC_ADDRESS, True)
5wethusdc_quotes = get_quotes(
6 wethusdc_pool,
7 w3.eth.block_number - CYCLE_BLOCKS*CYCLES_FOR_TEST,
8 w3.eth.block_number,
9 CYCLE_BLOCKS,
10)
11
12wethwbtc_pool = read_pool(WETHWBTC_ADDRESS)
13wethwbtc_quotes = get_quotes(
14 wethwbtc_pool,
15 w3.eth.block_number - CYCLE_BLOCKS*CYCLES_FOR_TEST,
16 w3.eth.block_number,
17 CYCLE_BLOCKS
18)

ہم CYCLES_FOR_TEST (یہاں 40 کے طور پر بیان کیا گیا ہے) دن پیچھے دیکھتے ہیں۔

1# پیش گوئیاں بنائیں اور حقیقی تاریخ سے ان کی جانچ کریں
2
3total_error = Decimal(0)
4changes = []

ہمیں دو قسم کی غلطیوں میں دلچسپی ہے۔ پہلی، total_error، محض ان غلطیوں کا مجموعہ ہے جو پیشین گوئی کرنے والے نے کی ہیں۔

دوسری، changes کو سمجھنے کے لیے، ہمیں ایجنٹ کا مقصد یاد رکھنے کی ضرورت ہے۔ یہ WETH/USDC تناسب (ETH کی قیمت) کی پیشین گوئی کرنا نہیں ہے۔ یہ بیچنے اور خریدنے کی سفارشات جاری کرنا ہے۔ اگر قیمت فی الحال $2000 ہے اور یہ کل $2010 کی پیشین گوئی کرتا ہے، تو ہمیں کوئی اعتراض نہیں اگر اصل نتیجہ $2020 ہو اور ہم اضافی رقم کمائیں۔ لیکن ہمیں ضرور اعتراض ہوگا اگر اس نے $2010 کی پیشین گوئی کی، اور اس سفارش کی بنیاد پر ETH خریدا، اور قیمت گر کر $1990 ہو گئی۔

1for index in range(0,len(wethusdc_quotes)-CYCLES_BACK):

ہم صرف ان صورتوں کو دیکھ سکتے ہیں جہاں مکمل تاریخ (پیشین گوئی کے لیے استعمال ہونے والی قدریں اور اس کا موازنہ کرنے کے لیے حقیقی دنیا کی قدر) دستیاب ہو۔ اس کا مطلب ہے کہ سب سے نیا کیس وہ ہونا چاہیے جو CYCLES_BACK پہلے شروع ہوا تھا۔

1 wethusdc_slice = wethusdc_quotes[index:index+CYCLES_BACK]
2 wethwbtc_slice = wethwbtc_quotes[index:index+CYCLES_BACK]

ایجنٹ کے استعمال کردہ نمونوں کی تعداد کے برابر نمونے حاصل کرنے کے لیے سلائسز (slices) (opens in a new tab) کا استعمال کریں۔ یہاں اور اگلے حصے کے درمیان کا کوڈ وہی پیشین گوئی حاصل کرنے والا کوڈ ہے جو ہمارے پاس ایجنٹ میں ہے۔

1 predicted_price = Decimal(response.choices[0].message.content.strip())
2 real_price = wethusdc_quotes[index+CYCLES_BACK].price
3 prediction_time_price = wethusdc_quotes[index+CYCLES_BACK-1].price

متوقع قیمت، اصل قیمت، اور پیشین گوئی کے وقت کی قیمت حاصل کریں۔ ہمیں پیشین گوئی کے وقت کی قیمت کی ضرورت ہے تاکہ یہ تعین کیا جا سکے کہ آیا سفارش خریدنے کی تھی یا بیچنے کی۔

1 error = abs(predicted_price - real_price)
2 total_error += error
3 print (f"Prediction for {prediction_time}: predicted {predicted_price} USD, real {real_price} USD, error {error} USD")

غلطی کا حساب لگائیں، اور اسے کل میں شامل کریں۔

1 recomended_action = 'buy' if predicted_price > prediction_time_price else 'sell'
2 price_increase = real_price - prediction_time_price
3 changes.append(price_increase if recomended_action == 'buy' else -price_increase)

changes کے لیے، ہم ایک ETH خریدنے یا بیچنے کا مالی اثر چاہتے ہیں۔ لہذا پہلے، ہمیں سفارش کا تعین کرنے کی ضرورت ہے، پھر اندازہ لگائیں کہ اصل قیمت کیسے بدلی، اور آیا سفارش نے پیسے کمائے (مثبت تبدیلی) یا پیسے خرچ کروائے (منفی تبدیلی)۔

1print (f"Mean prediction error over {len(wethusdc_quotes)-CYCLES_BACK} predictions: {total_error / Decimal(len(wethusdc_quotes)-CYCLES_BACK)} USD")
2
3length_changes = Decimal(len(changes))
4mean_change = sum(changes, Decimal(0)) / length_changes
5print (f"Mean change per recommendation: {mean_change} USD")
6var = sum((x - mean_change) ** 2 for x in changes) / length_changes
7print (f"Standard variance of changes: {var.sqrt().quantize(Decimal("0.01"))} USD")

نتائج کی رپورٹ دیں۔

1print (f"Profitable days: {len(list(filter(lambda x: x > 0, changes)))/length_changes:.2%}")
2print (f"Losing days: {len(list(filter(lambda x: x < 0, changes)))/length_changes:.2%}")

منافع بخش دنوں کی تعداد اور نقصان دہ دنوں کی تعداد گننے کے لیے filter (opens in a new tab) کا استعمال کریں۔ نتیجہ ایک فلٹر آبجیکٹ ہے، جسے لمبائی حاصل کرنے کے لیے ہمیں ایک فہرست میں تبدیل کرنے کی ضرورت ہے۔

ٹرانزیکشنز جمع کروانا

اب ہمیں درحقیقت ٹرانزیکشنز جمع کروانے کی ضرورت ہے۔ تاہم، میں اس مقام پر، سسٹم کے ثابت ہونے سے پہلے، حقیقی رقم خرچ نہیں کرنا چاہتا۔ اس کے بجائے، ہم مین نیٹ کا ایک مقامی فورک (fork) بنائیں گے، اور اس نیٹ ورک پر "ٹریڈ" کریں گے۔

مقامی فورک بنانے اور ٹریڈنگ کو فعال کرنے کے اقدامات یہ ہیں۔

  1. Foundry (opens in a new tab) انسٹال کریں

  2. anvil (opens in a new tab) شروع کریں

    1anvil --fork-url https://eth.drpc.org --block-time 12

    anvil Foundry کے ڈیفالٹ URL، http://localhost:8545 (opens in a new tab) پر سن رہا ہے، لہذا ہمیں اس cast کمانڈ (opens in a new tab) کے لیے URL کی وضاحت کرنے کی ضرورت نہیں ہے جسے ہم بلاک چین میں ہیرا پھیری کرنے کے لیے استعمال کرتے ہیں۔

  3. anvil میں چلاتے وقت، دس ٹیسٹ اکاؤنٹس ہوتے ہیں جن میں ETH ہوتا ہے—پہلے والے کے لیے انوائرنمنٹ ویری ایبلز سیٹ کریں

    1PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
    2ADDRESS=`cast wallet address $PRIVATE_KEY`
  4. یہ وہ کنٹریکٹس ہیں جنہیں ہمیں استعمال کرنے کی ضرورت ہے۔ SwapRouter (opens in a new tab) وہ Uniswap v3 کنٹریکٹ ہے جسے ہم درحقیقت ٹریڈ کرنے کے لیے استعمال کرتے ہیں۔ ہم براہ راست پول کے ذریعے ٹریڈ کر سکتے ہیں، لیکن یہ بہت آسان ہے۔

    نیچے والے دو ویری ایبلز Uniswap v3 پاتھس ہیں جو WETH اور USDC کے درمیان سویپ (swap) کرنے کے لیے درکار ہیں۔

    1WETH_ADDRESS=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
    2USDC_ADDRESS=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
    3POOL_ADDRESS=0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640
    4SWAP_ROUTER=0xE592427A0AEce92De3Edee1F18E0157C05861564
    5WETH_TO_USDC=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc20001F4A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
    6USDC_TO_WETH=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB480001F4C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
  5. ہر ٹیسٹ اکاؤنٹ میں 10,000 ETH ہیں۔ ٹریڈنگ کے لیے 1000 WETH حاصل کرنے کے لیے 1000 ETH کو ریپ (wrap) کرنے کے لیے WETH کنٹریکٹ کا استعمال کریں۔

    1cast send $WETH_ADDRESS "deposit()" --value 1000ether --private-key $PRIVATE_KEY
  6. USDC کے لیے 500 WETH کی ٹریڈ کرنے کے لیے SwapRouter کا استعمال کریں۔

    1cast send $WETH_ADDRESS "approve(address,uint256)" $SWAP_ROUTER 500ether --private-key $PRIVATE_KEY
    2MAXINT=`cast max-int uint256`
    3cast send $SWAP_ROUTER \
    4 "exactInput((bytes,address,uint256,uint256,uint256))" \
    5 "($WETH_TO_USDC,$ADDRESS,$MAXINT,500ether,1000000)" \
    6 --private-key $PRIVATE_KEY

    approve کال ایک الاؤنس (allowance) بناتی ہے جو SwapRouter کو ہمارے کچھ ٹوکنز خرچ کرنے کی اجازت دیتی ہے۔ کنٹریکٹس ایونٹس کی نگرانی نہیں کر سکتے، لہذا اگر ہم ٹوکنز براہ راست SwapRouter کنٹریکٹ میں منتقل کرتے ہیں، تو اسے معلوم نہیں ہوگا کہ اسے ادائیگی کی گئی تھی۔ اس کے بجائے، ہم SwapRouter کنٹریکٹ کو ایک مخصوص رقم خرچ کرنے کی اجازت دیتے ہیں، اور پھر SwapRouter ایسا کرتا ہے۔ یہ SwapRouter کے ذریعے کال کیے گئے ایک فنکشن کے ذریعے کیا جاتا ہے، تاکہ اسے معلوم ہو سکے کہ آیا یہ کامیاب رہا۔

  7. تصدیق کریں کہ آپ کے پاس دونوں ٹوکنز کافی مقدار میں ہیں۔

    1cast call $WETH_ADDRESS "balanceOf(address)" $ADDRESS | cast from-wei
    2echo `cast call $USDC_ADDRESS "balanceOf(address)" $ADDRESS | cast to-dec`/10^6 | bc

اب جب کہ ہمارے پاس WETH اور USDC ہیں، ہم درحقیقت ایجنٹ کو چلا سکتے ہیں۔

1git checkout 05-trade
2uv run agent.py

آؤٹ پٹ اس سے ملتا جلتا نظر آئے گا:

1(ai-trading-agent) qbzzt@Ori-Cloudnomics:~/260215-ai-agent$ uv run agent.py
2Current price: 1843.16
3In 2026-02-06T23:07, expected price: 1724.41 USD
4Account balances before trade:
5USDC Balance: 927301.578272
6WETH Balance: 500
7Sell, I expect the price to go down by 118.75 USD
8Approve transaction sent: 74e367ddbb407c1aaf567d87aa5863049991b1d2aa092b6b85195d925e2bd41f
9Approve transaction mined.
10Sell transaction sent: fad1bcf938585c9e90364b26ac7a80eea9efd34c37e5db81e58d7655bcae28bf
11Sell transaction mined.
12Account balances after trade:
13USDC Balance: 929143.797116
14WETH Balance: 499

اسے درحقیقت استعمال کرنے کے لیے، آپ کو چند معمولی تبدیلیوں کی ضرورت ہے۔

  • لائن 14 میں، MAINNET_URL کو ایک حقیقی ایکسیس پوائنٹ میں تبدیل کریں، جیسے https://eth.drpc.org
  • لائن 28 میں، PRIVATE_KEY کو اپنی پرائیویٹ کلید میں تبدیل کریں
  • جب تک کہ آپ بہت امیر نہ ہوں اور ایک غیر ثابت شدہ ایجنٹ کے لیے ہر روز 1 ETH خرید یا بیچ نہ سکیں، آپ WETH_TRADE_AMOUNT کو کم کرنے کے لیے 29 کو تبدیل کرنا چاہیں گے

کوڈ کی وضاحت

یہاں نیا کوڈ ہے۔

1SWAP_ROUTER_ADDRESS=Web3.to_checksum_address("0xE592427A0AEce92De3Edee1F18E0157C05861564")
2WETH_TO_USDC=bytes.fromhex("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc20001F4A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48")
3USDC_TO_WETH=bytes.fromhex("A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB480001F4C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")
4PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"

وہی ویری ایبلز جو ہم نے مرحلہ 4 میں استعمال کیے تھے۔

1WETH_TRADE_AMOUNT=1

ٹریڈ کرنے کی رقم۔

1ERC20_ABI = [
2 { "name": "symbol", ... },
3 { "name": "decimals", ... },
4 { "name": "balanceOf", ...},
5 { "name": "approve", ...}
6]

درحقیقت ٹریڈ کرنے کے لیے، ہمیں approve فنکشن کی ضرورت ہے۔ ہم پہلے اور بعد کے بیلنس بھی دکھانا چاہتے ہیں، اس لیے ہمیں balanceOf کی بھی ضرورت ہے۔

1SWAP_ROUTER_ABI = [
2 { "name": "exactInput", ...},
3]

SwapRouter ABI میں ہمیں صرف exactInput کی ضرورت ہے۔ ایک متعلقہ فنکشن، exactOutput ہے، جسے ہم بالکل ایک WETH خریدنے کے لیے استعمال کر سکتے ہیں، لیکن سادگی کے لیے ہم دونوں صورتوں میں صرف exactInput استعمال کرتے ہیں۔

1account = w3.eth.account.from_key(PRIVATE_KEY)
2swap_router = w3.eth.contract(
3 address=SWAP_ROUTER_ADDRESS,
4 abi=SWAP_ROUTER_ABI
5)

account (opens in a new tab) اور SwapRouter کنٹریکٹ کے لیے Web3 کی تعریفیں۔

1def txn_params() -> dict:
2 return {
3 "from": account.address,
4 "value": 0,
5 "gas": 300000,
6 "nonce": w3.eth.get_transaction_count(account.address),
7 }

ٹرانزیکشن کے پیرامیٹرز۔ ہمیں یہاں ایک فنکشن کی ضرورت ہے کیونکہ نونس (nonce) (opens in a new tab) کو ہر بار تبدیل ہونا چاہیے۔

1def approve_token(contract: Contract, amount: int):

SwapRouter کے لیے ٹوکن الاؤنس منظور کریں۔

1 txn = contract.functions.approve(SWAP_ROUTER_ADDRESS, amount).build_transaction(txn_params())
2 signed_txn = w3.eth.account.sign_transaction(txn, private_key=PRIVATE_KEY)
3 tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction)

اس طرح ہم Web3 میں ٹرانزیکشن بھیجتے ہیں۔ پہلے ہم ٹرانزیکشن بنانے کے لیے Contract آبجیکٹ (opens in a new tab) کا استعمال کرتے ہیں۔ پھر ہم PRIVATE_KEY کا استعمال کرتے ہوئے ٹرانزیکشن پر دستخط کرنے کے لیے web3.eth.account.sign_transaction (opens in a new tab) کا استعمال کرتے ہیں۔ آخر میں، ہم ٹرانزیکشن بھیجنے کے لیے w3.eth.send_raw_transaction (opens in a new tab) کا استعمال کرتے ہیں۔

1 print(f"Approve transaction sent: {tx_hash.hex()}")
2 w3.eth.wait_for_transaction_receipt(tx_hash)
3 print("Approve transaction mined.")

w3.eth.wait_for_transaction_receipt (opens in a new tab) اس وقت تک انتظار کرتا ہے جب تک کہ ٹرانزیکشن مائن نہ ہو جائے۔ ضرورت پڑنے پر یہ رسید واپس کرتا ہے۔

1SELL_PARAMS = {
2 "path": WETH_TO_USDC,
3 "recipient": account.address,
4 "deadline": 2**256 - 1,
5 "amountIn": WETH_TRADE_AMOUNT * 10 ** wethusdc_pool.token1.decimals,
6 "amountOutMinimum": 0,
7}

WETH بیچتے وقت یہ پیرامیٹرز ہوتے ہیں۔

1def make_buy_params(quote: Quote) -> dict:
2 return {
3 "path": USDC_TO_WETH,
4 "recipient": account.address,
5 "deadline": 2**256 - 1,
6 "amountIn": int(quote.price*WETH_TRADE_AMOUNT) * 10**wethusdc_pool.token0.decimals,
7 "amountOutMinimum": 0,
8 }

SELL_PARAMS کے برعکس، خریدنے کے پیرامیٹرز تبدیل ہو سکتے ہیں۔ ان پٹ کی رقم 1 WETH کی قیمت ہے، جیسا کہ quote میں دستیاب ہے۔

1def buy(quote: Quote):
2 buy_params = make_buy_params(quote)
3 approve_token(wethusdc_pool.token0.contract, buy_params["amountIn"])
4 txn = swap_router.functions.exactInput(buy_params).build_transaction(txn_params())
5 signed_txn = w3.eth.account.sign_transaction(txn, private_key=PRIVATE_KEY)
6 tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction)
7 print(f"Buy transaction sent: {tx_hash.hex()}")
8 w3.eth.wait_for_transaction_receipt(tx_hash)
9 print("Buy transaction mined.")
10
11
12def sell():
13 approve_token(wethusdc_pool.token1.contract,
14 WETH_TRADE_AMOUNT * 10**wethusdc_pool.token1.decimals)
15 txn = swap_router.functions.exactInput(SELL_PARAMS).build_transaction(txn_params())
16 signed_txn = w3.eth.account.sign_transaction(txn, private_key=PRIVATE_KEY)
17 tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction)
18 print(f"Sell transaction sent: {tx_hash.hex()}")
19 w3.eth.wait_for_transaction_receipt(tx_hash)
20 print("Sell transaction mined.")

buy() اور sell() فنکشنز تقریباً ایک جیسے ہیں۔ پہلے ہم SwapRouter کے لیے کافی الاؤنس منظور کرتے ہیں، اور پھر ہم اسے درست پاتھ اور رقم کے ساتھ کال کرتے ہیں۔

1def balances():
2 token0_balance = wethusdc_pool.token0.contract.functions.balanceOf(account.address).call()
3 token1_balance = wethusdc_pool.token1.contract.functions.balanceOf(account.address).call()
4
5 print(f"{wethusdc_pool.token0.symbol} Balance: {Decimal(token0_balance) / Decimal(10 ** wethusdc_pool.token0.decimals)}")
6 print(f"{wethusdc_pool.token1.symbol} Balance: {Decimal(token1_balance) / Decimal(10 ** wethusdc_pool.token1.decimals)}")

دونوں کرنسیوں میں صارف کے بیلنس کی رپورٹ دیں۔

1print("Account balances before trade:")
2balances()
3
4if (expected_price > current_price):
5 print(f"Buy, I expect the price to go up by {expected_price - current_price} USD")
6 buy(wethusdc_quotes[-1])
7else:
8 print(f"Sell, I expect the price to go down by {current_price - expected_price} USD")
9 sell()
10
11print("Account balances after trade:")
12balances()

یہ ایجنٹ فی الحال صرف ایک بار کام کرتا ہے۔ تاہم، آپ اسے مسلسل کام کرنے کے لیے تبدیل کر سکتے ہیں یا تو اسے crontab (opens in a new tab) سے چلا کر یا لائنز 368-400 کو ایک لوپ میں لپیٹ کر اور اگلے سائیکل کا وقت آنے تک انتظار کرنے کے لیے time.sleep (opens in a new tab) کا استعمال کر کے۔

ممکنہ بہتری

یہ مکمل پروڈکشن ورژن نہیں ہے؛ یہ محض بنیادی باتیں سکھانے کی ایک مثال ہے۔ بہتری کے لیے کچھ خیالات یہ ہیں۔

اسمارٹ ٹریڈنگ

دو اہم حقائق ہیں جنہیں ایجنٹ یہ فیصلہ کرتے وقت نظر انداز کر دیتا ہے کہ کیا کرنا ہے۔

  • متوقع تبدیلی کی شدت۔ اگر قیمت میں کمی کی توقع ہو تو ایجنٹ WETH کی ایک مقررہ رقم بیچ دیتا ہے، قطع نظر اس کے کہ کمی کی شدت کیا ہے۔ یقیناً، معمولی تبدیلیوں کو نظر انداز کرنا اور اس بنیاد پر بیچنا بہتر ہوگا کہ ہم قیمت میں کتنی کمی کی توقع کرتے ہیں۔
  • موجودہ پورٹ فولیو۔ اگر آپ کے پورٹ فولیو کا 10% WETH میں ہے اور آپ کو لگتا ہے کہ قیمت اوپر جائے گی، تو شاید مزید خریدنا سمجھ میں آتا ہے۔ لیکن اگر آپ کے پورٹ فولیو کا 90% WETH میں ہے، تو آپ کو کافی حد تک ایکسپوژر (exposure) حاصل ہو سکتا ہے، اور مزید خریدنے کی ضرورت نہیں ہے۔ اگر آپ کو قیمت نیچے جانے کی توقع ہے تو اس کا الٹ سچ ہے۔

کیا ہوگا اگر آپ اپنی ٹریڈنگ کی حکمت عملی کو خفیہ رکھنا چاہتے ہیں؟

AI وینڈرز وہ استفسارات دیکھ سکتے ہیں جو آپ ان کے LLMs کو بھیجتے ہیں، جو آپ کے ایجنٹ کے ساتھ تیار کردہ شاندار ٹریڈنگ سسٹم کو بے نقاب کر سکتا ہے۔ ایک ٹریڈنگ سسٹم جسے بہت زیادہ لوگ استعمال کرتے ہیں وہ بے کار ہے کیونکہ جب آپ خریدنا چاہتے ہیں تو بہت سے لوگ خریدنے کی کوشش کرتے ہیں (اور قیمت اوپر جاتی ہے) اور جب آپ بیچنا چاہتے ہیں تو بیچنے کی کوشش کرتے ہیں (اور قیمت نیچے جاتی ہے)۔

اس مسئلے سے بچنے کے لیے آپ مقامی طور پر ایک LLM چلا سکتے ہیں، مثال کے طور پر، LM-Studio (opens in a new tab) کا استعمال کرتے ہوئے۔

AI بوٹ سے AI ایجنٹ تک

آپ یہ اچھی دلیل دے سکتے ہیں کہ یہ ایک AI بوٹ ہے، نہ کہ AI ایجنٹ۔ یہ ایک نسبتاً سادہ حکمت عملی کو نافذ کرتا ہے جو پہلے سے طے شدہ معلومات پر انحصار کرتی ہے۔ ہم خود کو بہتر بنانے کے قابل بنا سکتے ہیں، مثال کے طور پر، Uniswap v3 پولز اور ان کی تازہ ترین قدروں کی فہرست فراہم کر کے اور یہ پوچھ کر کہ کس امتزاج کی پیشین گوئی کی قدر بہترین ہے۔

سلپیج پروٹیکشن (Slippage protection)

فی الحال کوئی سلپیج پروٹیکشن (opens in a new tab) نہیں ہے۔ اگر موجودہ کوٹ $2000 ہے، اور متوقع قیمت $2100 ہے، تو ایجنٹ خریدے گا۔ تاہم، اگر ایجنٹ کے خریدنے سے پہلے قیمت بڑھ کر $2200 ہو جاتی ہے، تو مزید خریدنے کا کوئی مطلب نہیں ہے۔

سلپیج پروٹیکشن کو لاگو کرنے کے لیے، agent.py (opens in a new tab) کی لائنز 325 اور 334 میں amountOutMinimum کی قدر کی وضاحت کریں۔

نتیجہ

امید ہے، اب آپ AI ایجنٹس کے ساتھ شروعات کرنے کے لیے کافی جانتے ہوں گے۔ یہ اس موضوع کا جامع جائزہ نہیں ہے؛ اس کے لیے پوری کتابیں وقف ہیں، لیکن یہ آپ کو شروع کرنے کے لیے کافی ہے۔ گڈ لک!

میرے مزید کام کے لیے یہاں دیکھیں (opens in a new tab)۔

صفحہ کی آخری اپ ڈیٹ: ۳ مارچ، ۲۰۲۶

کیا یہ ٹیوٹوریل مددگار تھا؟