В процессе загрузки ресурсов... загрузка...

Подробное объяснение стратегии торговли парой цифровых валют

Автор:FMZ~Lydia, Создано: 2024-07-08 11:41:23, Обновлено: 2024-11-05 17:43:03

img

Введение

Недавно я увидел в количественном дневнике BuOu упоминание о том, что вы можете использовать отрицательно коррелированные валюты для выбора валют и открывать позиции для получения прибыли на основе прорывов в цене. Цифровые валюты в основном положительно коррелируют, и только несколько валют отрицательно коррелируют, часто со специальными рыночными условиями, такими как независимые рыночные условия MEME монет, которые полностью отличаются от рыночной тенденции. Эти валюты могут быть выбраны и продолжаться долго после прорыва. Этот метод может приносить прибыль в определенных рыночных условиях. Однако наиболее распространенным методом в области количественной торговли является использование положительной корреляции для парной торговли. Эта статья кратко представит эту стратегию.

Торговля цифровыми валютными парами - это торговая стратегия, основанная на статистическом арбитраже, которая одновременно покупает и продает две высококоррелированные криптовалюты для получения прибыли от отклонений цен.

Принцип стратегии

Стратегии торговли парами опираются на историческую корреляцию между ценами двух цифровых валют. Когда цены двух валют показывают сильную корреляцию, их ценовые тенденции, как правило, синхронизируются. Если соотношение цен между ними значительно отклоняется в определенный момент, это может считаться временной аномалией, и цена будет иметь тенденцию возвращаться к нормальному уровню. Рынок цифровых валют сильно взаимосвязан. Когда крупная цифровая валюта (такая как Биткойн) значительно колеблется, это обычно вызывает скоординированную реакцию в других цифровых валютах.

Предположим, что валюта А и валюта В имеют высокую ценовую корреляцию. В определенный момент среднее значение соотношения цен A/B составляет 1. Если в определенный момент соотношение цен A/B отклоняется более чем на 0,001, то есть более чем на 1,001, то вы можете торговать следующими способами: Открыть длинную позицию на B и открыть короткую позицию на A. Напротив, когда соотношение цен A/B ниже 0,999: Открыть длинную позицию на A и открыть короткую позицию на B.

Ключ к рентабельности заключается в увеличении спреда, когда цены отклоняются от среднего и возвращаются в нормальное состояние.

Подготовка данных

Импорт соответствующей библиотеки

Эти коды можно использовать напрямую. Лучше всего скачать Anancoda и отлаживать его в ноутбуке Jupyer. Он включает пакеты для прямого анализа данных.

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) # Get all trading pairs being traded

Загрузить функцию K-линии

Основная функция функции GetKlines заключается в получении исторических данных K-линии указанного торгового пара вечного контракта с биржи Binance и хранении данных в Pandas DataFrame.

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

Загрузить данные

Объем данных относительно велик. Для быстрой загрузки получаются только почасовые данные K-линии за последние три месяца. 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')

Двигатель обратного тестирования

Мы определяем объект обмена для следующего обратного теста.

class Exchange:
    def __init__(self, trade_symbols, fee=0.0002, 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, '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 #Deduction fee
        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  #profit
            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 the assets
        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 означает отсутствие линейной корреляции, нет прямолинейных отношений между двумя переменными.

Коэффициент корреляции Пирсона определяет корреляцию между двумя переменными путем расчета их ковариантности и стандартного отклонения.

img

в которых:

  • imgявляется коэффициентом корреляции Пирсона между переменными X и Y.
  • imgКовариантность X и Y.
  • imgиimgстандартные отклонения X и Y соответственно.

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

img

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()

# Remove self-correlation (i.e. values ​​on the diagonal)
corr_pairs = corr_pairs[corr_pairs != 1]

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

# Extract the top 20 most and least correlated currency pairs
most_correlated = sorted_corr_pairs.tail(40)[::-2]

print("The top 20 most correlated currency pairs are:")
print(most_correlated)

Проверка обратного тестирования

Конкретный код бэкстеста выглядит следующим образом. Демонстрационная стратегия в основном наблюдает ценовое соотношение двух криптовалют (IOTA и ZIL) и торгует в соответствии с изменениями в этом соотношении. Конкретные шаги следующие:

  1. Инициализация:
  • Определите торговые пары (pair_a = IOTA, pair_b = ZIL).
  • Создать объект обменаeс первоначальным балансом $10,000 и комиссией за транзакцию в размере 0.02%.
  • Расчет первоначального соотношения средней ценыavg.
  • Установите начальное значение транзакцииvalue = 1000.
  1. Итерация данных о ценах:
  • Пройдите через данные о ценах в каждом этапе времениdf_close.
  • Вычисляет отклонение соотношения текущей цены от среднегоdiff.
  • Целевая стоимость сделки рассчитывается на основе отклоненияaim_valueОперации по покупке и продаже определяются на основе текущей позиции счета и ценовой ситуации.
  • Если отклонение слишком большое, выполните продажуpair_aи купитьpair_b operations.
  • Если отклонение слишком маленькое, купитьpair_aи продатьpair_bоперации выполняются.
  1. Настройка средней:
  • Обновляет соотношение средних ценavgчтобы отразить последние коэффициенты цен.
  1. Обновление счетов и записей:
  • Обновление информации о позиции и балансе обменного счета.
  • Запись состояния счета на каждом этапе (общий объем активов, удерживаемые активы, комиссии за транзакции, длинные и короткие позиции)res_list.
  1. Результат выхода:
  • Преобразоватьres_listк системе данныхresдля дальнейшего анализа и представления.
pair_a = 'IOTA'
pair_b = "ZIL"
e = Exchange([pair_a,pair_b], fee=0.0002, initial_balance=10000) #Exchange definition is placed in the comments section
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 группы валют были проверены, и результаты были идеальными. Текущий расчет корреляции использует будущие данные, поэтому он не очень точен. Эта статья также делит данные на две части, основываясь на предыдущем расчете корреляции и последующей торговой обратной проверке. Результаты немного отличаются, но неплохи. Мы оставляем пользователю практиковать и проверять.

img

Потенциальные риски и способы улучшения

Хотя стратегия торговли парой может быть прибыльной в теории, все еще существуют некоторые риски в фактической работе: корреляция между валютами может меняться с течением времени, в результате чего стратегия может потерпеть неудачу; при экстремальных рыночных условиях отклонения цен могут увеличиться, что приводит к большим потерям; низкая ликвидность некоторых валют может затруднить выполнение сделок или увеличить расходы; а сборы, генерируемые частыми операциями, могут снизить прибыль.

Для снижения рисков и повышения стабильности стратегий можно рассмотреть следующие меры улучшения: регулярно пересчитывать корреляцию между валютами и своевременно корректировать торговые пары; устанавливать точки остановки потери и получения прибыли для контроля максимальной потери одной сделки; торговать несколькими валютными парами одновременно для диверсификации рисков.

Заключение

Стратегия торговли цифровыми валютными парами достигает прибыли, используя взаимосвязь цен на валюту и выполняя арбитражные операции при отклонении цен. Эта стратегия имеет высокую теоретическую осуществимость. Простой исходный код стратегии торговли на основе этой стратегии будет выпущен позже. Если у вас есть дополнительные вопросы или необходимо дальнейшее обсуждение, пожалуйста, не стесняйтесь общаться.


Больше