Penjelasan terperinci tentang Optimum Parameter Strategi Grid Kontrak Perpetual

Penulis:Lydia, Dicipta: 2023-12-11 15:04:25, Dikemas kini: 2024-01-02 21:24:31

img

Strategi grid kekal adalah strategi klasik yang popular di platform FMZ. Berbanding dengan grid spot, tidak perlu mempunyai mata wang, dan leverage boleh ditambah, yang jauh lebih mudah daripada grid spot. Walau bagaimanapun, kerana tidak mungkin untuk backtest di Platform FMZ Quant secara langsung, ia tidak kondusif untuk menyaring mata wang dan menentukan pengoptimuman parameter. Dalam artikel ini, kami akan memperkenalkan proses backtesting Python lengkap, termasuk pengumpulan data, kerangka kerja backtesting, fungsi backtesting, pengoptimuman parameter, dll.

Pengumpulan data

Secara amnya, cukup untuk menggunakan data K-line. Untuk ketepatan, semakin kecil tempoh K-line, semakin baik. Walau bagaimanapun, untuk mengimbangi masa backtest dan jumlah data, dalam artikel ini, kami menggunakan 5min data dari dua tahun yang lalu untuk backtesting. Jumlah data akhir melebihi 200,000 baris. Kami memilih DYDX sebagai mata wang. Sudah tentu, mata wang tertentu dan tempoh K-line boleh dipilih mengikut minat anda sendiri.

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

Rangka Kerja Ujian Balik

Untuk backtesting, kami terus memilih kerangka yang biasa digunakan yang menyokong kontrak kekal USDT dalam pelbagai mata wang, yang mudah dan mudah digunakan.

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)

Grid Backtest Fungsi

Prinsip strategi grid adalah sangat mudah. Jual apabila harga naik dan beli apabila harga turun. Ia secara khusus melibatkan tiga parameter: harga awal, jarak grid, dan nilai dagangan. Pasaran DYDX turun naik sangat. Ia jatuh dari tahap rendah awal 8.6U ke 1U, dan kemudian naik kembali ke 3U dalam pasaran bull baru-baru ini. Harga awal lalai strategi adalah 8.6U, yang sangat tidak menguntungkan untuk strategi grid, tetapi parameter lalai yang diuji semula, keuntungan keseluruhan 9200U dibuat dalam dua tahun, dan kerugian 7500U dibuat dalam tempoh itu.

img

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

img

Kesan Harga Awal

Tetapan harga awal mempengaruhi kedudukan awal strategi. Harga awal lalai untuk backtest sekarang adalah harga awal pada permulaan, iaitu tidak ada kedudukan yang dipegang pada permulaan. Dan kita tahu bahawa strategi grid akan merealisasikan semua keuntungan apabila harga kembali ke peringkat awal, jadi jika strategi dapat meramalkan pasaran masa depan dengan betul apabila ia dilancarkan, pendapatan akan meningkat dengan ketara. Di sini, kita menetapkan harga awal kepada 3U dan kemudian backtest. Pada akhirnya, penarikan maksimum adalah 9200U, dan keuntungan akhir adalah 13372U. Strategi akhir tidak memegang kedudukan. Keuntungan adalah semua keuntungan turun naik, dan perbezaan antara keuntungan parameter lalai adalah kerugian kedudukan yang disebabkan oleh penghakiman harga akhir yang tidak tepat.

Walau bagaimanapun, jika harga awal ditetapkan kepada 3U, strategi akan pergi pendek pada mulanya dan memegang sebilangan besar kedudukan pendek.

img

Tetapan Jarak Grid

Jarak grid menentukan jarak antara pesanan yang menunggu. Jelas, semakin kecil jarak, semakin kerap transaksi, semakin rendah keuntungan satu transaksi, dan semakin tinggi yuran pengendalian. Walau bagaimanapun, perlu diperhatikan bahawa apabila jarak grid menjadi lebih kecil dan nilai grid tetap tidak berubah, apabila harga berubah, jumlah kedudukan akan meningkat, dan risiko yang dihadapi sama sekali berbeza. Oleh itu, untuk menguji semula kesan jarak grid, perlu menukar nilai grid.

Oleh kerana backtest menggunakan data 5m K-line, dan setiap K-line hanya diperdagangkan sekali, yang jelas tidak realistik, terutamanya kerana turun naik mata wang digital sangat tinggi. Jarak yang lebih kecil akan terlepas banyak transaksi dalam backtesting berbanding dengan perdagangan langsung. Hanya jarak yang lebih besar yang akan mempunyai nilai rujukan. Dalam mekanisme backtesting ini, kesimpulan yang diambil tidak tepat. Melalui backtesting aliran data pesanan tahap tik, jarak grid optimum harus 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

Nilai Transaksi Grid

Seperti yang disebutkan sebelum ini, apabila turun naik adalah sama, semakin besar nilai pegangan, risiko adalah sebanding. Walau bagaimanapun, selagi tidak ada penurunan pesat, 1% daripada jumlah dana dan 1% dari jarak grid harus dapat mengatasi kebanyakan keadaan pasaran. Dalam contoh DYDX ini, penurunan hampir 90% juga mencetuskan pembubaran. Walau bagaimanapun, perlu diperhatikan bahawa DYDX terutamanya jatuh. Apabila strategi grid pergi lama apabila jatuh, ia akan jatuh sebanyak 100% paling banyak, sementara tidak ada had untuk kenaikan, dan risiko jauh lebih tinggi. Oleh itu, Strategi Grid mengesyorkan pengguna untuk memilih hanya mod kedudukan panjang untuk mata wang yang mereka percayai berpotensi.


Lebih lanjut