3
집중하다
1444
수행원

디지털 화폐 페어 거래 전략에 대한 자세한 설명

만든 날짜: 2024-07-05 16:23:42, 업데이트 날짜: 2024-11-05 17:42:06
comments   3
hits   5800

디지털 화폐 페어 거래 전략에 대한 자세한 설명

디지털 화폐 페어 거래 전략에 대한 자세한 설명

소개

최근에 저는 Buu의 양적 일기를 보았는데, 거기에는 음의 상관관계를 갖는 통화를 사용하여 통화를 선택할 수 있고, 가격 차이 돌파에 따라 수익을 내기 위해 포지션을 오픈할 수 있다는 내용이 언급되어 있었습니다. 디지털 통화는 기본적으로 양의 상관관계가 있고, 소수의 통화만이 음의 상관관계를 가지고 있습니다. 종종 MEME 코인의 독립적인 시장 조건과 같이 시장 추세를 전혀 따르지 않는 특별한 시장 조건이 있습니다. 필터링 이러한 통화들은 돌파구가 생긴 후에도 오랫동안 가격이 유지되며, 이 방법은 특정 시장 조건 하에서 수익을 낼 수 있습니다. 그러나 양적 거래 분야에서 가장 흔한 방법은 페어 거래에 양의 상관관계를 사용하는 것입니다. 이 글에서는 이 전략을 간략하게 소개합니다.

암호화폐 페어 트레이딩은 통계적 차익거래를 기반으로 한 트레이딩 전략으로, 상관관계가 높은 두 개의 암호화폐 영구 계약을 동시에 매수 및 매도하여 가격 편차를 이용해 수익을 올리는 것을 목표로 합니다. 이 글에서는 전략의 원칙, 수익 메커니즘, 통화 선별 방법, 잠재적 위험 및 이를 개선하는 방법을 소개하고 몇 가지 실용적인 Python 코드 예제를 제공합니다.

전략 원칙

페어 트레이딩 전략은 두 암호화폐의 가격 간의 과거 상관관계에 의존합니다. 두 통화가 강력한 상관관계를 가지고 있으면, 두 통화의 가격은 대략적으로 동기화되어 움직입니다. 특정 순간에 두 가격의 비율에 큰 차이가 생긴다면 이는 일시적인 이상 현상으로 볼 수 있으며, 가격은 정상 수준으로 돌아가는 경향이 있습니다. 디지털 통화 시장은 매우 상호 연결되어 있습니다. 주요 디지털 통화(예: 비트코인)가 상당한 변동을 겪을 때 일반적으로 다른 디지털 통화 간의 연쇄 반응을 유발합니다. 일부 통화는 매우 확실한 긍정적 상관관계를 보일 수 있으며, 같은 투자 기관, 같은 시장 조성자, 같은 트랙에 속하기 때문에 그 상관관계가 지속될 수도 있습니다. 일부 통화는 음의 상관관계를 가지고 있지만, 음의 상관관계를 가진 통화는 그 수가 적고, 모두 전체 시장 추세에 영향을 받기 때문에 일관된 시장 추세를 보이는 경우가 많습니다.

동전 A와 동전 B의 가격 상관관계가 높다고 가정해보자. 특정 시점에서 A/B 가격 비율의 평균값은 1입니다. 특정 시점에서 A/B 가격 비율이 증가에서 0.001 이상, 즉 1.001 이상 벗어나면 다음과 같은 방식으로 거래할 수 있습니다. B에 롱 포지션을 열고 A에 숏 포지션을 엽니다. . 반대로, A/B 가격 비율이 0.999보다 낮은 경우: A에 롱 포지션을, B에 숏 포지션을 엽니다.

수익성의 핵심은 가격이 변동하여 정상화될 때 발생하는 가격 차이의 이익에 있습니다. 가격 편차는 보통 단기적으로 지속되므로, 트레이더는 가격이 평균으로 회귀하면 포지션을 정리하고 그 차이에서 수익을 낼 수 있습니다.

데이터 준비

해당 라이브러리를 가져옵니다

