Classificação de futuros de moeda digital

Autora:Sonhos pequenos, Criado: 2021-07-02 14:35:34, Atualizado: 2023-09-21 21:09:56

img

Classificação de futuros de moeda digital

Recentemente, o grupo oficial da FMZ discutiu mais estratégias do tipo Martin, e não houve muitas estratégias de Martin sobre contratos de moeda digital na plataforma. Por isso, aproveitei a oportunidade para criar uma estratégia de Martin simples para futuros de moeda digital. Por que dizer estratégia de Martin, pois o risco potencial é grande, não foi totalmente projetado de acordo com a estratégia de Martin?

Este artigo trata principalmente de aprender a partir do design de estratégias do tipo Martin, e a ideia estratégica em si já está bem clara. Como usuários do FMZ, nós pensamos mais no design estratégico.

Acesso a direitos e benefícios coletivos

Quando se desenha uma estratégia de futuros de moeda digital, é frequente usar os dados de ganhos totais; porque os ganhos são calculados, especialmente quando os ganhos flutuantes são calculados; porque os valores mobiliários ocupam o valor da garantia, os títulos pendentes também ocupam; quando se chama a interface API da plataforma FMZ.exchange.GetAccount()Os dados obtidos são os ativos disponíveis e os ativos congelados. Na verdade, a maioria das exchanges de futuros de moeda digital fornece esse dado, mas o FMZ não possui um pacote uniforme para esse atributo.

Então, nós criamos funções diferentes para cada uma das bolsas, para obter esses dados:

// OKEX V5 获取总权益
function getTotalEquity_OKEX_V5() {
    var totalEquity = null 
    var ret = exchange.IO("api", "GET", "/api/v5/account/balance", "ccy=USDT")
    if (ret) {
        try {
            totalEquity = parseFloat(ret.data[0].details[0].eq)
        } catch(e) {
            Log("获取账户总权益失败!")
            return null
        }
    }
    return totalEquity
}

// 币安期货
function getTotalEquity_Binance() {
    var totalEquity = null 
    var ret = exchange.GetAccount()
    if (ret) {
        try {
            totalEquity = parseFloat(ret.Info.totalWalletBalance)
        } catch(e) {
            Log("获取账户总权益失败!")
            return null
        }
    }
    return totalEquity
}

No códigototalEquityE então nós escrevemos uma função como uma entrada de chamada, para chamar a função correspondente de acordo com o nome da troca.

function getTotalEquity() {
    var exName = exchange.GetName()
    if (exName == "Futures_OKCoin") {
        return getTotalEquity_OKEX_V5()
    } else if (exName == "Futures_Binance") {
        return getTotalEquity_Binance()
    } else {
        throw "不支持该交易所"
    }
}

Desenhar algumas funções auxiliares

Antes de projetar funções principais, a lógica principal. Também precisamos fazer alguns preparativos para projetar funções auxiliares.

  • Cancelar todas as listas pendentes atuais

    function cancelAll() {
        while (1) {
            var orders = _C(exchange.GetOrders)
            if (orders.length == 0) {
                break
            }
            for (var i = 0 ; i < orders.length ; i++) {
                exchange.CancelOrder(orders[i].Id, orders[i])
                Sleep(500)
            }
            Sleep(500)
        }
    }
    

    Esta função é, acredito, familiar para quem frequenta o código do exemplo de estratégia no FMZ Strategy Square, onde muitas estratégias usaram um design semelhante.

  • Operações de sub-ordens de futuros

    function trade(distance, price, amount) {
        var tradeFunc = null 
        if (distance == "buy") {
            tradeFunc = exchange.Buy
        } else if (distance == "sell") {
            tradeFunc = exchange.Sell
        } else if (distance == "closebuy") {
            tradeFunc = exchange.Sell
        } else {
            tradeFunc = exchange.Buy
        }
        exchange.SetDirection(distance)
        return tradeFunc(price, amount)
    }
    
    function openLong(price, amount) {
        return trade("buy", price, amount)
    }
    
    function openShort(price, amount) {
        return trade("sell", price, amount)
    }
    
    function coverLong(price, amount) {
        return trade("closebuy", price, amount)
    }
    
    function coverShort(price, amount) {
        return trade("closesell", price, amount)
    }
    

    A negociação de futuros tem quatro direções: aberto longo, aberto curto, aberto curto, aberto curto, aberto curto e aberto curto. Portanto, projetamos quatro funções de sub-ordens para corresponder a essas operações. Se considerarmos apenas sub-ordens, existem alguns fatores necessários: direção, preço do sub-ordem e volume do sub-ordem. Por isso, também criamos um projeto chamado:tradeA função para tratar quando方向(distance)下单价格(price)下单量(amount)A maioria das vezes, o que é preciso é uma operação clara. As chamadas de funções openLong, openShort, coverLong e coverShort são feitas por uma única pessoa.tradeA função executa a função real, ou seja, encomenda no mercado de futuros de acordo com uma direção, preço ou quantidade estabelecida.

