O recurso está a ser carregado... Carregamento...

Tutorial primário de escrita de estratégia com a plataforma de negociação quântica FMZ (precisa ser lido)

Autora:FMZ~Lydia, Criado: 2023-07-12 15:09:33, Atualizado: 2024-02-05 20:05:43

[TOC]

img

Este tutorial contém conhecimentos básicos de escrita de estratégia, incluindo API introdução, backtest, gráficos e muito mais. Depois de aprender este tutorial básico, os usuários serão capazes de usar a API básica proficientemente e escrever uma estratégia de bot estável. Antes de aprender o tutorial, você precisa aprender como usarComece a plataforma FMZ Quant.

Tutorial da versão antiga:FMZ Quant (FMZ.COM) Manual de Escrita de Estratégia 2.0 (Tutorial)Há muitos índices de postagens no tutorial, que são recomendados para ler.

Instruções Preliminares sobre a Escrita de Estratégias

API Introdução

O programa de negociação é o uso de programas para se conectar com plataformas através de API para alcançar a compra e venda automática ou outras funções de acordo com a intenção do projeto.

Atualmente, existem dois protocolos principais de interface para plataformas de criptomoedas: REST e Websocket. Cada vez que o protocolo REST obtém dados, ele precisa ser acessado uma vez. Vamos tomar a API da plataforma simulada Wex.app como exemplo. Abra o [link] (https://api.wex.app/api/v1/public/ticker?market=BTC_USDT) diretamente no navegador e você pode obter o resultado da seguinte forma:

{"data:{"buy":"11351.73","high":"11595.77","last":"11351.85","low":"11118.45","open":"11358.74","quoteVol":"95995607137.00903936","sell":"11356.02","time":1565593489318,"vol":"3552.5153"}}

Desta forma, você pode ver que a negociação seguindo as últimas cotações de mercado do par de negociação BTC_USDT, mudará a cada vez que for atualizado; market=" é seguido pelos parâmetros específicos do par de negociação, que podem ser modificados para obter outros dados do par de negociação. Para interfaces públicas, como cotações de mercado, todos podem obtê-las, por isso não é necessária verificação. No entanto, algumas interfaces precisam determinar a identidade do usuário ao fazer um pedido ou obter uma conta. Neste caso, a API-KEY é necessária para assinar. Websocket é um modo de assinatura. Depois de enviar o conteúdo que precisa ser assinado, a plataforma enviará os dados atualizados para o programa, e não precisa ser revisado toda vez, por isso é mais eficiente.

A plataforma de negociação FMZ Quant encapsula a interface REST de cada plataforma e usa uma maneira unificada de chamar e um formato de dados unificado, tornando a escrita de estratégia mais simples e mais geral.

Diferentes linguagens de programação

A maioria das partes do documento da API da plataforma FMZ usa JavaScript como exemplo, mas devido à encapsulamento, quase não há diferença entre as diferentes linguagens, e você só precisa prestar atenção em questões de sintaxe. C++" é um pouco especial, e os tutoriais futuros terão uma introdução especializada. Uma vez que Js é relativamente simples e não tem problemas de compatibilidade, é recomendado para iniciantes. A plataforma FMZ Quant suporta o Python completo e pode instalar livremente vários pacotes. É recomendada para usuários que têm uma certa base de programação. Para usuários que não querem aprender linguagens de programação e apenas querem escrever estratégias, a plataforma FMZ Quant também suporta rapidamente a linguagem Mylanguage, que é basicamente compatível com as estratégias Webstock, e é recomendada para aqueles que têm experiência relevante. A desvantagem é que a linguagem Webstock não é tão poderosa e flexível quanto as linguagens de programação. Como a estratégias de programação FMZ, não é recomendada a escolha de blocos visuais, mas não é

Como o Python tem versões diferentes, ele pode ser especificado no início do programa, como:#!Python2e#!Python3. Observe que o JavaScript recentemente atualizou sua sintaxe ES6, e aqueles que estão interessados podem aprender sobre isso. Os códigos Python e Javascript com as mesmas funções são mostrados abaixo. Pode-se ver que há apenas diferenças de sintaxe, então o documento da API só dá exemplos de Javascript, e este tutorial também levará em conta os casos de uso especiais do Python.

#python code
def main():
    while True:
        Log(exchange.GetAccount().Balance)
        Sleep(2000)
#the corresponding Js code
function main(){
    while(true){
        Log(exchange.GetAccount().Balance)
        Sleep(2000)
    }
}

Recomendações de recursos

  • Este tutorial não vai dar uma introdução detalhada em cada interface no documento FMZ plataforma API, para que você possa verificareste artigo para mais detalhes.
  • Se quiser receber o sinal tradingview e fazer uma encomenda no FMZ, pode consultareste artigo.
  • Para o início rápido de Javascript e Python, escrever estratégias simples não precisa de sintaxe complexa, mas só precisa de alguns conceitos básicos; você pode estudar o tutorial enquanto você está aprendendo a programar (https://www.fmz.com/bbs-topic/9123, https://www.fmz.com/bbs-topic/9124).
  • Documento em língua mylanguageO Mylanguage continua a ser muito conveniente para estratégias de tendências.
  • Aqui está um exemplo de invocação de C++. Aqueles que estão interessados em C++ podem dar uma olhada. Como não é uma linguagem interpretativa, a depuração é muito difícil, entãoo exemplonão é recomendado.
  • Curso Quantitativo de Negociação de Criptomoedas da NetEase Cloud Classroom, produzido oficialmente pela FMZ, só precisa de 20 yuans, com conteúdo detalhado, de simples a profundo, adequado para iniciantes!cursolink
  • Aqui estão.algumas estratégias de ensinoPode tentar escrever estratégias enquanto estuda os fundamentos.
  • Explicação detalhada do código fonte da estratégia:A ligação.

Ferramenta de depuração

A plataforma FMZ Quant fornece oDebug ToolA ferramenta de depuração só suporta JavaScript e só pode ser executada por um período de tempo; a interface da plataforma pode ser depurada sem criar um bot; os dados de retorno serão devolvidos como resultado, e o código da ferramenta de depuração não será salvo.img

Quadro do programa de estratégia

O programa de estratégia é o mesmo que um programa normal, que é executado em ordens de código. A parte especial é que deve haver uma função main. Uma vez que a estratégia precisa ser executada ininterruptamente, geralmente um loop mais tempo de sono é necessário. Como a frequência de acesso das APIs da plataforma é limitada, o tempo de sono precisa ser ajustado de acordo. Esta estrutura é a execução típica em intervalos fixos, e você também usa o Websocket para escrever estratégias baseadas em eventos. Por exemplo, execução imediata desde que a profundidade mude, que será introduzida no tutorial avançado.

Outras funções com acções especiais são apresentadas da seguinte forma:

  • onexit() é uma função normal de saída; o seu tempo máximo de execução é de 5 minutos; pode não ser especificado; se o tempo expirar, será notificado um erro de interrupção.
  • onerror() é uma função de saída anormal; o seu tempo máximo de execução é de 5 minutos; pode não ser especificado.
  • init() é uma função de inicialização; seu programa de estratégia será chamado automaticamente quando começar a ser executado; pode não ser especificado.
function onTick(){
   var ticker = exchange.GetTicker()
   var account = exchange.GetAccount()
    //write the strategy logic here, and it will be called ever 6 seconds
}
function main(){
    while(true){
        onTick()
        Sleep(6000)
    }
}

No exemplo anterior, se houver um erro no acesso à rede, a estratégia pode parar diretamente. Se você quiser uma estratégia semelhante ao reinicio automático e não parar, você pode usar o loop principal try catch tolerante a falhas na estratégia do bot (não use try para o backtest).

function onTick(){
   var ticker = exchange.GetTicker()
   var account = exchange.GetAccount()
    //write the strategy logic here, and it will be called ever 6 seconds
}
function main(){
    try{
        while(true){
           onTick()
           Sleep(6000)
       }
    }catch(err){
        Log(err)
    }
}

Introdução à API da plataforma

Plataforma definida e par de negociação

Ao chamar qualquer API relacionada à plataforma, você precisa especificar a plataforma e o par de negociação.exchangePor exemplo, o queexchange.GetTicker()O preço de mercado para este par de câmbio é o ticker do mercado.

A plataforma FMZ Quant suporta a adição de múltiplos objetos pares de negociação de câmbio ao mesmo tempo. Por exemplo, você pode operar BTC e ETH da mesma conta da plataforma ao mesmo tempo, ou você pode operar BTC de uma troca e ETH de outra troca ao mesmo tempo.exchangesmatriz para representá-los, ou sejaexchanges[0]eexchanges[1]... e assim por diante, de acordo com a ordem de adição quando o bot é criado.BTC_USDT, o antigo BTC é a moeda de negociação, e USDT é a moeda de cotação.

img

Obviamente, se operarmos muitos pares de negociação, este método será muito inconveniente.exchange.SetCurrency("BTC_USDT"); em seguida, o par de negociação vinculado aexchangetorna-seBTC_USDT, que permanecerá válido até à próxima chamada para alterar o par de negociação.Observe que o backtest suporta trocar pares comerciais recentementeAbaixo está um exemplo específico:

var symbols = ["BTC_USDT", "LTC_USDT", "EOS_USDT", "ETH_USDT"]
var buyValue = 1000
function main(){
  for(var i=0;i<symbols.length;i++){
      exchange.SetCurrency(symbols[i])
      var ticker = exchange.GetTicker()
      var amount = _N(buyValue/ticker.Sell, 3)
      exchange.Buy(ticker.Sell, amount)
      Sleep(1000)
  }
}

Obter Interfaces Públicas

Como mencionado no exemplo anterior, a interface de mercado é geralmente uma interface pública, que pode ser acessada por todos. As interfaces de mercado comuns são: GetTicker, GetDepth, GetRecords e GetTrades. A cotação de mercado é a base para a estratégia para fazer julgamentos de negociação. Mais tarde, vou apresentá-los um por um. É melhor experimentá-los na Debug Tool por conta própria. Se você precisar de uma explicação detalhada, você pode verificá-lo no documento API.

Cada interface tem geralmente umaInfocampo, que representa a cadeia de dados original devolvida pela plataforma, e que pode ser usada para complementar informações adicionais.JSON.parse(), enquanto Python usa biblioteca json.TimeO campo indica o carimbo horário da solicitação, que pode ser utilizado para julgar o atraso.

quando se usa qualquer API no bot, o acesso pode falhar e retornarnull, e Python retornaNoneNeste momento, os dados em uso irão relatar um erro e fazer com que o bot pare, então a tolerância a falhas é muito importante.

GetTicker

GetTicker é provavelmente a interface mais usada. Você pode encontrar o preço executado pela última vez, preço buy1 e preço sell1, e o volume de negociação mais recente. Antes de colocar uma ordem, o preço executado pode ser determinado de acordo com as informações do ticker.{"Info:{}, "High":5226.69, "Low":5086.37,"Sell":5210.63, "Buy":5208.5, "Last":5208.51, "Volume":1703.1245, "OpenInterest":0, "Time":1554884195976}.

function main() {
    var ticker = exchange.GetTicker()
    Log(ticker) //return ticker in the debugging tool, and you can see the specific result
    Log('Last time executed price:',ticker.Last, 'Buy1 price:', ticker.Buy)
}

GetDepth

GetDepth para obter as informações de profundidade das ordens pendentes. Embora o GetTicker inclua preços de compra 1 e venda 1, se você quiser consultar ordens pendentes mais profundas, você pode usar essa interface, para geralmente verificar 200 ordens pendentes. Os preços de choque podem ser calculados usando essa interface. Abaixo está um resultado de retorno real. Entre eles, Asks representa a ordem de venda pendente, e a matriz é Sell1, Sell2... Então o preço também sobe por sua vez. Bids representa a ordem de compra pendente, e a matriz é buy1, buy2... O preço desce por sua vez.

{
    "Info":null,
    "Asks":[
        {"Price":5866.38,"Amount":0.068644},
        {"Price":5866.39,"Amount":0.263985},
        ......
        ]
    "Bids":[
        {"Price":5865.13,"Amount":0.001898},
        {"Price":5865,"Amount":0.085575},
        ......
        ],
    "Time":1530241857399
}

Exemplo de uso do GetDepth para Asks & Bids:

function main() {
    var depth = exchange.GetDepth()
    Log('Buy 1 price:', depth.Bids[0].Price, 'Sell 1 price:', depth.Asks[0].Price)
}

GetRecords

GetRecords é uma das interfaces mais usadas, pode retornar informações de preço em um longo período de tempo, que é a base para o cálculo de vários indicadores. Se o período da linha K não for especificado, significa usar o período padrão ao adicionar um bot. O comprimento da linha K não pode ser especificado e continuará a aumentar ao longo do tempo. O número máximo é de 2000, e na primeira chamada o número é de cerca de 200 (plataformas diferentes retornam números diferentes).

exchange.SetMaxBarLen(Len)Pode definir o número de K-lines adquiridas pela primeira vez (suportado por algumas plataformas) e definir o número máximo de K-lines.Como por exemplo:exchange.SetMaxBarLen(500).

GetRecords pode especificar períodos como PERIOD_M1: 1 minuto, PERIOD_M5: 5 minutos, PERIOD_M15: 15 minutos, PERIOD_M30: 30 minutos, PERIOD_H1: 1 hora e PERIOD_D1: 1 dia.exchange.GetRecords(PERIOD_M1)Após a atualização do último docker, ele suportará períodos de personalização, que apenas passam o segundo número do período como um parâmetro. A personalização de nível de minuto será sintetizada de acordo com a linha K de 1 minuto, a linha K abaixo de 1 minuto será sintetizada através do GetTrades ((), e os futuros de commodities serão sintetizados de acordo com o tick.Observe que também existem outras variáveis maiúsculas completas comoPERIOD_M1Eles são as variáveis globais padrão do FMZ. Se você estiver interessado, você pode log seus valores específicos por si mesmo, e você pode usá-los diretamente no habitual.

Exemplo de dados de retorno:

[
    {"Time":1526616000000,"Open":7995,"High":8067.65,"Low":7986.6,"Close":8027.22,"Volume":9444676.27669432},
    {"Time":1526619600000,"Open":8019.03,"High":8049.99,"Low":7982.78,"Close":8027,"Volume":5354251.80804935},
    {"Time":1526623200000,"Open":8027.01,"High":8036.41,"Low":7955.24,"Close":7955.39,"Volume":6659842.42025361},
    ......
]

Exemplo de linha K iterada:

function main(){
    var close = []
    var records = exchange.GetRecords(PERIOD_H1)
    Log('total bars: ', records.length)
    for(var i=0;i<records.length;i++){
        close.push(records[i].Close)
    }
    return close
}

GetTrades

GetTrades obtém os dados de negociação dentro de um determinado intervalo de tempo (não seus próprios dados de negociação), o que não é suportado por algumas plataformas.

Obter conta para o comércio

Essas interfaces estão relacionadas à conta, por isso não podem ser obtidas diretamente. Para obtê-las, você precisa usar o API-KEY para assinar. Após o processamento automático unificado de fundo da plataforma FMZ, você pode usá-las diretamente.

GetAccount

GetAccount para obter as informações da conta. Como uma das interfaces mais usadas, ela precisa ser chamada antes de fazer um pedido, para evitar um saldo insuficiente.{"Stocks":0.38594816,"FrozenStocks":0,"Balance":542.858308,"FrozenBalance":0,"Info":{}}Se o par de negociação for um par de negociação, o valor da moeda em que o par de negociação é negociado é o valor da moeda em que o par de negociação é negociado.BTC_USDT, Stocks refere-se ao BTC, e Balance refere-se ao USDT.

Observe que o resultado de retorno é o resultado do par de negociação especificado, e as informações de outras moedas na conta de negociação está no campo Info, por isso você não precisa chamá-lo várias vezes, quando você opera vários pares de negociação.

Um bot que imprime constantemente o valor total do par de negociação atual:

function main(){
    while(true){
        var ticker = exchange.GetTicker()
        var account = exchange.GetAccount()
        var price = ticker.Buy
        var stocks = account.Stocks + account.FrozenStocks
        var balance = account.Balance + account.FrozenBalance
        var value = stocks*price + balance
        Log('Account value is: ', value)
        LogProfit(value)
        Sleep(3000)//sleep 3000ms(3s), A loop must has a sleep, or the rate-limit of the exchange will be exceed
        //when run in debug tool, add a break here
    }
}

Ordem de compra

Métodos de invocação incluemexchange.Buy(Price, Amount)eexchange.Buy(Price, Amount, Msg), em que Price indica o preço, Amount é a quantidade, Msg é uma cadeia extra que pode ser exibida no registro do bot, mas não é necessária. Estes métodos são ordens pendentes. Se a ordem não puder ser completamente executada imediatamente, uma ordem não concluída será gerada; o id da ordem é devolvido se a ordem for colocada com sucesso, enullserá devolvido se a encomenda não for bem sucedida, que é usada para consultar o estado da encomenda.

Se você quiser colocar uma ordem de compra no preço de mercado, Price é -1, e Amount é o valor da ordem.exchange.Buy(-1, 0.5); se o par de negociação for:ETH_BTCAlgumas plataformas não suportam ordens de mercado, nem o backtest de futuros.

Algumas plataformas têm os requisitos de precisão para preço e quantidade, que podem ser controlados com a função de precisão_N()Para a negociação de futuros, Buy e Sell têm outros significados, que serão introduzidos especialmente.

Um exemplo de compra uma vez atingido o preço correspondente:

function main(){
    while(true){
        var ticker = exchange.GetTicker()
        var price = ticker.Sell
        if(price >= 7000){
            exchange.Buy(_N(price+5,2), 1, 'BTC-USDT')
            break
        }
        Sleep(3000)//Sleep 3000ms
    }
    Log('done')
}

Ordem de venda

Os parâmetros da ordem de mercado têm significados diferentes.exchange.Sell(-1, 0.2), significa vender 0,2 ETH ao preço de mercado.

GetOrder

GetOrder obtém as informações de ordem com base no id de ordem.exchange.GetOrder(OrderId), OrderId é o id da ordem, que será devolvido ao fazer uma ordem.Typee o valor real da ordemStatusOs números são números, que representam significados diferentes, mas não são propícios para a memória.StatusO valor de uma encomenda não concluída é 0, o que equivale aORDER_STATE_PENDING. Todas estas constantes globais podem ser visualizadas no documento... Retorno do resultado:

{
    "Id":125723661, //Order id
    "Amount":0.01, //Order ammount 
    "Price":7000, //Order price 
    "DealAmount":0, //Executed amount 
    "AvgPrice":0, //executed average price
    "Status":0, //0: not completely executed; 1: executed; 2: canceled 
    "Type":1,//Order type; 0: buy order; 1: sell order 
    "ContractType":"",//contract type, used in futures trading
    "Info":{} //the platform returns the raw information
    }
}

Uma estratégia para comprar uma quantidade específica de moeda:

function main(){
    while(true){
        var amount = exchange.GetAccount().Stocks
        var ticker = exchange.GetTicker()
        var id = null
        if(5-amount>0.01){
            id = exchange.Buy(ticker.Sell, Math.min(5-amount,0.2))
        }else{
            Log('Job completed')
            return //return the main function, bot will stop
        }
        Sleep(3000) //Sleep 3000ms
        if(id){
            var status = exchange.GetOrder(id).Status
            if(status == 0){ //Here you can aslo use "status == ORDER_STATE_PENDING" to judge 
                exchange.CancelOrder(id)
            }
        }
    }
}

GetOrders

GetOrder obtém a lista de todas as ordens inacabadas do par de negociação atual. Se não houver nenhuma ordem inacabada, retorne uma matriz vazia. O resultado específico da lista de ordens, como GetOrder.

Exemplo de cancelamento de todas as ordens do par de negociação em curso:

function CancelAll(){
    var orders = exchange.GetOrders()
    for(var i=0;i<orders.length;i++){
        exchange.CancelOrder(orders[i].Id) // cancel order by orderID
    }
}
function main(){
    CancelAll()
    while(true){
        //do something
        Sleep(10000)
    }
}

Cancelar encomenda

De acordo com o ID da encomenda, cancele a encomenda.exchange.CancelOrder(OrderId). Se o cancelamento for bem-sucedido, retorne true; caso contrário, retorne false.

Futures e contrato perpétuo

Para a criptomoeda, a negociação de futuros é diferente da negociação spot. As funções acima da negociação spot também são aplicáveis à negociação de futuros, e a negociação de futuros individuais tem suas próprias funções. Antes de realizar a negociação de futuros de criptomoeda no programa, você deve estar familiarizado com as operações manuais no site e entender os conceitos básicos, como aberto, fechado, cruzado, isolado, alavancagem, lucro e perda fechados, renda flutuante, margem e outros conceitos, bem como as fórmulas de cálculo correspondentes. Os tutoriais correspondentes podem ser encontrados em várias plataformas de futuros, e você precisa aprendê-los sozinho.

Os contratos perpétuos são semelhantes aos contratos futuros, mas a diferença é que não existe tal conceito de manter posições longas e curtas ao mesmo tempo.

Se a plataforma suportar futuros e spot, como futuros da OKEX e Huobi, você precisa selecionar OKEX Futures e Huobi Futures separadamente na interface da plataforma para adicionar, pois essas plataformas de futuros são consideradas como plataformas diferentes das spot no FMZ.

Tipo de contrato

O primeiro passo na negociação de futuros é definir o contrato a ser negociado. Tomando OKEX futuros como exemplo, selecione um par de negociação BTC ao criar um bot ou backtesting, e você também precisa definir o contrato semanal, da próxima semana ou trimestral no código.invalid contract type. Diferente dos pares de negociação à vista, os contratos de futuros geralmente usam moeda de negociação como BTC como margem. Adicionar BTC a um par de negociação geralmente representa um par de negociação BTC_USD que usa BTC como margem. Se houver um contrato de futuros com USDT como margem, um bot precisa ser criado para adicionar o par de negociação BTC_USDT. Por exemplo, contratos perpétuos como Binance OKEX Futures, com contratos cripto-marginados e USDT-marginados.Depois de definir o par de negociação, você também deve definir o tipo de contrato específico, como perpétuo, semanal, semana seguinte, etc. Depois de configurar o contrato, você pode realizar operações como obter cotações de mercado, comprar e vender.

Binance, OKEX, HuobiDM, etc. têm contratos com margem de criptomoedas e contratos com margem de USDT, que precisam ser distinguidos ao adicionar um bot e configurar um contrato.

//OKEX Futures
exchange.SetContractType("swap")        // set to perpetual contract
exchange.SetContractType("this_week")   // set to weekly contract 
exchange.SetContractType("next_week")   // set to next week contract 
exchange.SetContractType("quarter")     // set to quarterly contract

//HuobiDM
exchange.SetContractType("this_week")   // set to weekly contract 
exchange.SetContractType("next_week")   // set to next week contract
exchange.SetContractType("quarter")     // set to quarterly contract 
exchange.SetContractType("swap")        // set to perpetual contract

//Binance Futures
exchange.SetContractType("swap")   // set to perpetual contract, and notice that crypto-margined and USDT-margined contracts are all in the perpetual contract
exchange.SetContractType("quarter")   // set to quarterly contract
exchange.SetContractType("next_quarter")  // set to next quarter contract

//BitMEX
exchange.SetContractType("XBTUSD")    // set to perpetual contract
exchange.SetContractType("XBTM19")  // the contract settled at a specific time; for more details, please log in BitMEX to check each contract code

//GateIO
exchange.SetContractType("swap")      // set to perpetual contract, and do not set the default as swap perpetual contract 
//Deribit
exchange.SetContractType("BTC-27APR18")  // the contract settled at a specific time; for more details, please log in Deribit to check out 

GetPosition

Para obter a lista de informações de posição atual, os futuros OKEX (OKCOIN) podem passar em um parâmetro para especificar o tipo de contrato a ser obtido.[]A informação da posição é devolvida da seguinte forma. Há muita informação específica, que precisa ser analisada em combinação com o par de negociação.

Tipo de dados Nome da variável Descrição
Objeto Informações a estrutura em bruto que a plataforma retorna
Número Nível de margem tamanho de alavancagem; OKCoin é 10 ou 20, e a posição cruzada de futuros OK retorna 10 (fixo), para a API crua não suporta
Número Montante montante da posição; OKCoin indica a quantidade do contrato (número inteiro sobre 1)
Número Número congelado montante da posição congelada
Número Preço Preço médio da posição
Número Margem margem congelada
Número Lucro commodity futures: o lucro e a perda da marca de posição para o mercado; criptomoeda: unidade de criptomoeda: BTC/LTC, unidade de futuros tradicional: RMB (nota:No caso de uma posição cruzada de futuros OKCoin, refere-se ao lucro e à perda realizados, não ao lucro e à perda da posição. Sob a posição isolada, refere-se ao lucro e à perda da posição.)
const Tipo PD_LONG é a posição longa (CTP usa closebuy_today para fechar uma posição ); PD_SHORT é a posição curta (CTP usa closesell_today para fechar uma posição); nos futuros CTP, PD_LONG_YD indica a posição longa de ontem (que usa closebuy para fechar a posição); PD_SHORT_YD é a posição curta de ontem (que usa closesell para fechar a posição)
cordel Tipo de contrato Os futuros de mercadorias são códigos de contrato e as ações são código da plataforma_código de ações; o tipo de parâmetros específicos do SetContractType passado
function main(){
    exchange.SetContractType("this_week");
    var position = exchange.GetPosition();
    if(position.length>0){ //especially pay attention to judging the length of position before call, or an error will occur
        Log("Amount:", position[0].Amount, "FrozenAmount:", position[0].FrozenAmount, "Price:",
            position[0].Price, "Profit:", position[0].Profit, "Type:", position[0].Type,"ContractType:", position[0].ContractType)
    }
}

Futuros de posições abertas e fechadas

Primeiro de tudo, você precisa definir o tamanho da alavancagem; método de invocação:exchange.SetMarginLevel(10), onde 10 significa 10 vezes a alavancagem e o tamanho específico da alavancagem suportada pode ser verificado nas plataformas correspondentes,Observe que a alavancagem deve ser definida na plataforma e o código deve ser consistente com as configurações definidas na plataforma, caso contrário, ocorrerá um erroVocê também pode deixá-lo desativado e usar a alavancagem padrão. Em seguida, defina a direção de negociação; método de invocação:exchange.SetDirection(Direction), que corresponde às posições abertas e fechadas.Ao contrário dos futuros, se um contrato perpétuo não contém os conceitos de longo e curto ao mesmo tempo, ou seja, uma única posição não é permitida.buyesellSe ele suporta posições bidirecionais, você precisa definirclosebuy, closesell.Relações específicas:

Operação Parâmetros de direção definidos Função de Ordem
Posições longas abertas troca.Configurar direcção ((comprar) troca.Comprar()
Fechar posição longa troca.SetDirection ((closebuy) Troca.Venda.
Posição curta aberta troca.SetDirection ((venda) Troca.Venda.
Fechar posição curta troca.SetDirection ((closesell) troca.Comprar()

Por fim, há o código específico para posições abertas e fechadas. A quantidade de ordens colocadas varia de plataforma para plataforma. Por exemplo, os futuros Huobi são baseados no número de quantidade de contrato e um contrato é de 100 dólares americanos.

function main(){
    exchange.SetContractType("this_week")    // for example, set OKEX futures to weekly contract 
    price = exchange.GetTicker().Last
    exchange.SetMarginLevel(10) // set to 10 times of leverage  
    exchange.SetDirection("buy") // set the order type as buy long 
    exchange.Buy(price+10, 20) // set contract quantity as 20 orders
    pos = exchange.GetPosition()
    Log(pos)
    Log(exchange.GetOrders()) // check out if there is any unfinished order 
    exchange.SetDirection("closebuy"); // if it is a perpetual contract, directly set exchange.SetDirection("sell")
    exchange.Sell(price-10, 20)
}

Cite um exemplo específico de estratégia de posições fechadas completas:

function main(){
    while(true){
        var pos = exchange.GetPosition()
        var ticker = exchange.GetTicekr()
        if(!ticker){
            Log('not able to obtain ticker')
            return
        }
        if(!pos || pos.length == 0 ){
            Log('no position')
            return
        }
        for(var i=0;i<pos.length;i++){
            if(pos[i].Type == PD_LONG){
                exchange.SetContractType(pos[i].ContractType)
                exchange.SetDirection('closebuy')
                exchange.Sell(ticker.Buy, pos[i].Amount - pos[i].FrozenAmount)
            }
            if(pos[i].Type == PD_SHORT){
                exchange.SetContractType(pos[i].ContractType)
                exchange.SetDirection('closesell')
                exchange.Buy(ticker.Sell, pos[i].Amount - pos[i].FrozenAmount)
            }
        }
        var orders = exchange.Getorders()
        Sleep(500)
        for(var j=0;j<orders.length;j++){
            if(orders[i].Status == ORDER_STATE_PENDING){
                exchange.CancelOrder(orders[i].Id)
            }
        }
    }
}

Negociação de alavancagem de criptomoedas

A negociação de alavancagem de criptomoedas precisa mudar para a conta de alavancagem no código, e outras partes são as mesmas que a negociação spot.

Utilizaçãoexchange.IO("trade_margin") para mudar para o modo de conta de alavancagem; a colocação de uma ordem e a obtenção de ativos da conta acederão à interface da alavancagem da plataforma. Utilizaçãoexchange.IO("trade_normal") para voltar ao modo de conta normal.

Plataformas suportadas:

  • OKEX V3: Os pares de negociação do modo de conta de alavancagem são diferentes dos comuns e alguns pares de negociação podem não existir.
  • Huobi: os pares de negociação do modo de conta de alavancagem são diferentes dos comuns e alguns pares de negociação podem não existir.
  • ZB: os ativos só podem ser transferidos em QC. No setor de negociação de alavancagem, os ativos entre diferentes pares de negociação são independentes, ou seja, o número de moedas QC sob o par de negociação ETH_QC não é visível no BTC_QC.
  • FCoin
  • Binance

Negociação de futuros de mercadorias

A negociação de futuros de commodities e a negociação de futuros de criptomoedas são bastante diferentes. Em primeiro lugar, o tempo de negociação de futuros de commodities é muito curto, mas a criptomoeda é negociada por 24 horas; o protocolo de futuros de commodities não é uma API REST comumente usada; a frequência de negociação e o valor da ordem pendente de futuros de commodities são limitados, mas os de criptomoeda são muito soltos, e assim por diante. Portanto, há muitos pontos que precisam de atenção especial ao negociar futuros de commodities, e é recomendado para aqueles que têm rica experiência em operações manuais.https://www.fmz.com/bbs-topic/325Para adicionar empresas de futuros de mercadorias:https://www.fmz.com/bbs-topic/371

Os futuros de commodities implementaram a supervisão transparente em junho de 2019; para o programa individual, os usuários individuais precisam abrir uma conta para solicitar um código de autorização para corretores de futuros (o modelo de informações de aplicativo específico pode ser enviado para o grupo WeChat ou o grupo QQ), o que geralmente leva 4-5 dias; os procedimentos são bastante complicados. Como um provedor de negociação programática, a plataforma FMZ solicitou códigos de autorização de software de vários provedores de serviços de futuros. Os usuários podem usá-los diretamente sem aplicar. Ao adicionar um corretor de futuros, pesquise see through para ver a lista que a FMZ solicitou.https://www.fmz.com/bbs-topic/3860. Se o seu corretor de futuros não estiver mais na lista, você só pode se inscrever sozinho, ou abrir uma nova conta de um corretor suportado, o que geralmente leva 2 dias. A FMZ tem relações de cooperação aprofundadas com alguns provedores de serviços; por exemplo, a Guotai Junan Hongyuan Futures comprou a versão institucional da plataforma FMZ, que pode ser usada por seus usuários, e os usuários se tornam automaticamente VIP ao abrir uma conta, e a taxa de serviço é minimizada.https://www.fmz.com/bbs-topic/506.

Devido às vantagens da estrutura da plataforma FMZ Quant, os usuários também podem adicionar várias contas de corretor de futuros e implementar algumas funções que outros softwares de negociação de futuros de commodities não podem completar, como a síntese de tick de alta frequência; você pode se referir a:https://www.fmz.com/bbs-topic/1184

Quadro estratégico

Em primeiro lugar, como não é uma negociação de 24 horas e requer uma operação de login, é necessário julgar o status do link antes da negociação.exchange.IO("status")étrue, o que indica uma conexão bem-sucedida com a plataforma. Se a API for chamada quando o login não for bem-sucedido, not login não é solicitado. Você pode adicionar Sleep (2000) após o início da estratégia, dando-lhe um certo tempo para fazer login. Você também pode tentar novamente se inscrever_C(exchange.SetContractType,"MA888"), o que assegurará um login bem sucedido.

Os códigos de aquisição e negociação de cotações de mercado de futuros de commodities são os mesmos que os de futuros de criptomoedas.

function main(){
    _C(exchange.SetContractType,"MA888") //If you do not log in successfully, you cannot subscribe to the contract, so better to try again
    while(true){
        if(exchange.IO("status")){
            var ticker = exchange.GetTicker()
            Log("MA888 ticker:", ticker)
            LogStatus(_D(), "Already connected with CTP !")//_D obtain event
        } else {
            LogStatus(_D(), "Not connected with CTP !")
            Sleep(1000)
        }
    }
}

Recomenda-se usar a biblioteca de futuros de commodities para negociação (que será descrita mais tarde), o código será muito simples neste momento, e não há necessidade de lidar com detalhes tediosos.https://www.fmz.com/strategy/57029

function main() {
    // Use the CTA strategy framework of commodity futures library 
    $.CTA(Symbols, function(st) {
        var r = st.records
        var mp = st.position.amount
        var symbol = st.symbol
        /*
        "r" represents K-line, "mp" indicates the position amount of the current variety; positive number means long position, negative number means short position, and 0 means no position; "symbol" is the variety name
        if the return value is n: 
            n = 0 : full close positions (no matter now they are long or short)
            n > 0 : if right now long positions are held, add n long positions; if now they are short positions, close n short posiitons; if n is over the position amount right now, reverse to open long positions 
            n < 0 : if right now short positions are held, add n short positions; if now they are long positions, close n long posiitons; if -n is over the position amount right now, reverse to open short positions 
        */
        if (r.length < SlowPeriod) {
            return
        }
        var cross = _Cross(TA.EMA(r, FastPeriod), TA.EMA(r, SlowPeriod));
        if (mp <= 0 && cross > ConfirmPeriod) {
            Log(symbol, "Golden Cross Period", cross, "the moment position", mp);
            return Lots * (mp < 0 ? 2 : 1)
        } else if (mp >= 0 && cross < -ConfirmPeriod) {
            Log(symbol, "Death Cross Period", cross, "the moment position", mp);
            return -Lots * (mp > 0 ? 2 : 1)
        }
    });
}

Modos de obtenção de dados CTP

Os futuros de commodities usam o protocolo CTP, e todas as cotações de mercado e as execuções de ordens serão notificadas apenas após as mudanças, enquanto consultas sobre ordens, contas e posições são consultas ativas.GetTicker, GetDeptheGetRecords, todos precisam ter dados em cache para obter os dados mais recentes. Se não houver dados, ele esperará até que haja dados, por isso não é necessário que a estratégia use Sleep. Quando houver mudanças de cotação de mercado, ticker, profundidade e registros serão atualizados. Neste momento, chamar qualquer uma dessas interfaces retornará imediatamente, e o estado da interface chamada será definido para o modo wait for update. A próxima vez que a mesma interface for chamada, ele esperará até que haja novos dados retornados. Alguns contratos impopulares ou o limite de preço causarão nenhuma negociação por um longo tempo, o que significa que a estratégia ficou presa por um longo tempo, também normal.

Se você quiser obter dados toda vez que você obter as cotações de mercado, mesmo que seja dados antigos, você pode mudar para o modo de atualização imediata das cotações de mercadoexchange.IO("mode", 0)Neste momento, a estratégia não pode ser escrita como orientada por eventos, e um evento SLeep precisa ser adicionado para evitar um loop infinito rápido. Algumas estratégias raras podem usar esse modo, e o design da estratégia é simples.exchange.IO("mode", 1)para voltar ao modo de cache padrão.

No entanto, se houver vários contratos, é possível que um dos contratos não atualize as cotações de mercado, resultando no bloqueio da interface para obter cotações de mercado, e as atualizações de cotações de outros contratos também não possam ser obtidas. Para resolver esse problema, o modo de atualização imediata pode ser usado, mas é inconveniente escrever estratégias de alta frequência.exchange.IO("wait")Se múltiplos objetos de troca são adicionados, o que é raro em futuros de commodities, você pode usarexchange.IO("wait_any"), e o Index devolvido indicará o índice da plataforma devolvido.

Impulso das alterações do mercado:{Event:"tick", Index: platform index (in the order of the platforms added in the bot), Nano: event of nanosecond-level time, Symbol: contract name}Push de ordem:{Event:"order", Index:Exchange index, Nano:Event of nanosecond-level time, Order:Order information (same as GetOrder)}

Neste momento, a estrutura da estratégia pode ser escrita como:

function on_tick(symbol){
    Log("symbol update")
    exchange.SetContractType(symbol)
    Log(exchange.GetTicker())
}

function on_order(order){
    Log("order update", order)
}

function main(){
    while(true){
        if(exchange.IO("status")){ //Judge the link status 
            exchange.IO("mode", 0)
            _C(exchange.SetContractType, "MA888")//Subscribe to MA; only the subscription request for the first time is ture, and the later ones are program switches, which do not consume time
            _C(exchange.SetContractType, "rb888")//Subscribe to rb
            while(true){
                var e = exchange.IO("wait")
                if(e){
                    if(e.event == "tick"){
                        on_tick(e.Symbol)
                    }else if(e.event == "order"){
                        on_order(e.Order)
                    }
                }
           }
        }else{
            Sleep(10*1000)
        }
    }
}

Diferenças entre futuros de commodities e criptomoedas

Observe também a diferença entre futuros de commodities e plataformas de criptomoedas. Por exemplo, GetDepth na verdade tem apenas um nível de profundidade (5 níveis de profundidade são caros), e GetTrades não pode obter o histórico de negociação (todos são simulados com base em mudanças de posição, e não há registro de negociação real). Os futuros de commodities têm um mecanismo de limite de preço. Quando o limite é elevado, o preço de uma ordem de venda de profundidade para vender uma é o preço limite, e o volume de ordem é 0.

Contrato em conjunto

exchange.IO("instruments"): devolve a lista de todos os contratos na plataforma {nome do contrato: detalhes} em forma de dicionário e suporta apenas bots.exchange.IO("produções"): devolve a lista de todos os itens da plataforma {nome do contrato: detalhes} em forma de dicionário e suporta apenas bots.exchange.IO("subscrito"): retorna as cotações de mercado subscritas na plataforma em forma de dicionário e suporta apenas bots.

OContractTypeOs futuros de CTP tradicionais referem-se ao ID do contrato, que é sensível a minúsculas e minúsculas.exchange.SetContractType("au1506"). Após o contrato ser definido com sucesso, ele retornará as informações detalhadas do contrato, como o valor mínimo de compra, taxa de serviço, tempo de entrega, etc. Ao assinar vários contratos, apenas a primeira vez que um pedido de assinatura é realmente enviado, e então o par de negociação é simplesmente trocado no nível de código, o que não leva tempo. O principal contrato contínuo é o código 888, como MA888, o contrato de taxa contínua é 000, como MA000; 888 e 000 são negociações de contratos virtuais que apenas suportam backtest, e bots reais apenas suportam cotações de mercado.No entanto, a Mylanguage pode operar o contrato principal, e o programa mudará automaticamente as posições, ou seja, fechará as posições não principais e abrirá novas posições nas posições principais.

O login falhado não pode definir contratos, mas retornará imediatamente, então você pode tentar por _c novamente, para saber se o login do CTP foi concluído.

Posição aberta e posição fechada

A Direcção doSetDirectionpode obter quatro parâmetros:buy, closebuy, sell, closesellOs futuros de commodities têm maisclosebuy_todayeclosesell_today, indicando o encerramento das posições correntes; o valor por defeito éclosebuy/ closesell, indicando o fechamento de posições de ontem; apenas as variedades da Shanghai Futures Exchange são divididas em fechamento de hoje e fechamento de ontem, o que pode afetar a taxa de serviço, por isso é necessário dar prioridade ao fechamento de posições de ontem. Para futuros tradicionais do CTP, você pode definir o segundo parâmetro como 1 ou 2 ou 3, que se refere a especulação, arbitragem e hedge, respectivamente. Se não for definido, o padrão é especulação.As operações específicas, tais como compra e venda, obtenção de posições, obtenção de ordens, cancelamento de ordens e obtenção de contas, são as mesmas que a negociação de futuros de criptomoedas, por isso consulte a seção anterior.

Operação Parâmetros de direção definidos Função de Ordem
Posições longas abertas troca.Configurar direcção ((comprar) troca.Comprar()
Fechar posição longa troca.SetDirection ((closebuy) Troca.Venda.
Posição curta aberta troca.SetDirection ((venda) Troca.Venda.
Fechar posição curta troca.SetDirection ((closesell) troca.Comprar()

O exemplo a seguir é uma função de posição de fechamento específica. Observe que este exemplo é muito simples. Você também deve considerar se está dentro do tempo de negociação, como tentar novamente a ordem pendente se não estiver completamente preenchida, qual é o volume máximo de ordem, se a frequência é muito alta e se é preço deslizante ou preço de mercado e assim por diante.é um pacote de biblioteca das plataformas sugeridas para abertura e fechamento de posições em bots reais:https://www.fmz.com/strategy/12961Há uma introdução específica na secção da biblioteca, e também é recomendável estudar os códigos fonte da biblioteca.

function Cover(contractType, amount, slide) {
    for (var i = 0; i < positions.length; i++) {
        if (positions[i].ContractType != contractType) {
            continue;
        }
        var depth = _C(e.GetDepth);
        if (positions[i].Type == PD_LONG || positions[i].Type == PD_LONG_YD) {
            exchange.SetDirection(positions[i].Type == PD_LONG ? "closebuy_today" : "closebuy");
            exchange.Sell(depth.Bids[0]-slide, amount, contractType, positions[i].Type == PD_LONG ? "Close today" : "Close yesterday", 'Bid', depth.Bids[0]);
        } else {
            exchange.SetDirection(positions[i].Type == PD_SHORT ? "closesell_today" : "closesell");
            exchange.Buy(depth.Asks[0]+slide, amount, contractType, positions[i].Type == PD_SHORT ? "Close today" : "Close yesterday", 'Ask', depth.Asks[0]);
        }
    }
}

Os futuros de commodities suportam tipos de ordens personalizados (suporte para bots, mas não para backtest), que são especificados por sufixo, anexado a _, tais como:

exchange.SetDirection("buy_ioc");
exchange.SetDirection("sell_gtd-20170111")

Sufixos específicos:

  • ioc concluir imediatamente, ou cancelar THOST_FTDC_TC_IOC
  • gfs válido no nó THOST_FTDC_TC_GFS
  • gfd válido no dia THOST_FTDC_TC_GFD
  • gtd válido antes da data especificada THOST_FTDC_TC_GTD
  • gtc válido antes do cancelamento THOST_FTDC_TC_GTC
  • gfa válido em licitações THOST_FTDC_TC_GFA

Interface Esunny

Por padrão, as interfaces abertas nos corretores de futuros de commodities são todas interfaces CTP. Se necessário, elas podem ser substituídas por interfaces Esunny. Através da encapsulamento do FMZ, o método de invocação é o mesmo. A diferença é que as contas, ordens e posições estão todas no modo push, então o docker manterá esses dados localmente e retornará imediatamente quando a interface correspondente for chamada, sem realmente fazer um pedido.

Protocolo Esunny Tipos de encomendas personalizadas são:

  • gfd válido no dia TAPI_ORDER_TIMEINFORCE_GFD
  • gtc válido antes do cancelamento TAPI_ORDER_TIMEINFORCE_GTC
  • gtd válido antes da data especificada TAPI_ORDER_TIMEINFORCE_GTD
  • fak parcialmente executado, cancelar o resto TAPI_ORDER_TIMEINFORCE_FAK
  • ioc executar imediatamente, ou cancelar TAPI_ORDER_TIMEINFORCE_FAK
  • fok não executado completamente, cancelar todos TAPI_ORDER_TIMEINFORCE_FOK

Funções globais comumente utilizadas

Log - Log & WeChat Push

Ao registrar um registro de log na interface do bot, e adicionar o caractere @ após a cadeia, a mensagem entrará na fila de push, e será empurrada diretamente após a ligação ao WeChat ou telegrama, comoLog('Push to WeChat@').

A cor do log também pode ser personalizada, tais comoLog('this is a log in red font #ff0000'). #ff0000é o hexadecimal da cor RGB, indicando que todos os arquivos de log são armazenados no banco de dados SqLit do bot no diretório onde o docker está localizado, que pode ser baixado e aberto com o software do banco de dados, ou pode ser usado para copiar backup e restaurar (nome do banco de dados e o bot id são os mesmos).

LogProfit - Lucros de impressão

Ele registra os lucros e desenha a curva de lucro na interface do bot, que pode ser retida após o bot ser reiniciado.LogProfit(1000)Observe que o parâmetro deLogProfitnão é necessariamente o lucro, e pode ser qualquer número e precisa ser preenchido por si mesmo.

LogStatus - Apresentação do estado (incluindo tabelas)

Se o estado do bot, uma vez que o registro será salvo primeiro e atualizado continuamente, precisa das informações apenas para exibição e não para salvar, você pode usar oLogStatusOs parâmetros deLogStatussão strings, que também podem ser usados para representar as informações da tabela.

Um exemplo de uma tabela de exibição específica de posição real de bot:

var table = {type: 'table', title: 'position information', cols: ['Column1', 'Column2'], rows: [ ['abc', 'def'], ['ABC', 'support color #ff0000']]}; 
LogStatus('`' + JSON.stringify(table) + '`'); // After serialization, JSON will be added the character "'" on both sides, which is regarded as a comlpex messag format (now supporting tables)
LogStatus('The first line information\n`' + JSON.stringify(table) + '`\nthe third line information'); // the table information can be displayed in multiple lines
LogStatus('`' + JSON.stringify([table, table]) + '`'); // Multiple tables are supported to be displayed at the same time, which will be displayed in one group by TAB  
LogStatus('`' + JSON.stringify(tab1) + '`\n' + '`' + JSON.stringify(tab2) + '`\n

Mais.