이러한 코드는 직접 사용할 수도 있지만, Anancoda를 다운로드하여 Jupyer Notebook에서 디버깅하는 것이 가장 좋습니다. 일반적으로 사용되는 데이터 분석을 위한 패키지를 직접 포함합니다.

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')
b_symbols = [s['symbol'] for s in Info.json()['symbols'] if s['contractType'] == 'PERPETUAL' and s['status'] == 'TRADING' and s['quoteAsset'] == 'USDT']
b_symbols = list(filter(lambda x: x[-4:] == 'USDT', [s.split('_')[0] for s in b_symbols]))
b_symbols = [x[:-4] for x in b_symbols]
print(b_symbols) # 获取所有的正在交易的交易对

K-line 함수 다운로드

GetKlines 함수의 주요 기능은 Binance 거래소에서 지정된 거래 쌍의 무기한 계약에 대한 과거 K-라인 데이터를 얻고 이 데이터를 Pandas DataFrame에 저장하는 것입니다. K-라인 데이터에는 시가, 최고가, 최저가, 종가, 거래량 및 기타 정보가 포함됩니다. 이번에는 주로 종가 데이터를 활용했습니다.

def GetKlines(symbol='BTCUSDT',start='2020-8-10',end='2024-7-01',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:
        time.sleep(0.3)
        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)
        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

데이터 다운로드

데이터 양이 비교적 많습니다. 더 빠르게 다운로드하기 위해 지난 3개월 동안의 시간별 K-line 데이터만 얻었습니다. df_close에는 모든 통화에 대한 종가 데이터가 포함되어 있습니다.

start_date = '2024-04-01'
end_date   = '2024-07-05'
period = '1h'
df_dict = {}

for symbol in b_symbols:   
    print(symbol)
    if symbol in df_dict.keys():
        continue
    df_s = GetKlines(symbol=symbol+'USDT',start=start_date,end=end_date,period=period)
    if not df_s.empty:
        df_dict[symbol] = df_s
df_close = pd.DataFrame(index=pd.date_range(start=start_date, end=end_date, freq=period),columns=df_dict.keys())
for symbol in symbols:
    df_close[symbol] = df_dict[symbol].close
df_close = df_close.dropna(how='all')

백테스팅 엔진

다음 백테스트에 대한 Exchange 객체를 정의합니다.

class Exchange:
    def __init__(self, trade_symbols, fee=0.0002, 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, 'leverage':0, 'hold':0, 'long':0, 'short':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
        self.account['USDT']['hold'] = 0
        self.account['USDT']['long'] = 0
        self.account['USDT']['short'] = 0
        for symbol in self.trade_symbols:
            if not np.isnan(close_price[symbol]):
                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'] = self.account[symbol]['amount']*close_price[symbol]
                if self.account[symbol]['amount'] > 0:
                    self.account['USDT']['long'] += self.account[symbol]['value']
                if self.account[symbol]['amount'] < 0:
                    self.account['USDT']['short'] += self.account[symbol]['value']
                self.account['USDT']['hold'] += abs(self.account[symbol]['value'])
                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)
        self.account['USDT']['leverage'] = round(self.account['USDT']['hold']/self.account['USDT']['total'],3)

통화 필터링을 위한 상관관계 분석

상관관계 계산은 두 변수 간의 선형 관계를 측정하는 데 사용되는 통계학적 방법입니다. 가장 일반적으로 사용되는 상관관계 계산 방법은 피어슨 상관 계수입니다. 상관관계 계산의 원칙, 공식, 구현 방법은 아래와 같습니다. 피어슨 상관 계수는 두 변수 간의 선형 관계를 측정하는 데 사용되며 값 범위는 -1과 1 사이입니다.

  • 1 두 변수가 항상 동시에 변하는 완벽한 양의 상관관계를 나타냅니다. 한 변수가 증가하면, 다른 변수도 비례해서 증가합니다. 1에 가까울수록 상관관계가 강해집니다.
  • -1 두 변수가 항상 반대 방향으로 변하는 완벽한 음의 상관관계를 나타냅니다. -1에 가까울수록 음의 상관관계가 강하다는 것을 의미합니다.
  • 0 선형 상관관계가 없음을 나타내며, 두 변수 사이에 직선 관계가 없습니다.

피어슨 상관계수는 공분산과 표준편차를 계산하여 두 변수 간의 상관관계를 결정합니다. 공식은 다음과 같습니다.

[ \rho_{X,Y} = \frac{\text{cov}(X,Y)}{\sigma_X \sigma_Y} ]