Função principal

A ideia estratégica é simples: pendurar a venda ("fazer vazios") ou a compra ("fazer mais") a uma certa distância abaixo do preço atual na linha de base. Ao concluir o negócio, todos os pedidos remanescentes são cancelados e, em seguida, um novo pedido de liquidação é pendurado a uma certa distância de acordo com o preço do estoque, pendurando um pedido de aumento de estoque no preço atual após a atualização, mas sem dobrar o volume do pedido.

  • Trabalho inicial Para fazer a listagem, precisamos de duas variáveis globais para registrar o ID do pedido.

    var buyOrderId = null
    var sellOrderId = null
    

    A opção de usar o disco OKEX_V5 é então projetada nos parâmetros da interface da política, então há algumas manipulações a serem feitas no código:

    var exName = exchange.GetName()    
    // 切换OKEX V5模拟盘
    if (isSimulate && exName == "Futures_OKCoin") {
        exchange.IO("simulate", true)
    }
    

    A interface também tem uma opção para reiniciar todas as informações, então o código também tem um tratamento correspondente:

    if (isReset) {
        _G(null)
        LogReset(1)
        LogProfitReset()
        LogVacuum()
        Log("重置所有数据", "#FF0000")
    }
    

    Nós apenas corremos um contrato perpétuo, então aqui está escrito que morremos, apenas estabelecidos como um contrato perpétuo.

    exchange.SetContractType("swap")
    

    Então, devemos também considerar o problema da precisão do preço do pedido, da precisão do pedido, se a precisão não for bem definida, a precisão é perdida no cálculo da estratégia, muitos números fracos de dados podem facilmente causar a rejeição da interface do mercado quando o pedido é feito.

    exchange.SetPrecision(pricePrecision, amountPrecision)
    Log("设置精度", pricePrecision, amountPrecision)
    

    Funções de recuperação de dados simples de desenhar

    if (totalEq == -1 && !IsVirtual()) {
        var recoverTotalEq = _G("totalEq")
        if (!recoverTotalEq) {
            var currTotalEq = getTotalEquity()
            if (currTotalEq) {
                totalEq = currTotalEq
                _G("totalEq", currTotalEq)
            } else {
                throw "获取初始权益失败"
            }
        } else {
            totalEq = recoverTotalEq
        }
    }
    

    Se você quiser especificar o total de direitos da conta inicial quando a política for executada, você pode definir o parâmetrototalEqSe o parâmetro for definido como -1, a política lê os dados de benefícios totais armazenados. Se não tiver dados de benefícios totais armazenados, o benefício total inicial é o benefício total da estratégia, com o benefício total atualmente lido como o progresso da execução da estratégia.

  • A lógica principal Após o trabalho inicial, finalmente chegamos à parte da lógica principal da estratégia, e para facilitar a explicação, eu escrevi diretamente a explicação na notação do código.

      while (1) {                                  // 策略主要逻辑设计为一个死循环
          var ticker = _C(exchange.GetTicker)      // 首先读取当前行情信息,主要用到最新成交价
          var pos = _C(exchange.GetPosition)       // 读取当前持仓数据
          if (pos.length > 1) {                    // 判断持仓数据,由于这个策略的逻辑,是不太可能同时出现多空持仓的,所以发现同时出现多空持仓就抛出错误
              Log(pos)
              throw "同时有多空持仓"                  // 抛出错误,让策略停止
          }
          // 根据状态而定
          if (pos.length == 0) {                    // 根据持仓状态做出不同操作,pos.length == 0是当没有持仓时
              // 未持仓了,统计一次收益
              if (!IsVirtual()) {
                  var currTotalEq = getTotalEquity()
                  if (currTotalEq) {
                      LogProfit(currTotalEq - totalEq, "当前总权益:", currTotalEq)
                  }
              }
    
              buyOrderId = openLong(ticker.Last - targetProfit, amount)       // 挂开多仓的买单
              sellOrderId = openShort(ticker.Last + targetProfit, amount)     // 挂开空仓的卖单
          } else if (pos[0].Type == PD_LONG) {   // 有多头持仓,挂单位置、数量有所不同
              var n = 1
              var price = ticker.Last
              buyOrderId = openLong(price - targetProfit * n, amount)
              sellOrderId = coverLong(pos[0].Price + targetProfit, pos[0].Amount)
          } else if (pos[0].Type == PD_SHORT) {   // 有空头持仓,挂单位置、数量有所不同
              var n = 1
              var price = ticker.Last
              buyOrderId = coverShort(pos[0].Price - targetProfit, pos[0].Amount)
              sellOrderId = openShort(price + targetProfit * n, amount)
          }
    
          if (!sellOrderId || !buyOrderId) {   // 如果有一边挂单失败就取消所有挂单,重来
              cancelAll()
              buyOrderId = null 
              sellOrderId = null
              continue
          } 
    
          while (1) {  // 挂单完成,开始监控订单
              var isFindBuyId = false 
              var isFindSellId = false
              var orders = _C(exchange.GetOrders)
              for (var i = 0 ; i < orders.length ; i++) {
                  if (buyOrderId == orders[i].Id) {
                      isFindBuyId = true 
                  }
                  if (sellOrderId == orders[i].Id) {
                      isFindSellId = true 
                  }               
              }
              if (!isFindSellId && !isFindBuyId) {    // 检测到买卖单都成交了
                  cancelAll()
                  break
              } else if (!isFindBuyId) {   // 检测到买单成交
                  Log("买单成交")
                  cancelAll()
                  break
              } else if (!isFindSellId) {  // 检测到卖单成交
                  Log("卖单成交")
                  cancelAll()
                  break
              }
              LogStatus(_D())
              Sleep(3000)
          }
          Sleep(500)
      }
    

