Type/to search
2
Follow
480
Followers
Краткий анализ арбитражных стратегий: как воспользоваться возможностями с низким риском и короткими временными задержками
Discussions
Created 2025-03-07 14:11:55  Updated 2025-03-10 17:38:06
 0
 1806

img

Вдохновение для этой стратегии пришло из публикации автора журнала Zhihu «Dream Dealer» — «Низкорисковая корреляционная арбитражная модель TRUMP и MELANIA». В статье исследуется ценовая корреляция между двумя контрактами, запущенными на BN (TRUMP и MELANIA), и используется небольшая временная задержка между ними, чтобы попытаться уловить краткосрочные рыночные колебания и добиться арбитража с низким риском. Далее мы объясним принципы этой стратегии, логику реализации кода и рассмотрим возможные направления оптимизации.

Нужно быть заранееУведомлениеПроблема в том, что эта стратегия эквивалентна ручной торговле. Она имеет определенную возможность получения прибыли только после нахождения двух подходящих торговых пар, а срок действия прибыли торговой пары может быть коротким. Когда обнаруживается, что возможности получения прибыли нет, необходимо вовремя остановить стратегию, чтобы предотвратить просадку прибыли или даже убыток.


1. Принципы стратегии и рыночная значимость

1.1 Стратегический фон

Контракты TRUMP и MELANIA выпускаются одной и той же командой эмитентов и имеют одни и те же контролирующие фонды, поэтому их ценовые тенденции большую часть времени в высокой степени синхронизированы. Однако из-за таких факторов, как структура контракта или рыночное исполнение, цена MELANIA имеет тенденцию отставать от цены TRUMP на 1-2 секунды. Эта небольшая задержка дает арбитражерам возможность улавливать разницу в ценах и проводить высокочастотную копировальную торговлю. Проще говоря, когда TRUMP быстро колеблется, MELANIA имеет тенденцию следовать его примеру очень скоро. Используя эту задержку, транзакции могут быть завершены с меньшим риском.

img

img

1.2 Распространенность на рынке криптовалют

Подобные явления корреляции не редкость на рынке криптовалют:

  • Различные контракты или производные от одного и того же проекта: Из-за одинаковых базовых активов или опыта работы команды цены на различные продукты часто имеют тесную связь.
  • Кросс-биржевой арбитраж:Один и тот же актив на разных биржах может иметь небольшую разницу в цене из-за различий в ликвидности и механизмах сопоставления.
  • Стейблкоины и продукты, привязанные к фиату: Эти продукты часто имеют ожидаемые отклонения обменного курса, и арбитражеры могут извлечь прибыль из небольших колебаний.

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


2. Подробное объяснение логики кода

Код в основном состоит из нескольких частей, каждый модуль соответствует ключевым шагам арбитражной стратегии.

2.1 Описание вспомогательных функций

Получить информацию о позиции

javascript
function GetPosition(pair){ let pos = exchange.GetPosition(pair) if(pos.length == 0){ return {amount:0, price:0, profit:0} }else if(pos.length > 1){ throw '不支持双向持仓' }else if(pos.length == 1){ return {amount:pos[0].Type == 0 ? pos[0].Amount : -pos[0].Amount, price:pos[0].Price, profit:pos[0].Profit} }else{ Log('未获取仓位数据') return null } }
  • Функции: Эта функция используется для равномерного получения информации о позициях указанной торговой пары и преобразования длинных и коротких позиций в положительные и отрицательные числа.
  • Логика: Если позиция пуста, вернуть нулевую позицию по умолчанию; если ордеров больше одного, выдается ошибка (для обеспечения односторонней позиции); в противном случае вернуть направление, цену и плавающую прибыль и убыток текущей позиции.

Инициализировать учетную запись

javascript
function InitAccount(){ let account = _C(exchange.GetAccount) let total_eq = account.Equity let init_eq = 0 if(!_G('init_eq')){ init_eq = total_eq _G('init_eq', total_eq) }else{ init_eq = _G('init_eq') } return init_eq }
  • Функции: Эта функция используется для инициализации и записи капитала счета в качестве основы для последующих расчетов прибылей и убытков.

Отменить отложенный заказ

