Parâmetros de otimização da estratégia de rede de contratos permanentes

Autora:Ervas daninhas, Criado: 2023-12-08 17:00:38, Atualizado: 2023-12-14 17:07:42

img

A estratégia de grelha permanente é uma estratégia clássica muito popular para plataformas. Comparada com a grelha real, não usa moeda, pode ser alavancada e é muito mais conveniente do que a grelha real. Mas, como não é possível quantificar o retest diretamente na plataforma do inventor, prejudicando a seleção de moedas e a otimização de parâmetros, este artigo apresentará o processo de retest completo do Python, que inclui todos os aspectos da coleta de dados, retest do quadro, funções de teste, otimização de parâmetros e outros, que podem ser experimentados no notebook juypter.

Coleta de dados

Em geral, basta com dados de linha K, para maior precisão, o menor ciclo de linha K é melhor, mas para equilibrar o tempo de retrospecção e o volume de dados, este artigo usa 5min para retrospecção de dados dos últimos dois anos, o volume final de dados excede 20 W de linha, a moeda escolhe DYDX. Claro que a moeda específica e o ciclo de linha K podem ser escolhidos de acordo com seus interesses.

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

Quadro de avaliação

A revisão continua a optar por um quadro de apoio ao USDT para a multicurrency de contratos permanentes, simples e útil.

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)

Função de retorno da grade

O princípio da estratégia da rede é muito simples, o aumento da venda, a queda da compra, que envolve três parâmetros: preço inicial, intervalo da rede, valor da transação. A DYDX tem uma grande volatilidade do mercado, caindo 1U do mínimo inicial de 8.6U, o recente mercado de touros voltou a 3U, a estratégia de preço inicial padrão é de 8.6U, o que é muito desfavorável para a estratégia da rede, mas o parâmetro padrão retrospectiva ganha 9200U em dois anos, perdendo 7500U durante o período.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 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

img

Efeito do preço inicial

A configuração do preço inicial afeta a posição inicial da estratégia, o preço inicial padrão que acabamos de reverter é o preço inicial no início, ou seja, não manter a posição no início. E nós sabemos que a estratégia de grelha irá obter todos os lucros quando o preço retornar inicialmente, por isso, se a estratégia for capaz de prever corretamente o futuro, o lucro aumentará significativamente.

No entanto, o preço inicial é de 3 U, o que significa que a estratégia vai ficar vazia no início e manter uma grande quantidade de estoque vazio, no caso de um empréstimo vazio de 17 mil U, portanto, o risco é maior.

img

Configuração do intervalo da grade

O intervalo de grelha determina a distância entre os pedidos pendurados, e, obviamente, quanto menor o intervalo, mais freqüentes são as transações, menor o lucro de cada moeda e maior a taxa de processamento. No entanto, note-se que o intervalo de grelha fica menor e o valor da grelha não muda, quando os preços mudam, o total de participações aumenta, o risco é completamente diferente.

Uma vez que o retraso é feito com dados de linha de 5mK e apenas uma transação é feita em uma linha K. Isso é obviamente irreal, especialmente porque a volatilidade da moeda digital é muito grande, e intervalos menores perdem muitas transações no retraso em comparação com o disco real. Somente o aumento do intervalo é um valor de referência.

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

Valor da negociação da rede

Como mencionado anteriormente, quando a volatilidade é simultânea, o maior o valor da posse, o maior o risco e outros métodos proporcionais, mas desde que não seja uma queda rápida, 1% do total de capital com 1% de intervalo de rede deve lidar com a maioria dos mercados. No exemplo deste DYDX, a queda de quase 90% também desencadeou a explosão.

Preço de retorno variável

O preço de retorno é o preço inicial, a diferença entre o preço atual e o preço inicial e o tamanho da rede determinam quantos posições devem ser mantidas. Se o preço de retorno for definido acima do preço atual, a estratégia da rede fará mais e ficará vazia. O preço de retorno padrão é o preço no início da estratégia.img

Quando a estratégia é iniciada, o preço de retorno é definido como 1.6 vezes o preço inicial, de modo que a estratégia da rede começa a manter o poluição causada por essa parte do diferencial quando o preço cai de 1.6 vezes para o preço atual. Se o preço posterior exceder o preço de retorno / 1.6, o preço inicial é reiniciado, mantendo sempre um mínimo de 60% do diferencial usado para fazer mais. Os resultados do retorno são:img

Claro que se você for mais otimista com o mercado, você pode definir essa proporção maior, e o lucro final também aumentará de acordo, e, claro, se o mercado cair, essa configuração também aumenta o risco de posicionamento.


Mais.

EEEEPor que o fmz não pode rastrear diretamente a política da grade?