Стратегия постоянного баланса, подходящая для падения медвежьего рынка

Автор:Лидия., Создано: 2022-08-16 09:22:14, Обновлено: 2023-09-19 21:42:12

img

В прошлом FMZ официально выпустила стратегию вечной сети, которая была популярна среди пользователей, и зрители, которые торговали TRX в реальных ботах, получили много прибыли в прошлом году с контролируемыми рисками.

  1. Необходимо установить такие параметры, как начальная цена, расстояние между сетями, значение сетки, режим длинный-короткий и т. д. Настройки громоздкие и оказывают большое влияние на прибыль, что затрудняет установку новичкам.
  2. Стратегия постоянной сети имеет высокий риск короткой продажи, в то время как риск длинной продажи относительно низок. Даже если сетевая стоимость установлена на небольшое значение, это не окажет большого влияния на цену короткой продажи.
  3. Вечная контрактная сетка может выбрать только длинный, чтобы избежать риска короткого расширения, пока что это кажется нормальным.

Я написал статью о принципе балансовой стратегии и сравнении со стратегией сети раньше, и вы все еще можете обратиться к нему сейчас:https://www.fmz.com/digest-topic/9294. Стратегия баланса всегда держит позиции с фиксированным коэффициентом стоимости или стоимостью, продает некоторые, когда он растет, и покупает, когда он падает. Ее можно управлять с помощью простых настроек. Даже если цена валюты сильно растет, нет риска короткого. Проблема со стратегией спотового баланса заключается в том, что использование капитала низкое, и нет простого способа увеличить рычаг. И вечные контракты могут решить проблему. Если общий капитал составляет 1000, 2000 можно удерживать фиксированно, что превышает первоначальный капитал и улучшает использование капитала.

Для новичков стратегию баланса очень рекомендуется. Операция проста, просто установите параметр соотношения удержания или стоимости позиции, и вы можете управлять ею бездумно, не беспокоясь о постоянном росте цен. Те, у кого есть определенный опыт, могут выбрать стратегию сетки, и решить верхние и нижние пределы колебаний и средств на сетку, чтобы улучшить использование средств и получить максимальную прибыль.

Для того, чтобы облегчить обратное тестирование большего количества торговых пар, в этом документе будет показан полный процесс обратного тестирования, и пользователи могут настроить различные параметры и торговые пары для сравнения. (Версия Python3, и агент требуется для загрузки котировки. Пользователи могут загрузить Anancoda3 сами или запустить его через Googles colab)

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

Загрузив цены закрытия всех торговых пар с 2021 года по настоящее время, мы можем наблюдать изменения в общем индексе рынка: с 2021 по 2022 год, несомненно, бычий рынок, а индекс когда-то вырос в 14 раз. Можно сказать, что золото повсюду, и многие валюты выросли в сотни раз. Однако в 2022 году начался медвежий рынок, который длится уже полгода, с падением индекса на 80%, а десятки валют вышли на более чем 90%. Такой насос и сброс отражает огромный риск стратегий сетки. Индекс в настоящее время находится на уровне около 3, что по-прежнему составляет 200% прироста по сравнению с началом 2021 года, и в данный момент он должен быть относительно низким, учитывая развитие рынка.

Валюты, цены которых с начала года выросли более чем в 10 раз:

КРУСДТ: 10.294, КРВУСДТ: 10.513, СТОРЖДТ: 10.674, SKLUSDT: 11.009, CVCUSDT: 11.026, SRMUSDT: 11.031, QTUMUSDT: 12.066, ALPUSDT: 12.103, ZENUSDT: 12.631, VETUSDT: 13.296, ROSEUSDT: 13.429, FTTUSDT: 13.705, IOSTT: 13.786, TICOTUSDT: 13.958, NEARUSDT: 14.855, HUDMUSDT: 14.845, HUDMUSDT: 15.311, 312, 37.41, 37.41, 37.41, 37.41, 37.41, 37.41, 38.9, 38.9, 38.9, 3

Валюты с текущим снижением свыше 80% от самой высокой точки:

Одновременно с тем, как и в других странах, в США, в США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США, США

#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}

Во-первых, мы используем самый простой код для моделирования ситуации падения вниз, и видим цену ликвидации различных позиций. Поскольку стратегия всегда держит длинную позицию, нет риска повышения. Начальный капитал составляет 1000, цена валюты - 1, а коэффициент корректировки - 0,01. Результаты следующие. Можно увидеть, что риск длинной ликвидации не низок. При 1,5 разном рычаге он может противостоять снижению на 50%. Учитывая текущую относительную ситуацию внизу, это приемлемый риск.

Стоимость позиций Цена длинной позиции
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)

В первую очередь, мы проверяем эффективность стратегии баланса TRX. Максимальное ретрекше TRX в этом раунде медвежьего рынка относительно мало, поэтому он имеет определенную специфику. Данные отобраны из 5min K-линии с 2021 года по настоящее время, с начальным капиталом 1000, соотношение корректировки составляет 0,01, значение позиции - 2000, а комиссионная за обработку составляет 0,0002.

Первоначальная цена TRX составила 0,02676U, а самая высокая цена за этот период достигла 0,18U. В настоящее время она составляет около 0,08U, а колебания очень сильны. Если вы вначале используете долго-короткую сетевую стратегию, трудно избежать результатов короткой продажи.

Окончательная доходность бэкстеста составляет 4524U, что очень близко к доходности TRX на уровне 0,18.

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

Давайте еще раз проверим WAVES. Эта валюта довольно особенная. Она поднялась с 6U до 60U в начале, и, наконец, упала обратно до текущей 8U. Конечная прибыль составляет 4945, намного больше, чем прибыль от удержания валюты без изменений.

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

Кстати, производительность сетевой стратегии проверяется, расстояние между сетями составляет 0,01, а значение сетки - 10. В случае почти 10-кратного увеличения, как WAVES, так и TRX испытали огромные снижения. Среди них WAVES снял 5000U, а TRX также превысил 3000U. Если начальный капитал невелик, позиции будут ликвидированы.

#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

Резюме

На этот раз анализ бэкстеста использовал 5-минутную K-линию, колебания в середине не полностью имитируются, поэтому фактическая прибыль должна быть немного выше. В целом стратегия баланса несет относительно небольшой риск, не боится взрывов, и нет необходимости корректировать параметры, она относительно проста в использовании и подходит для новичков. Стратегия сетки очень чувствительна к первоначальному ценовому установлению и требует некоторого суждения о рынке. В долгосрочной перспективе риск короткого курса высок. Нынешний раунд медвежьего рынка стабилен на дне в течение некоторого времени, многие валюты в настоящее время снижаются более чем на 90% от своих максимумов, если вы оптимистичны по отношению к некоторым валютам, это хорошее время, чтобы выйти на рынок, вы можете открыть стратегию баланса, чтобы купить дно, добавить немного рычага и получить прибыль от волатильности и роста цены.

Битва Binance Thousand League Battle предоставит бесплатный доступ к стратегии вечного баланса, и каждый может испытать ее.


Связанные

Больше