Desenvolvimento de estratégias de negociação

Autora:Sonhos pequenos, Criado: 2019-08-06 17:15:13, Atualizado: 2023-10-20 20:06:49

img

Desenvolvimento de estratégias de negociação

O objetivo deste artigo é falar sobre algumas experiências no desenvolvimento de estratégias, bem como pequenas dicas que podem ajudar o leitor a entender rapidamente o que está acontecendo no desenvolvimento de estratégias de negociação. Quando se depara com problemas de detalhes semelhantes no projeto de uma estratégia, uma solução razoável pode ser imediatamente concebida. A plataforma de negociação quantitativa do inventor serve como plataforma de ensino, teste e prática. Língua de programação estratégica: JavaScript Mercado de negociação: mercado de ativos blockchain (BTC, ETH, etc.)

  • Acesso e processamento de dados

    Normalmente, de acordo com a lógica da estratégia, é possível usar as seguintes interfaces diferentes para obter dados de mercado, pois a lógica de negociação da estratégia geralmente é impulsionada por dados de mercado.

    • GetTicker: Obtenha o mercado de ticks em tempo real É geralmente usado para obter rapidamente os preços atuais mais recentes, comprar um preço, vender um preço.

    • GetDepth: Obtenção de pedidos de mercado de profundidade mínima. Geralmente usado para obter o preço por faixa, o tamanho do pedido. O que é que isso significa para mim?

    • GetTrade: Obtenha registros de transações recentes no mercado. Geralmente usado para analisar o comportamento do mercado em um curto período de tempo, para analisar mudanças microscópicas no mercado. Geralmente usado para estratégias de alta frequência, estratégias de algoritmos.

    • GetRecords: obter dados da linha K do mercado. É usado geralmente como uma estratégia de rastreamento de tendências. A partir de agora, o número de pessoas que se inscreveram no projeto aumentará.

    • Permitir erros

      Em geral, quando se desenha uma estratégia, os iniciantes ignoram as situações errôneas, e intuitivamente pensam que os resultados de cada um dos eixos da estratégia são estabelecidos. Mas na realidade não é assim. Por exemplo, algumas interfaces de mercado retornaram dados anormais:

      var depth = exchange.GetDepth()
      
      // depth.Asks[0].Price < depth.Bids[0].Price      卖一价格低于了买一价格,这种情况不可能存在于盘面上,
      //                                                因为卖出的价格低于买入的价格,必定已经成交了。
      // depth.Bids[n].Amount = 0                       订单薄买入列表第n档,订单量为0
      // depth.Asks[m].Price = 0                        订单薄卖出列表第m档,订单价格为0
      

      Ou, diretamente, exchange.GetDepth ((() retorna o valor null.

      O que é mais estranho é que a maioria das pessoas não sabe o que fazer. Por isso, é necessário fazer um tratamento correspondente a esses problemas previsíveis, que é chamado de tratamento tolerante a erros.

      A forma mais comum de lidar com erros é descartando os dados e recuperando-os.

      Por exemplo:

      function main () {
          while (true) {
              onTick()
              Sleep(500)
          }
      }
      
      function GetTicker () {
          while (true) {
              var ticker = exchange.GetTicker()
              if (ticker.Sell > ticker.Buy) {       // 以 检测卖一价格是不是小于买一价这个错误的容错处理为例,
                                                    // 排除这个错误,当前函数返回 ticker 。
                  return ticker
              }
              Sleep(500)
          }
      }
      
      function onTick () {
          var ticker = GetTicker()                  // 确保获取到的 ticker 不会存在 卖一价格小于买一价格这种数据错误的情况。
          // ...  具体的策略逻辑
      }
      

      Outras soluções de erro previsíveis podem ser usadas de forma semelhante. O princípio de design é que não se pode dar dados errados para conduzir a lógica estratégica.

    • Uso de dados de linha K

      A partir de agora, a rede está em fase de recuperação.

      var r = exchange.GetRecords()
      

      O resultado é uma matriz de dados de linha K, que pode parecer, por exemplo:

      [
          {"Time":1562068800000,"Open":10000.7,"High":10208.9,"Low":9942.4,"Close":10058.8,"Volume":6281.887000000001},
          {"Time":1562072400000,"Open":10058.6,"High":10154.4,"Low":9914.5,"Close":9990.7,"Volume":4322.099},
          ...
          {"Time":1562079600000,"Open":10535.1,"High":10654.6,"Low":10383.6,"Close":10630.7,"Volume":5163.484000000004}
      ]
      

      Aqui estão os parênteses de cada flor.{}No meio estão incluídos o tempo, o preço aberto, o preço máximo, o preço mínimo, o preço de fechamento, o volume. Esta é uma coluna de linha K. Os dados gerais da linha K são usados para calcular indicadores, como: linha média MA, MACD, etc. Entrar dados da linha K como parâmetros (dados de matéria-prima) e, em seguida, definir parâmetros de indicadores para calcular funções de dados de indicadores, que chamamos de funções de indicadores. A plataforma de negociação quantitativa do inventor possui muitas funções de indicadores.

      Por exemplo, nós calculamos um indicador da linha uniforme, com base nos períodos diferentes dos dados da linha K que nós transmitimos, o que é calculado é a linha uniforme do período correspondente. Por exemplo, os dados da linha K diária (um K coluna representa um dia) são calculados como a linha média diária, semelhante se os dados da linha K da função de indicador da linha média são transmitidos como um período de 1 hora, então o indicador calculado é uma linha média de 1 hora.

      Normalmente, há um problema que muitas vezes é ignorado quando estamos calculando indicadores, se eu vou calcular um indicador da linha média de 5 dias, então primeiro vamos preparar os dados da linha K:

      var r = exchange.GetRecords(PERIOD_D1)  // 给GetRecords 函数传入参数 PERIOD_D1就是指定获取日K线,
                                              // 具体函数使用可以参看:https://www.fmz.com/api#GetRecords
      

      Com os dados da linha K do dia, podemos calcular o indicador da linha média, e se quisermos calcular a linha média de 5 dias, então temos que definir o parâmetro do indicador da função de indicador para 5.

      var ma = TA.MA(r, 5)        // TA.MA() 就是指标函数,用来计算均线指标,第一个参数设置刚才获取的日K线数据r,
                                  // 第二个参数设置5,计算出来的就是5日均线,其它指标函数同理。
      

      Nós ignoramos um problema potencial, se o número de colunas da linha K não for superior a 5 em dados da linha K de r dias, o que fazer para calcular um indicador da linha média de 5 dias eficaz? A resposta é não. O indicador de linha média é o valor médio do preço de fechamento de um determinado número de colunas de linha K.

      img

      Portanto, antes de usar dados de linha K, para calcular dados de linha K, é necessário determinar se o número de colunas de linha K nos dados de linha K atende às condições para o cálculo de indicadores (parâmetros de indicadores).

      A partir daí, antes de calcular a linha média de 5 dias, o código completo é:

      function CalcMA () {
          var r = _C(exchange.GetRecords, PERIOD_D1)     // _C() 是容错函数,目的就是避免 r 为 null , 具体可以查询文档:https://www.fmz.com/api#_C
          if (r.length > 5) {
              return TA.MA(r, 5)                         // 用均线指标函数 TA.MA 计算出均线数据,做为函数返回值,返回。
          }
      
          return false 
      }
      
      function main () {
          var ma = CalcMA()
          Log(ma)
      }
      

      img

      O teste mostrou: [null, null, null, null, 428.7, 4402.9400000000005,... ]

      Pode-se ver que os indicadores da linha média de 5 dias calculados, os primeiros 4 são nulos, porque o número de colunas de linha K é inferior a 5, não é possível calcular o valor médio.

    • Técnicas para determinar a atualização da linha K

      Muitas vezes, quando escrevemos algumas estratégias, temos que processar algumas operações ou imprimir alguns registros quando cada ciclo da linha K é concluído. Como podemos fazer isso? Para iniciantes sem experiência em programação, talvez não saibam qual o mecanismo para lidar com isso, mas aqui damos algumas dicas.

      Decidimos que um ciclo de K colunas está concluído e podemos começar com a propriedade de tempo nos dados de K colunas, cada vez que obtemos dados de K colunas, decidimos se o valor da propriedade Time ocorreu na última coluna de K colunas desse dado de K colunas, se ocorreu uma mudança, ou seja, se houve uma nova coluna de K colunas (provando que o ciclo de K colunas anteriores ao novo ciclo de K colunas foi concluído), se não houve mudança, ou seja, se não houve uma nova coluna de K colunas que representem a última coluna atual (o ciclo de K colunas ainda não foi concluído).

      Então nós temos que ter uma variável para registrar o tempo da última coluna da linha K de dados.

      var r = exchange.GetRecords()
      var lastTime = r[r.length - 1].Time       // lastTime 用来记录最后一根K线柱的时间。
      

      Em aplicações práticas, a estrutura é geralmente a seguinte:

      function main () {
          var lastTime = 0
          while (true) {
              var r = _C(exchange.GetRecords)
              if (r[r.length - 1].Time != lastTime) {
                  Log("新K线柱产生")
                  lastTime = r[r.length - 1].Time      // 一定要更新 lastTime ,这个至关重要。
      
                  // ... 其它处理逻辑
                  // ...
              }
      
              Sleep(500)
          }
      }
      

      img

      Como pode ser visto no retrospecto, o ciclo de K linha é definido como dia (exchange.GetRecords não especifica parâmetros quando a função é chamada, sendo o parâmetro padrão baseado no ciclo de K linha definido como retrospecto), e um registro é impresso quando uma nova coluna de K linha aparece.

  • Cálculo numérico

    • Calcule o tempo de acesso à interface do exchange

      Se você quiser ter uma visualização ou controle sobre o tempo de uso da interface de acesso estratégico à bolsa, você pode usar o seguinte código:

      function main () {
          while (true) {
              var beginTime = new Date().getTime()
              var ticker = exchange.GetTicker()
              var endTime = new Date().getTime()
      
              LogStatus(_D(), "GetTicker() 函数耗时:", endTime - beginTime, "毫秒")
              Sleep(1000)
          } 
      }
      

      Simplificando, a função GetTicker utiliza o intervalo de tempo registrado após a chamada, menos o intervalo de tempo antes da chamada, para calcular o milissegundo de experiência, ou seja, o tempo que a função GetTicker leva para executar e retornar o resultado.

    • Limitação superior e inferior dos valores usando Math.min / Math.max

      Se quisermos que o valor tenha um limite, normalmente usamos o limite Math.min.

      Por exemplo, no processo de venda, o número de moedas vendidas não pode ser maior do que o número de moedas na conta. A primeira coisa que você precisa saber é que o número de moedas disponíveis na conta é maior do que o número de moedas disponíveis na conta.

      O que é que isso tem a ver? Por exemplo, o plano de venda de uma moeda de 0.2 cêntimos.

      var planAmount = 0.2
      var account = _C(exchange.GetAccount)
      var amount = Math.min(account.Stocks, planAmount)
      

      Isso garante que o número de moedas disponíveis na conta não exceda a quantidade de moedas disponíveis na quantidade de moedas a serem encomendadas.

      Da mesma forma, Math.max é usado para garantir o limite inferior de um valor numérico. Em que cenários isso costuma ser aplicado? Em geral, as bolsas de câmbio têm um limite de quantidade de pedido mínimo para certos pares de transações, e se for inferior a esse mínimo, a ordem será rejeitada. Suponhamos que o BTC normalmente tenha um mínimo de 0.01 unidades. A estratégia de negociação é que, por vezes, é possível obter menos de 0.01 unidades por computação, então podemos usar Math.max para garantir o menor número de unidades.

    • Quantidade, preço, controle de precisão

      O controle de precisão pode ser feito usando a função _N() ou a função SetPrecision.

      A função SetPrecision ((() pode ser configurada uma vez e cortar automaticamente o número de dígitos em excesso de quantidade e preço no sistema.

      A função _N() é uma função para fazer uma interceptação numérica numérica para um determinado valor.

      Por exemplo:

      var pi = _N(3.141592653, 2)
      Log(pi)
      

      O valor de pi é cortado em decimais, mantendo dois decimais, ou seja: 3.14

      Para mais informações, consulte a documentação da API.

  • Algumas configurações lógicas

    • O cronograma é o tempo de execução de uma determinada operação.

      Pode-se usar um mecanismo como o detecção do fuso horário para determinar o fuso horário atual menos o fuso horário do momento em que a tarefa de cronometragem anterior foi concluída, e calcular em tempo real o tempo que já passou, quando esse tempo passado excede um determinado comprimento de tempo, ou seja, executar uma nova operação.

      Por exemplo, para estratégias de investimento.

      var lastActTime = 0
      var waitTime = 1000 * 60 * 60 * 12   // 一天的毫秒数
      function main () {
          while (true) {
              var nowTime = new Date().getTime()
              if (nowTime - lastActTime > waitTime) {
                  Log("执行定投")
                  // ... 具体的定投操作,买入操作。
      
      
                  lastActTime = nowTime
              }
      
              Sleep(500)
          }
      }
      

      Este é um exemplo simples.

    • Desenhar mecanismos de recuperação automática para a política

      Usando a função _G(), quantificada pelos inventores, e a função de resgate de saída, é conveniente projetar uma política para sair do progresso de conservação e reiniciar o estado de recuperação automática.

      var hold = {
          price : 0, 
          amount : 0,
      }
      
      function main () {
          if (_G("hold")) {
              var ret = _G("hold")
              hold.price = ret.price
              hold.amount = ret.amount
              Log("恢复 hold:", hold)
          }
      
          var count = 1
          while (true) {
              // ... 策略逻辑
              // ... 策略运行中,可能开仓,交易,把开仓的持仓价格赋值给 hold.price ,开仓的数量赋值给 hold.amount,用以记录持仓信息。
      
              hold.price = count++     // 模拟一些数值
              hold.amount = count/10   // 模拟一些数值
      
              Sleep(500)
          }
      }
      
      function onexit () {    // 点击机器人上的停止按钮,会触发执行这个函数,执行完毕机器人停止。
          _G("hold", hold)
          Log("保存 hold:", JSON.stringify(hold))
      }
      

      img

      Como pode ser visto, a cada parada do robô, os dados do objeto de hold são salvos, e a cada reinicialização, os dados são lidos, restaurando o valor do hold ao estado anterior à parada. É claro que este é um exemplo simples, e se for usado em uma estratégia real, deve ser projetado com base nos dados críticos que a estratégia precisa recuperar (geralmente informações sobre a conta, ações, lucros, direção de negociação, etc.). A partir daí, o governo decidiu que o país deveria voltar a ser um estado de emergência.

Aqui estão algumas pequenas dicas para o desenvolvimento de estratégias, que espero sejam úteis para iniciantes e desenvolvedores! A prática manual é o caminho mais rápido para o progresso!


Relacionados

Mais.

- Não, não.Para quem não sabe como escrever um API, é muito bom, mas se você quiser saber se a nossa plataforma suporta versões mais antigas do es, como por exemplo, você costuma usar?

O MAIKEOObrigada Dreamweaver! Dreamweaver professor, você é realmente bem-sucedido, sua tecnologia de programação é alta, seu texto é bom, admiração é ótima!

Sonhos pequenosOlá, o padrão ES8 é atualmente suportado.

Sonhos pequenosObrigado por apoiar a quantificação do FMZ!