안에:

  • ( \rho_{X,Y} ) 변수입니다( X ) 그리고 ( Y ) 피어슨 상관계수.
  • ( \text{cov}(X,Y) ) 예 ( X ) 그리고 ( Y ) .의 공분산.
  • ( \sigma_X ) 그리고 ( \sigma_Y ) 그들은( X ) 그리고 ( Y ) .의 표준편차.

물론, 계산 방법에 대해 너무 걱정할 필요는 없습니다. 단 한 줄의 Python 코드로 모든 통화의 상관관계를 계산할 수 있습니다. 그림은 상관관계 히트 맵을 보여줍니다. 빨간색은 양의 상관관계를 나타내고, 파란색은 음의 상관관계를 나타내며, 색상이 진할수록 상관관계가 강합니다. 넓은 영역이 진한 빨간색으로 표시되어 있어 디지털 화폐의 양의 상관관계가 매우 강함을 알 수 있습니다.

디지털 화폐 페어 거래 전략에 대한 자세한 설명

import seaborn as sns
corr = df_close.corr()
plt.figure(figsize=(20, 20))
sns.heatmap(corr, annot=False, cmap='coolwarm', vmin=-1, vmax=1)
plt.title('Correlation Heatmap of Cryptocurrency Closing Prices', fontsize=20);

상관관계를 바탕으로 가장 관련성이 높은 상위 20개의 통화 쌍이 선택됩니다. 결과는 다음과 같습니다. 상관관계는 모두 0.99 이상으로 매우 강합니다.

MANA     SAND     0.996562
ICX      ZIL      0.996000
STORJ    FLOW     0.994193
FLOW     SXP      0.993861
STORJ    SXP      0.993822
IOTA     ZIL      0.993204
         SAND     0.993095
KAVA     SAND     0.992303
ZIL      SXP      0.992285
         SAND     0.992103
DYDX     ZIL      0.992053
DENT     REEF     0.991789
RDNT     MANTA    0.991690
STMX     STORJ    0.991222
BIGTIME  ACE      0.990987
RDNT     HOOK     0.990718
IOST     GAS      0.990643
ZIL      HOOK     0.990576
MATIC    FLOW     0.990564
MANTA    HOOK     0.990563

해당 코드는 다음과 같습니다.

corr_pairs = corr.unstack()

# 移除自身相关性(即对角线上的值)
corr_pairs = corr_pairs[corr_pairs != 1]

sorted_corr_pairs = corr_pairs.sort_values(kind="quicksort")

# 提取最相关和最不相关的前20个币种对
most_correlated = sorted_corr_pairs.tail(40)[::-2]

print("最相关的前20个币种对:")
print(most_correlated)

백테스팅 검증

구체적인 백테스트 코드는 다음과 같습니다. 데모 전략은 두 가지 암호화폐(IOTA와 ZIL)의 가격 비율을 관찰하고 이 비율의 변화에 ​​따라 거래하는 데 중점을 둡니다. 구체적인 단계는 다음과 같습니다.

  1. 초기화

    • 거래 쌍을 정의합니다(pair_a = ‘IOTA’, pair_b = ‘ZIL’).
    • 교환 객체 생성e초기 잔액은 10,000달러이고 거래 수수료는 0.02%입니다.
    • 초기 평균 가격 비율 계산avg
    • 초기 거래 가치 설정value = 1000
  2. 반복적으로 가격 데이터 처리

    • 각 시간 지점의 가격 데이터를 탐색합니다.df_close
    • 현재 가격 비율의 평균으로부터의 편차를 계산합니다.diff
    • 편차를 기준으로 목표 거래 가치를 계산합니다.aim_value0.01의 편차마다 하나의 값을 교환합니다. 그리고 현재 계좌 포지션과 가격 상황에 따라 매수 및 매도 작업을 결정합니다.
    • 편차가 너무 큰 경우 매도를 실행하세요.pair_a 그리고 구매하다pair_b 작동하다.
    • 편차가 너무 작으면 매수를 실행하세요.pair_a 그리고 판매하다pair_b 작동하다.
  3. 조정된 평균

    • 업데이트된 평균 가격 비율avg최신 가격 비율을 반영하기 위해.
  4. 계정 및 기록 업데이트

    • 거래소 계좌의 포지션 및 잔액 정보를 업데이트합니다.
    • 각 단계의 계정 상태(총 자산, 보유 자산, 거래 수수료, 롱 포지션 및 숏 포지션)를 기록합니다.res_list
  5. 결과 출력

    • 할 것이다 res_list 데이터 프레임으로 변환res추가 분석 및 프레젠테이션을 위해.
