The term “hedging” in quantitative trading and programmatic trading is a very basic concept. In cryptocurrency quantitative trading, the typical hedging strategies are: Spots-Futures hedging, intertemporal hedging and individual spot hedging.
Most of hedging tradings are based on the price difference of two trading varieties. The concept, principle and details of hedging trading may not very clear to traders who have just entered the field of quantitative trading. That’s ok, Let’s use the “Data science research environment” tool provided by the FMZ Quant platform to master these knowledge.
On FMZ Quant website Dashboard page, click on “Research” to jump to the page of this tool:
Here I uploaded this analysis file directly:
This analysis file is an analysis of the process of the opening and closing positions in a Spots-Futures hedging trading. The futures side exchange is OKEX and the contract is quarterly contract; The spots side exchange is OKEX spots trading. The transaction pair is BTC_USDT, The following specific analysis environment file, contains two version of it, both Python and JavaScript.
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":"OKEX","currency":"BTC_USDT","balance":10000,"stocks":0}] ''') # Create a backtest environment import matplotlib.pyplot as plt import numpy as np # Imported drawing library matplotlib and numpy library
exchanges[0].SetContractType("quarter") # The first exchange object OKEX futures (eid: Futures_OKCoin) calls the function that sets the current contract, set to the quarterly contract initQuarterAcc = exchanges[0].GetAccount() # Account information at the OKEX Futures Exchange, recorded in the variable initQuarterAcc initQuarterAcc
{'Balance': 0.0, 'FrozenBalance': 0.0, 'Stocks': 1.0, 'FrozenStocks': 0.0}
initSpotAcc = exchanges[1].GetAccount() # Account information at the OKEX spot exchange, recorded in the variable initSpotAcc initSpotAcc
{'Balance': 10000.0, 'FrozenBalance': 0.0, 'Stocks': 0.0, 'FrozenStocks': 0.0}
quarterTicker1 = exchanges[0].GetTicker() # Get the futures exchange market quotes, recorded in the variable quarterTicker1 quarterTicker1
{'Time': 1568851210000, 'High': 10441.25002, 'Low': 10441.25, 'Sell': 10441.25002, 'Buy': 10441.25, 'Last': 10441.25001, 'Volume': 1772.0, 'OpenInterest': 0.0}
spotTicker1 = exchanges[1].GetTicker() # Get the spot exchange market quotes, recorded in the variable spotTicker1 spotTicker1
{'Time': 1568851210000, 'High': 10156.60000002, 'Low': 10156.6, 'Sell': 10156.60000002, 'Buy': 10156.6, 'Last': 10156.60000001, 'Volume': 7.4443, 'OpenInterest': 0.0}
quarterTicker1.Buy - spotTicker1.Sell # The price difference between Short selling futures and Buying long spots
284.64999997999985
exchanges[0].SetDirection("sell") # Set up the futures exchange, the trading direction is short quarterId1 = exchanges[0].Sell(quarterTicker1.Buy, 10) # The futures are short-selled, the order quantity is 10 contracts, and the returned order ID is recorded in the variable quarterId1. exchanges[0].GetOrder(quarterId1) # Query the order details of the futures order ID is quarterId1
{'Id': 1, 'Price': 10441.25, 'Amount': 10.0, 'DealAmount': 10.0, 'AvgPrice': 10441.25, 'Type': 1, 'Offset': 0, 'Status': 1, 'ContractType': b'quarter'}
spotAmount = 10 * 100 / quarterTicker1.Buy # Calculate the number of cryptocurrency equivalent to 10 contracts, as the spots amount of the order placed spotId1 = exchanges[1].Buy(spotTicker1.Sell, spotAmount) # Spot exchange placing order exchanges[1].GetOrder(spotId1) # Query the order details of the spot order ID as spotId1
{'Id': 1, 'Price': 10156.60000002, 'Amount': 0.0957, 'DealAmount': 0.0957, 'AvgPrice': 10156.60000002, 'Type': 0, 'Offset': 0, 'Status': 1, 'ContractType': b'BTC_USDT_OKEX'}
It can be seen that the orders of the order quarterId1 and the spotId1 are all completely filled, that is, the opening position of the hedge is completed.
Sleep(1000 * 60 * 60 * 24 * 7) # Hold the position for a while, wait for the difference to become smaller and close the position.
After the waiting time has elapsed, prepare to close the position. Get the current quotes
quarterTicker2
,spotTicker2
and print. The trading direction of the futures exchange object is set to close short positions:exchanges[0].SetDirection("closesell")
to close the position. Print the details of the closing positions, showing that the closing position is completely done.
quarterTicker2 = exchanges[0].GetTicker() # Get the current market quotes of the futures exchange, recorded in the variable quarterTicker2 quarterTicker2
{'Time': 1569456010000, 'High': 8497.20002, 'Low': 8497.2, 'Sell': 8497.20002, 'Buy': 8497.2, 'Last': 8497.20001, 'Volume': 4311.0, 'OpenInterest': 0.0}
spotTicker2 = exchanges[1].GetTicker() # Get the current spot exchange market quotes, recorded in the variable spotTicker2 spotTicker2
{'Time': 1569456114600, 'High': 8444.70000001, 'Low': 8444.69999999, 'Sell': 8444.70000001, 'Buy': 8444.69999999, 'Last': 8444.7, 'Volume': 78.6273, 'OpenInterest': 0.0}
quarterTicker2.Sell - spotTicker2.Buy # The price difference of closing position between Short position of futures and the Long position of spot
52.5000200100003
exchanges[0].SetDirection("closesell") # Set the current trading direction of the futures exchange to close short position quarterId2 = exchanges[0].Buy(quarterTicker2.Sell, 10) # The futures exchange closing positions, and records the order ID, recorded to the variable quarterId2 exchanges[0].GetOrder(quarterId2) # Query futures closing position orders detail
{'Id': 2, 'Price': 8497.20002, 'Amount': 10.0, 'DealAmount': 10.0, 'AvgPrice': 8493.95335, 'Type': 0, 'Offset': 1, 'Status': 1, 'ContractType': b'quarter'}
spotId2 = exchanges[1].Sell(spotTicker2.Buy, spotAmount) # The spot exchange place order to closing positions, and records the order ID, recorded to the variable spotId2 exchanges[1].GetOrder(spotId2) # Query spots closing order details
{'Id': 2, 'Price': 8444.69999999, 'Amount': 0.0957, 'DealAmount': 0.0957, 'AvgPrice': 8444.69999999, 'Type': 1, 'Offset': 0, 'Status': 1, 'ContractType': b'BTC_USDT_OKEX'}
nowQuarterAcc = exchanges[0].GetAccount() # Get current futures exchange account information, recorded in the variable nowQuarterAcc nowQuarterAcc
{'Balance': 0.0, 'FrozenBalance': 0.0, 'Stocks': 1.021786026184, 'FrozenStocks': 0.0}
nowSpotAcc = exchanges[1].GetAccount() # Get current spot exchange account information, recorded in the variable nowSpotAcc nowSpotAcc
{'Balance': 9834.74705446, 'FrozenBalance': 0.0, 'Stocks': 0.0, 'FrozenStocks': 0.0}
Calculate the profit and loss of this hedging operation by comparing the initial account with the current account.
diffStocks = abs(nowQuarterAcc.Stocks - initQuarterAcc.Stocks) diffBalance = nowSpotAcc.Balance - initSpotAcc.Balance if nowQuarterAcc.Stocks - initQuarterAcc.Stocks > 0 : print("profit:", diffStocks * spotTicker2.Buy + diffBalance) else : print("profit:", diffBalance - diffStocks * spotTicker2.Buy)
收益: 18.72350977580652
Below we look at why the hedge is profitable. We can see the chart drawn, the futures price is the blue line, the spot price is the orange line, both prices are falling, and the futures price is falling faster than the spot price.
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()
<Figure size 432x288 with 1 Axes>
Let us look at the changes in the price difference. The difference is 284 when the hedge is opened (that is, shorting the futures, longing the spot), reaching 52 when the position is closed (the futures short positions are closed, and the spot long positions are closed). The difference is from big to small.
xDiff = [1, 2] yDiff = [quarterTicker1.Buy - spotTicker1.Sell, quarterTicker2.Sell - spotTicker2.Buy] plt.plot(xDiff, yDiff, linewidth=5) plt.show()
<Figure size 432x288 with 1 Axes>
Let me give an example, a1 is the futures price of time 1, and b1 is the spot price of time 1. A2 is the futures price at time 2, and b2 is the spot price at time 2.
As long as a1-b1, that is, the futures-spot price difference of time 1 is greater than the futures-spot price difference of a2-b2 of time 2, a1 - a2 > b1 - b2 can be introduced. There are three cases: (the futures-spot holding position are the same size)
a1 - a2 is greater than 0, b1 - b2 is greater than 0, a1 - a2 is the difference in futures profit, b1 - b2 is the difference in spot loss (because the spot is long position, the price of opening position is higher than the price of closing position, therefore, the position loses money), but the futures profit is greater than the spot loss. So the overall trading operation is profitable. This case corresponds to the chart in step In[8]
.
a1 - a2 is greater than 0, b1 - b2 is less than 0, a1 - a2 is the difference of futures profit, b1 - b2 is the difference of spot profit (b1 - b2 is less than 0, indicating that b2 is greater than b1, that is, the price of opening the position is low, the price of selling the position is high, so the position make profit)
a1 - a2 is less than 0, b1 - b2 is less than 0, a1 - a2 is the difference of futures losses, b1 - b2 is the difference of spot profit due to a1 - a2 > b1 - b2, the absolute value of a1 - a2 is less than b1 - b2 Absolute value, the profit of the spot is greater than the loss of the futures. So the overall trading operation is profitable.
There is no case where a1 - a2 is less than 0 and b1 - b2 is greater than 0, because a1 - a2 > b1 - b2 have been defined. Similarly, if a1 - a2 is equal to 0, since a1 - a2 > b1 - b2 is defined, b1 - b2 must be less than 0. Therefore, as long as the futures are short position and the spot are long position in a long-term hedging method, which meets the conditions a1 - b1 > a2 - b2, the opening and closing position operation is the profit hedging.
For example, the following model is one of the cases:
a1 = 10 b1 = 5 a2 = 11 b2 = 9 if a1 - b1 > a2 - b2: print(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()
True <Figure size 432x288 with 1 Axes>
Research environment not only supports Python, but also supports JavaScript Below I also give an example of a JavaScript research environment:
// Import the required package, click "Save Backtest Settings" on the FMZ Quant "Strategy Editing Page" to get the string configuration and convert it to an object. var fmz = require("fmz") // Automatically import talib, TA, plot library 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":"OKEX","currency":"BTC_USDT","balance":10000,"stocks":0}] })
exchanges[0].SetContractType("quarter") // The first exchange object OKEX futures (eid: Futures_OKCoin) calls the function that sets the current contract, set to the quarterly contract var initQuarterAcc = exchanges[0].GetAccount() // Account information at the OKEX Futures Exchange, recorded in the variable initQuarterAcc initQuarterAcc
{ Balance: 0, FrozenBalance: 0, Stocks: 1, FrozenStocks: 0 }
var initSpotAcc = exchanges[1].GetAccount() // Account information at the OKEX spot exchange, recorded in the variable initSpotAcc initSpotAcc
{ Balance: 10000, FrozenBalance: 0, Stocks: 0, FrozenStocks: 0 }
var quarterTicker1 = exchanges[0].GetTicker() // Get the futures exchange market quotes, recorded in the variable quarterTicker1 quarterTicker1
{ Time: 1568851210000, High: 10441.25002, Low: 10441.25, Sell: 10441.25002, Buy: 10441.25, Last: 10441.25001, Volume: 1772, OpenInterest: 0 }
var spotTicker1 = exchanges[1].GetTicker() // Get the spot exchange market quotes, recorded in the variable spotTicker1 spotTicker1
{ Time: 1568851210000, High: 10156.60000002, Low: 10156.6, Sell: 10156.60000002, Buy: 10156.6, Last: 10156.60000001, Volume: 7.4443, OpenInterest: 0 }
quarterTicker1.Buy - spotTicker1.Sell // the price difference between Short selling futures and long buying spot
284.64999997999985
exchanges[0].SetDirection("sell") // Set up the futures exchange, the trading direction is shorting var quarterId1 = exchanges[0].Sell(quarterTicker1.Buy, 10) // The futures are short-selled, the order quantity is 10 contracts, and the returned order ID is recorded in the variable quarterId1. exchanges[0].GetOrder(quarterId1) // Query the order details of the futures order ID is quarterId1
{ Id: 1, Price: 10441.25, Amount: 10, DealAmount: 10, AvgPrice: 10441.25, Type: 1, Offset: 0, Status: 1, ContractType: 'quarter' }
var spotAmount = 10 * 100 / quarterTicker1.Buy // Calculate the number of cryptocurrency equivalent to 10 contracts, as the amount of the order placed var spotId1 = exchanges[1].Buy(spotTicker1.Sell, spotAmount) // Spot exchange placing order exchanges[1].GetOrder(spotId1) // Query the order details of the spot order ID as spotId1
{ Id: 1, Price: 10156.60000002, Amount: 0.0957, DealAmount: 0.0957, AvgPrice: 10156.60000002, Type: 0, Offset: 0, Status: 1, ContractType: 'BTC_USDT_OKEX' }
It can be seen that the orders of the order quarterId1 and the spotId1 are all completely filled, that is, the opening of the hedge is completed.
Sleep(1000 * 60 * 60 * 24 * 7) // Hold the position for a while, wait for the difference to become smaller and close the position.
等待时间过后,准备平仓。获取当前的行情
quarterTicker2
、spotTicker2
并且打印。 期货交易所对象的交易方向设置为平空仓:exchanges[0].SetDirection("closesell")
下单平仓。 打印平仓订单的详情,显示平仓订单完全成交,平仓完成。
var quarterTicker2 = exchanges[0].GetTicker() // Get the current market quote of the futures exchange, recorded in the variable quarterTicker2 quarterTicker2
{ Time: 1569456010000, High: 8497.20002, Low: 8497.2, Sell: 8497.20002, Buy: 8497.2, Last: 8497.20001, Volume: 4311, OpenInterest: 0 }
var spotTicker2 = exchanges[1].GetTicker() // Get the current spot exchange market quotes, recorded in the variable spotTicker2 spotTicker2
{ Time: 1569456114600, High: 8444.70000001, Low: 8444.69999999, Sell: 8444.70000001, Buy: 8444.69999999, Last: 8444.7, Volume: 78.6273, OpenInterest: 0 }
quarterTicker2.Sell - spotTicker2.Buy // the price difference between the short position of futures and the long position of spot
52.5000200100003
exchanges[0].SetDirection("closesell") // Set the current trading direction of the futures exchange to close short position var quarterId2 = exchanges[0].Buy(quarterTicker2.Sell, 10) // The futures exchange place orders to close position, and records the order ID, recorded to the variable quarterId2 exchanges[0].GetOrder(quarterId2) // Query futures closing position order details
{ Id: 2, Price: 8497.20002, Amount: 10, DealAmount: 10, AvgPrice: 8493.95335, Type: 0, Offset: 1, Status: 1, ContractType: 'quarter' }
var spotId2 = exchanges[1].Sell(spotTicker2.Buy, spotAmount) // The spot exchange place orders to close position, and records the order ID, recorded to the variable spotId2 exchanges[1].GetOrder(spotId2) // Query spot closing position order details
{ Id: 2, Price: 8444.69999999, Amount: 0.0957, DealAmount: 0.0957, AvgPrice: 8444.69999999, Type: 1, Offset: 0, Status: 1, ContractType: 'BTC_USDT_OKEX' }
var nowQuarterAcc = exchanges[0].GetAccount() // Get current futures exchange account information, recorded in the variable nowQuarterAcc nowQuarterAcc
{ Balance: 0, FrozenBalance: 0, Stocks: 1.021786026184, FrozenStocks: 0 }
var nowSpotAcc = exchanges[1].GetAccount() // Get current spot exchange account information, recorded in the variable nowSpotAcc nowSpotAcc
{ Balance: 9834.74705446, FrozenBalance: 0, Stocks: 0, FrozenStocks: 0 }
Calculate the profit and loss of this hedging operation by comparing the initial account with the current account.
var diffStocks = Math.abs(nowQuarterAcc.Stocks - initQuarterAcc.Stocks) var diffBalance = nowSpotAcc.Balance - initSpotAcc.Balance if (nowQuarterAcc.Stocks - initQuarterAcc.Stocks > 0) { console.log("profit:", diffStocks * spotTicker2.Buy + diffBalance) } else { console.log("profit:", diffBalance - diffStocks * spotTicker2.Buy) }
收益: 18.72350977580652
Below we look at why the hedge is profitable. We can see the chart drawn, the futures price is the blue line, the spot price is the orange line, both prices are falling, and the futures price is falling faster than the spot price.
var objQuarter = { "index" : [1, 2], // The index 1 for the first moment, the opening position time, and 2 for the closing position 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}])
Let us look at the changes in the price difference. The difference is 284 when the hedge is opened (that is, shorting the futures, longing the spot), reaching 52 when the position is closed (the futures short positions are closed, and the spot long positions are closed). The difference is from big to small.
var arrDiffPrice = [quarterTicker1.Buy - spotTicker1.Sell, quarterTicker2.Sell - spotTicker2.Buy] plot(arrDiffPrice)
Let me give an example, a1 is the futures price of time 1, and b1 is the spot price of time 1. A2 is the futures price at time 2, and b2 is the spot price at time 2.
As long as a1-b1, that is, the futures-spot price difference of time 1 is greater than the futures-spot price difference of a2-b2 of time 2, a1 - a2 > b1 - b2 can be introduced. There are three cases: (the futures-spot holding position are the same size)
a1 - a2 is greater than 0, b1 - b2 is greater than 0, a1 - a2 is the difference in futures profit, b1 - b2 is the difference in spot loss (because the spot is long position, the price of opening position is higher than the price of closing position, therefore, the position loses money), but the futures profit is greater than the spot loss. So the overall trading operation is profitable. This case corresponds to the chart in step In[8]
.
a1 - a2 is greater than 0, b1 - b2 is less than 0, a1 - a2 is the difference of futures profit, b1 - b2 is the difference of spot profit (b1 - b2 is less than 0, indicating that b2 is greater than b1, that is, the price of opening the position is low, the price of selling the position is high, so the position make profit)
a1 - a2 is less than 0, b1 - b2 is less than 0, a1 - a2 is the difference of futures losses, b1 - b2 is the difference of spot profit due to a1 - a2 > b1 - b2, the absolute value of a1 - a2 is less than b1 - b2 Absolute value, the profit of the spot is greater than the loss of the futures. So the overall trading operation is profitable.
There is no case where a1 - a2 is less than 0 and b1 - b2 is greater than 0, because a1 - a2 > b1 - b2 have been defined. Similarly, if a1 - a2 is equal to 0, since a1 - a2 > b1 - b2 is defined, b1 - b2 must be less than 0. Therefore, as long as the futures are short position and the spot are long position in a long-term hedging method, which meets the conditions a1 - b1 > a2 - b2, the opening and closing position operation is the profit hedging.
For example, the following model is one of the cases:
var a1 = 10 var b1 = 5 var a2 = 11 var b2 = 9 // a1 - b1 > a2 - b2 get : 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}])