Термин "хеджирование" является очень базовым понятием в области количественной торговли и программной торговли. В количественной торговле цифровой валютой часто используются стратегии хеджирования: фьючерс-спот хеджирование, кросс-период хеджирование и спот хеджирование, которые по сути являются операциями на ценовые различия. Может быть, когда дело доходит до концепции, принципа и деталей хеджирования, многие студенты, которые только начали заниматься количественной торговлей, все еще не очень понятны.
В панели FMZ Quant кликните на
Здесь я загружаю файл анализа напрямую:
Этот анализ представляет собой анализ процесса открытия и закрытия позиции хеджирования фьючерс-спота во время обратного тестирования.quarter
Спотный обмен представляет собой транзакцию валют-валюты OKX, а торговая пара -BTC_USDT
. Для анализа процесса работы фьючерс-спот хеджирования, вы можете увидеть следующий конкретный файл исследовательской среды, написанный в двух версиях: версия языка Python, версия языка JavaScript.
Анализ принципа хеджирования фьючерсов на месте.ipynb В [1]:
from fmz import *
task = VCtx('''backtest
start: 2019-09-19 00:00:00
end: 2019-09-28 12:00:00
period: 15m
exchanges: [{"eid":"Futures_OKCoin","currency":"BTC_USD", "stocks":1}, {"eid":"OKX","currency":"BTC_USDT","balance":10000,"stocks":0}]
''')
# Create backtesting environment
import matplotlib.pyplot as plt
import numpy as np
# Import the plot library matplotlib and library numpy
В [2]:
exchanges[0].SetContractType("quarter") # The first exchange object OKX Futures (eid: Futures_OKCoin) calls the function to set the current contract as a quarterly contract
initQuarterAcc = exchanges[0].GetAccount() # The initial account information of OKX Futures Exchange is recorded in the variable initQuarterAcc
initQuarterAcc
Выбыли[2]:
{
В [3]:
initSpotAcc = exchanges[1].GetAccount() # The initial account information of the OKX Spot Exchange is recorded in the variable initSpotAcc
initSpotAcc
Выход[3]:
{
В [4]:
quarterTicker1 = exchanges[0].GetTicker() # Get the futures exchange ticker, recorded in the variable quarterTicker1
quarterTicker1
Выход[4]:
Время: 1568851210000,
В [5]:
spotTicker1 = exchanges[1].GetTicker() # Get the spot exchange ticker, recorded in the variable spotTicker1
spotTicker1
Выход[5]:
Время: 1568851210000,
В [6]:
quarterTicker1.Buy - spotTicker1.Sell # The price difference between going short on futures and going long on spot.
Выход[6]: 284.64999997999985
В [7]:
exchanges[0].SetDirection("sell") # Set up a futures exchange and trade in the direction of going short
quarterId1 = exchanges[0].Sell(quarterTicker1.Buy, 10) # Futures go short to place orders. The order quantity is 10 contracts. The returned order ID is recorded in the variable quarterId1.
exchanges[0].GetOrder(quarterId1) # Check the details of the order with futures order ID quarterId1.
Выход[7]:
Идентификатор: 1,
В [8]:
spotAmount = 10 * 100 / quarterTicker1.Buy # Calculate the currency equivalent of 10 contracts as the order quantity of the spot.
spotId1 = exchanges[1].Buy(spotTicker1.Sell, spotAmount) # Place orders on the spot exchange
exchanges[1].GetOrder(spotId1) # Check the order details of the spot order ID of spotId1
Вне[8]:
Идентификатор: 1,
Вы можете видеть, что заказы quarterId1 и spotId1 полностью выполнены, т.е. хеджирование открытых позиций завершено.
В [9]:
Sleep(1000 * 60 * 60 * 24 * 7) # Hold the position for a while and wait for the price difference to become smaller to close the position.
После времени ожидания, приготовьтесь закрыть позицию.quarterTicker2
, spotTicker2
и распечатать их.
Направление сделки объекта биржи фьючерсов настроено на закрытие короткой позиции:exchanges[0].SetDirection("closesell")
разместить ордер на закрытие позиции.
Напечатать данные ордера закрытия позиции, указывающие, что ордер закрытия завершен, позиция закрытия завершена.
В [10]:
quarterTicker2 = exchanges[0].GetTicker() # Get the current futures exchange ticker, recorded in the variable quarterTicker2
quarterTicker2
Выход[10]:
Время: 1569456010000,
В [11]:
spotTicker2 = exchanges[1].GetTicker() # Get the current ticker of the spot exchange, recorded in the variable spotTicker2
spotTicker2
Выход[11]:
Время: 1569456114600,
В [12]:
quarterTicker2.Sell - spotTicker2.Buy # The price difference between closing a short futures position and closing a long spot position.
Выход[12]: 52.5000200100003
В [13]:
exchanges[0].SetDirection("closesell") # Set the current trading direction of the futures exchange to close short positions.
quarterId2 = exchanges[0].Buy(quarterTicker2.Sell, 10) # The futures exchange places an order to close a position and records the order ID to the variable quarterId2.
exchanges[0].GetOrder(quarterId2) # Check futures close out order details
Выход[13]:
Идентификатор: 2,
В [14]:
spotId2 = exchanges[1].Sell(spotTicker2.Buy, spotAmount) # The spot exchange places an order to close a position and records the order ID, which is recorded to the variable spotId2.
exchanges[1].GetOrder(spotId2) # Check spot close out order details
Выход[14]:
Идентификатор: 2,
В [15]:
nowQuarterAcc = exchanges[0].GetAccount() # Get the current futures exchange account information, recorded in the variable nowQuarterAcc.
nowQuarterAcc
Выход[15]:
{
В [16]:
nowSpotAcc = exchanges[1].GetAccount() # Get the current spot exchange account information, recorded in the variable nowSpotAcc.
nowSpotAcc
Выход[16]:
(Ставка: 9834.74705446,
При сравнении первоначального счета с текущим счетом рассчитывается прибыль и убыток операции хеджирования.
В [17]:
diffStocks = abs(nowQuarterAcc.Stocks - initQuarterAcc.Stocks)
diffBalance = nowSpotAcc.Balance - initSpotAcc.Balance
if nowQuarterAcc.Stocks - initQuarterAcc.Stocks > 0 :
print("profits:", diffStocks * spotTicker2.Buy + diffBalance)
else :
print("profits:", diffBalance - diffStocks * spotTicker2.Buy)
Выход[17]: Прибыль: 18,72350977580652
Теперь давайте посмотрим, почему хеджирование выгодно. Мы можем увидеть рисунок. Цена фьючерса - синяя линия, а спотовая цена - оранжевая линия. Обе цены падают. Цена фьючерса падает быстрее, чем спотовая цена.
В [18]:
xQuarter = [1, 2]
yQuarter = [quarterTicker1.Buy, quarterTicker2.Sell]
xSpot = [1, 2]
ySpot = [spotTicker1.Sell, spotTicker2.Buy]
plt.plot(xQuarter, yQuarter, linewidth=5)
plt.plot(xSpot, ySpot, linewidth=5)
plt.show()
Выход[18]:
Давайте посмотрим на изменение ценовой разницы. Ценовая разница варьируется от 284 в момент хеджирования открывающей позиции (т.е. фьючерсы становятся короткими, а спот длинными) до 52 в момент закрытия позиции (фьючерсы короткие позиции закрываются, спот длинные позиции закрываются).
В [19]:
xDiff = [1, 2]
yDiff = [quarterTicker1.Buy - spotTicker1.Sell, quarterTicker2.Sell - spotTicker2.Buy]
plt.plot(xDiff, yDiff, linewidth=5)
plt.show()
Выход[19]:
Например, a1 - это цена фьючерса в момент 1, а b1 - спотовая цена в момент 1. A2 - это цена фьючерса в момент 2, а b2 - спотовая цена в момент 2.До тех пор, пока разница спотовой цены фьючерсов в момент 1 (a1-b1) больше, чем разница спотовой цены фьючерсов в момент 2 (a2-b2), может быть введена a1 - a2>b1 - b2. Существует три ситуации: (количество фьючерсных и спотовых позиций одинаковое)
a1 - a2 больше 0, b1 - b2 больше 0 a1 - a2 относится к ценовой разнице прибыли фьючерсов, а b1 - b2 относится к ценовой разнице спотовых потерь (поскольку спот ушел в длинный, цена начала покупки выше цены продажи для закрытия позиции, поэтому деньги теряются), но прибыли фьючерсов больше, чем спотовые убытки. Таким образом, это прибыльно в целом. Эта ситуация соответствует графику в шаге В [8].
a1 - a2 больше 0, b1 - b2 меньше 0 a1 - a2 - ценовая разница прибыли от фьючерсов, а b1 - b2 - ценовая разница прибыли от спотов (b1 - b2 меньше 0, что указывает на то, что b2 больше, чем b1, то есть цена открытия и покупки позиции низкая, а цена продажи и закрытия высокая, поэтому она прибыльна).
a1 - a2 меньше 0, b1 - b2 меньше 0 a1 - a2 - это ценовая разница фьючерсных убытков, а b1 - b2 - ценовая разница спотовых прибылей. Поскольку a1 - a2 > b1 - b2, абсолютная стоимость a1 - a2 меньше абсолютной стоимости b1 - b2, и спотовые прибыли больше, чем фьючерсные убытки.
Нет случая, когда a1 - a2 меньше 0, а b1 - b2 больше 0, потому что a1 - a2 > b1 - b2 было определено. Аналогично, если a1 - a2 равна 0, так как a1 - a2 > b1 - b2 определено, b1 - b2 должно быть меньше 0, поэтому, пока метод хеджирования коротких фьючерсов и длинных спотов отвечает условиям a1 - b1 > a2 - b2, операции по открытию и закрытию позиций являются хеджированием прибыли.
Например, следующая модель является одним из случаев:
В [20]:
a1 = 10
b1 = 5
a2 = 11
b2 = 9
# a1 - b1 > a2 - b2 launches: a1 - a2 > b1 - b2
xA = [1, 2]
yA = [a1, a2]
xB = [1, 2]
yB = [b1, b2]
plt.plot(xA, yA, linewidth=5)
plt.plot(xB, yB, linewidth=5)
plt.show()
Выход[20]:
Исследовательская среда поддерживает не только Python, но и JavaScript Я также приведу пример исследовательской среды JavaScript:
Анализ принципа хеджирования фьючерсных спотов (JavaScript).ipynb В [1]:
// Import the required package, click "Save settings" on the FMZ's "Strategy editing page" to get the string configuration and convert it to an object.
var fmz = require("fmz") // Import the talib, TA, and plot libraries automatically after import
var task = fmz.VCtx({
start: '2019-09-19 00:00:00',
end: '2019-09-28 12:00:00',
period: '15m',
exchanges: [{"eid":"Futures_OKCoin","currency":"BTC_USD","stocks":1},{"eid":"OKX","currency":"BTC_USDT","balance":10000,"stocks":0}]
})
В [2]:
exchanges[0].SetContractType("quarter") // The first exchange object OKX Futures (eid: Futures_OKCoin) calls the function to set the current contract as a quarterly contract.
var initQuarterAcc = exchanges[0].GetAccount() // The initial account information of OKX Futures Exchange is recorded in the variable initQuarterAcc.
initQuarterAcc
Выход[2]: { Баланс: 0, FrozenBalance: 0, Запасы: 1, FrozenStocks: 0 }
В [3]:
var initSpotAcc = exchanges[1].GetAccount() // The initial account information of the OKX Spot Exchange is recorded in the variable initSpotAcc.
initSpotAcc
Выход[3]: { Баланс: 10000, FrozenBalance: 0, Запасы: 0, FrozenStocks: 0 }
В [4]:
var quarterTicker1 = exchanges[0].GetTicker() // Get the futures exchange ticker, recorded in the variable quarterTicker1.
quarterTicker1
Выход[4]: { Время: 1568851210000, Высокий: 10441,25002, Низкий уровень: 10441,25. Продать: 10441.25002, Купить: 10441.25, Последнее: 10441.25001, Объем: 1772 Открытый интерес:
В [5]:
var spotTicker1 = exchanges[1].GetTicker() // Get the spot exchange ticker, recorded in the variable spotTicker1.
spotTicker1
Выход[5]: Время: 1568851210000, Высокий: 10156.60000002, Низкий уровень: 10156,6. Продать: 10156.60000002, Купить: 10156.6, Последнее: 10156.60000001, Объем: 7.4443, Открытый интерес:
В [6]:
quarterTicker1.Buy - spotTicker1.Sell // The price difference between going short on futures and going long on spot.
Выход[6]: 284.64999997999985 В [7]:
exchanges[0].SetDirection("sell") // Set up a futures exchange and trade in the direction of going short
var quarterId1 = exchanges[0].Sell(quarterTicker1.Buy, 10) // Go short futures to place orders. The order quantity is 10 contracts. The returned order ID is recorded in the variable quarterId1.
exchanges[0].GetOrder(quarterId1) // Check the details of the order with futures order ID quarterId1.
Выход[7]:
{ Идентификатор: 1,
Цена: 10441.25,
Сумма: 10
Сумма сделки: 10,
Средняя цена: 10441,25.
Тип: 1,
Сдвиг: 0,
Статус: 1,
Контракт тип:
В [8]:
var spotAmount = 10 * 100 / quarterTicker1.Buy // Calculate the currency equivalent of 10 contracts as the order quantity of the spot.
var spotId1 = exchanges[1].Buy(spotTicker1.Sell, spotAmount) // Place orders on the spot exchange.
exchanges[1].GetOrder(spotId1) // Check the order details of the spot order ID of spotId1.
Вне[8]:
{ Идентификатор: 1,
Цена: 10156,60000002,
Сумма: 0,0957,
Сумма сделки: 0,0957,
Средняя цена: 10156.60000002,
Тип: 0,
Сдвиг: 0,
Статус: 1,
Контракт тип:
Вы можете видеть, что заказы quarterId1 и spotId1 полностью выполнены, т.е. хеджирование открытых позиций завершено.
В [9]:
Sleep(1000 * 60 * 60 * 24 * 7) // Hold the position for a while and wait for the price difference to become smaller to close the position.
После времени ожидания, приготовьтесь закрыть позицию.quarterTicker2
, spotTicker2
и распечатать их.
Направление сделки объекта биржи фьючерсов настроено на закрытие короткой позиции:exchanges[0].SetDirection("closesell")
разместить ордер на закрытие позиции.
Напечатать данные ордера закрытия позиции, указывающие, что ордер закрытия завершен, позиция закрытия завершена.
В [10]:
var quarterTicker2 = exchanges[0].GetTicker() // Get the current futures exchange ticker, recorded in the variable quarterTicker2.
quarterTicker2
Выход[10]: Время: 1569456010000, Высокий: 8497.20002, Низкий показатель: 8497,2. Продать: 8497.20002, Купить: 8497.2, Последний: 8497.20001, Объем: 4311, Открытый интерес:
В [11]:
var spotTicker2 = exchanges[1].GetTicker() // Get the current ticker of the spot exchange, recorded in the variable spotTicker2.
spotTicker2
Выход[11]: { Время: 1569456114600, Высокий: 8444.70000001, Низкий уровень: 8444,69999999, Продать: 8444.70000001, Купить: 8444.69999999, Последнее: 8444,7, Объем: 78.6273, Открытый интерес:
В [12]:
quarterTicker2.Sell - spotTicker2.Buy // The price difference between closing short position of futures and closing long position of spot.
Выход[12]: 52.5000200100003
В [13]:
exchanges[0].SetDirection("closesell") // Set the current trading direction of the futures exchange to close short positions.
var quarterId2 = exchanges[0].Buy(quarterTicker2.Sell, 10) // The futures exchange places an order to close the position, and records the order ID to the variable quarterId2.
exchanges[0].GetOrder(quarterId2) // Check futures closing position order details.
Выход[13]:
Идентификатор: 2,
Цена: 8497,20002,
Сумма: 10
Сумма сделки: 10,
Средняя цена: 8493,95335,
Тип: 0,
Замещение: 1,
Статус: 1,
Контракт тип:
В [14]:
var spotId2 = exchanges[1].Sell(spotTicker2.Buy, spotAmount) // The spot exchange places an order to close the position, and records the order ID to the variable spotId2.
exchanges[1].GetOrder(spotId2) // Check spot closing position order details.
Выход[14]:
Идентификатор: 2,
Цена: 8444,69999999,
Сумма: 0,0957,
Сумма сделки: 0,0957,
Средняя цена: 8444,69999999,
Тип: 1,
Сдвиг: 0,
Статус: 1,
Контракт тип:
В [15]:
var nowQuarterAcc = exchanges[0].GetAccount() // Get the current futures exchange account information, recorded in the variable nowQuarterAcc.
nowQuarterAcc
Выход[15]: { Сальдо: 0, Замороженный баланс: 0, Запасы: 1,021786026184, ФрозенСтокс: 0 }
В [16]:
var nowSpotAcc = exchanges[1].GetAccount() // Get the current spot exchange account information, recorded in the variable nowSpotAcc.
nowSpotAcc
Выход[16]: { Остаток: 9834.74705446, Замороженный баланс: 0, Запасы: 0, Замороженные запасы: При сравнении первоначального счета с текущим счетом рассчитывается прибыль и убыток операции хеджирования.
В [17]:
var diffStocks = Math.abs(nowQuarterAcc.Stocks - initQuarterAcc.Stocks)
var diffBalance = nowSpotAcc.Balance - initSpotAcc.Balance
if (nowQuarterAcc.Stocks - initQuarterAcc.Stocks > 0) {
console.log("profits:", diffStocks * spotTicker2.Buy + diffBalance)
} else {
console.log("profits:", diffBalance - diffStocks * spotTicker2.Buy)
}
Выход[17]: Прибыль: 18,72350977580652
Теперь давайте посмотрим, почему хеджирование выгодно. Мы можем увидеть рисунок. Цена фьючерса - синяя линия, а спотовая цена - оранжевая линия. Обе цены падают. Цена фьючерса падает быстрее, чем спотовая цена.
В [18]:
var objQuarter = {
"index" : [1, 2], // The index is 1, that is, the first time, the opening time, and 2 is the closing time.
"arrPrice" : [quarterTicker1.Buy, quarterTicker2.Sell],
}
var objSpot = {
"index" : [1, 2],
"arrPrice" : [spotTicker1.Sell, spotTicker2.Buy],
}
plot([{name: 'quarter', x: objQuarter.index, y: objQuarter.arrPrice}, {name: 'spot', x: objSpot.index, y: objSpot.arrPrice}])
Выход[18]: Давайте посмотрим на изменение ценовой разницы. Ценовая разница варьируется от 284 в момент хеджирования открывающихся позиций (то есть фьючерсы шли коротко, а спот шел длинно) до 52 в момент закрытия (закрытие короткой позиции фьючерсов и закрытие длинной позиции спота).
В [19]:
var arrDiffPrice = [quarterTicker1.Buy - spotTicker1.Sell, quarterTicker2.Sell - spotTicker2.Buy]
plot(arrDiffPrice)
Выход[19]:Например, a1 - это цена фьючерса в момент 1, а b1 - спотовая цена в момент 1. A2 - это цена фьючерса в момент 2, а b2 - спотовая цена в момент 2.До тех пор, пока разница спотовой цены фьючерсов в момент 1 (a1-b1) больше, чем разница спотовой цены фьючерсов в момент 2 (a2-b2), может быть введена a1 - a2>b1 - b2. Существует три ситуации: (количество фьючерсных и спотовых позиций одинаковое)
a1 - a2 больше 0, b1 - b2 больше 0 a1 - a2 относится к ценовой разнице прибыли фьючерсов, а b1 - b2 относится к ценовой разнице спотовых потерь (поскольку спот ушел в длинный, цена начала покупки выше цены продажи для закрытия позиции, поэтому деньги теряются), но прибыли фьючерсов больше, чем спотовые убытки. Таким образом, это прибыльно в целом. Эта ситуация соответствует графику в шаге В [8].
a1 - a2 больше 0, b1 - b2 меньше 0 a1 - a2 - ценовая разница прибыли от фьючерсов, а b1 - b2 - ценовая разница прибыли от спотов (b1 - b2 меньше 0, что указывает на то, что b2 больше, чем b1, то есть цена открытия и покупки позиции низкая, а цена продажи и закрытия высокая, поэтому она прибыльна).
a1 - a2 меньше 0, b1 - b2 меньше 0 a1 - a2 - это ценовая разница фьючерсных убытков, а b1 - b2 - ценовая разница спотовых прибылей. Поскольку a1 - a2 > b1 - b2, абсолютная стоимость a1 - a2 меньше абсолютной стоимости b1 - b2, и спотовые прибыли больше, чем фьючерсные убытки.
Нет случая, когда a1 - a2 меньше 0, а b1 - b2 больше 0, потому что a1 - a2 > b1 - b2 было определено. Аналогично, если a1 - a2 равна 0, так как a1 - a2 > b1 - b2 определено, b1 - b2 должно быть меньше 0, поэтому, пока метод хеджирования коротких фьючерсов и длинных спотов отвечает условиям a1 - b1 > a2 - b2, операции по открытию и закрытию позиций являются хеджированием прибыли.
Например, следующая модель является одним из случаев:
В [20]:
var a1 = 10
var b1 = 5
var a2 = 11
var b2 = 9
// a1 - b1 > a2 - b2 launches: a1 - a2 > b1 - b2
var objA = {
"index" : [1, 2],
"arrPrice" : [a1, a2],
}
var objB = {
"index" : [1, 2],
"arrPrice" : [b1, b2],
}
plot([{name : "a", x : objA.index, y : objA.arrPrice}, {name : "b", x : objB.index, y : objB.arrPrice}])
Выход[20]:
Попробуйте, ребята!