La stratégie de la grille permanente est une stratégie classique très populaire sur les plateformes. Elle n'utilise pas de jetons, peut être utilisée comme un levier et est beaucoup plus pratique que la grille instantanée. Mais comme il n'est pas possible de retester directement sur la plate-forme de quantification des inventeurs, ce qui est préjudiciable à la sélection des pièces et à l'optimisation des paramètres, cet article présentera le processus de retest complet de Python, qui comprend tous les aspects de la collecte de données, du retest du cadre, des fonctions de mesure et de l'optimisation des paramètres, que vous pouvez essayer vous-même dans le notebook juypter.
En règle générale, les données de ligne K suffisent, pour plus de précision, les cycles de ligne K plus petits sont meilleurs, mais pour équilibrer le temps de retouche et la quantité de données, cet article utilise 5 min pour retoucher les données des deux dernières années, la quantité de données finale dépassant les lignes 20W, la monnaie choisit DYDX. Bien sûr, les devises spécifiques et les cycles de ligne K peuvent être choisis en fonction de vos intérêts.
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()
La réévaluation continue de choisir le cadre précédemment couramment utilisé pour soutenir l'USDT en tant que monnaie multi-monnaie contractuelle permanente, simple et pratique.
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)
Le principe de la stratégie de la grille est simple: les ventes et les achats sont en hausse et en baisse, ce qui implique trois paramètres: le prix initial, l'intervalle de grille et la valeur de la transaction.
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
Le prix de l'initiation affecte la position initiale de la stratégie, le prix initial par défaut que nous venons de répéter est le prix initial au démarrage, c'est-à-dire ne pas avoir de position au démarrage. Et nous savons que la stratégie de la grille rapporte tous les bénéfices au moment où le prix revient au début, de sorte que si la stratégie est en mesure de prévoir correctement les événements futurs au démarrage, les bénéfices seront considérablement améliorés.
Cependant, le prix initial est de 3 U, la stratégie consiste à détenir une quantité importante d'entrepôts vides au début, dans cet exemple, en détenant directement des billets vides de 17 000 U, ce qui représente un risque plus important pour les utilisateurs.
L'intervalle de grille détermine la distance entre les ordres, et il est évident que plus l'intervalle est petit, plus les transactions sont fréquentes, moins le profit d'un seul billet est élevé, et plus les frais de traitement sont élevés. Mais il est à noter que l'intervalle de grille devient plus petit et que la valeur du grille ne change pas, lorsque les prix changent, le total des avoirs augmente, les risques sont complètement différents.
Étant donné que le retouche utilise des données de ligne de 5 mK et ne traite qu'une seule fois sur une ligne de K. Cela est manifestement irréaliste, en particulier si la volatilité de la monnaie numérique est très élevée et que de plus petits intervalles manquent beaucoup de transactions dans le retouche par rapport au disque réel, il suffit d'augmenter l'intervalle pour avoir une valeur de référence. Dans ce mécanisme de retouche, les conclusions ne sont pas exactes.
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
Comme nous l'avons mentionné précédemment, lorsque la volatilité est simultanée, la valeur de la détention est plus élevée, le risque et d'autres méthodes proportionnelles, mais à condition qu'il n'y ait pas de chute rapide, 1% du capital total et 1% de l'écart de grille devraient être en mesure de faire face à la plupart des marchés. Dans l'exemple de DYDX, une chute de près de 90% a également déclenché une explosion.
Le prix de rebond est le prix initial, la différence entre le prix actuel et le prix initial et la taille du filet déterminent le nombre de positions à détenir. Si le prix de rebond est placé au-dessus du prix actuel, la stratégie du filet sera plus élevée et sera à son tour vide. Le prix de rebond par défaut est le prix au début de la stratégie.
Lorsque la stratégie est lancée, le prix de retour est fixé à 1,6 fois le prix de lancement, de sorte que la stratégie de filet commence à détenir la partie de l'écart générée par la prise de position lorsque le prix est tombé de 1,6 fois au prix actuel. Si le prix ultérieur dépasse le prix de retour / 1.6, le prix initial est réinitialisé, ce qui maintient toujours au moins 60% de l'écart utilisé pour faire de l'écart.
Bien sûr, si vous êtes plus optimiste sur le marché, vous pouvez augmenter ce ratio, et les bénéfices finaux augmenteront en conséquence, bien sûr, si le marché baisse, cela augmente également le risque de détention.
Nom de la sociétéPourquoi fmz ne peut-il pas retranscrire directement la stratégie de la grille?