O recurso está a ser carregado... Carregamento...

Uma estratégia de equilíbrio perpétuo adequada para um mercado de baixa

Autora:FMZ~Lydia, Criado: 2022-08-16 09:22:14, Atualizado: 2023-09-19 21:42:12

img

No passado, a FMZ lançou oficialmente uma estratégia de rede perpétua, que foi popular entre os usuários, e os espectadores que negociaram TRX em bots reais ganharam muitos lucros no ano passado com riscos controláveis.

  1. É necessário definir parâmetros como preço inicial, espaçamento da grade, valor da grade, modo longo-curto, etc. As configurações são complicadas e têm um grande impacto nos lucros, dificultando a definição dos iniciantes.
  2. A estratégia de rede perpétua apresenta um elevado risco de venda a descoberto, enquanto o risco de venda a longo prazo é relativamente baixo.
  3. A grelha de contratos perpétuos pode optar por apenas longo para evitar o risco de curto, parece estar bem até agora.

Eu escrevi um artigo sobre o princípio da estratégia de equilíbrio e a comparação com a estratégia de rede antes, e você ainda pode consultar agora:https://www.fmz.com/digest-topic/9294A estratégia de equilíbrio é sempre a de manter posições com uma relação de valor fixo ou valor, vender alguns quando ele sobe, e comprar quando ele cai. Pode ser executado com configurações simples. Mesmo que o preço da moeda suba muito, não há risco de ficar curto. O problema com a estratégia de equilíbrio no local é que a utilização do capital é baixa, e não há uma maneira fácil de aumentar a alavancagem. E contratos perpétuos podem resolver o problema. Se o capital total for de 1000, 2000 pode ser mantido fixamente, o que excede o capital original e melhora a utilização do capital. Outro parâmetro é a taxa de ajuste, que controla o quanto saquear ou despejar a posição. Se for definida em 0,01, isso significa que a posição é despejada uma vez para 1% de aumento e escalada uma vez para 1% de diminuição.

Para iniciantes, a estratégia de equilíbrio é altamente recomendada. A operação é simples, basta definir um parâmetro de relação de detenção ou valor da posição, e você pode executá-lo sem pensar em aumentos constantes de preços. Aqueles com certa experiência podem escolher a estratégia de grade, e decidir os limites superiores e inferiores de flutuações e os fundos por grade, a fim de melhorar a utilização de fundos e obter lucros máximos.

Para facilitar o backtesting de mais pares de negociação, este documento mostrará o processo completo de backtesting, e os usuários podem ajustar diferentes parâmetros e pares de negociação para comparação. (A versão é Python3, e um agente é necessário para baixar a cotação. Os usuários podem baixar o Anancoda3 por si mesmos ou executá-lo através do colab do Google)

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
## Current trading pairs
Info = requests.get('https://fapi.binance.com/fapi/v1/exchangeInfo')
symbols = [s['symbol'] for s in Info.json()['symbols']]
symbols = list(set(filter(lambda x: x[-4:] == 'USDT', [s.split('_')[0] for s in symbols]))-
                 set(['1000SHIBUSDT','1000XECUSDT','BTCDOMUSDT','DEFIUSDT','BTCSTUSDT'])) + ['SHIBUSDT','XECUSDT']
