Como e por que escrevi um analisador para o site Tradingview. Automação comercial DIY

Problema: No momento, o software mais conveniente e completo (doravante denominado software) para automação de negociação no mercado de ações russo é o notório TSLAB .


Apesar das vantagens indiscutíveis na forma de um editor visual conveniente para escrever scripts de negociação, que permite escrever robôs mesmo sem o conhecimento das linguagens de programação, existem várias desvantagens que tornam o uso deste software extremamente inútil para mim. E acho que não apenas para mim, dado que, em regra, o tamanho médio de uma conta em Mosbirz não excede 500 mil rublos.


1. Custo: taxa de assinatura de 4500 rublos por mês + aluguel de um servidor virtual (1000 rublos por mês)
Esse custo fixo impõe um fardo muito pesado ao resultado financeiro do meu comércio. Portanto, ter um tamanho de conta de 500 mil rublos e com a esperança de obter pelo menos 20% ao ano, com os custos existentes, você precisa ganhar entre 32 e 35% para alcançar a lucratividade planejada.


2. Instabilidade do trabalho: apesar de meus algoritmos trabalharem principalmente com ordens de mercado (tipo de ordem, que assume 100% de execução), minhas posições muitas vezes dobraram ou não foram executadas.


Objetivo: escrever um software para automatizar a negociação, a fim de minimizar os custos fixos, com uma interface conveniente para a criação de scripts de negociação que permitem escrever robôs de negociação sem nenhum conhecimento aprofundado de programação.


A arquitetura de todo o projeto, com as melhorias atuais e de funcionalidade e planejadas, é apresentada na figura abaixo.



O link mais importante no programa é, sem dúvida, o site da Tradingview (doravante referido como TV). Ele apenas apresenta uma funcionalidade conveniente para escrever seus scripts de negociação devido à linguagem Pine_Script interna.


O idioma, a propósito, não requer conhecimento específico e basicamente se assemelha ao Easy Language do pacote Metastock, e a disponibilidade de ajuda on-line em russo torna a escrita do código o mais agradável possível.


Um exemplo de estratégia para romper a média móvel (literalmente em três linhas de código):


mov_average=sma(close,x) strategy.entry("My Long Entry Id", strategy.long,when=close>mov_average) strategy.entry("My Short Entry Id", strategy.short,when=close<mov_average) 

Agora, com uma interface conveniente para escrever scripts de negociação, resta estabelecer o processo de envio de aplicativos da TV diretamente para o sistema de negociação (no meu caso, é o programa Quik) ou diretamente para o servidor do corretor. O único problema é que a TV não possui uma API aberta para implementar essa funcionalidade.


Ao tentar resolver esse problema, a primeira coisa que me ocorreu foi usar um plug-in para testar o WebSelenium e pesquisar nos localizadores XPath para encontrar os elementos de que precisamos que são responsáveis ​​pelos sinais de compra e venda.


Os sinais em si são exibidos na tabela e não deve haver problemas. Mas, para procurar o sinal extremo, a tabela exigia rolagem, mas não consegui encontrar o elemento de rolagem (veja a figura abaixo).



Portanto, eu tive que procurar outra solução.


Visualmente, os sinais de TV são exibidos no elemento canvas. A cor do sinal pode ser alterada, se necessário (por exemplo: venda vermelha, compra verde).


As cores definidas na TV configuramos em nosso aplicativo. O aplicativo em si é escrito em Java, a interface gráfica é implementada usando a biblioteca Swing
Além disso, no próprio programa, precisamos selecionar a área da tela (ou apenas a área digitalizada), na qual procuraremos cores de controle.


A figura abaixo mostra o site da tradingview com três instrumentos selecionados, a cor do sinal de negociação é definida para cada um deles. Essas cores são duplicadas no meu programa Parse_Signal.


.


Após definir a área de digitalização e o tipo de instrumento que está sendo negociado (a propósito, as configurações do programa levam 5 minutos e são salvas em um arquivo com a extensão .txt). Em seguida, pressione o botão "INICIAR" e o programa começará a funcionar.


Funciona em dois threads.


