Criar um bot de cotação de ações no WhatsApp com Java e Twilio

March 31, 2021
Escrito por
Liz Moy
Twilion
Revisado por

Criar um bot de cotação de ações no WhatsApp Bot com Java e Twilio

Não importa se você é um investidor experiente, se baixou o aplicativo RobinHood quando os eventos de r/wallstreetbets dominaram as manchetes ou se apenas está interessado em experimentar uma nova API, nunca é demais ter métodos novos para verificar os preços das ações mais recentes. Você criará um bot para o WhatsApp que enviará ao usuário uma mensagem com informações básicas sobre cotação de ações quando ele enviar um símbolo de cotação válido.

Você usará a API da Finnhub.io Stock para fazer isso. Eles também oferecem a API Forex e Crypto, então, dê uma olhada nelas se quiser complementar o que será criado aqui.

Pré-requisitos

  • Uma conta do Twilio. Cadastre-se gratuitamente aqui e ganhe 10 dólares ao fazer o upgrade de sua conta
  • Java 8 ou superior (para ver uma instalação mais simples, confira o SDKMAN! Este tutorial usa a versão 11.0.10.hs-adpt.
  • Chave API para a API da Finnhub.io. Registre-se gratuitamente para receber uma chave aqui.
  • ngrok - faça o download aqui

Você precisa se inscrever em uma conta da Finnhub.io para obter uma chave API. Se preferir uma opção que não exija inscrição, você pode usar algo como a API do Yahoo Finance. Vamos em frente!

Configurar o projeto Java

Use o Spring Initializr para configurar seu projeto clicando neste link, que preencherá os detalhes da configuração para você. Clique em "Generate" (Gerar) e, em seguida, importe o projeto para seu IDE (eu estou usando o IntelliJ IDEA). (E, sim, o projeto é chamado de "stonks" aqui porque, bem, stonks).

Crie um controlador para lidar com mensagens

Em seguida, você fará a configuração de um Controlador para criar um endpoint e adicioná-lo à configuração Programmable Messaging (mensagens programáveis) no Console da Twilio.

Se você abrir src/main/java/com/whatsappstonksbot/whatsappbot, verá que o Spring gera uma classe que iniciará o aplicativo. Não é necessário alterar nada nesse arquivo.

Nesse mesmo local, crie uma nova classe chamada MessagingController. Exclua o código gerado automaticamente e adicione o código abaixo, deixando a linha do pacote na parte superior:

@RestController
public class MessagingController {
   private final Set<String> repeatCallers = Collections.synchronizedSet(new HashSet<>());

   @PostMapping(path="/messages", produces = "text/plain")
   public String service(@RequestParam("From") String fromNumber,
                         @RequestParam("Body") String symbol) {

      if (repeatCallers.add(fromNumber)){
           return "Welcome to stonksbot \uD83D\uDCC8. Text me a valid ticker symbol and I'll give you quote data.";
       }
       return "We've heard from you.";
   }
}

Inicie o servidor ngrok e envie uma mensagem

Em uma janela de terminal, navegue até o arquivo raiz de seu aplicativo (provavelmente algo como whatsappbot). Execute o seguinte comando para iniciar o servidor:

./mvnw spring-boot:run

Nesse ponto, se você estiver sem alguma das dependências necessárias, ela não será compilada nem executada. Se você usou o link de configuração, ele deveria ter incluído o Spring Web na configuração. Quando ele for executado, você pode abrir um túnel ngrok para se conectar ao localhost:8080, a porta padrão para esse aplicativo. Se você mudou a porta por algum motivo, precisará da configuração adequada ao executar o ngrok.

Em uma nova janela de terminal, navegue até onde o ngrok está instalado e execute o comando abaixo:

ngrok http 8080 

Quando estiver em execução, ele deve ter a seguinte aparência:

a janela do ngrok sendo executada na porta 8080

Copie o endereço https:// e adicione /messages ao URL, pois esse é o nome do caminho do URL que você definiu no controlador.

Faça login em sua conta da Twilio e navegue até Programmable Messaging (Mensagens programáveis) > Setting (Configuração) > WhatsApp Sandbox Settings (Configurações de sandbox do WhatsApp). Se for a primeira vez que você configura o sandbox da Twilio para WhatsApp, siga as instruções. Ele solicitará que você envie uma mensagem com um código de área 415 com um código de texto exclusivo; por exemplo, o meu é join shop-birds.

Quando isso estiver funcionando, você pode colar o link seguro do ngrok na janela do webhook em "When a message comes in" (Quando uma mensagem chegar).

imagem da configuração da sandbox onde você deve colar o link do ngrok para quando uma mensagem for recebida

Agora, ao enviar uma mensagem para o sandbox do WhatsApp, você deverá ver o conteúdo abaixo. Se não funcionar, verifique se o servidor ainda está em execução, se o ngrok está configurado corretamente e em execução e se você tem o endpoint correto no sandbox (verifique httpe se você tem o slug /messages).

imagem de um iPhone com a mensagem de confirmação da sandbox e a primeira mensagem do bot de ações

Crie um serviço para a API do Finnhub e adicione a variável env

Criar uma nova classe no mesmo local chamada FinnhubService. Exclua o código gerado automaticamente e cole o código abaixo em

public class FinnhubService {

   public static final String FINNHUB_TOKEN = System.getenv("FINNHUB_API_KEY");

   private static final ObjectMapper MAPPER = new ObjectMapper();

   public static Optional<Price> getStockDetails(String symbol) {

       try {

           String stockUrlQuery = URLEncoder.encode(symbol.toUpperCase(), StandardCharsets.UTF_8);
           String tokenUrlQuery = URLEncoder.encode(FINNHUB_TOKEN, StandardCharsets.UTF_8);

           URL url = new URL("https://finnhub.io/api/v1/quote?symbol=" + stockUrlQuery + "&token=" + tokenUrlQuery);
           HttpURLConnection connection = (HttpURLConnection) url.openConnection();
           connection.setRequestProperty("accept", "application/json");
           InputStream responseStream = connection.getInputStream();
           Price price = MAPPER.readValue(responseStream, Price.class);

           if ("0".equals(price.open)){
               return Optional.empty();

           } else {
               return Optional.of(price);
           }

       } catch (IOException e){
           e.printStackTrace();
           return Optional.empty();
       }

   }
}

Este código faz uma solicitação GET para a API do Finnhub e, em seguida, gerencia a resposta JSON. Em seguida, ele mapeia a resposta para um objeto chamado Price (você obterá o mapeador de objetos na próxima etapa). Por fim, ele envia esse objeto de volta ao Controller para que ele possa ser formatado perfeitamente em uma mensagem.

Se quiser tentar fazer a solicitação antes de executá-la em seu código, você pode usar uma ferramenta como o Postman. Há também um Chave do sandbox da API do Finnhub separado que você pode usar se quiser testar qualquer um dos dados premium (eles são marcados como premium na documentação) ou se tiver preocupações sobre atingir os limites de taxa (60/1 minuto, então, provavelmente nada a se preocupar).

Há uma série de maneiras de fazer solicitações HTTP em Java (veja aqui a excelente publicação de Matthew sobre as 5 maneiras de fazer solicitações HTTP com Java). Neste exemplo, você usará um método clássico que já está incluído no seu kit do desenvolvedor Java, principalmente para que você não precise adicionar nenhuma biblioteca extra.

Observe que o URL tem o parâmetro symbol, que é o símbolo de cotação registro do mercado de ações que você obterá do corpo da mensagem do usuário. Passe isso como uma string.

Também é essencial que você coloque o símbolo com todas as letras maiúsculas caso o usuário tenha digitado alguma letra minúscula; a chamada de API retornará nulo se o símbolo não estiver totalmente em maiúscula.

Você também deve definir o parâmetro de token aqui como a chave API Finnhub.

Lembre-se de que, no início, você precisava de uma chave API Finnhub como requisito? É aí que ela entra. Você vai copiar a chave API de seu dashboard do Finnhub e vai defini-la como uma variável de ambiente.

como deve ser a chave de API quando você faz login no Finnhub para obtê-la, que é um modal branco com um botão verde da documentação de API e um botão de regeneração preto

Definir variáveis de ambiente é outra tarefa pode ser realizada de diferentes formas. Contato que esteja oculta, você não a confirma publicamente em nenhum lugar e ainda pode acessá-la, usando a forma que preferir. Você pode seguir esse caminho se desejar, e o código incluído acima deve funcionar corretamente usando System.getenv(). Substitua a string de Xs por sua própria chave API.

echo "export finnhubToken='XXXXXXXXXXXX'" > twilio.env
source ./twilio.env

Agora que a string finnhubToken está definida, ela extrairá a variável de seu sistema. Você pode executar o comando abaixo para garantir que seu .env seja ignorado se decidir confirmar esse código em qualquer lugar.

echo "twilio.env" >> .gitignore

Mapear o objeto Price

De acordo com o Documentação da API de cotação de ações do Finnhub, você pode ver que a resposta retorna com os atributos como letras únicas. Ao fazer o mapeamento, pode ser útil dar nomes mais descritivos à resposta para que você possa se certificar de que, ao formatar a mensagem, os atributos corretos sejam definidos com as descrições corretas.

Você poderá enviar informações ao usuário, como o preço de abertura do dia da ação, preço alto do dia, preço baixo do dia, preço atual e preço do fechamento anterior.

public class Price {
    public final String open;
    public final String high;
    public final String low;
    public final String current;
    public final String close;
    public final String time;

    public Price(@JsonProperty("o") String open,
                 @JsonProperty("h") String high,
                 @JsonProperty("l") String low,
                 @JsonProperty("c") String current,
                 @JsonProperty("pc") String close,
                 @JsonProperty("t") String time) {
        this.open = open;
        this.high = high;
        this.low = low;
        this.current = current;
        this.close = close;
        this.time = time;
    }
}

No código anterior, você já retornou o objeto Price do serviço. Agora você precisa chamar o serviço no MessagingController.

Formatar bem a mensagem no Controlador

Em MessagingController, abaixo da instrução IF que verifica se há chamadores repetidos, adicione o código abaixo (veja o código completo no github). Isso pegará o símbolo que alguém digitou e usará o messageBuilder para criar uma mensagem legível a ser enviada de volta para a pessoa que enviou a mensagem.

   Optional<Price> price = FinnhubService.getStockDetails(symbol);

   if (price.isPresent()){
       return messageBuilder(price.get(), symbol);
   } else {
       return "Sorry. We couldn't find any info on that one. Try another.";
   }
}