print(symbols)
['FLMUSDT', 'ICPUSDT', 'CHZUSDT', 'APEUSDT', 'DARUSDT', 'TLMUSDT', 'ETHUSDT', 'STMXUSDT', 'ENJUSDT', 'LINKUSDT', 'OGNUSDT', 'RSRUSDT', 'QTUMUSDT', 'UNIUSDT', 'BNBUSDT', 'XLMUSDT', 'ATOMUSDT', 'LPTUSDT', 'UNFIUSDT', 'DASHUSDT', 'BTCUSDT', 'NEOUSDT', 'AAVEUSDT', 'DUSKUSDT', 'XRPUSDT', 'IOTXUSDT', 'CVCUSDT', 'SANDUSDT', 'XTZUSDT', 'IOTAUSDT', 'BELUSDT', 'MANAUSDT', 'IOSTUSDT', 'IMXUSDT', 'THETAUSDT', 'SCUSDT', 'DOGEUSDT', 'CELOUSDT', 'BNXUSDT', 'SNXUSDT', 'ZRXUSDT', 'HBARUSDT', 'DOTUSDT', 'ANKRUSDT', 'CELRUSDT', 'BAKEUSDT', 'GALUSDT', 'ICXUSDT', 'LRCUSDT', 'AVAXUSDT', 'C98USDT', 'MTLUSDT', 'FTTUSDT', 'MASKUSDT', 'RLCUSDT', 'MATICUSDT', 'COMPUSDT', 'BLZUSDT', 'CRVUSDT', 'ZECUSDT', 'RUNEUSDT', 'LITUSDT', 'ONEUSDT', 'ADAUSDT', 'NKNUSDT', 'LTCUSDT', 'ATAUSDT', 'GALAUSDT', 'BALUSDT', 'ROSEUSDT', 'EOSUSDT', 'YFIUSDT', 'SKLUSDT', 'BANDUSDT', 'ALGOUSDT', 'NEARUSDT', 'AXSUSDT', 'KSMUSDT', 'AUDIOUSDT', 'SRMUSDT', 'HNTUSDT', 'MKRUSDT', 'KLAYUSDT', 'FLOWUSDT', 'STORJUSDT', 'BCHUSDT', 'DYDXUSDT', 'ARUSDT', 'GMTUSDT', 'CHRUSDT', 'API3USDT', 'VETUSDT', 'KAVAUSDT', 'WAVESUSDT', 'EGLDUSDT', 'SFPUSDT', 'RENUSDT', 'SUSHIUSDT', 'SOLUSDT', 'RVNUSDT', 'ONTUSDT', 'BTSUSDT', 'ZILUSDT', 'GTCUSDT', 'ZENUSDT', 'ALICEUSDT', 'ETCUSDT', 'TRXUSDT', 'TOMOUSDT', 'FILUSDT', 'ARPAUSDT', 'CTKUSDT', 'BATUSDT', 'SXPUSDT', '1INCHUSDT', 'HOTUSDT', 'WOOUSDT', 'LINAUSDT', 'REEFUSDT', 'GRTUSDT', 'RAYUSDT', 'COTIUSDT', 'XMRUSDT', 'PEOPLEUSDT', 'OCEANUSDT', 'JASMYUSDT', 'TRBUSDT', 'ANTUSDT', 'XEMUSDT', 'DGBUSDT', 'ENSUSDT', 'OMGUSDT', 'ALPHAUSDT', 'FTMUSDT', 'DENTUSDT', 'KNCUSDT', 'CTSIUSDT', 'SHIBUSDT', 'XECUSDT']
#Get the function of the K-line of any period
def GetKlines(symbol='BTCUSDT',start='2020-8-10',end='2021-8-10',period='1h',base='fapi',v = 'v1'):
    Klines = []
    start_time = int(time.mktime(datetime.strptime(start, "%Y-%m-%d").timetuple()))*1000 + 8*60*60*1000
    end_time =  min(int(time.mktime(datetime.strptime(end, "%Y-%m-%d").timetuple()))*1000 + 8*60*60*1000,time.time()*1000)
    intervel_map = {'m':60*1000,'h':60*60*1000,'d':24*60*60*1000}
    while start_time < end_time:
        mid_time = start_time+1000*int(period[:-1])*intervel_map[period[-1]]
        url = 'https://'+base+'.binance.com/'+base+'/'+v+'/klines?symbol=%s&interval=%s&startTime=%s&endTime=%s&limit=1000'%(symbol,period,start_time,mid_time)
        #print(url)
        res = requests.get(url)
        res_list = res.json()
        if type(res_list) == list and len(res_list) > 0:
            start_time = res_list[-1][0]+int(period[:-1])*intervel_map[period[-1]]
            Klines += res_list
        if type(res_list) == list and len(res_list) == 0:
            start_time = start_time+1000*int(period[:-1])*intervel_map[period[-1]]
        if mid_time >= end_time:
            break

    df = pd.DataFrame(Klines,columns=['time','open','high','low','close','amount','end_time','volume','count','buy_amount','buy_volume','null']).astype('float')
    df.index = pd.to_datetime(df.time,unit='ms')
    return df

