No artigo anterior, implementamos uma estratégia de hedge simples juntos, e então vamos aprender como atualizar essa estratégia. As mudanças de estratégia não são grandes, mas os detalhes das mudanças precisam de atenção.
A exchange -> B exchange
, B exchange -> A exchange
, e desenhar a linha horizontal que desencadeia a propagação.line drawing class library
A vantagem é que é fácil de usar, aqui também aprendemos como usar otemplate class library
Função da FMZ.Em seguida, vamos implementar estes projetos um por um.
Pegue Binance spot real bot como um exemplo, mudar para o local alavancado modo, usar o códigoexchanges[i].IO
, introduzir o parâmetrotrade_normal
para mudar para posição de alavancagem por posição e entrada,trade_super_margin
para mudar para alavancagem posição total, backtesting não é suportado.
Adicionar à fase de preparação no início domain
Função:
// Switch leverage mode
for (var i = 0 ; i < exchanges.length ; i++) { // Traverse and detect all added exchange objects
if (exchanges[i].GetName() == "Binance" && marginType != 0) { //If the exchange object represented by the current i-index is Binance spot, and the parameter marginType of the strategy interface is not the option of "common currency", execute the switch operation
if (marginType == 1) {
Log(exchanges[i].GetName(), "Set to leveraged position-by-position")
exchanges[i].IO("trade_normal")
} else if (marginType == 2) {
Log(exchanges[i].GetName(), "Set to leveraged full position")
exchanges[i].IO("trade_super_margin")
}
}
}
A estratégia aqui só adiciona o código para mudar o modo de alavancagem moeda para moeda do Binance spot, então a configuração do interruptor nos parâmetros da estratégia é válida apenas para o Binance spot.
É muito fácil de usar o modelo de desenho já embrulhado.Line Drawing Library
Pode ser obtido pesquisando diretamente no quadrado de estratégia da plataforma FMZ.
Ou clique diretamente no link:https://www.fmz.com/strategy/27293para saltar para a página de cópia para este modelo.
Clique no botão para copiar esta biblioteca de classe modelo para sua própria biblioteca de estratégia.
Em seguida, você pode verificar a biblioteca de classes de modelo a ser usada na coluna de modelo na página de edição de estratégia. Salve a estratégia depois de verificá-la, e a estratégia irá se referir a este modelo. Esta é apenas uma breve descrição do uso da biblioteca de classes de modelo. Esta estratégia já fez referência a este modelo, por isso não há necessidade de repetir a operação. Quando você copia esta estratégia no quadrado de estratégia, você pode ver queLine Drawing Library
foi referenciado na barra de modelo na página de edição da estratégia.
Aprenderemos principalmente como utilizar as funções doLine Drawing Library
para desenhar um gráfico.
Planejamos desenhar a propagação deA->B
, a disseminação deB->A
Precisamos desenhar duas curvas (currente A para B, B para A spread), duas linhas horizontais (trigger spread line), como mostrado na figura acima.
Porque queremos projetar cobertura unilateral, as linhas de gatilho deA->B
eB->A
Não podemos usar o desenho do artigo anterior.
No artigo anterior:
var targetDiffPrice = hedgeDiffPrice
if (diffAsPercentage) {
targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
}
Só há um disparo.targetDiffPrice
- Não.
Então aqui temos que transformar o código, transformar os parâmetros primeiro.
Então, modifique o código:
var targetDiffPriceA2B = hedgeDiffPriceA2B
var targetDiffPriceB2A = hedgeDiffPriceB2A
if (diffAsPercentage) {
targetDiffPriceA2B = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentageA2B
targetDiffPriceB2A = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentageB2A
}
Desta forma, a diferença linha gatilho mudou a partir do anteriortargetDiffPrice
A dois.targetDiffPriceA2B
, targetDiffPriceB2A
- Não.
O próximo passo é desenhar esses dados no gráfico usando a função de linha de desenho da biblioteca de desenho de linha.
// drawing
$.PlotHLine(targetDiffPriceA2B, "A->B") // The first parameter of this function is the value of the horizontal line in the Y-axis direction, and the second parameter is the display text
$.PlotHLine(targetDiffPriceB2A, "B->A")
Quando a estratégia está em execução, há um gráfico como este.
Em seguida, desenhe a curva de spread em tempo real, para evitar exagerar a linha. Coloque o código que desenha a curva dos dados de spread em tempo real na verificação de saldo.
if (ts - lastKeepBalanceTS > keepBalanceCyc * 1000) {
nowAccs = _C(updateAccs, exchanges)
var isBalance = keepBalance(initAccs, nowAccs, [depthA, depthB])
cancelAll()
if (isBalance) {
lastKeepBalanceTS = ts
if (isTrade) {
var nowBalance = _.reduce(nowAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
var initBalance = _.reduce(initAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
LogProfit(nowBalance - initBalance, nowBalance, initBalance, nowAccs)
isTrade = false
}
}
$.PlotLine("A2B", depthA.Bids[0].Price - depthB.Asks[0].Price) // Draw real-time spread curves
$.PlotLine("B2A", depthB.Bids[0].Price - depthA.Asks[0].Price) // The first parameter is the name of the curve, and the second parameter is the value of the curve at the current moment, that is, the value in the Y-axis direction at the current moment
}
Desta forma, o código de desenho é de apenas 4 linhas, permitindo que a estratégia tenha um gráfico exibido no tempo de execução.
Como mencionado acima, a linha de desencadeamento do spread foi modificada em duas, controlando o desencadeador de cobertura deA->B
eB->A
Assim, não se pode utilizar o algoritmo anterior do preço da encomenda e, em vez disso, utiliza-se o método de adição do preço de saída ao preço de mercado.
if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPriceA2B && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) { // A -> B market conditions are met
var priceSell = depthA.Bids[0].Price - slidePrice
var priceBuy = depthB.Asks[0].Price + slidePrice
var amount = Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount)
if (nowAccs[0].Stocks > minHedgeAmount && nowAccs[1].Balance * 0.8 / priceSell > minHedgeAmount) {
amount = Math.min(amount, nowAccs[0].Stocks, nowAccs[1].Balance * 0.8 / priceSell, maxHedgeAmount)
Log("trigger A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[1].Balance * 0.8 / priceSell, nowAccs[0].Stocks) // Tips
hedge(exB, exA, priceBuy, priceSell, amount)
cancelAll()
lastKeepBalanceTS = 0
isTrade = true
}
} else if (depthB.Bids[0].Price - depthA.Asks[0].Price > targetDiffPriceB2A && Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount) >= minHedgeAmount) { // B -> A market conditions are met
var priceBuy = depthA.Asks[0].Price + slidePrice
var priceSell = depthB.Bids[0].Price - slidePrice
var amount = Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount)
if (nowAccs[1].Stocks > minHedgeAmount && nowAccs[0].Balance * 0.8 / priceBuy > minHedgeAmount) {
amount = Math.min(amount, nowAccs[1].Stocks, nowAccs[0].Balance * 0.8 / priceBuy, maxHedgeAmount)
Log("trigger B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[0].Balance * 0.8 / priceBuy, nowAccs[1].Stocks) //Tips
hedge(exA, exB, priceBuy, priceSell, amount)
cancelAll()
lastKeepBalanceTS = 0
isTrade = true
}
}
Uma vez que os preços de compra e venda são separados em dois dados, a função de coberturahedge
O que é que se passa?
function hedge(buyEx, sellEx, priceBuy, priceSell, amount) {
var buyRoutine = buyEx.Go("Buy", priceBuy, amount)
var sellRoutine = sellEx.Go("Sell", priceSell, amount)
Sleep(500)
buyRoutine.wait()
sellRoutine.wait()
}
Há também alguns ajustes menores baseados nestas alterações, que não serão repetidos aqui.
Adicionar interação à estratégia, para que a estratégia possa modificar a linha de gatilho de propagação em tempo real. Primeiro, adicione controles de interação à estratégia na página de edição de estratégia.
Adicionou dois controles, um chamado A2B e outro chamado B2A. Depois de inserir um valor na caixa de entrada de controle, clique no botão à direita da caixa de entrada. Uma instrução será enviada para a estratégia imediatamente, por exemplo: inserir o valor123
na caixa de entrada, clique noA2B
O botão, e uma instrução será enviada para a estratégia imediatamente.
A2B:123
Projetar código de detecção e processamento interativo no código de estratégia.
// interact
var cmd = GetCommand() // Every time the loop is executed here, it checks whether there is an interactive command, and returns to an empty string if not.
if (cmd) { // An interactive command was detected, such as A2B:123
Log("command received:", cmd)
var arr = cmd.split(":") // Split out the interactive control name and the value in the input box, arr[0] is A2B, arr[1] is 123
if (arr[0] == "A2B") { // Determine whether the triggered interactive control is A2B
Log("Modify the parameters of A2B, ", diffAsPercentage ? "The parameter is the difference percentage" : "The parameter is the difference:", arr[1])
if (diffAsPercentage) {
hedgeDiffPercentageB2A = parseFloat(arr[1]) // Modify the trigger spread line
} else {
hedgeDiffPriceA2B = parseFloat(arr[1]) // Modify the trigger spread line
}
} else if (arr[0] == "B2A") { // Triggered control detected is B2A
Log("Modify the parameters of B2A, ", diffAsPercentage ? "The parameter is the difference percentage" : "The parameter is the difference:", arr[1])
if (diffAsPercentage) {
hedgeDiffPercentageA2B = parseFloat(arr[1])
} else {
hedgeDiffPriceB2A = parseFloat(arr[1])
}
}
}
Torne a exibição dos dados da barra de status mais organizada e fácil de observar.
var tbl = {
"type" : "table",
"title" : "data",
"cols" : ["exchange", "coin", "freeze coin", "denominated currency", "freeze denominated currency", "trigger spread", "current spread"],
"rows" : [],
}
tbl.rows.push(["A:" + exA.GetName(), nowAccs[0].Stocks, nowAccs[0].FrozenStocks, nowAccs[0].Balance, nowAccs[0].FrozenBalance, "A->B:" + targetDiffPriceA2B, "A->B:" + (depthA.Bids[0].Price - depthB.Asks[0].Price)])
tbl.rows.push(["B:" + exB.GetName(), nowAccs[1].Stocks, nowAccs[1].FrozenStocks, nowAccs[1].Balance, nowAccs[1].FrozenBalance, "B->A:" + targetDiffPriceB2A, "B->A:" + (depthB.Bids[0].Price - depthA.Asks[0].Price)])
LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
O backtesting é apenas uma estratégia de teste, uma função de detecção preliminar, e muitos bugs podem ser testados na fase de backtesting na verdade.
Código fonte da estratégia:https://www.fmz.com/strategy/302834