Strategi grid permanen adalah strategi klasik platform yang sangat populer. Tidak menggunakan koin, leverage, dan lebih mudah daripada grid langsung dibandingkan dengan grid langsung. Tetapi karena tidak dapat melakukan retest langsung di platform penemu, tidak menguntungkan untuk menyaring jenis mata uang dan menentukan optimasi parameter, artikel ini akan memperkenalkan proses retest Python yang lengkap, yang mencakup semua aspek pengumpulan data, retest framework, fungsi pengukuran, optimasi parameter, dan lainnya. Anda dapat mencoba sendiri di notebook juypter.
Secara umum data K-line sudah cukup, untuk akurasi, semakin kecil siklus K-line semakin baik, tetapi untuk menyeimbangkan waktu retesting dan jumlah data, artikel ini menggunakan 5min untuk retesting data dari dua tahun terakhir, dan volume data akhirnya melebihi 20W baris, mata uang memilih DYDX. Tentu saja mata uang tertentu dan siklus K-line dapat dipilih sesuai dengan 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()
Resi terus memilih kerangka kerja yang sebelumnya digunakan untuk mendukung USDT untuk kontrak multi mata uang yang berkelanjutan, sederhana dan berguna.
class Exchange:
def __init__(self, trade_symbols, fee=0.0004, initial_balance=10000):
self.initial_balance = initial_balance #初始的资产
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 #扣除手续费
self.account['USDT']['fee'] += price*amount*self.fee
self.account[symbol]['fee'] += price*amount*self.fee
if cover_amount > 0: #先平仓
self.account['USDT']['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount #利润
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): #对资产进行更新
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)
Prinsip strategi grid sangat sederhana, menjual lebih banyak, membeli lebih sedikit, dan secara khusus melibatkan tiga parameter: harga awal, interval grid, nilai transaksi. DYDX memiliki volatilitas pasar yang sangat besar, turun 1U dari minimum awal 8.6U, pasar sapi baru-baru ini kembali ke 3U, strategi harga awal default adalah 8.6U, yang sangat merugikan untuk strategi grid, tetapi parameter default menunjukkan laba total 9200U selama dua tahun, kehilangan 7500U selama periode tersebut.
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 row in df.iterrows():
kline = row[1] #这样会测一根K线只会产生一个买单或一个卖单,不是特别精确
buy_price = (value / pct - value) / ((value / pct) / init_price + e.account[symbol]['amount']) #买单价格,由于是挂单成交,也是最终的撮合价格
sell_price = (value / pct + value) / ((value / pct) / init_price + e.account[symbol]['amount'])
if kline.low < buy_price: #K线最低价低于当前挂单价,买单成交
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
Pengaturan harga awal mempengaruhi strategi kepemilikan awal, harga awal default yang baru saja diulas adalah harga awal saat memulai, yaitu tidak memegang saham pada saat memulai. Dan kita tahu bahwa strategi grid akan menghasilkan semua keuntungan pada saat harga kembali awal, jadi jika strategi dimulai dengan prediksi yang benar tentang keadaan pasar di masa depan, maka akan ada peningkatan keuntungan yang signifikan. Di sini, aturkan harga awal menjadi 3U untuk diulas kembali.
Namun harga awal ditetapkan menjadi 3U, dan strategi akan menjadi kosong di awal dan memiliki banyak stok kosong, dalam contoh ini langsung memegang 17,000 U kosong, dan karena itu juga menghadapi risiko yang lebih besar.
Jarak jaring menentukan jarak pesanan yang diikat, jelas bahwa semakin kecil jeda transaksi semakin sering, semakin rendah keuntungan per butir, dan semakin tinggi biaya prosedur. Namun, perlu dicatat bahwa jeda jaring menjadi lebih kecil dan nilai jaring tidak berubah, ketika harga berubah, total kepemilikan akan meningkat, risiko yang dihadapi sama sekali berbeda.
Karena retesting menggunakan data 5mK, dan hanya satu transaksi di K-line. Ini jelas tidak sesuai dengan realitas, terutama karena volatilitas mata uang digital sangat besar, selang yang lebih kecil akan kehilangan banyak transaksi dalam retesting dibandingkan dengan disk nyata, dan hanya selang yang lebih besar yang memiliki nilai referensi. Dengan mekanisme retesting ini, kesimpulan tidak akurat.
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
Seperti yang telah disebutkan sebelumnya, ketika fluktuasi bersamaan, metode proporsional, nilai yang dimiliki semakin besar, risiko, dll, tetapi asalkan tidak turun pesat, 1% dari total modal ditambah 1% dari selang grid harus dapat mengatasi sebagian besar pasar. Dalam contoh DYDX ini, penurunan hampir 90% juga memicu ledakan.
Harga kemunduran adalah harga awal, perbedaan antara harga saat ini dan harga awal, dan ukuran grid menentukan berapa banyak posisi yang harus dipegang. Jika harga kemunduran ditetapkan lebih tinggi dari harga saat ini, strategi grid akan melakukan lebih banyak, yang pada gilirannya akan kosong. Harga kemunduran default adalah harga ketika strategi dimulai. Untuk mengurangi risiko, direkomendasikan untuk melakukan lebih banyak grid, ide alami adalah, tidak dapat mengubah harga kemunduran, sehingga bahkan jika harga naik, masih memiliki banyak saham, tidak disesuaikan secara otomatis.
Pada saat memulai strategi pertama, harga kembali diatur menjadi 1.6 kali harga awal, sehingga strategi grid akan mulai memegang banyak posisi yang disebabkan oleh sebagian dari perbedaan ini ketika harga turun dari 1.6 kali ke harga saat ini, dan jika harga kemudian melebihi harga kembali / 1.6, harga awal disetel kembali, sehingga selalu mempertahankan setidaknya 60% dari perbedaan yang digunakan untuk melakukan banyak. Hasil retesting adalah sebagai berikut:
Tentu saja jika Anda lebih optimis terhadap pasar, Anda dapat mengatur rasio ini lebih besar, dan hasil akhir akan meningkat sesuai, tentu saja jika pasar turun, pengaturan ini juga meningkatkan risiko kepemilikan.
NanSegMengapa fmz tidak dapat langsung mengulangi kebijakan grid?