Ao baixar os preços de fechamento de todos os pares de negociação de 2021 até o presente, podemos observar as mudanças no índice geral do mercado: de 2021 a 2022 é, sem dúvida, um mercado alcista, e o índice uma vez subiu 14 vezes. Pode-se dizer que o ouro está em todos os lugares e muitas moedas subiram centenas de vezes. No entanto, em 2022, o mercado de urso que durou meio ano começou, com o índice caindo 80%, e dezenas de moedas se retiraram em mais de 90%. Tal bomba e descarte reflete o enorme risco das estratégias de rede. O índice está atualmente em torno de 3, o que ainda é um ganho de 200% em comparação com o início de 2021, e deve ser um fundo relativo no momento, considerando o desenvolvimento do mercado.

Moedas cujo preço mais elevado aumentou mais de 10 vezes desde o início do ano:

Atividades de pesquisa de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado de mercado.

Moedas com uma retirada corrente superior a 80% a partir do ponto mais elevado:

Atividades de pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pesquisa de dados em pes

#Download closing prices for all trading pairs
start_date = '2021-1-1'
end_date = '2022-05-30'
period = '1d'
df_all = pd.DataFrame(index=pd.date_range(start=start_date, end=end_date, freq=period),columns=symbols)
for i in range(len(symbols)):
    #print(symbols[i])
    symbol = symbols[i]
    df_s = GetKlines(symbol=symbol,start=start_date,end=end_date,period=period,base='api',v='v3')
    df_all[symbol] = df_s[~df_s.index.duplicated(keep='first')].close
#Index changes
df_norm = df_all/df_all.fillna(method='bfill').iloc[0] #Normalization
df_norm.mean(axis=1).plot(figsize=(15,6),grid=True);

png

