No último artigo, pensamos e projetamos uma estratégia simples de grade de múltiplos símbolos juntos. Em seguida, continuaremos a aprender e avançar no caminho da negociação quantitativa. Neste artigo, discutiremos um projeto de estratégia mais complicado - o projeto da estratégia de hedge. O artigo planeja projetar uma estratégia de hedge de período cruzado de múltiplos símbolos. Quando se trata de estratégia de hedge de período cruzado, aqueles que estão familiarizados com a negociação de futuros devem estar familiarizados com ela. Para iniciantes, você pode não entender esses conceitos, então vamos explicar brevemente os conceitos sobre hedge de período cruzado.
De um modo geral, a cobertura de período cruzado tem um contrato de fazer longo e um contrato de fazer curto e espera três situações (longo, curto) para fechar posições ao mesmo tempo:
Para outras situações em que existem perdas flutuantes, pode manter ou continuar a adicionar mais posições. (porque a flutuação do spread é menor do que a flutuação unilateral, o risco será menor, mas note que é apenas comparativo!)
Set A1 as the price of contract A at the time 1, and set B1 as the price of contract B at the time 1. At the time, do short in contract A, at A1; do long in contract B, at B1.
Set A2 as the price of contract A at the time 2, and set B2 as the price of contract B at the time 2. At the time, close positions (close short) of contract A, at A2; close positions (close long) of contract B, at B2.
Spread at time 1: A1 - B1 = X
Spread at time 2: A2 - B2 = Y
X - Y = A1 - B1 - (A2 - B2)
X - Y = A1 - B1 - A2 + B2
X - Y = A1 - A2 + B2 - B1
As you can see, "A1 - A2 " is the profit spread of closing position in contract A.
"B2 - B1" is the profit spread of closing position in contract B. It is profitable, as long as the closing postion spread of the two contracts is a positive number, namely A1 - A2 + B2 - B1 > 0. That is to say as long as X - Y > 0,
for: X - Y = A1 - A2 + B2 - B1
It is concluded that as long as the spread X when opening a position is greater than the spread Y when closing a position, it is profitable (note that it is making short in contract A and making long in contract B to open a position; if the situation is reversed, the result will be opposite). Of course, this is just theoretical, and factors such as the handling fee and slippoint should also be considered in practice.
Porque as plataformas de criptomoeda têm contratos de entrega e contratos perpétuos. E o preço dos contratos perpétuos é sempre próximo do preço ao instante devido à taxa de financiamento. Então escolhemos usar contratos de entrega e contratos perpétuos para fazer hedge e arbitragem. Para o contrato de entrega, podemos escolher um com um período comparativamente longo, para que o contrato de hedge não precise ser definido com frequência.
Depois de familiarizar-se com o princípio básico, você não precisa se apressar em escrever a estratégia. Primeiro, faça estatísticas de spread, gráficos de gráficos e observe os spreads. Nós projetamos com base emContrato OKEXÉ muito fácil de traçar em FMZ, e você só precisa usar a função encapsulada, com a biblioteca de gráficosHighcharts (Highcharts). A descrição da função de gráfico na documentação da API:https://www.fmz.com/api#chart..- Não. Uma vez que é uma estratégia multi-símbolo, em primeiro lugar, é necessário determinar o spread de preço desses símbolos antes de traçar.
var arrSwapContractType = ["BTC-USDT-SWAP", "LTC-USDT-SWAP", "ETH-USDT-SWAP", "ETC-USDT-SWAP"] // perpetual contract
var arrDeliveryContractType = ["BTC-USDT-210924", "LTC-USDT-210924", "ETH-USDT-210924", "ETC-USDT-210924"] // delivery contract
De acordo com o código de contrato definido aqui, inicialize a configuração do gráfico. A configuração do gráfico não pode ser escrita em um loop infinito, porque você não sabe qual símbolo fazer e quantos símbolos fazer (que são determinados de acordo com os valores de arrDeliveryContractType e arrSwapContractType), então a configuração do gráfico é devolvida por uma função.
function createCfg(symbol) {
var cfg = {
extension: {
// it is not part of the group, and is individually displayed; the default is 'group'
layout: 'single',
// the specified height, which can be set as string; "300px", which means it will be replaced by "300px" automatically through setting a value of 300
height: 300,
// the occupied unit value of the specified width, with a total value of 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 the chart configuration information
_.each(arrSwapContractType, function(ct) { // iteratively record the array of perpetual contract codes, 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 "push" returned by "createCfg" is in the "arrCfg" array
})
var objCharts = Chart(arrCfg) // call the function Chart on FMZ platform, and create a chart controlled object called objCharts
objCharts.reset() // initialize the chart content
// the rest is omitted...
}
Vamos preparar os dados; usamos a interface de mercado agregada do contrato OKEX:
Contrato perpétuo USDT:
https://www.okex.com/api/v5/market/tickers?instType=SWAP
Contrato de entrega em USDT:
https://www.okex.com/api/v5/market/tickers?instType=FUTURES
Aqui escrevemos uma função para lidar com a invocação das duas interfaces, e processar 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), // buy one price
bid1Vol: parseFloat(ele.bidSz), // volume of buy one price
ask1: parseFloat(ele.askPx), // ell one price
ask1Vol: parseFloat(ele.askSz), // volume of sell one price
symbol: formatSymbol(ele.instId)[0], // in the format of trading pair
type: "Futures", // type
originalSymbol: ele.instId // original contract code
})
})
} catch (e) {
return null
}
return ret
}
Escreva mais uma 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]]
}
Em seguida, só precisamos iterar e combinar os dados obtidos, calcular os spreads e traçar gráficos para exportar, etc.
Aqui testamos o spread do contrato do próximo trimestre 210924 e do 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: {
// it is not part of the group, and is individually displayed; the default is 'group'
layout: 'single',
// the specified height, which can be set as string; "300px", which means it will be replaced by "300px" automatically through setting a value of 300
height: 300,
// the occupied unit value of the specified width, with a total value of 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 the market quote 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 pair", "delivery", "perpetual", "positive hedge", "negative hedge"],
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)
}
}
Foge por uns tempos.
Observe primeiro os espalhamentos!