private String messageBuilder(Price price, String symbol) {
   return String.format("Here are the most up-to-date %s prices:\n" +
                   "\uD83C\uDF05 Open price of the day: $%s\n" +
                   "\uD83D\uDCC8 High price of the day: $%s\n" +
                   "\uD83D\uDCC9 Low price of the day: $%s\n" +
                   "\uD83D\uDD14 Current price: $%s\n" +
                   "\uD83D\uDCC6 Previous close price: $%s\n" +
                   "\uD83E\uDD1E Send another symbol.",
           symbol.toUpperCase(), price.open, price.high, price.low, price.current, price.close);
}

Agora, você pode ver se está funcionando.

Faça o teste

Execute novamente o servidor e envie uma mensagem de WhatsApp com um símbolo de ação válido para o bot. Você deve obter o seguinte:

Uma imagem do bot e sua resposta depois de receber o símbolo de ação TWLO

Se não funcionar, verifique os erros no rastreamento de pilha. As armadilhas mais comuns são variáveis de ambiente definidas incorretamente e variáveis ausentes que podem não ter sido adicionadas nas etapas.

Saber mais sobre finanças é divertido. Java é divertido.

Esperamos que tenha gostado desta publicação e já esteja pensando em dados adicionais para adicionar ao seu bot. Também recomendamos que você veja esta publicação sobre como verificar Preços de gás da Ethereum usando o Twilio Serverless. E se o TypeScript é mais sua área, você pode construí-lo com ele.

Se encontrar erros pelo caminho, não se preocupe. Você provavelmente não perdeu 460 milhões de dólares por causa disso. Se decidir fazer seu próprio bot, eu adoraria saber mais sobre ele. Envie um e-mail para lleao[arroba]twilio.com para me avisar

Este artigo foi traduzido do original "Build a Stock Quote WhatsApp Bot with Java and Twilio". Enquanto melhoramos nossos processos de tradução, adoraríamos receber seus comentários em help@twilio.com - contribuições valiosas podem render brindes da Twilio.