#The highest increase over the beginning of the year
max_up = df_all.max()/df_all.fillna(method='bfill').iloc[0]
print(max_up.map(lambda x:round(x,3)).sort_values().to_dict())
{'JASMYUSDT': 1.0, 'ICPUSDT': 1.0, 'LINAUSDT': 1.0, 'WOOUSDT': 1.0, 'GALUSDT': 1.0, 'PEOPLEUSDT': 1.0, 'XECUSDT': 1.026, 'ENSUSDT': 1.032, 'TLMUSDT': 1.039, 'IMXUSDT': 1.099, 'FLOWUSDT': 1.155, 'ATAUSDT': 1.216, 'DARUSDT': 1.261, 'ALICEUSDT': 1.312, 'BNXUSDT': 1.522, 'API3USDT': 1.732, 'GTCUSDT': 1.833, 'KLAYUSDT': 1.891, 'BAKEUSDT': 1.892, 'DYDXUSDT': 2.062, 'SHIBUSDT': 2.281, 'BTCUSDT': 2.302, 'MASKUSDT': 2.396, 'SFPUSDT': 2.74, 'LPTUSDT': 2.75, 'APEUSDT': 2.783, 'ARUSDT': 2.928, 'CELOUSDT': 2.951, 'ZILUSDT': 2.999, 'LTCUSDT': 3.072, 'SNXUSDT': 3.266, 'XEMUSDT': 3.555, 'XMRUSDT': 3.564, 'YFIUSDT': 3.794, 'BANDUSDT': 3.812, 'RAYUSDT': 3.924, 'REEFUSDT': 4.184, 'ANTUSDT': 4.205, 'XTZUSDT': 4.339, 'CTKUSDT': 4.352, 'LITUSDT': 4.38, 'RSRUSDT': 4.407, 'LINKUSDT': 4.412, 'BCHUSDT': 4.527, 'DASHUSDT': 5.037, 'BALUSDT': 5.172, 'OCEANUSDT': 5.277, 'EOSUSDT': 5.503, 'RENUSDT': 5.538, 'XLMUSDT': 5.563, 'TOMOUSDT': 5.567, 'ZECUSDT': 5.654, 'COMPUSDT': 5.87, 'DGBUSDT': 5.948, 'ALGOUSDT': 5.981, 'ONTUSDT': 5.997, 'BELUSDT': 6.101, 'TRXUSDT': 6.116, 'ZRXUSDT': 6.135, 'GRTUSDT': 6.45, '1INCHUSDT': 6.479, 'DOTUSDT': 6.502, 'ETHUSDT': 6.596, 'KAVAUSDT': 6.687, 'ICXUSDT': 6.74, 'SUSHIUSDT': 6.848, 'AAVEUSDT': 6.931, 'BTSUSDT': 6.961, 'KNCUSDT': 6.966, 'C98USDT': 7.091, 'THETAUSDT': 7.222, 'ATOMUSDT': 7.553, 'OMGUSDT': 7.556, 'SXPUSDT': 7.681, 'UNFIUSDT': 7.696, 'XRPUSDT': 7.726, 'TRBUSDT': 8.241, 'BLZUSDT': 8.434, 'NEOUSDT': 8.491, 'FLMUSDT': 8.506, 'KSMUSDT': 8.571, 'FILUSDT': 8.591, 'IOTAUSDT': 8.616, 'BATUSDT': 8.647, 'ARPAUSDT': 9.055, 'UNIUSDT': 9.104, 'WAVESUSDT': 9.106, 'MKRUSDT': 10.294, 'CRVUSDT': 10.513, 'STORJUSDT': 10.674, 'SKLUSDT': 11.009, 'CVCUSDT': 11.026, 'SRMUSDT': 11.031, 'QTUMUSDT': 12.066, 'ALPHAUSDT': 12.103, 'ZENUSDT': 12.631, 'VETUSDT': 13.296, 'ROSEUSDT': 13.429, 'FTTUSDT': 13.705, 'IOSTUSDT': 13.786, 'COTIUSDT': 13.958, 'NEARUSDT': 14.855, 'HBARUSDT': 15.312, 'RLCUSDT': 15.432, 'SCUSDT': 15.6, 'GALAUSDT': 15.722, 'RUNEUSDT': 15.795, 'ADAUSDT': 16.94, 'MTLUSDT': 17.18, 'BNBUSDT': 17.899, 'RVNUSDT': 18.169, 'EGLDUSDT': 18.879, 'LRCUSDT': 19.499, 'ANKRUSDT': 21.398, 'ETCUSDT': 23.51, 'DUSKUSDT': 23.55, 'AUDIOUSDT': 25.306, 'OGNUSDT': 25.524, 'GMTUSDT': 28.83, 'ENJUSDT': 33.073, 'STMXUSDT': 33.18, 'IOTXUSDT': 35.866, 'AVAXUSDT': 36.946, 'CHZUSDT': 37.128, 'CELRUSDT': 37.273, 'HNTUSDT': 38.779, 'CTSIUSDT': 41.108, 'HOTUSDT': 46.466, 'CHRUSDT': 61.091, 'MANAUSDT': 62.143, 'NKNUSDT': 70.636, 'ONEUSDT': 84.132, 'DENTUSDT': 99.973, 'DOGEUSDT': 121.447, 'SOLUSDT': 140.296, 'MATICUSDT': 161.846, 'FTMUSDT': 192.507, 'SANDUSDT': 203.219, 'AXSUSDT': 270.41}
#Current maximum backtest
draw_down = df_all.iloc[-1]/df_all.max()
print(draw_down.map(lambda x:round(x,3)).sort_values().to_dict())
{'ICPUSDT': 0.022, 'FILUSDT': 0.043, 'BAKEUSDT': 0.046, 'TLMUSDT': 0.05, 'LITUSDT': 0.053, 'LINAUSDT': 0.054, 'JASMYUSDT': 0.056, 'ALPHAUSDT': 0.062, 'RAYUSDT': 0.062, 'GRTUSDT': 0.067, 'DENTUSDT': 0.068, 'RSRUSDT': 0.068, 'XEMUSDT': 0.068, 'UNFIUSDT': 0.072, 'DYDXUSDT': 0.074, 'SUSHIUSDT': 0.074, 'OGNUSDT': 0.074, 'COMPUSDT': 0.074, 'NKNUSDT': 0.078, 'SKLUSDT': 0.08, 'DGBUSDT': 0.081, 'RLCUSDT': 0.085, 'REEFUSDT': 0.086, 'BANDUSDT': 0.086, 'HOTUSDT': 0.092, 'SRMUSDT': 0.092, 'RENUSDT': 0.092, 'BTSUSDT': 0.093, 'THETAUSDT': 0.094, 'FLMUSDT': 0.094, 'EOSUSDT': 0.095, 'TRBUSDT': 0.095, 'SXPUSDT': 0.095, 'ATAUSDT': 0.096, 'NEOUSDT': 0.096, 'FLOWUSDT': 0.097, 'YFIUSDT': 0.101, 'BALUSDT': 0.106, 'MASKUSDT': 0.106, 'ONTUSDT': 0.108, 'CELRUSDT': 0.108, 'AUDIOUSDT': 0.108, 'SCUSDT': 0.11, 'GALAUSDT': 0.113, 'GTCUSDT': 0.117, 'CTSIUSDT': 0.117, 'STMXUSDT': 0.118, 'DARUSDT': 0.118, 'ALICEUSDT': 0.119, 'SNXUSDT': 0.124, 'FTMUSDT': 0.126, 'BCHUSDT': 0.127, 'SFPUSDT': 0.127, 'ROSEUSDT': 0.128, 'DOGEUSDT': 0.128, 'RVNUSDT': 0.129, 'OCEANUSDT': 0.129, 'VETUSDT': 0.13, 'KSMUSDT': 0.131, 'ICXUSDT': 0.131, 'UNIUSDT': 0.131, 'ONEUSDT': 0.131, '1INCHUSDT': 0.134, 'IOTAUSDT': 0.139, 'C98USDT': 0.139, 'WAVESUSDT': 0.14, 'DUSKUSDT': 0.141, 'LINKUSDT': 0.143, 'DASHUSDT': 0.143, 'OMGUSDT': 0.143, 'PEOPLEUSDT': 0.143, 'AXSUSDT': 0.15, 'ENJUSDT': 0.15, 'QTUMUSDT': 0.152, 'SHIBUSDT': 0.154, 'ZENUSDT': 0.154, 'BLZUSDT': 0.154, 'ANTUSDT': 0.155, 'XECUSDT': 0.155, 'CHZUSDT': 0.158, 'RUNEUSDT': 0.163, 'ENSUSDT': 0.165, 'LRCUSDT': 0.167, 'CHRUSDT': 0.168, 'IOTXUSDT': 0.174, 'TOMOUSDT': 0.176, 'ALGOUSDT': 0.177, 'EGLDUSDT': 0.177, 'ARUSDT': 0.178, 'LTCUSDT': 0.178, 'HNTUSDT': 0.18, 'LPTUSDT': 0.181, 'SOLUSDT': 0.183, 'ARPAUSDT': 0.184, 'BELUSDT': 0.184, 'ETCUSDT': 0.186, 'ZRXUSDT': 0.187, 'AAVEUSDT': 0.187, 'CVCUSDT': 0.188, 'STORJUSDT': 0.189, 'COTIUSDT': 0.19, 'CELOUSDT': 0.191, 'SANDUSDT': 0.191, 'ADAUSDT': 0.192, 'HBARUSDT': 0.194, 'DOTUSDT': 0.195, 'XLMUSDT': 0.195, 'AVAXUSDT': 0.206, 'ANKRUSDT': 0.207, 'MTLUSDT': 0.208, 'MANAUSDT': 0.209, 'CRVUSDT': 0.213, 'API3USDT': 0.221, 'IOSTUSDT': 0.227, 'XRPUSDT': 0.228, 'BATUSDT': 0.228, 'MKRUSDT': 0.229, 'MATICUSDT': 0.229, 'CTKUSDT': 0.233, 'ZILUSDT': 0.233, 'WOOUSDT': 0.234, 'ATOMUSDT': 0.237, 'KLAYUSDT': 0.239, 'XTZUSDT': 0.245, 'IMXUSDT': 0.278, 'NEARUSDT': 0.285, 'GALUSDT': 0.299, 'APEUSDT': 0.305, 'ZECUSDT': 0.309, 'KAVAUSDT': 0.31, 'GMTUSDT': 0.327, 'FTTUSDT': 0.366, 'KNCUSDT': 0.401, 'ETHUSDT': 0.416, 'XMRUSDT': 0.422, 'BTCUSDT': 0.47, 'BNBUSDT': 0.476, 'TRXUSDT': 0.507, 'BNXUSDT': 0.64}

