Este bot responde a /cotacao PETR4 com o último preço, a variação e o horário
disponíveis na brapi. O projeto usa Python, python-telegram-bot e httpx.
Criar o bot no Telegram
Abra uma conversa com @BotFather no Telegram:
- envie
/newbot; - escolha nome e usuário;
- copie o token gerado;
- não publique esse token.
Crie também um token no dashboard da brapi. Guarde os dois em variáveis de ambiente:
export TELEGRAM_BOT_TOKEN="SEU_TOKEN_DO_TELEGRAM"
export BRAPI_TOKEN="SEU_TOKEN_DA_BRAPI"Instalar as dependências
pip install python-telegram-bot httpxCódigo do comando de cotação
import os
import re
import httpx
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes
TELEGRAM_TOKEN = os.environ["TELEGRAM_BOT_TOKEN"]
BRAPI_TOKEN = os.getenv("BRAPI_TOKEN")
TICKER_PATTERN = re.compile(r"^[A-Z0-9^]{3,12}$")
async def get_quote(symbol: str) -> dict:
headers = (
{"Authorization": f"Bearer {BRAPI_TOKEN}"}
if BRAPI_TOKEN
else {}
)
async with httpx.AsyncClient(timeout=15) as client:
response = await client.get(
"https://brapi.dev/api/v2/stocks/quote",
params={"symbols": symbol},
headers=headers,
)
response.raise_for_status()
payload = response.json()
if not payload.get("results"):
raise ValueError("Ticker não encontrado")
return payload["results"][0]
async def cotacao(
update: Update,
context: ContextTypes.DEFAULT_TYPE,
) -> None:
if not context.args:
await update.message.reply_text("Use /cotacao PETR4")
return
symbol = context.args[0].strip().upper()
if not TICKER_PATTERN.fullmatch(symbol):
await update.message.reply_text("Ticker inválido")
return
try:
result = await get_quote(symbol)
quote = result["data"]
price = quote["regularMarketPrice"]
change = quote["regularMarketChangePercent"]
market_time = quote["regularMarketTime"]
await update.message.reply_text(
f"{result['symbol']}\n"
f"Preço: R$ {price:.2f}\n"
f"Variação: {change:.2f}%\n"
f"Horário: {market_time}"
)
except (httpx.HTTPError, ValueError, KeyError) as error:
await update.message.reply_text(f"Não foi possível consultar: {error}")
def main() -> None:
app = Application.builder().token(TELEGRAM_TOKEN).build()
app.add_handler(CommandHandler("cotacao", cotacao))
app.run_polling()
if __name__ == "__main__":
main()Execute o arquivo e envie /cotacao PETR4 para o bot.
Preço recente não é streaming
Mostre regularMarketTime junto com a resposta. A disponibilidade e o atraso
variam por ativo, fonte e plano. Não apresente o bot como terminal de execução.
Consultar vários ativos
A API aceita até 20 símbolos por chamada. Você pode criar /carteira e enviar
os argumentos separados por espaço:
/carteira PETR4 VALE3 ITUB4Valide cada ticker, junte com vírgulas e consulte:
/api/v2/stocks/quote?symbols=PETR4,VALE3,ITUB4Limite a quantidade antes de montar a URL. Isso evita pedidos enormes ou entrada malformada enviada por usuários do bot.
Estruturar alertas de preço
Um alerta precisa guardar:
- usuário e chat do Telegram;
- ticker canônico;
- preço alvo;
- direção, acima ou abaixo;
- data de criação;
- estado do alerta;
- horário da última verificação.
Não execute uma chamada para cada alerta. Agrupe tickers, consulte até 20 por requisição e compare os preços em memória.
Depois de disparar, marque o alerta como concluído ou aplique uma janela de silêncio. Sem isso, o usuário recebe a mesma mensagem a cada verificação.
Evitar alertas repetidos
Uma regra "PETR4 acima de 40" continua verdadeira enquanto o preço permanecer acima de 40. Dispare apenas na transição entre os estados.
crossed = previous_price < target <= current_pricePara alertas abaixo do preço:
crossed = previous_price > target >= current_priceSalve o último preço observado. Reiniciar o processo sem estado pode gerar uma notificação duplicada.
Segurança e limites
- nunca aceite uma URL de API enviada pelo usuário;
- valide ticker e quantidade de argumentos;
- aplique limite por chat;
- guarde tokens fora do código;
- trate status 401, 403, 429 e 500;
- use timeout em todas as chamadas;
- não registre tokens nos logs.
Se o bot crescer, troque memória local por um banco e mova as verificações para um worker. O processo do Telegram não precisa executar todos os alertas.
O endpoint e os campos atuais estão na documentação de cotação. Para um alerta independente do Telegram, veja alertas de preço com Python.