1 primeiro segmento:


  • Digitaliza a área selecionada (neste caso, tela).
    Fazemos a varredura clássica usando a funcionalidade da classe Robot:


     BufferedImage buf= robot.createScreenCapture(new Rectangle(selection.x, selection.y, selection.width, selection.height)) 

  • Em seguida, divide a varredura resultante em uma matriz de pixels:


     int[] pixels = copyFromBufferedImage(buf); //,     ,        : public int[] copyFromBufferedImage(BufferedImage bi) { int[] pict = new int[bi.getHeight() * bi.getWidth()]; for (int i = 0; i < bi.getWidth(); i++) for (int j = 0; j < bi.getHeight(); j++) pict[i * bi.getHeight() + j] = bi.getRGB(i, j) & 0xFFFFFF; // 0xFFFFFF:   3   RGB return pict; 

  • Procura na matriz de pixels as cores de controle dos sinais de negociação. Pesquise da esquerda para a direita. I.e. é a cor do pixel mais à direita que é relevante para o programa:


     for(int i=0;i<pixels.length;i++ ) { if (pixels[i] == (buy.getBackground().getRGB() & 0xFFFFFF)) { position = 1; //System.out.println("  ")} else if (pixels[i] == (sell.getBackground().getRGB() & 0xFFFFFF)) { position = -1; //System.out.println("  ");} else if (pixels[i] == (hold.getBackground().getRGB() & 0xFFFFFF)) { position = 0; ...................... ...................... 


  • Registra uma transação comercial (em um arquivo com a extensão .tri) de acordo com o modelo, dependendo da cor encontrada. Aqui, de fato, tudo é simples no terminal de negociação Quik, é possível ler automaticamente as transações de um arquivo. Basta registrá-los de acordo com um determinado padrão. Quik, quando uma nova entrada aparece, envia uma solicitação ao servidor do broker. O arquivo é lido a cada 500 ms. Opcionalmente, informações sobre sinais de negociação podem ser enviadas para correio, telefone ou sistema de negociação (três parâmetros podem ser selecionados simultaneamente). 1 thread trabalha com uma frequência de 500 ms.



 if (position==1&&status!=1&&b1==1) { if(dialog.isSend_phone()==true) { new SMS().sendSms(dialog.getPhone(), "TS_1:    "+ (String)dialog.cbFirst.getSelectedItem()+" "+price+" "+new Date(), "TEST-SMS", dialog.getLogin(), dialog.getPassword());} if(dialog.isSend_trade()==true){ tr.Order_Buy();} if(dialog.isSend_mail()==true){ test.sendSignal("BUY","TS_1: Buy in signal at price "+ (String)dialog.cbFirst.getSelectedItem()+" "+price+" "+new Date());} status = 1;} ...................... ...................... 

2 o fluxo do programa realiza a solicitação do preço do instrumento negociado analisando a página html do site da Finam . O plug-in JSOUP é usado. Aqui, simplesmente carrego as páginas html e procuro o código do instrumento de negociação necessário (ex: Si, Sber, etc.).


 public void run() { while (true) { Document doc = null; Document doc_2 = null; try { doc = Jsoup.connect("https://www.finam.ru/quotes/futures/moex/").get(); doc_2 = Jsoup.connect("https://www.finam.ru/profile/mosbirzha-fyuchersy/sbrf").get();} catch (IOException e) { e.printStackTrace(); continue;} StringBuffer buffer = new StringBuffer(doc.text()); StringBuffer buffer_2 = new StringBuffer(doc_2.text()); Map<String, String> map = new HashMap<>() try {map.put(elements[1], buffer.substring(buffer.indexOf("Si "), buffer.indexOf("Si ") + 8).split("Si ")[1]); map.put(elements[2], buffer.substring(buffer.indexOf("RTS "), buffer.indexOf("RTS ") + 10).split("RTS ")[1]); map.put(elements[3], buffer.substring(buffer.indexOf("LKOH "), buffer.indexOf("LKOH ") + 10).split("LKOH ")[1]); map.put(elements[4], buffer.substring(buffer.indexOf("BR "), buffer.indexOf("BR ") +8).split("BR ")[1]); map.put(elements[5], buffer.substring(buffer.indexOf("GAZP "), buffer.indexOf("GAZP ") + 10).split("GAZP ")[1]); map.put(elements[6], buffer.substring(buffer.indexOf("GOLD "), buffer.indexOf("GOLD ") + 11).split("GOLD ")[1]); map.put(elements[7], buffer.substring(buffer.indexOf("MOEX "), buffer.indexOf("MOEX ") + 10).split("MOEX ")[1]); map.put(elements[8], buffer.substring(buffer.indexOf("MIX "), buffer.indexOf("MIX ") + 10).split("MIX ")[1]); map.put(elements[9], "0"); map.put(elements[10], buffer_2.substring(buffer_2.indexOf("  "), buffer_2.indexOf("  ") + 23).split(" ")[2] + buffer_2.substring(buffer_2.indexOf("  "), buffer_2.indexOf("  ") + 23).split(" ")[3]);} catch (Exception e) { System.out.println(e); text.setText("     "); continue;} price = String.valueOf((int) Double.parseDouble(map.get((String) 

É claro que este é um elo fraco no programa, pois qualquer alteração na página html gerará uma exceção. Portanto, no futuro, está planejado solicitar informações de troca para solicitar diretamente através do Quik ou diretamente do servidor do broker.
Para fazer isso, você pode usar a biblioteca .dll pronta para Quik em C #, mas como eu escrevo em Java, no meu caso, será mais fácil implementar um script em lua (a linguagem Quik interna), que registrará os preços de compra e venda em um arquivo separado, o programa. Parse_Signal e, em seguida, lerá.


Note-se que, de fato, temos um monte bastante volumoso de TV + Parser + Quik. E, apesar da estabilidade dessa solução, no futuro, está planejado enviar aplicativos não para o Quik, mas diretamente para o servidor do broker (por exemplo, usando a interface Atlentis da Alora como opção ). A biblioteca realmente é novamente implementada em C #, então você precisa criar algo.


Este programa me permitiu resolver as tarefas iniciais que defini para mim:
ou seja, às vezes para reduzir custos fixos.


O código do programa é publicado em domínio público.


Se alguém estiver pronto para compartilhar suas idéias sobre a interação com a TV, ficarei muito feliz em ver isso nos comentários.

Source: https://habr.com/ru/post/pt447912/


All Articles