Em primeiro lugar, usamos o código mais simples para simular a situação de queda completa e ver o preço de liquidação de diferentes valores de posição. Uma vez que a estratégia sempre mantém uma posição longa, não há risco de subir. O capital inicial é de 1000, o preço da moeda é de 1, e a taxa de ajuste é de 0,01. Os resultados são os seguintes. Pode-se ver que o risco de liquidação longa não é baixo. Com alavancagem de 1,5 vezes, ele pode resistir a uma queda de 50%. Dada a atual situação relativa de fundo, é um risco aceitável.

Valor das posições Preço da posição longa
300 0.035
500 0.133
800 0.285
1000 0.362
1500 0.51
2000 0.599
3000 0.711
5000 0.81
10000 0.904
for Hold_value in [300,500,800,1000,1500,2000,3000,5000,10000]:
    amount = Hold_value/1
    hold_price = 1
    margin = 1000
    Pct = 0.01
    i = 0
    while margin > 0:
        i += 1
        if i>500:
            break
        buy_price = (1-Pct)*Hold_value/amount
        buy_amount = Hold_value*Pct/buy_price
        hold_price = (amount * hold_price + buy_amount * buy_price) / (buy_amount + amount)
        amount += buy_amount
        margin = 1000 + amount * (buy_price - hold_price)
    print(Hold_value, round(buy_price,3))