pair_a = 'IOTA'
pair_b = "ZIL"
e = Exchange([pair_a,pair_b], fee=0.0002, initial_balance=10000) #Exchange定义放在评论区
res_list = []
index_list = []
avg = df_close[pair_a][0] / df_close[pair_b][0]
value = 1000
for idx, row in df_close.iterrows():
    diff = (row[pair_a] / row[pair_b] - avg)/avg
    aim_value = -value * diff / 0.01
    if -aim_value + e.account[pair_a]['amount']*row[pair_a] > 0.5*value:
        e.Sell(pair_a,row[pair_a],(-aim_value + e.account[pair_a]['amount']*row[pair_a])/row[pair_a])
        e.Buy(pair_b,row[pair_b],(-aim_value - e.account[pair_b]['amount']*row[pair_b])/row[pair_b])
    if -aim_value + e.account[pair_a]['amount']*row[pair_a]  < -0.5*value:
        e.Buy(pair_a, row[pair_a],(aim_value - e.account[pair_a]['amount']*row[pair_a])/row[pair_a])
        e.Sell(pair_b, row[pair_b],(aim_value + e.account[pair_b]['amount']*row[pair_b])/row[pair_b])
    avg = 0.99*avg + 0.01*row[pair_a] / row[pair_b]
    index_list.append(idx)
    e.Update(row)
    res_list.append([e.account['USDT']['total'],e.account['USDT']['hold'],
                         e.account['USDT']['fee'],e.account['USDT']['long'],e.account['USDT']['short']])
res = pd.DataFrame(data=res_list, columns=['total','hold', 'fee', 'long', 'short'],index = index_list)
res['total'].plot(grid=True);

총 4개의 통화 그룹에 대해 백테스트를 실시하였고, 그 결과는 비교적 이상적이었습니다. 현재의 상관관계 계산은 미래의 데이터를 사용하므로 그다지 정확하지 않습니다. 이 글에서는 또한 데이터를 두 부분으로 나눕니다. 앞부분은 계산된 상관관계를 나타내고, 뒷부분은 백테스트된 거래를 나타냅니다. 결과는 약간 떨어졌지만 여전히 꽤 좋았습니다. 검증은 사용자에게 맡겨집니다.

디지털 화폐 페어 거래 전략에 대한 자세한 설명

잠재적 위험 및 개선 방법

페어 트레이딩 전략은 이론상으로는 수익성이 있을 수 있지만, 실제로 운영되는 데는 여전히 몇 가지 위험이 있습니다. 즉, 시간이 지남에 따라 통화 간 상관관계가 변하여 전략이 실패할 수 있으며, 극단적인 시장 상황에서는 가격 편차가 커져 큰 손실이 발생할 수 있습니다. 특정 통화의 유동성이 낮아 거래 실행이 어려워지거나 비용이 증가할 수 있으며, 빈번한 거래로 인해 발생하는 수수료로 인해 수익이 잠식될 수 있습니다.

위험을 줄이고 전략의 안정성을 높이기 위해 다음과 같은 개선 조치를 고려할 수 있습니다. 정기적으로 통화 간 상관관계를 다시 계산하고 거래 쌍을 적절한 시기에 조정합니다. 손절매 지점과 이익실현 지점을 설정하여 단일 거래의 최대 손실을 통제합니다. 위험을 분산하기 위해 다양한 코인 쌍을 거래하세요.

결론적으로

디지털 통화 쌍 거래 전략은 통화 가격 간의 상관관계를 활용하고, 가격이 변동할 때 차익거래를 수행하여 수익을 창출합니다. 이 전략은 이론적으로 실현 가능성이 높습니다. 이 전략을 기반으로 한 간단한 실시간 전략 소스 코드는 나중에 공개될 예정입니다. 더 궁금한 점이 있거나 추가 논의가 필요하면 언제든지 문의하세요.