베어시장의 바닥에 적합한 영구 균형 전략

저자:리디아, 창작: 2022-08-16 09:22:14, 업데이트: 2023-09-19 21:42:12

img

과거에는 FMZ가 사용자들 사이에서 인기를 끌었던 영구적 그리드 전략을 공식적으로 출시했으며, 실제 봇으로 TRX를 거래한 관람객들은 통제 가능한 위험과 함께 지난 1년 동안 많은 수익을 얻었습니다. 그러나 영구적 그리드 전략에는 몇 가지 문제도 있습니다.

  1. 초기 가격, 그리드 간격, 그리드 값, 긴-단기 모드 등과 같은 매개 변수를 설정하는 것이 필요합니다. 설정은 번거롭고 이익에 큰 영향을 미치므로 초보자가 설정하기가 어렵습니다.
  2. 영구적 네트워크 전략은 단축 판매의 위험이 높고, 장기 판매의 위험은 상대적으로 낮습니다. 그리드 값이 작은 값으로 설정되어 있더라도 단축 판매 가격에 큰 영향을 미치지 않습니다.
  3. 영구 계약 격자는 단축의 위험을 피하기 위해 단지 길게 가는 것을 선택할 수 있습니다. 지금까지는 괜찮은 것처럼 보입니다. 그러나 현재 가격이 초기 가격을 초과하여 짧은 지위에 이르고 초기 가격이 재설정되어야한다는 문제에 직면해야합니다.

전 균형 전략의 원리와 전력망 전략과의 비교에 대한 기사를 썼는데,https://www.fmz.com/digest-topic/9294. 밸런스 전략은 항상 고정된 가치 비율 또는 가치로 포지션을 보유하고, 상승할 때 일부를 판매하고, 떨어질 때 구입합니다. 간단한 설정으로 실행할 수 있습니다. 통화 가격이 많이 상승하더라도 단축 될 위험이 없습니다. 현금 밸런스 전략의 문제는 자본 활용도가 낮고, 레버리지를 증가시키는 쉬운 방법이 없다는 것입니다. 그리고 영구 계약이 문제를 해결할 수 있습니다. 총 자본이 1000이면 2000을 고정적으로 보유 할 수 있으며, 이는 원래 자본을 초과하고 자본 활용도를 향상시킵니다. 또 다른 매개 변수는 조정 비율입니다. 포지션을 얼마나 거나 덤핑하는지를 제어합니다. 0.01로 설정되면, 포지션은 1% 증가 한 번 덤핑되고 1% 감소 한 번 확장됩니다.

초보자에게는 균형 전략이 매우 좋습니다. 작업은 간단합니다, 보유 비율 또는 위치 가치의 매개 변수를 설정하면 지속적인 가격 상승에 대해 걱정하지 않고 무심하게 실행할 수 있습니다. 특정 경험을 가진 사람들은 격자 전략을 선택하고 격자 당 변동의 상부 및 하부 한계 및 자금을 결정하여 자금의 활용도를 향상시키고 최대 이익을 얻을 수 있습니다.

더 많은 거래 쌍의 백테스팅을 용이하게 하기 위해, 이 문서는 전체 백테스팅 프로세스를 보여 주며, 사용자는 비교를 위해 다른 매개 변수와 거래 쌍을 조정할 수 있습니다. (버전은 파이썬3이며 요약서를 다운로드 할 에이전트가 필요합니다. 사용자는 Anancoda3를 직접 다운로드하거나 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

2021 년부터 현재까지 모든 거래 쌍의 폐쇄 가격을 다운로드하면 전체 시장 지수의 변화를 관찰 할 수 있습니다: 2021 년에서 2022 년까지는 의심 할 여지없이 황소 시장이며 지수는 한때 14 배 증가했습니다. 금이 곳곳에 있으며 많은 화폐가 수백 배 상승했다고 말할 수 있습니다. 그러나 2022 년에는 지수가 80% 떨어지고 수십 개의 화폐가 90% 이상 철수하면서 반 년 동안 지속 된 곰 시장이 시작되었습니다. 그러한 펌프 앤 덤프는 그리드 전략의 엄청난 위험을 반영합니다. 현재 지수는 3위 정도이며, 2021년 초에 비해 200% 증가한 것으로 보이며, 시장의 발전을 고려하면 현재는 상대적으로 낮아야 합니다.

올해 초부터 최대 가격이 10배 이상 상승한 통화:

주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회사 주식회

가장 높은 지점으로부터 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의 최대 리트레이스는 상대적으로 작기 때문에 특정 특성을 가지고 있습니다. 데이터는 2021 년부터 현재까지 5min K 라인에서 선택되며 초기 자본이 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);

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

요약

이번 배트테스트 분석에서는 5min K-라인, 중간 변동이 완전히 시뮬레이션되지 않았기 때문에 실제 수익은 약간 높아야 합니다. 전반적으로, 균형 전략은 상대적으로 작은 위험을 안고, 급격히 상승할 것을 두려워하지 않으며, 매개 변수를 조정할 필요가 없으며, 사용이 비교적 쉽고 초보자도 적합합니다. 그리드 전략은 초기 가격 설정에 매우 민감하며 시장에 대한 판단이 필요합니다. 장기적으로, 단축의 위험이 높습니다. 현재 곰 시장의 라운드는 잠시 동안 바닥에 안정되어 있으며, 많은 통화가 현재 최고 수준에서 90% 이상 떨어졌습니다. 일부 통화에 대해 낙관적 인 경우 시장에 진입하는 좋은 시간이며, 바닥을 구입하고 약간의 레버리지를 추가하고 가격 변동과 증가로부터 이익을 얻기 위해 균형 전략을 열고 싶을 수 있습니다.

바이낸스 천리그 전투는 영구 균형 전략에 대한 무료 접근을 제공하며 모든 사람들이 그것을 경험할 수 있습니다.


관련

더 많은