3
focar em
1444
Seguidores

Explicação detalhada da otimização dos parâmetros da estratégia de grade de contrato perpétuo

Criado em: 2023-12-08 17:00:38, atualizado em: 2023-12-14 17:07:42
comments   1
hits   2866

Explicação detalhada da otimização dos parâmetros da estratégia de grade de contrato perpétuo

A estratégia de grade perpétua é uma estratégia clássica popular na plataforma. Comparado com a grade de pontos, não há necessidade de segurar moedas e é possível adicionar alavancagem, o que é muito mais conveniente. No entanto, como é impossível fazer backtest diretamente na Inventor Quantitative Platform, isso não é propício para triagem de moedas e determinação de otimização de parâmetros. Este artigo apresentará o processo completo de backtesting do Python, incluindo coleta de dados, estrutura de backtesting, função de backtesting, otimização de parâmetros, etc. Você pode tentar fazer isso sozinho no Juypter Notebook.

Coleta de dados

Geralmente, os dados da linha K são suficientes. Para fins de precisão, quanto menor o período da linha K, melhor. No entanto, o tempo de backtest e o volume de dados devem ser equilibrados. Este artigo usa dados de 5 minutos dos últimos dois anos para backtesting . O volume final de dados excede 200.000 linhas. Escolha DYDX. É claro que a moeda específica e o período da linha K podem ser selecionados de acordo com seus próprios 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()

Estrutura de Backtesting

O backtest continua a usar a estrutura comumente usada anteriormente, que suporta diversas moedas de contratos perpétuos USDT, o que é simples e fácil de usar.

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 backtesting de grade

O princípio da estratégia de grade é muito simples: vender quando o preço sobe e comprar quando o preço cai. Envolve três parâmetros específicos: preço inicial, espaçamento de grade e valor da transação. As flutuações de mercado do DYDX são muito grandes. Ele caiu dos 8,6U iniciais para 1U e subiu de volta para 3U no recente mercado de alta. O preço inicial padrão da estratégia é 8,6U, o que é muito desfavorável para a grade estratégia, mas o parâmetro padrão backtest O lucro total em dois anos foi de 9200U, e houve uma perda de 7500U em um ponto. Explicação detalhada da otimização dos parâmetros da estratégia de grade de contrato perpétuo

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

Explicação detalhada da otimização dos parâmetros da estratégia de grade de contrato perpétuo

O impacto 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 do backtest agora é o preço inicial na inicialização, ou seja, nenhuma posição é mantida na inicialização. Sabemos que a estratégia de grade realizará todos os lucros quando o preço retornar ao nível inicial, portanto, se a estratégia puder prever corretamente o mercado futuro quando for lançada, ela aumentará significativamente os lucros. Aqui definimos o preço inicial para 3U e depois fazemos o backtest. O drawdown máximo final foi de 9200U, e o lucro final foi de 13372U. A estratégia final não mantém posições. Esse lucro é todo o lucro de volatilidade, e a diferença entre o lucro dos parâmetros padrão e esse lucro é a perda de posição causada pelo julgamento impreciso do preço final.

No entanto, se o preço inicial for definido em 3U, a estratégia ficará vendida no início e manterá um grande número de posições vendidas. Neste exemplo, uma posição vendida de 17.000 U é mantida diretamente, então ela enfrenta riscos maiores.

Explicação detalhada da otimização dos parâmetros da estratégia de grade de contrato perpétuo

Configurações de espaçamento de grade

O espaçamento da grade determina a distância entre ordens pendentes. Obviamente, quanto menor o espaçamento, mais frequentes as transações, menor o lucro de uma única transação e maior a taxa de manuseio. Mas vale a pena notar que quando o espaçamento da grade fica menor e o valor da grade permanece inalterado, a posição total aumentará quando o preço mudar, e os riscos enfrentados serão completamente diferentes. Portanto, para testar novamente o efeito do espaçamento da grade, é necessário converter o valor da grade.

Já que o backtest usa dados de 5mK linhas, e apenas uma transação é feita em uma linha K. Isso obviamente não está de acordo com a realidade, especialmente porque a volatilidade das moedas digitais é muito grande. Espaçamentos menores perderão muitas transações em backtesting em comparação com a negociação real. Apenas espaçamentos maiores terão valor de referência. Com esse mecanismo de backtesting, as conclusões tiradas não são precisas. Por meio de backtesting de dados de fluxo de ordens em nível de tick, o espaçamento ideal da grade deve ser de 0,005 a 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

Valor da transação da grade

Conforme mencionado anteriormente, quando a volatilidade é a mesma, quanto maior o valor mantido, maior o método proporcional ao risco. No entanto, desde que não seja um declínio rápido, 1% do total dos fundos combinados com 1% do espaçamento da grade deve ser capaz de lidar com a maioria das condições de mercado. Neste exemplo do DYDX, uma queda de quase 90% também acionou uma chamada de margem. Mas observe que o DYDX cai principalmente. Quando cai, a estratégia de grade fica longa e a queda máxima é de 100%. No entanto, não há limite para a alta e o risco é muito maior. Portanto, a estratégia de grade recomenda que os usuários escolham moedas que eles acham que têm potencial e só operem em posições longas.

Preço de Regressão Variável

O preço de regressão é o preço inicial. A diferença entre o preço atual e o preço inicial e o tamanho da grade determinam quanta posição deve ser mantida. Se o preço de regressão for definido mais alto do que o preço atual, a estratégia da grade ficará longa, e vice-versa. O preço de regressão padrão é o preço no qual a estratégia foi iniciada. Para reduzir o risco, é recomendado usar uma grade long-only. Uma ideia natural é se é possível alterar o preço de regressão para que, mesmo que o preço suba, você ainda possa manter posições longas sem ter que ajustá-las você mesmo. Tomando o mercado de BTC deste ano como exemplo, ele subiu de 15.000 no início do ano para 43.000 no final do ano. Se você começar a executar a estratégia de grade desde o início do ano, o preço de retorno padrão é 15.000, e você faz negociações longas e curtas. Os retornos específicos são mostrados na figura abaixo. Você perderá dinheiro o tempo todo, pois BTC sobe. Mesmo que o modo long-only não esteja configurado corretamente, o preço pode exceder rapidamente o limite sem manter uma posição. Explicação detalhada da otimização dos parâmetros da estratégia de grade de contrato perpétuo

Primeiro, quando a estratégia é iniciada, o preço de regressão é definido como 1,6 vezes o preço no momento da inicialização. Dessa forma, a estratégia de grade tratará o preço como uma queda de 1,6 vezes para o preço atual e começará a segurar o longo posição causada por esta parte da diferença de preço. Se o preço subsequente exceder Quando o preço de retorno for /1,6, o preço inicial será redefinido, de modo que pelo menos 60% da diferença esteja sempre disponível para posições longas. Os resultados do backtest são os seguintes: Explicação detalhada da otimização dos parâmetros da estratégia de grade de contrato perpétuo

Claro, se você for mais otimista sobre o mercado, você pode definir essa proporção para um valor maior, e o lucro final aumentará de acordo. Claro, se o mercado cair, essa configuração também aumentará o risco de manter posições.