javascript
function CancelPendingOrders() { orders = exchange.GetOrders(); // 获取订单 for (let order of orders) { if (order.Status == ORDER_STATE_PENDING) { // 只取消未完成的订单 exchange.CancelOrder(order.Id); // 取消挂单 } } }
  • Функции: Перед размещением заказа обязательно отмените все незавершенные заказы, чтобы избежать конфликтов заказов или дублирования заказов.

2.2 Основная логика транзакции

Основная функция использует бесконечный цикл для непрерывного выполнения следующих шагов:

  1. Сбор данных и расчет рынка
    Каждый цикл начинается сexchange.GetRecords Получите рыночные данные Pair_A и Pair_B соответственно.

    • Формула расчета:
      [
      ratio = \frac{Close_{A} - Open_{A}}{Open_{A}} - \frac{Close_{B} - Open_{B}}{Open_{B}}
      ]
      Сравнивая рост и падение этих двух показателей, мы можем определить, существует ли аномальная разница в ценах. Когда разница в цене превышает заданный diffLevel, срабатывает условие открытия.
  2. Определите условия открытия и оформите заказ
    Когда текущей позиции нет (position_B.amount == 0) и торговля разрешена (afterTrade==1):

    • Если соотношение больше diffLevel, считается, что рынок собирается вырасти, поэтому выдается ордер на покупку Pair_B (длинная позиция на покупку).
    • Если коэффициент меньше -diffLevel, считается, что рынок готов упасть, и выдается ордер на продажу (открывается короткая позиция).
      Перед размещением заказа будет вызвана функция отмены заказа, чтобы убедиться, что текущий статус заказа очищен.
  3. Логика стоп-профита и стоп-лосса
    После открытия позиции стратегия установит соответствующие ордера тейк-профит и стоп-лосс в соответствии с направлением позиции:

    • Длинная позиция (покупка): Установите цену тейк-профита на цену позиции, умноженную на (1 + stopProfitLevel), а цену стоп-лосса на цену позиции, умноженную на (1 - stopLossLevel).
    • Короткая позиция (продажа): Цена тейк-профита устанавливается на уровне цены позиции, умноженной на (1 - stopProfitLevel), а цена стоп-лосса устанавливается на уровне цены позиции, умноженной на (1 + stopLossLevel).
      Система будет отслеживать рыночную цену в реальном времени. После срабатывания условий тейк-профита или стоп-лосса исходный отложенный ордер будет отменен и будет размещен ордер на закрытие позиции.
  4. Статистика прибыли и записи журнала после закрытия позиции
    После закрытия каждой позиции система получит данные об изменениях в капитале счета и подсчитает количество прибылей, количество убытков и совокупную сумму прибылей/убытков.
    При этом таблицы и графики используются для отображения информации о текущих позициях, статистики транзакций и задержек циклов в режиме реального времени, что удобно для последующего анализа эффекта стратегии.


3. Методы оптимизации и расширения стратегии

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

3.1 Оптимизация параметров и динамическая регулировка

  • Регулировка порога: Такие параметры, как diffLevel, stopProfitLevel и stopLossLevel, могут потребовать корректировки в различных рыночных условиях. Эти параметры можно автоматически оптимизировать посредством бэктестинга исторических данных или путем динамической корректировки моделей в режиме реального времени (например, алгоритмов машинного обучения).
  • Управление позицией:Текущая стратегия использует фиксированный Trade_Number для открытия позиции. В будущем мы можем рассмотреть возможность внедрения динамического управления позициями или механизма открытия позиций партиями и постепенного извлечения прибыли для снижения риска единичной сделки.

3.2 Фильтрация торговых сигналов

  • Многофакторный сигнал: Расчет коэффициента, основанный только на увеличении и уменьшении цен, может быть подвержен влиянию шума. Вы можете рассмотреть возможность введения объема торгов, глубины книги заявок и технических индикаторов (таких как RSI, MACD и т. д.) для дальнейшей фильтрации ложных сигналов.
  • Компенсация за задержку: Учитывая, что MELANIA имеет задержку в 1-2 секунды, разработка более точного механизма синхронизации времени и прогнозирования сигнала поможет повысить точность определения времени входа.

3.3 Надежность системы и контроль рисков

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

3.4 Оптимизация кода и архитектуры

  • Асинхронная обработка: В настоящее время цикл стратегии выполняется каждые 100 миллисекунд. Благодаря асинхронной обработке и многопоточной оптимизации можно снизить задержку и риск блокировки выполнения.
  • Тестирование стратегии и моделирование:Внедрить полную систему бэктестинга и имитационную торговую среду в реальном времени для проверки эффективности стратегий в различных рыночных условиях и повышения стабильности работы стратегий в реальной торговле.

IV.Заключение

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

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


Примечание: Средой тестирования стратегии является имитационная торговля OKX, и конкретные детали могут быть изменены для разных бирж.

javascript
function GetPosition(pair){ let pos = exchange.GetPosition(pair) if(pos.length == 0){ return {amount:0, price:0, profit:0} }else if(pos.length > 1){ throw '不支持双向持仓' }else if(pos.length == 1){ return {amount:pos[0].Type == 0 ? pos[0].Amount : -pos[0].Amount, price:pos[0].Price, profit:pos[0].Profit} }else{ Log('未获取仓位数据') return null } } function InitAccount(){ let account = _C(exchange.GetAccount) let total_eq = account.Equity let init_eq = 0 if(!_G('init_eq')){ init_eq = total_eq _G('init_eq', total_eq) }else{ init_eq = _G('init_eq') } return init_eq } function CancelPendingOrders() { orders = exchange.GetOrders(); // 获取订单 for (let order of orders) { if (order.Status == ORDER_STATE_PENDING) { // 只取消未完成的订单 exchange.CancelOrder(order.Id); // 取消挂单 } } } var pair_a = Pair_A + "_USDT.swap"; var pair_b = Pair_B + "_USDT.swap"; function main() { exchange.IO('simulate', true); LogReset(0); Log('策略开始运行') var precision = exchange.GetMarkets(); var ratio = 0 var takeProfitOrderId = null; var stopLossOrderId = null; var successCount = 0; var lossCount = 0; var winMoney = 0; var failMoney = 0; var afterTrade = 1; var initEq = InitAccount(); var curEq = initEq var pricePrecision = precision[pair_b].PricePrecision; while (true) { try{ let startLoopTime = Date.now(); let position_B = GetPosition(pair_b); let new_r_pairB = exchange.GetRecords(pair_b, 1).slice(-1)[0]; if (!new_r_pairB || !position_B) { Log('跳过当前循环'); continue; } // 合并交易条件:检查是否可以开仓并进行交易 if (afterTrade == 1 && position_B.amount == 0) { let new_r_pairA = exchange.GetRecords(pair_a, 1).slice(-1)[0]; if (!new_r_pairA ) { Log('跳过当前循环'); continue; } ratio = (new_r_pairA.Close - new_r_pairA.Open) / new_r_pairA.Open - (new_r_pairB.Close - new_r_pairB.Open) / new_r_pairB.Open; if (ratio > diffLevel) { CancelPendingOrders(); Log('实时ratio:', ratio, '买入:', pair_b, position_B.amount); exchange.CreateOrder(pair_b, "buy", -1, Trade_Number); afterTrade = 0; } else if (ratio < -diffLevel) { CancelPendingOrders(); Log('实时ratio:', ratio, '卖出:', pair_b, position_B.amount); exchange.CreateOrder(pair_b, "sell", -1, Trade_Number); afterTrade = 0; } } // 判断止盈止损 if (position_B.amount > 0 && takeProfitOrderId == null && stopLossOrderId == null && afterTrade == 0) { Log('多仓持仓价格:', position_B.price, '止盈价格:', position_B.price * (1 + stopProfitLevel), '止损价格:', position_B.price * (1 - stopLossLevel)); takeProfitOrderId = exchange.CreateOrder(pair_b, "closebuy", position_B.price * (1 + stopProfitLevel), position_B.amount); Log('止盈订单:', takeProfitOrderId); } if (position_B.amount > 0 && takeProfitOrderId != null && stopLossOrderId == null && new_r_pairB.Close < position_B.price * (1 - stopLossLevel) && afterTrade == 0) { CancelPendingOrders(); takeProfitOrderId = null Log('多仓止损'); stopLossOrderId = exchange.CreateOrder(pair_b, "closebuy", -1, position_B.amount); Log('多仓止损订单:', stopLossOrderId); } if (position_B.amount < 0 && takeProfitOrderId == null && stopLossOrderId == null && afterTrade == 0) { Log('空仓持仓价格:', position_B.price, '止盈价格:', position_B.price * (1 - stopProfitLevel), '止损价格:', position_B.price * (1 + stopLossLevel)); takeProfitOrderId = exchange.CreateOrder(pair_b, "closesell", position_B.price * (1 - stopProfitLevel), -position_B.amount); Log('止盈订单:', takeProfitOrderId, '当前价格:', new_r_pairB.Close ); } if (position_B.amount < 0 && takeProfitOrderId != null && stopLossOrderId == null && new_r_pairB.Close > position_B.price * (1 + stopLossLevel) && afterTrade == 0) { CancelPendingOrders(); takeProfitOrderId = null Log('空仓止损'); stopLossOrderId = exchange.CreateOrder(pair_b, "closesell", -1, -position_B.amount); Log('空仓止损订单:', stopLossOrderId); } // 平市价单未完成 if (takeProfitOrderId == null && stopLossOrderId != null && afterTrade == 0) { let stoplosspos = GetPosition(pair_b) if(stoplosspos.amount > 0){ Log('平多仓市价单未完成') exchange.CreateOrder(pair_b, 'closebuy', -1, stoplosspos.amount) } if(stoplosspos.amount < 0){ Log('平空仓市价单未完成') exchange.CreateOrder(pair_b, 'closesell', -1, -stoplosspos.amount) } } // 未平仓完毕 if (Math.abs(position_B.amount) < Trade_Number && Math.abs(position_B.amount) > 0 && afterTrade == 0){ Log('未平仓完毕') if(position_B.amount > 0){ exchange.CreateOrder(pair_b, 'closebuy', -1, position_B.amount) }else{ exchange.CreateOrder(pair_b, 'closesell', -1, -position_B.amount) } } // 计算盈亏 if (position_B.amount == 0 && afterTrade == 0) { if (stopLossOrderId != null || takeProfitOrderId != null) { stopLossOrderId = null; takeProfitOrderId = null; let afterEquity = exchange.GetAccount().Equity; let curAmount = afterEquity - curEq; curEq = afterEquity if (curAmount > 0) { successCount += 1; winMoney += curAmount; Log('盈利金额:', curAmount); } else { lossCount += 1; failMoney += curAmount; Log('亏损金额:', curAmount); } afterTrade = 1; } } if (startLoopTime % 10 == 0) { // 每 10 次循环记录一次 let curEquity = exchange.GetAccount().Equity // 输出交易信息表 let table = { type: "table", title: "交易信息", cols: [ "初始权益", "当前权益", Pair_B + "仓位", Pair_B + "持仓价", Pair_B + "收益", Pair_B + "价格", "盈利次数", "盈利金额", "亏损次数", "亏损金额", "胜率", "盈亏比" ], rows: [ [ _N(_G('init_eq'), 2), // 初始权益 _N(curEquity, 2), // 当前权益 _N(position_B.amount, 1), // Pair B 仓位 _N(position_B.price, pricePrecision), // Pair B 持仓价 _N(position_B.profit, 1), // Pair B 收益 _N(new_r_pairB.Close, pricePrecision), // Pair B 价格 _N(successCount, 0), // 盈利次数 _N(winMoney, 2), // 盈利金额 _N(lossCount, 0), // 亏损次数 _N(failMoney, 2), // 亏损金额 _N(successCount + lossCount === 0 ? 0 : successCount / (successCount + lossCount), 2), // 胜率 _N(failMoney === 0 ? 0 : winMoney / failMoney * -1, 2) // 盈亏比 ] ] }; $.PlotMultLine("ratio plot", "幅度变化差值", ratio, startLoopTime); $.PlotMultHLine("ratio plot", diffLevel, "差价上限", "red", "ShortDot"); $.PlotMultHLine("ratio plot", -diffLevel, "差价下限", "blue", "ShortDot"); LogStatus("`" + JSON.stringify(table) + "`"); LogProfit(curEquity - initEq, '&') } }catch(e){ Log('策略出现错误:', e) } Sleep(200); } }
Comment
All comments (0)
No data
No data
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)