300 0.035
500 0.133
800 0.285
1000 0.362
1500 0.51
2000 0.599
3000 0.711
5000 0.81
10000 0.904
#Still using the original backtesting engine
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 #Deduct the handling fees
        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): #Update 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)

Em primeiro lugar, testamos o desempenho da estratégia de equilíbrio do TRX. O retracement máximo do TRX nesta rodada de mercado de baixa é relativamente pequeno, por isso tem uma certa especificidade. Os dados são selecionados a partir da linha 5min K de 2021 até o presente, com um capital inicial de 1000, a taxa de ajuste é de 0,01, o valor da posição é de 2000 e a taxa de manipulação é de 0,0002.

O preço inicial do TRX foi de 0,02676U, e o preço mais alto durante o período atingiu 0,18U. Atualmente está em torno de 0,08U, e as flutuações são muito violentas.

O retorno final do backtest é de 4524U, que é muito próximo do retorno do TRX em 0,18. A alavancagem é inferior a 2 vezes desde o início e finalmente inferior a 0,4, e a possibilidade de liquidação também está ficando menor e menor, durante o qual pode haver uma oportunidade de aumentar o valor da posição.

symbol = 'TRXUSDT'
df_trx = GetKlines(symbol=symbol,start='2021-1-1',end='2022-5-30',period='5m')
df_trx.close.plot(figsize=(15,6),grid=True);

png

