3
Подписаться
1444
Подписчики

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

Создано: 2024-07-05 16:23:42, Обновлено: 2024-11-05 17:42:06
comments   3
hits   5800

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

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

введение

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

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

Стратегический принцип

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

Предположим, что монета A и монета B имеют высокую ценовую корреляцию. В определенный момент среднее значение соотношения цен 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) # 获取所有的正在交易的交易对

Скачать функцию K-line

Основная функция функции GetKlines — получение исторических данных K-line бессрочного контракта указанной торговой пары с биржи Binance и сохранение этих данных в Pandas DataFrame. Данные K-line включают цену открытия, максимальную цену, минимальную цену, цену закрытия, объем торгов и другую информацию. На этот раз мы в основном используем данные о ценах закрытия.

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-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_value, для каждого отклонения в 0,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 группы валют, и результаты оказались относительно идеальными. Текущий расчет корреляции использует будущие данные, поэтому он не очень точный. В этой статье данные также делятся на две части: на основе расчета корреляции в начале и бэк-тестирования транзакций в конце. Результаты были немного не такими, но все равно довольно хорошими. Проверку осуществляет сам пользователь.

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

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

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

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

в заключение

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