Na primeira parte deste tutorial, que é obrigatório você ter realizado para que consiga avançar para esta (link aqui), nós preparamos o ambiente de desenvolvimento, estruturamos nosso projeto, aprendemos a carregar as contas dos copy traders e a nos conectarmos na stream do trader mestre, a fim de que possamos monitorá-la. E conseguimos, ao término da primeira parte o seu bot já está monitorando a conta mestra e imprimindo no console os trades, aliás, sem repetição.
Agora nesta segunda e última parte, vamos replicar o trade a partir das informações da atualização de conta e vamos enviá-la para a Binance Futures, uma vez em nome de cada copy trader.
Vamos lá!
#1 – Replicando o Trade
Nossa primeira missão é, dadas as informações que vem no Order Trade Update da user data stream (basicamente os dados do trade realizado), temos de montar um objeto de order para ser enviado na API de new order da Binance Futures. Conforme a documentação da Binance, o que recebemos de informações do trade é documentado aqui. E também conforme a documentação da Binance, o que devemos enviar de informações na ordem é documentado aqui. Olhando as duas documentações verá que precisaremos fazer uma “conversão” de um objeto de trade para um objeto de ordem. Faço uma proposta de nova função para seu index.js abaixo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
function copyTrade(trade) { const data = { symbol: trade.s, side: trade.S, type: trade.o } if (trade.q && parseFloat(trade.q)) data.quantity = trade.q; if (trade.p && parseFloat(trade.p)) data.price = trade.p if (trade.f && trade.f !== "GTC") data.timeInForce = trade.f; if (trade.sp && parseFloat(trade.sp)) data.stopPrice = trade.sp; if (trade.ps && parseFloat(trade.ps)) data.positionSide = trade.ps; if (trade.AP && parseFloat(trade.AP)) data.activationPrice = trade.AP; if (trade.cr && parseFloat(trade.cr)) data.callbackRate = trade.cr; return data; } |
Nesta função copyTrade nós recebemos um objeto de trade e pegamos imediatamente algumas informações dele: as propriedades s (symbol), S (side) e o (order type). Depois fazemos alguns testes para saber quais outras informações podemos/devemos pegar, como a q (quantity), a p (price), a f (time in force), sp (stop price) e AP/cr (usadas em trailing stops). Essa verificação consiste em nos certificarmos que a propriedade está presente e seu valor não é zero ou default. Isso porque a API de ordem dá erro se enviarmos zero em algum parâmetro.
Essa função copy trade deve ser usado na sua função de start do index.js, dentro do if de processamento do ORDER_TRADE_UPDATE, como abaixo.
1 2 3 4 5 6 7 8 9 10 |
if (trade.e === "ORDER_TRADE_UPDATE" && !oldOrders[trade.i]) { oldOrders[trade.i] = true; console.clear(); const data = copyTrade(trade.o);//atenção ao trade.o console.log(data); } |
Com isso, recomendo que faça novos testes e veja se a conversão de trade para order está acontecendo como deveria antes de avançar.
#2 – Copiando os Trades
Agora que já temos o objeto no padrão de ordem da Binance, é hora de enviá-lo para a API new order a fim de efetivar novos trades para os copy traders. Para isso, teremos de primeiro ir no api.js e criar a função que envia a ordem para a Binance, como abaixo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
const crypto = require('crypto'); async function newOrder(data, apiKey, apiSecret) { if (!apiKey || !apiSecret) throw new Error('Preencha corretamente sua API KEY e SECRET KEY'); data.timestamp = Date.now(); data.recvWindow = 60000;//máximo permitido, default 5000 const signature = crypto .createHmac('sha256', apiSecret) .update(`${new URLSearchParams(data)}`) .digest('hex'); const qs = `?${new URLSearchParams({ ...data, signature })}`; try { const result = await axios({ method: "POST", url: `${apiUrl}/v1/order${qs}`, headers: { 'X-MBX-APIKEY': apiKey } }); return result.data; } catch (err) { console.error(err.response ? err.response : err); } } module.exports = { newOrder, connectAccount } |
Aqui nós começamos carregando um pacote nativo do Node.js para criptografia (não requer instalação) e declaramos a assinatura da nossa função newOrder que vai esperar os dados da ordem e as chaves da conta que vai executá-la. É importante que as chaves sejam passadas aqui pois chamaremos esta função de maneira repetida, mas para contas diferentes.
Uma vez na função, pegamos a hora do sistema (seu relógio precisa estar precisamente ajustado ou terá erros) e definimos a janela de tolerância para execução da ordem após envio dos dados para a Binance (quanto mais lenta a Internet, maior deve ser esse valor). Na sequência nós criamos a assinatura criptográfica dessa ordem usando o pacote crypto, os dados da ordem e a api secret da conta. A próxima etapa é montar a query string com os dados da ordem mais a assinatura criptográfica e enviar isso para a Binance conforme a documentação exige. O resultado desse envio é devolvido para o requisitante.
Agora essa função deve ser usada no index.js, após a construção do objeto com os dados da ordem (primeira linha do código abaixo) e uma vez para cada trader carregado inicialmente.
1 2 3 4 5 6 7 8 9 10 |
const data = copyTrade(trade); const promises = accounts.map(acc => api.newOrder(data, acc.apiKey, acc.apiSecret)); const results = await Promise.allSettled(promises); console.log(results); //para não entrar em loop durante os testes, descomente abaixo process.exit(0); |
Essa iteração por todas contas eu optei por fazer com um map, chamando uma vez a api.newOrder para cada conta carregada e usando os respectivos pares de chaves delas. Ao término desse laço, teremos um array de promises já que cada chamada à API retorna uma promise ao invés do resultado final. Usando Promise.allSettled nós aguardamos na linha de baixo pela execução de todas chamadas e devolvemos todos os seus resultados no console.
Apenas para testes que envolvam a mesma conta sendo a mestre e a cópia, incluí uma linha adicional que derruba o bot após um copy trade, caso contrário ele entraria em loop. Essa linha final é desnecessária caso você esteja testando com contas mestre e copy diferentes.
Agora você pode testar finalmente o seu bot com a funcionalidade final. Se fizer um trade na conta mestre, por qualquer que seja o meio, o bot receberá a atualização e vai enviar uma ordem idêntica para cada uma das contas copy configuradas.
Indo além do que mostrei aqui, você pode fazer modificações, como por exemplo cada copy trader fazer a mesma ordem, mas com quantidades diferentes, por exemplo. Ou o bot verificar se tem saldo para conseguir fazer a mesma ordem por exemplo. Ou ainda construir uma interface gráfica para este bot e um banco de dados, a fim de que ele possa ser usado e configurado mais facilmente por você. Ou ainda plugar ele no Telegram ou no WhatsApp, para avisar os copy traders, podendo ser também via email ou SMS.
Enfim, o céu é o limite em termos de melhorias futuras.
Até a próxima!
Olá, tudo bem?
O que você achou deste conteúdo? Conte nos comentários.