#TRX balance strategy backtest
hold_value = 2000
pct = 0.01
e = Exchange([symbol], fee=0.0002, initial_balance=1000)
init_price =  df_trx.iloc[0].open
res_list = [] #For storing intermediate results
e.Buy(symbol,init_price,hold_value/init_price)
e.Update({symbol:init_price})
for row in df_trx.itertuples():
    buy_price = (1-pct)*hold_value/e.account[symbol]['amount']
    sell_price = (1+pct)*hold_value/e.account[symbol]['amount']
    
    while row.low < buy_price:
        e.Buy(symbol,buy_price,pct*hold_value/buy_price)
        e.Update({symbol:row.close})
        buy_price = (1-pct)*hold_value/e.account[symbol]['amount']
        sell_price = (1+pct)*hold_value/e.account[symbol]['amount']
    while row.high > sell_price:
        e.Sell(symbol,sell_price,pct*hold_value/sell_price)
        e.Update({symbol:row.close})
        buy_price = (1-pct)*hold_value/e.account[symbol]['amount']
        sell_price = (1+pct)*hold_value/e.account[symbol]['amount']
    if int(row.time)%(60*60*1000) == 0:
        e.Update({symbol:row.close})
        res_list.append([row.time, row.close, e.account[symbol]['amount'],e.account[symbol]['amount']*row.close, e.account['USDT']['total']-e.initial_balance])
res_trx = pd.DataFrame(data=res_list, columns=['time','price','amount','value','profit'])
res_trx.index = pd.to_datetime(res_trx.time,unit='ms')
print(pct,e.account['USDT']['realised_profit']+e.account['USDT']['unrealised_profit'] ,round(e.account['USDT']['fee'],0))
0.01 4524.226998288555 91.0
#Profit
res_trx.profit.plot(figsize=(15,6),grid=True);

png

#Actual leverage of occupancy
(res_trx.value/(res_trx.profit+1000)).plot(figsize=(15,6),grid=True);

png

Vamos testar WAVES novamente. Esta moeda é bastante especial. Subiu de 6U para 60U no início, e finalmente caiu de volta para os atuais 8U. O lucro final é 4945, muito mais do que o lucro de manter a moeda inalterada.

symbol = 'WAVESUSDT'
df_waves = GetKlines(symbol=symbol,start='2021-1-1',end='2022-5-30',period='5m')
df_waves.close.plot(figsize=(15,6),grid=True);

png

#TWAVES balanced strategy backtest
hold_value = 2000
pct = 0.01
e = Exchange([symbol], fee=0.0002, initial_balance=1000)
init_price =  df_waves.iloc[0].open
res_list = [] #For storing intermediate results
e.Buy(symbol,init_price,hold_value/init_price)
e.Update({symbol:init_price})
for row in df_waves.itertuples():
    buy_price = (1-pct)*hold_value/e.account[symbol]['amount']
    sell_price = (1+pct)*hold_value/e.account[symbol]['amount']
    
    while row.low < buy_price:
        e.Buy(symbol,buy_price,pct*hold_value/buy_price)
        e.Update({symbol:row.close})
        buy_price = (1-pct)*hold_value/e.account[symbol]['amount']
        sell_price = (1+pct)*hold_value/e.account[symbol]['amount']
    while row.high > sell_price:
        e.Sell(symbol,sell_price,pct*hold_value/sell_price)
        e.Update({symbol:row.close})
        buy_price = (1-pct)*hold_value/e.account[symbol]['amount']
        sell_price = (1+pct)*hold_value/e.account[symbol]['amount']
    if int(row.time)%(60*60*1000) == 0:
        e.Update({symbol:row.close})
        res_list.append([row.time, row.close, e.account[symbol]['amount'],e.account[symbol]['amount']*row.close, e.account['USDT']['total']-e.initial_balance])
res_waves = pd.DataFrame(data=res_list, columns=['time','price','amount','value','profit'])
res_waves.index = pd.to_datetime(res_waves.time,unit='ms')
print(pct,e.account['USDT']['realised_profit']+e.account['USDT']['unrealised_profit'] ,round(e.account['USDT']['fee'],0))
0.01 4945.149323437233 178.0
df_waves.profit.plot(figsize=(15,6),grid=True);

png

A propósito, o desempenho da estratégia da rede é testado de volta, o espaçamento da rede é de 0,01, e o valor da rede é de 10. No caso de quase 10 vezes o aumento, tanto a WAVES quanto a TRX experimentaram enormes quedas. Entre eles, a WAVES retirou 5000U e a TRX também excedeu 3000U. Se o capital inicial for pequeno, as posições quase serão liquidadas.

