Em outras oportunidades aqui no blog e também no meu canal do Youtube eu trouxe tutoriais de como criar robôs de criptomoedas, ou seja, automações via software para comprar e vender criptoativos em corretoras como Binance, Mercado Bitcoin e BityPreço. Em todas essas ocasiões eu trouxe como gatilho de compra e venda o preço do ativo no mercado à vista, afinal nada é mais importante (e óbvio para leigos) do que o preço do ativo, já que a estratégia mais bruta que existe é comprar barato e vender caro, certo?
No entanto estratégias mais elaboradas (e geralmente mais assertivas) não usam unicamente o preço como indicador de melhor momento de compra ou de venda. O mais comum é o uso dos chamados indicadores técnicos: métricas obtidas através de matemática sobre o comportamento passado daquele ativo. Existem centenas de indicadores mas a imensa maioria deles é obtido da seguinte forma:
- pega-se uma amostra de velas (candles) do ativo;
- aplica-se uma fórmula matemática sobre as velas (geralmente o preço de fechamento);
- obtém-se o indicador atualizado para comparação;
E é justamente isso que quero mostrar como você pode fazer hoje. Se preferir, pode assistir ao vídeo abaixo ao invés de ler.
Vamos lá!
#1 – Setup do Projeto
Dentre os players mundiais de criptomoedas, uma das mais agressivas em termos de taxas e portfólio de moedas é a Binance, considerada a maior exchange de criptomoedas do mundo em volume de negociações. Usaremos ela como fonte de dados aqui pois é um bom termômetro do mercado de criptomoedas, mas o que vou mostrar pode ser usado com qualquer exchange (de cripto ou não) que disponibilize publicamente as suas velas. Nem mesmo você precisa ter conta na Binance para fazer este tutorial, pois ele não efetuará as compras e vendas de fato, ok?
Além disso, existem centenas de indicadores técnicos diferentes, como citei na introdução, então pegarei um como exemplo e depois eu posso trazer outros em oportunidades futuras ou você pega o que aprender aqui e adapta para outros indicadores, ok?
Dito isso, antes de sairmos programando precisamos configurar nosso projeto. Usarei aqui a linguagem JavaScript, então precisamos do Node.js instalado na máquina. Se ainda não tem o ambiente de desenvolvimento para Node.js configurado, você pode ver como fazer no vídeo abaixo.
Agora crie uma pasta no seu computador com o nome de binance-sma-ema e dentro dela rode o comando abaixo pelo seu terminal de linha de comando para inicializar um projeto Node.js na pasta.
1 2 3 |
npm init -y |
Agora coloque um arquivo index.js vazio dentro da pasta e vamos instalar alguns pacotes via NPM pra deixar nosso projeto preparado. Seguem os comandos de instalação:
1 2 3 |
npm i dotenv axios |
O módulo dotenv serve para carregar automaticamente variáveis de ambiente na sua aplicação Node.js. Usaremos estas variáveis de ambiente para colocar as configurações do nosso bot. Agora crie um arquivo “.env” na raiz do seu projeto colocando nele os valores abaixo, conforme instruções:
- API_URL: o endereço base da URL de API da Binance que você vai utilizar, produção ou desenvolvimento;
- SYMBOL: o par de moedas que seu robô vai monitorar e calcular indicadores. Ex: BTCUSDT (sempre em maiúsculas);
- INTERVAL: o tempo gráfico das suas velas. Ex: 1h (para velas de 1h);
- PERIOD: o período (quantidade de velas) que serão usadas no seu cálculo. Ex: 20;
Seu arquivo deve ficar mais ou menos assim:
1 2 3 4 5 6 |
API_URL=https://api.binance.com/api SYMBOL=BTCUSDT INTERVAL=1h PERIOD=20 |
Para carregar estas configurações na sua aplicação, modifique o seu package.json para que no script de start ele carregue o .env:
1 2 3 4 5 |
"scripts": { "start": "node -r dotenv/config index" }, |
Note que este robô de monitoramento de indicador irá funcionar com um par de moedas e um indicador, mas pode ser adaptado para vários pares ou pode replicar o projeto várias vezes na sua máquina.
#2 – Obtendo os dados das velas
Para a finalidade de monitoramento das velas/candles a Binance fornece uma API histórica, que é útil para pegar velas em quantidade, e um fluxo de streams que é útil para pegar somente a vela atual. É possível fazer uma abordagem que une o melhor dos dois mundos mas isso complicaria demais esse tutorial, então vou usar uma abordagem mais simplificada, apenas com a API.
Para consumir a API de velas históricas da Binance eu usarei o pacote Axios, que instalamos anteriormente. Se você nunca programou com Axios antes, ele é um cliente HTTP bem popular para JavaScript e o vídeo abaixo dá uma excelente introdução (não é obrigatório, mas ajuda).
Com o Axios importado em seu arquivo index.js (abaixo) e as variáveis do .env devidamente carregadas, você pode combiná-los para chamar a API de velas históricas e imprimir no console o resultado.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
const axios = require("axios"); const API_URL = process.env.API_URL; const SYMBOL = process.env.SYMBOL; const INTERVAL = process.env.INTERVAL; const PERIOD = parseInt(process.env.PERIOD); async function getCandles(){ const response = await axios.get(`${API_URL}/v3/klines?symbol=${SYMBOL}&interval=${INTERVAL}&limit=1000`); const closes = response.data.map(k => parseFloat(k[4])); console.log(closes); } getCandles(); |
Nesta amostra de código, após eu ter todas as variáveis necessárias, eu chamo uma função getCandles que faz a request com Axios para a rota klines da REST API da Binance. Essa API espera que a gente passe o symbol (par de moedas), o interval (tempo gráfico) e a quantidade de velas que queremos, sendo que o valor máximo é 1000, que é justamente o que estou pegando aqui (explicarei porquê mais adiante). Isso retornará um array de velas que mapeamos para pegar somente o close de cada vela (valor de fechamento), pois é a única informação que precisamos.
Neste primeiro momento, apenas imprimimos os closes no terminal para que você consiga ver se esta primeira etapa funcionou. Experimente rodar o seu projeto com o comando npm start e terá os valores impressos no terminal.
#3 – Entendendo o Cálculo do Indicador
Agora que temos os dados que precisamos para a grande maioria dos indicadores técnicos, é hora de escolher um, estudarmos sua fórmula e implementarmos o seu cálculo em JavaScript. Para este tutorial eu escolhi trabalhar com Médias Móveis, sendo que existem dois tipos, a Simples (SMA ou Simple Moving Average) e a Exponencial (EMA ou Exponential Moving Average). Como a EMA depende da SMA para ser calculada, vamos começar com a simples.
A SMA ou Média Móvel Simples possui como fórmula uma média aritmética simples, como o próprio nome sugere. Ou seja, somam-se todos os valores de fechamento das velas de um período e divide-se pelo próprio período. Isso é facilmente programado em JavaScript como abaixo, nem exige muito estudo.
1 2 3 4 5 6 |
function SMA(closes){ const sum = closes.reduce((a,b) => a + b); return sum / closes.length; } |
Aqui eu usei um reduce para fazer o somatório, mas sinta-se à vontade de usar um for caso não entenda de High Order Functions, o que eu explico no vídeo abaixo caso deseje entender.
Assim, para testar essa função, basta juntar ela à função de getCandles que criamos antes, algo como abaixo. Repare como eu pego apenas os últimos 20 closes (PERIOD) para calcular o SMA de 20 períodos.
1 2 3 4 5 6 7 8 9 |
async function getCandles(){ const response = await axios.get(`${API_URL}/v3/klines?symbol=${SYMBOL}&interval=${INTERVAL}&limit=1000`); const closes = response.data.map(k => parseFloat(k[4])); console.log("SMA: " + SMA(closes.slice(closes.length - PERIOD))); } getCandles(); |
Experimente executar este código com ‘npm start’ e compare o resultado com o obtido em ferramentas como TradingView, verá que batem (às vezes com diferença de precisão em casas decimais).
Agora que temos uma função para calcular o SMA, é hora de partirmos para o EMA que é uma versão evoluída dele e mais sensível às alterações recentes de preço, enquanto dá menos importância a preços antigos. Antes de escrever algoritmos para indicadores técnicos mais complexos é sempre importante que você entenda a fórmula do mesmo. No caso do EMA, ela é facilmente encontrada na Internet e é expressa como:
Resumidamente, o que esta fórmula nos diz é que para achar o EMA atual, temos de pegar o preço médio de hoje (Price(t)), multiplicar por um expoente de suavização (k, uma divisão de 2 sobre períodos + 1) e por fim somar com o EMA do dia anterior (EMA(y) x (1-k)). Essa fórmula é aplicada a várias velas até chegar na última, que é a que vai entregar o EMA atual, então teremos um laço e note que são fórmulas dentro de fórmulas, então tem de ser feito bem passo a passo.
Que tal começarmos com o ‘k’? Esse coeficiente de suavização (smoothing) é muito simples de ser implementado, como abaixo, onde a função recebe o período e ele aplica a fórmula anteriormente exibida:
1 2 3 4 5 |
function smoothing(period){ return 2 / (period + 1); } |
Outro ponto crucial da fórmula é que ela exige que tenhamos um EMA anteriormente calculado. Mas o que acontece quando estamos calculando o EMA da primeira vela? Neste caso, aplicamos o algoritmo SMA no primeiro bloco de N velas, onde N é o período configurado.
1 2 3 |
let prevEma = SMA(closes.slice(0, period)); |
Assim, o meu prevEma inicial será o resultado de um SMA das primeiras 20 velas recebidas da API (considerando um período de 20). Com esse prevEma inicial, podemos fazer o nosso laço que, a partir da vela 21 (as primeiras 20 foram usadas no SMA), vamos conseguir calcular o EMA vela a vela aplicando a fórmula, sendo que quanto mais velas você tiver para esse algoritmo todo, melhor (o Trading View usa as 1000 velas que a Binance disponibiliza).
1 2 3 4 5 |
for (let i = period; i < closes.length; i++) { prevEma = (closes[i] - prevEma) * multiplier + prevEma; } |
Note como estou guardando apenas o último EMA calculado, mas você pode ir armazenando em um vetor se quiser ter todos os valores. Isso vai nos dar o EMA para o período. Bora juntar os pedaços?
#4 – Calculando o EMA em JS
Agora que entendemos como calcular a fórmula em JS, transpor o entendimento acima para uma função é muito simples, como abaixo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function EMA(closes, period = 20) { if (closes.length < period) throw new Error("Não há dados suficientes para calcular o EMA."); const multiplier = smoothing(period); let prevEma = SMA(closes.slice(0, period)); for (let i = period; i < closes.length; i++) { prevEma = (closes[i] - prevEma) * multiplier + prevEma; } return prevEma; } |
Isso vai permitir que apenas informando os closes e o período para a função, que teremos o EMA calculado. Agora você pode voltar na função getCandles e adicionar a chamada ao cálculo do EMA, imprimindo o resultado.
1 2 3 4 5 6 7 8 |
async function getCandles(){ const response = await axios.get(`${API_URL}/v3/klines?symbol=${SYMBOL}&interval=${INTERVAL}&limit=1000`); const closes = response.data.map(k => parseFloat(k[4])); console.log("SMA: " + SMA(closes.slice(closes.length - PERIOD))); console.log("EMA: " + EMA(closes, PERIOD)); } |
Por fim, se quiser que esse comportamento se repita de tempos em tempos, basta criar um timer, como abaixo, onde exemplifiquei um intervalo de 3 segundos entre cada cálculo.
1 2 3 4 |
getCandles(); setInterval(getCandles, 3000); |
O resultado, você vê no seu terminal.
Para me certificar que estava comparando certo, eu abri um gráfico no Trading View com o mesmo ativo e tempo gráfico e os valores ficaram muito próximos, alguns décimos de diferença apenas, o que não influencia na análise do indicador, que geralmente é focada no valor inteiro.
Quer aprender a calcular outro indicador? Confira este post.
Um abraço e até a próxima!
Olá, tudo bem?
O que você achou deste conteúdo? Conte nos comentários.