مستقل گرڈ کی حکمت عملی ایف ایم زیڈ پلیٹ فارم پر ایک مشہور کلاسک حکمت عملی ہے۔ اسپاٹ گرڈ کے مقابلے میں ، کرنسیوں کی ضرورت نہیں ہے ، اور فائدہ اٹھانا شامل کیا جاسکتا ہے ، جو اسپاٹ گرڈ سے کہیں زیادہ آسان ہے۔ تاہم ، چونکہ ایف ایم زیڈ کوانٹ پلیٹ فارم پر براہ راست بیک ٹیسٹ کرنا ممکن نہیں ہے ، لہذا یہ کرنسیوں کی اسکریننگ اور پیرامیٹر کی اصلاح کا تعین کرنے کے لئے موزوں نہیں ہے۔ اس مضمون میں ، ہم ڈیٹا اکٹھا کرنے ، بیک ٹیسٹنگ فریم ورک ، بیک ٹیسٹنگ افعال ، پیرامیٹر کی اصلاح وغیرہ سمیت پائیتھون کے مکمل بیک ٹیسٹنگ کے عمل کو متعارف کروائیں گے۔ آپ اسے خود جپٹر نوٹ بک میں آزما سکتے ہیں۔
عام طور پر ، K لائن ڈیٹا کا استعمال کرنا کافی ہے۔ درستگی کے ل the ، جتنا کم K لائن مدت ، اتنا ہی بہتر ہے۔ تاہم ، بیک ٹیسٹ کے وقت اور ڈیٹا کے حجم کو متوازن کرنے کے لئے ، اس مضمون میں ، ہم بیک ٹیسٹنگ کے لئے پچھلے دو سالوں کے 5 منٹ کے ڈیٹا کا استعمال کرتے ہیں۔ حتمی ڈیٹا کا حجم 200,000 لائنوں سے تجاوز کر گیا۔ ہم کرنسی کے طور پر DYDX کا انتخاب کرتے ہیں۔ یقینا ، مخصوص کرنسی اور K لائن مدت کو آپ کے اپنے مفادات کے مطابق منتخب کیا جاسکتا ہے۔
import requests
from datetime import date,datetime
import time
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import requests, zipfile, io
%matplotlib inline
def GetKlines(symbol='BTC',start='2020-8-10',end='2021-8-10',period='1h'):
Klines = []
start_time = int(time.mktime(datetime.strptime(start, "%Y-%m-%d").timetuple()))*1000
end_time = int(time.mktime(datetime.strptime(end, "%Y-%m-%d").timetuple()))*1000
while start_time < end_time:
res = requests.get('https://fapi.binance.com/fapi/v1/klines?symbol=%sUSDT&interval=%s&startTime=%s&limit=1000'%(symbol,period,start_time))
res_list = res.json()
Klines += res_list
start_time = res_list[-1][0]
return pd.DataFrame(Klines,columns=['time','open','high','low','close','amount','end_time','volume','count','buy_amount','buy_volume','null']).astype('float')
df = GetKlines(symbol='DYDX',start='2022-1-1',end='2023-12-7',period='5m')
df = df.drop_duplicates()
بیک ٹسٹنگ کے لیے، ہم عام طور پر استعمال ہونے والے فریم ورک کا انتخاب کرتے ہیں جو متعدد کرنسیوں میں یو ایس ڈی ٹی دائمی معاہدوں کی حمایت کرتا ہے، جو استعمال میں آسان اور آسان ہے۔
class Exchange:
def __init__(self, trade_symbols, fee=0.0004, initial_balance=10000):
self.initial_balance = initial_balance #Initial assets
self.fee = fee
self.trade_symbols = trade_symbols
self.account = {'USDT':{'realised_profit':0, 'unrealised_profit':0, 'total':initial_balance, 'fee':0}}
for symbol in trade_symbols:
self.account[symbol] = {'amount':0, 'hold_price':0, 'value':0, 'price':0, 'realised_profit':0,'unrealised_profit':0,'fee':0}
def Trade(self, symbol, direction, price, amount):
cover_amount = 0 if direction*self.account[symbol]['amount'] >=0 else min(abs(self.account[symbol]['amount']), amount)
open_amount = amount - cover_amount
self.account['USDT']['realised_profit'] -= price*amount*self.fee #Deduction of handling fee
self.account['USDT']['fee'] += price*amount*self.fee
self.account[symbol]['fee'] += price*amount*self.fee
if cover_amount > 0: #Close the position first.
self.account['USDT']['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount #Profits
self.account[symbol]['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount
self.account[symbol]['amount'] -= -direction*cover_amount
self.account[symbol]['hold_price'] = 0 if self.account[symbol]['amount'] == 0 else self.account[symbol]['hold_price']
if open_amount > 0:
total_cost = self.account[symbol]['hold_price']*direction*self.account[symbol]['amount'] + price*open_amount
total_amount = direction*self.account[symbol]['amount']+open_amount
self.account[symbol]['hold_price'] = total_cost/total_amount
self.account[symbol]['amount'] += direction*open_amount
def Buy(self, symbol, price, amount):
self.Trade(symbol, 1, price, amount)
def Sell(self, symbol, price, amount):
self.Trade(symbol, -1, price, amount)
def Update(self, close_price): #Updating of assets
self.account['USDT']['unrealised_profit'] = 0
for symbol in self.trade_symbols:
self.account[symbol]['unrealised_profit'] = (close_price[symbol] - self.account[symbol]['hold_price'])*self.account[symbol]['amount']
self.account[symbol]['price'] = close_price[symbol]
self.account[symbol]['value'] = abs(self.account[symbol]['amount'])*close_price[symbol]
self.account['USDT']['unrealised_profit'] += self.account[symbol]['unrealised_profit']
self.account['USDT']['total'] = round(self.account['USDT']['realised_profit'] + self.initial_balance + self.account['USDT']['unrealised_profit'],6)
گرڈ حکمت عملی کا اصول بہت آسان ہے۔ جب قیمت بڑھتی ہے تو فروخت کریں اور جب قیمت گرتی ہے تو خریدیں۔ اس میں خاص طور پر تین پیرامیٹرز شامل ہیں: ابتدائی قیمت ، گرڈ اسپیسنگ ، اور تجارتی قدر۔ ڈی ڈبلیو ڈی ایکس کی مارکیٹ بہت اتار چڑھاؤ کرتی ہے۔ یہ ابتدائی کم سے 8.6U سے 1U تک گر گئی ، اور پھر حالیہ بیل مارکیٹ میں 3U تک واپس آگئی۔ حکمت عملی کی ڈیفالٹ ابتدائی قیمت 8.6U ہے ، جو گرڈ حکمت عملی کے لئے بہت منفی ہے ، لیکن ڈیفالٹ پیرامیٹرز نے بیک ٹیسٹ کیا دو سالوں میں 9200U کا مجموعی منافع حاصل کیا گیا ، اور اس مدت کے دوران 7500U کا نقصان ہوا۔
symbol = 'DYDX'
value = 100
pct = 0.01
def Grid(fee=0.0002, value=100, pct=0.01, init = df.close[0]):
e = Exchange([symbol], fee=0.0002, initial_balance=10000)
init_price = init
res_list = [] #For storing intermediate results
for row in df.iterrows():
kline = row[1] #To backtest a K-line will only generate one buy order or one sell order, which is not particularly accurate.
buy_price = (value / pct - value) / ((value / pct) / init_price + e.account[symbol]['amount']) #The buy order price, as it is a pending order transaction, is also the final aggregated price
sell_price = (value / pct + value) / ((value / pct) / init_price + e.account[symbol]['amount'])
if kline.low < buy_price: #The lowest price of the K-line is lower than the current pending order price, the buy order is filled
e.Buy(symbol,buy_price,value/buy_price)
if kline.high > sell_price:
e.Sell(symbol,sell_price,value/sell_price)
e.Update({symbol:kline.close})
res_list.append([kline.time, kline.close, e.account[symbol]['amount'], e.account['USDT']['total']-e.initial_balance,e.account['USDT']['fee'] ])
res = pd.DataFrame(data=res_list, columns=['time','price','amount','profit', 'fee'])
res.index = pd.to_datetime(res.time,unit='ms')
return res
ابتدائی قیمت کی ترتیب حکمت عملی کی ابتدائی پوزیشن کو متاثر کرتی ہے۔ ابھی بیک ٹیسٹ کے لئے ڈیفالٹ ابتدائی قیمت اسٹارٹ اپ کی ابتدائی قیمت ہے ، یعنی اسٹارٹ اپ پر کوئی پوزیشن نہیں رکھی جاتی ہے۔ اور ہم جانتے ہیں کہ گرڈ حکمت عملی تمام منافع کو اس وقت حاصل کرے گی جب قیمت ابتدائی مرحلے میں واپس آجائے گی ، لہذا اگر حکمت عملی شروع ہونے پر مستقبل کی مارکیٹ کی درست پیش گوئی کرسکتی ہے تو ، آمدنی میں نمایاں بہتری آئے گی۔ یہاں ، ہم ابتدائی قیمت کو 3U پر مقرر کرتے ہیں اور پھر بیک ٹیسٹ کرتے ہیں۔ آخر میں ، زیادہ سے زیادہ ڈراؤونگ 9200U تھا ، اور حتمی منافع 13372U تھا۔ حتمی حکمت عملی پوزیشن نہیں رکھتی ہے۔ منافع تمام اتار چڑھاؤ منافع ہے ، اور ڈیفالٹ پیرامیٹرز کے منافع کے درمیان فرق حتمی قیمت کے غلط فیصلے کی وجہ سے پوزیشن نقصان ہے۔
تاہم ، اگر ابتدائی قیمت 3U پر مقرر کی جاتی ہے تو ، حکمت عملی شروع میں مختصر ہوجائے گی اور بڑی تعداد میں مختصر پوزیشنیں رکھے گی۔ اس مثال میں ، 17،000 U کا ایک مختصر آرڈر براہ راست منعقد ہوتا ہے ، لہذا اس کا سامنا کرنا پڑتا ہے زیادہ خطرات.
گرڈ اسپیسنگ زیر التوا آرڈرز کے مابین فاصلہ طے کرتی ہے۔ ظاہر ہے ، جتنا چھوٹا اسپیسنگ ، زیادہ بار بار لین دین ہوتا ہے ، ایک ہی لین دین کا منافع اتنا ہی کم ہوتا ہے ، اور ہینڈلنگ فیس اتنی ہی زیادہ ہوتی ہے۔ تاہم ، یہ نوٹ کرنے کے قابل ہے کہ چونکہ گرڈ اسپیسنگ چھوٹا ہوجاتا ہے اور گرڈ ویلیو برقرار رہتا ہے ، جب قیمت میں تبدیلی آتی ہے تو ، کل پوزیشنیں بڑھیں گی ، اور خطرات کا سامنا کرنا پڑتا ہے بالکل مختلف ہوتا ہے۔ لہذا ، گرڈ اسپیسنگ کے اثر کو بیک ٹیسٹ کرنے کے لئے ، گرڈ ویلیو کو تبدیل کرنا ضروری ہے۔
چونکہ بیک ٹیسٹ میں 5m K- لائن ڈیٹا استعمال ہوتا ہے ، اور ہر K- لائن میں صرف ایک بار ہی تجارت کی جاتی ہے ، جو ظاہر ہے غیر حقیقت پسندانہ ہے ، خاص طور پر چونکہ ڈیجیٹل کرنسیوں کی اتار چڑھاؤ بہت زیادہ ہے۔ براہ راست تجارت کے مقابلے میں بیک ٹیسٹنگ میں بہت سارے لین دین کو چھوٹا فاصلہ یاد نہیں آئے گا۔ صرف ایک بڑا فاصلہ ہی ریفرنس ویلیو رکھتا ہے۔ اس بیک ٹیسٹنگ میکانزم میں ، اخذ کردہ نتائج درست نہیں ہیں۔ ٹِک لیول آرڈر فلو ڈیٹا بیک ٹیسٹنگ کے ذریعے ، زیادہ سے زیادہ گرڈ اسپیسنگ 0.005-0.01 ہونی چاہئے۔
for p in [0.0005, 0.001 ,0.002 ,0.005, 0.01, 0.02, 0.05]:
res = Grid( fee=0.0002, value=value*p/0.01, pct=p, init =3)
print(p, round(min(res['profit']),0), round(res['profit'][-1],0), round(res['fee'][-1],0))
0.0005 -8378.0 144.0 237.0
0.001 -9323.0 1031.0 465.0
0.002 -9306.0 3606.0 738.0
0.005 -9267.0 9457.0 781.0
0.01 -9228.0 13375.0 550.0
0.02 -9183.0 15212.0 309.0
0.05 -9037.0 16263.0 131.0
جیسا کہ پہلے ذکر کیا گیا ہے ، جب اتار چڑھاؤ ایک جیسے ہوتے ہیں تو ، ہولڈنگ کی قدر جتنی زیادہ ہوتی ہے ، خطرہ متناسب ہوتا ہے۔ تاہم ، جب تک کہ تیزی سے کمی نہیں ہوتی ، کل فنڈز کا 1٪ اور گرڈ اسپیسنگ کا 1٪ زیادہ تر مارکیٹ کے حالات سے نمٹنے کے قابل ہونا چاہئے۔ اس DYDX مثال میں ، تقریبا 90٪ کی کمی نے بھی معاوضہ کو متحرک کردیا۔ تاہم ، یہ نوٹ کیا جانا چاہئے کہ DYDX بنیادی طور پر گر جاتا ہے۔ جب گرڈ کی حکمت عملی گرتی ہے تو ، یہ زیادہ سے زیادہ 100٪ گر جائے گی ، جبکہ اضافے کی کوئی حد نہیں ہے ، اور خطرہ بہت زیادہ ہے۔ لہذا ، گرڈ حکمت عملی صارفین کو مشورہ دیتی ہے کہ وہ صرف ان کرنسیوں کے لئے طویل پوزیشن موڈ کا انتخاب کریں جن کے بارے میں وہ سمجھتے ہیں کہ ان کی صلاحیت ہے۔