#Grid strategy
pct = 0.01
value = 10*pct/0.01
e = Exchange([symbol], fee=0.0002, initial_balance=1000)
init_price =  df_waves.iloc[0].open
res_list = [] #For storing intermediate results
for row in df_waves.itertuples():
    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'])

    while row.low < buy_price:
        e.Buy(symbol,buy_price,value/buy_price)
        e.Update({symbol:row.close})
        buy_price = (value / pct - value) / (value / (pct * init_price) + e.account[symbol]['amount']) #The buy order price, since it is a pending order transaction, is also the final matching price=
    while row.high > sell_price:
        e.Sell(symbol,sell_price,value/sell_price)
        e.Update({symbol:row.close})
        sell_price = (value / pct + value) / (value / (pct *init_price) + e.account[symbol]['amount'])
    if int(row.time)%(60*60*1000) == 0:
        e.Update({symbol:row.close})
        res_list.append([row.time, row.close, e.account[symbol]['amount'],e.account[symbol]['amount']*row.close, e.account['USDT']['total']-e.initial_balance])
res_waves_net = pd.DataFrame(data=res_list, columns=['time','price','amount','value','profit'])
res_waves_net.index = pd.to_datetime(res_waves_net.time,unit='ms')
print(pct,e.account['USDT']['realised_profit']+e.account['USDT']['unrealised_profit'] ,round(e.account['USDT']['fee'],0))
0.01 1678.0516101975015 70.0
res_waves_net.profit.plot(figsize=(15,6),grid=True);

png

#Grid strategy
pct = 0.01
value = 10*pct/0.01
e = Exchange([symbol], fee=0.0002, initial_balance=1000)
init_price =  df_trx.iloc[0].open
res_list = [] #For storing intermediate results
for row in df_trx.itertuples():
    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'])

    while row.low < buy_price:
        e.Buy(symbol,buy_price,value/buy_price)
        e.Update({symbol:row.close})
        buy_price = (value / pct - value) / (value / (pct * init_price) + e.account[symbol]['amount']) 
    while row.high > sell_price:
        e.Sell(symbol,sell_price,value/sell_price)
        e.Update({symbol:row.close})
        sell_price = (value / pct + value) / (value / (pct *init_price) + e.account[symbol]['amount'])
    if int(row.time)%(60*60*1000) == 0:
        e.Update({symbol:row.close})
        res_list.append([row.time, row.close, e.account[symbol]['amount'],e.account[symbol]['amount']*row.close, e.account['USDT']['total']-e.initial_balance])
res_trx_net = pd.DataFrame(data=res_list, columns=['time','price','amount','value','profit'])
res_trx_net.index = pd.to_datetime(res_trx_net.time,unit='ms')
print(pct,e.account['USDT']['realised_profit']+e.account['USDT']['unrealised_profit'] ,round(e.account['USDT']['fee'],0))
0.01 -161.06952570521656 37.0
res_trx_net.profit.plot(figsize=(15,6),grid=True);

png

Resumo

Desta vez, a análise do backtest usou a linha K de 5min, as flutuações no meio não são completamente simuladas, então os lucros reais devem ser ligeiramente maiores. No geral, a estratégia de equilíbrio tem um risco relativamente pequeno, não tem medo de disparar, e não há necessidade de ajustar os parâmetros, é relativamente fácil de usar e adequado para usuários novatos. A estratégia de grade é muito sensível à definição inicial do preço e requer algum julgamento do mercado. A longo prazo, o risco de curto é alto. A rodada atual do mercado de baixa está está estável no fundo há algum tempo, muitas moedas estão atualmente abaixo de mais de 90% de suas máximas, se você é otimista sobre algumas moedas, este é um bom momento para entrar no mercado, você pode querer abrir uma estratégia de equilíbrio para comprar o fundo, adicionar um pouco de alavancagem e obter lucros da volatilidade e aumento do preço.

A Batalha Binance de Mil Ligas irá fornecer acesso gratuito à estratégia de equilíbrio perpétuo, e todos são bem-vindos para experimentá-la.


Relacionados

Mais.