
В прошлом FMZ официально запустила стратегию вечной сетки, которая пользовалась большой популярностью среди пользователей, а торговля TRX в реальном времени принесла большую прибыль за последний год или около того при контролируемых рисках. Стратегия единой устойчивой сети также имеет некоторые проблемы:
Ранее я написал статью о принципах стратегии баланса и ее сравнении со стратегией сетки, на которую и сейчас можно ссылаться: https://www.fmz.com/digest-topic/5930. Сбалансированная стратегия всегда удерживает позицию с фиксированным соотношением стоимости или стоимостью. Она продает часть, когда она растет, и покупает часть, когда она падает. Ее можно легко настроить и запустить. Даже если цена валюты значительно вырастет, риска упустить выгоду нет. Проблема стратегии спотового балансирования заключается в том, что использование капитала низкое, и нет простого способа увеличить кредитное плечо. Бессрочный контракт может решить эту проблему. Если общий капитал составляет 1000, вы можете держать 2000 в фиксированной сумме, что превышает первоначальный капитал и улучшает коэффициент использования средств. Также есть параметр для настройки соотношения, который контролирует, насколько увеличивать или уменьшать позиции при росте или падении цены. Например, если он установлен на 0,01, это означает уменьшать позиции один раз, когда цена растет на 1%, и увеличивать позиции один раз, когда цена падает на 1%.
Для новичков настоятельно рекомендуется стратегия баланса. Она проста в использовании и требует только установки параметра коэффициента удержания или стоимости удержания, и вы можете запустить ее, не беспокоясь о росте цен. Те, кто имеет определенный опыт, могут выбрать стратегию сетки, определить верхние и нижние пределы колебаний и фонды для каждой сетки, улучшить использование капитала и стремиться к максимальной прибыли.
Для облегчения бэктестинга большего количества торговых пар в этом документе будет показан полный процесс бэктестинга, а пользователи смогут настраивать различные параметры и торговые пары для сравнения. (Версия — Python3, и для загрузки Market требуется агент. Пользователи могут загрузить Anancoda3 самостоятельно или запустить его через Google 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
## 当前交易对
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']
#获取任意周期K线的函数
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 раз по сравнению с началом года:
‘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
Текущее откат превышает 80% от наивысшей точки:
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
#下载所有交易对的收盘价
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
#指数变化
df_norm = df_all/df_all.fillna(method='bfill').iloc[0] #归一化
df_norm.mean(axis=1).plot(figsize=(15,6),grid=True);

#比年初的最高涨幅
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}
#当前最大回测
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
#还是用原来的回测引擎
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)
Во-первых, мы проведем бэктест производительности стратегии баланса TRX. Максимальная просадка TRX в этом раунде медвежьего рынка относительно невелика, поэтому у нее есть определенные особенности. Выбранные данные представляют собой 5-минутную K-линию с 2021 года по настоящее время с начальным капиталом 1000, коэффициентом корректировки 0,01, стоимостью удержания 2000 и комиссией за обслуживание 0,0002.
Первоначальная цена TRX составляла 0,02676U, а самая высокая цена за этот период достигла 0,18U. В настоящее время она составляет около 0,08U, с очень сильными колебаниями. Если вы с самого начала будете использовать стратегию сетки длинных и коротких позиций, вы неизбежно придете к ликвидации короткой позиции. Сбалансированная стратегия не является большой проблемой.
Окончательный возврат обратного теста составляет 4524U, что очень близко к возврату TRX в 0,18. Кредитное плечо ниже 2 раз в начале и ниже 0,4 в конце. Вероятность ликвидации становится все ниже и ниже. В течение в этот период стоимость активов может быть увеличена. Шанс. Но доход ниже 2000U остается неизменным. Это также один из недостатков сбалансированной стратегии.
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);

#TRX平衡策略回测
hold_value = 2000
pct = 0.01
e = Exchange([symbol], fee=0.0002, initial_balance=1000)
init_price = df_trx.iloc[0].open
res_list = [] #用于储存中间结果
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
#收益
res_trx.profit.plot(figsize=(15,6),grid=True);

#实际占用杠杆
(res_trx.value/(res_trx.profit+1000)).plot(figsize=(15,6),grid=True);

Давайте проведем бэктест 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);

#TWAVES平衡策略回测
hold_value = 2000
pct = 0.01
e = Exchange([symbol], fee=0.0002, initial_balance=1000)
init_price = df_waves.iloc[0].open
res_list = [] #用于储存中间结果
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);

Кстати, давайте проверим на исторических данных эффективность стратегии сетки. Шаг сетки — 0,01, а значение сетки — 10. При почти 10-кратном росте WAVES и TRX испытали огромные откаты, при этом WAVES отступил на 5000U, а TRX отступил более чем на 3000U. Если начальный капитал невелик, позиция по сути будет ликвидирована.
#网格策略
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 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']) #买单价格,由于是挂单成交,也是最终的撮合价格=
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);

#网格策略
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 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);

В этом анализе бэктестинга использовалась 5-минутная К-линия, а колебания в середине не были полностью смоделированы, поэтому фактическая доходность должна быть немного выше. В целом сбалансированная стратегия несет в себе сравнительно небольшие риски, не боится резких скачков, не требует настройки параметров, сравнительно удобна в использовании и подходит для начинающих пользователей. Стратегия сетки очень чувствительна к установлению начальной цены и требует определенного суждения о рыночных условиях. В долгосрочной перспективе риск коротких продаж очень высок. Этот раунд медвежьего рынка некоторое время был стабильным на дне. Многие монеты упали более чем на 90% от своих максимумов. Если вы оптимистично настроены по отношению к некоторым монетам, это хорошее время для входа на рынок. Вы можете захотеть Начните сбалансированную стратегию, чтобы купить на дне. Добавьте немного кредитного плеча, чтобы извлечь выгоду из волатильности и роста цен. В рамках Binance Thousand Group War будет предоставлена возможность бесплатного использования стратегии Perpetual Balance, и каждый может опробовать ее на себе.