No artigo anterior, pensamos e projetamos juntos uma estratégia de grade de múltiplas espécies simples. Em seguida, continuaremos a aprender e avançar no caminho da negociação quantitativa. Neste artigo, exploraremos um projeto de estratégia mais complexo - o projeto de estratégias de hedge. Este artigo planeja projetar uma estratégia de hedge intertemporal de múltiplas espécies. Quando se trata de estratégias de hedge intertemporal, aqueles que estão familiarizados com a negociação de futuros devem estar familiarizados com ela. Para iniciantes, eles podem não entender esses conceitos, então vamos começar com uma breve explicação do conceito de hedge intertemporal.
Simplificando, a cobertura intertemporal consiste em fazer um longo contrato, fazer um curto contrato e esperar três situações (longo e curto) para fechar a posição ao mesmo tempo:
Em outros casos, são perdas flutuantes, carregando ou continuando a escalar na posição (porque a flutuação do spread é mais moderada do que a flutuação unilateral, o risco relativo é menor, note que apenas relativo!)
Let A1 be the price of contract A at moment 1, and set B1 to be the price of contract B at moment 1. At this time, short contract A, short price A1, long contract B, and long price B1.
Let A2 be the price of contract A at moment 2, and set B2 to be the price of contract B at moment 2. At this time, close the position contract A (short), close short A2, close the position B contract (long), and close long price B2.
Moment 1 difference:A1 - B1 = X
Moment 2 difference:A2 - B2 = Y
X - Y = A1 - B1 - (A2 - B2)
X - Y = A1 - B1 - A2 + B2
X - Y = A1 - A2 + B2 - B1
It can be seen that A1 - A2 is the profit difference in closing the position of contract A.
B2 - B1 is the profit spread of closing the position of contract B. As long as the two closed positions are overall positive, ie: A1 - A2 + B2 - B1 > 0 is profitable. That is, as long as X - Y > 0.
Because of: X - Y = A1 - A2 + B2 - B1
It is concluded that as long as the difference X of opening a position is greater than the difference Y of closing a position, it is profitable (note that it is short A, long B to open a position, the reverse will be the opposite), of course, this is theoretical, practical factors such as commission and slippage should also be considered.
Porque as bolsas de criptomoedas têm contratos de entrega e contratos perpétuos. E o preço dos contratos perpétuos é sempre perto do preço ao instante devido à taxa de financiamento. Então escolhemos usar contratos de entrega e contratos perpétuos para hedge arbitragem. O contrato de entrega escolhe um contrato de longo prazo, de modo que o contrato de hedge não precisa ser definido com frequência.
Uma vez que você esteja familiarizado com os princípios básicos, você não precisa se apressar em escrever estratégias. Em primeiro lugar, você pode obter uma estatística de propagação, desenhar um gráfico e observar as propagações. Vamos aprender a desenhar uma estratégia multiespécie juntos.
Desenhamos com base noContrato OKEX. É muito simples de desenhar em FMZ. É muito fácil de usar as funções empacotadas para desenhar.Highcharts (Highcharts)Descrição da função de desenho na documentação API:https://www.fmz.com/api#chart...
Uma vez que é uma espécie multi, em primeiro lugar, é necessário determinar a diferença de preço dessas espécies antes de desenhar. no código, escrever duas matrizes primeiro, representando os contratos a serem feitos.
var arrSwapContractType = ["BTC-USDT-SWAP", "LTC-USDT-SWAP", "ETH-USDT-SWAP", "ETC-USDT-SWAP"] // Perpetual contracts
var arrDeliveryContractType = ["BTC-USDT-210924", "LTC-USDT-210924", "ETH-USDT-210924", "ETC-USDT-210924"] // Delivery contracts
Inicie a configuração do gráfico de acordo com o código de contrato definido aqui. Esta configuração do gráfico certamente não pode ser codificada, porque você não sabe quais espécies e quantas espécies fazer (estes são determinados pelos valores de arrDeliveryContractType e arrSwapContractType), então a configuração do gráfico é devolvida por uma função.
function createCfg(symbol) {
var cfg = {
extension: {
// No grouping, displayed separately, default is 'group'
layout: 'single',
// Specify the height, which can be set as a string, "300px", and the value 300 will be replaced with "300px" automatically
height: 300,
// The unit value of the specified width, the total value is 12
col: 6
},
title: {
text: symbol
},
xAxis: {
type: 'datetime'
},
series: [{
name: 'plus',
data: []
}]
}
return cfg
}
function main() {
// Declare arrCfg
var arrCfg = [] // Declare an array to store chart configuration information
_.each(arrSwapContractType, function(ct) { // Record the array of perpetual contract codes iteratively, pass the XXX-USDT part of the contract name as a parameter to the createCfg function, construct the chart configuration information, and return
arrCfg.push(createCfg(formatSymbol(ct)[0])) // The chart configuration information returned by createCfg is pushed into the arrCfg array
})
var objCharts = Chart(arrCfg) // Call the chart function Chart of the FMZ platform to create the chart control object objCharts
objCharts.reset() // Initialize chart content
// Hereafter omitted ...
}
Em seguida, vamos preparar os dados. Usamos a interface de mercado agregada do contrato OKEX:
Contratos perpétuos em USDT:
https://www.okex.com/api/v5/market/tickers?instType=SWAP
Contratos de entrega em USDT:
https://www.okex.com/api/v5/market/tickers?instType=FUTURES
Escrevemos uma função para lidar com as chamadas destas duas interfaces e colocar os dados em um formato:
function getTickers(url) {
var ret = []
try {
var arr = JSON.parse(HttpQuery(url)).data
_.each(arr, function(ele) {
ret.push({
bid1: parseFloat(ele.bidPx), // Price of stock buy order
bid1Vol: parseFloat(ele.bidSz), // Amount for the price of stock buy order
ask1: parseFloat(ele.askPx), // Price of stock sell order
ask1Vol: parseFloat(ele.askSz), // Amount for the price of stock sell order
symbol: formatSymbol(ele.instId)[0], // Formats into trading pairs
type: "Futures", // Type
originalSymbol: ele.instId // Original contract code
})
})
} catch (e) {
return null
}
return ret
}
Escrever outra função para processar o código do contrato
function formatSymbol(originalSymbol) {
var arr = originalSymbol.split("-")
return [arr[0] + "_" + arr[1], arr[0], arr[1]]
}
Tudo o que resta é emparelhar os dados adquiridos iterativamente, calcular os spreads, traçar a saída, etc. O teste aqui é o diferencial entre o contrato do segundo trimestre 210924 e o contrato perpétuo. Código completo:
// Temporary parameters
var arrSwapContractType = ["BTC-USDT-SWAP", "LTC-USDT-SWAP", "ETH-USDT-SWAP", "ETC-USDT-SWAP"]
var arrDeliveryContractType = ["BTC-USDT-210924", "LTC-USDT-210924", "ETH-USDT-210924", "ETC-USDT-210924"]
var interval = 2000
function createCfg(symbol) {
var cfg = {
extension: {
// No grouping, displayed separately, default is 'group'
layout: 'single',
// Specify the height, which can be set as a string, "300px", and the value 300 will be replaced with "300px" automatically
height: 300,
// The unit value of the specified width, the total value is 12
col: 6
},
title: {
text: symbol
},
xAxis: {
type: 'datetime'
},
series: [{
name: 'plus',
data: []
}]
}
return cfg
}
function formatSymbol(originalSymbol) {
var arr = originalSymbol.split("-")
return [arr[0] + "_" + arr[1], arr[0], arr[1]]
}
function getTickers(url) {
var ret = []
try {
var arr = JSON.parse(HttpQuery(url)).data
_.each(arr, function(ele) {
ret.push({
bid1: parseFloat(ele.bidPx),
bid1Vol: parseFloat(ele.bidSz),
ask1: parseFloat(ele.askPx),
ask1Vol: parseFloat(ele.askSz),
symbol: formatSymbol(ele.instId)[0],
type: "Futures",
originalSymbol: ele.instId
})
})
} catch (e) {
return null
}
return ret
}
function main() {
// Declare arrCfg
var arrCfg = []
_.each(arrSwapContractType, function(ct) {
arrCfg.push(createCfg(formatSymbol(ct)[0]))
})
var objCharts = Chart(arrCfg)
objCharts.reset()
while (true) {
// Obtain market data
var deliveryTickers = getTickers("https://www.okex.com/api/v5/market/tickers?instType=FUTURES")
var swapTickers = getTickers("https://www.okex.com/api/v5/market/tickers?instType=SWAP")
if (!deliveryTickers || !swapTickers) {
Sleep(2000)
continue
}
var tbl = {
type : "table",
title : "delivery - perpetual spread",
cols : ["trading pairs", "delivery", "perpetual", "positive hedging", "negative hedging"],
rows : []
}
var subscribeDeliveryTickers = []
var subscribeSwapTickers = []
_.each(deliveryTickers, function(deliveryTicker) {
_.each(arrDeliveryContractType, function(symbol) {
if (deliveryTicker.originalSymbol == symbol) {
subscribeDeliveryTickers.push(deliveryTicker)
}
})
})
_.each(swapTickers, function(swapTicker) {
_.each(arrSwapContractType, function(symbol) {
if (swapTicker.originalSymbol == symbol) {
subscribeSwapTickers.push(swapTicker)
}
})
})
var pairs = []
var ts = new Date().getTime()
_.each(subscribeDeliveryTickers, function(deliveryTicker) {
_.each(subscribeSwapTickers, function(swapTicker) {
if (deliveryTicker.symbol == swapTicker.symbol) {
var pair = {symbol: swapTicker.symbol, swapTicker: swapTicker, deliveryTicker: deliveryTicker, plusDiff: deliveryTicker.bid1 - swapTicker.ask1, minusDiff: deliveryTicker.ask1 - swapTicker.bid1}
pairs.push(pair)
tbl.rows.push([pair.symbol, deliveryTicker.originalSymbol, swapTicker.originalSymbol, pair.plusDiff, pair.minusDiff])
for (var i = 0 ; i < arrCfg.length ; i++) {
if (arrCfg[i].title.text == pair.symbol) {
objCharts.add([i, [ts, pair.plusDiff]])
}
}
}
})
})
LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`")
Sleep(interval)
}
}
A correr por um tempo.
Observe a propagação e depois fale sobre isso!