A lógica e o projeto são explicados.

Revisão

A estratégia deve passar por uma experiência do dia 19 de maio.

img

img

Como pode ser visto, a estratégia do tipo Martin ainda é um pouco arriscada.

Discos reais podem ser jogados em simulação de corrida com o OKEX V5

img

A estratégia é endereçada:https://www.fmz.com/strategy/294957

A estratégia é usada principalmente para a aprendizagem, e o ouro e a prata são usados com cuidado ~!


Relacionados

Mais.

Lisa20231O que é que ele está a fazer? if (!isFindSellId &&!isFindBuyId) { // detecta que todas as encomendas foram feitas Quando se detecta um pedido, se o comprador fizer um comprovativo de compra e venda ao mesmo tempo, e se o comprador fizer um comprovativo de compra e venda ao mesmo tempo, será um erro?

Neo1898A outra questão é se o modelo de contrato é de estoque inteiro ou de estoque por estoque.

Neo1898Se o contrato foi aberto, por que não foi estabelecido o dobro do contrato? Quantas vezes a venda é feita?

Nuvens levesGraças a DreamDa, eu finalmente entendo tudo. Depois, aprendeu a monitorar a lista pendurada e escreveu um Martin bilateral. Durante dois dias, escreveu 580 linhas. Graças ao seu esforço.

hk quantidade/upload/asset/1a9ebf427c4e2cbf1c327.png Falso verdadeiro em troca?

Sonhos custam oito dígitosSe

Sonhos custam oito dígitosTotal dos direitos de propriedade

zeroO que fazer para parar o dano?

btcrobotMartin, refazemos e é zero.

WqyE se você não percebe o número de dígitos é igual a igual, então o n é sempre igual a 1.

LvdaleiA estratégia é multi-espaço, duplo-aberto ou separado?

Sonhos pequenosNão lança erros. Ainda cancela todos os pedidos pendurados, salta do ciclo atual e continua a fazer a lógica.

Sonhos pequenosEm geral, é melhor usar o estoque inteiro.

Sonhos pequenosA alavancagem pode ser definida no mercado, dependendo das preferências de risco.

Sonhos pequenosO total de nuvens é 666!

Sonhos pequenosEssa variável é chamada isFindBuyId e não é apropriada.

Sonhos pequenosA estratégia não foi projetada para parar o prejuízo.

Sonhos pequenosHa ha, o destino de Martin. Este artigo é principalmente sobre estratégias de ensino, sem muita atenção.

Sonhos pequenosEsse N é usado para alterações posteriores, como pensar em n vezes a distância de armazenamento, que pode ser definida temporariamente como 1⁄2.

Sonhos pequenosO que você está fazendo é errado.