/** * Este script coleta dados de um endpoint protegido com suporte tanto para requisições únicas quanto em lote. * * ENDPOINTS DISPONÍVEIS: * * Para maiores detalhes consulte a documentação em https://plexa.com.br/json-api * * ===== REQUISIÇÕES ÚNICAS ===== * 1. https://api.plexa.com.br/json/fundo - Dados gerais de todos os fundos * 2. https://api.plexa.com.br/json/fundo/KNHF11 - Dados gerais do fundo KNHF11 * 3. https://api.plexa.com.br/json/fundo/cotacao/KNHY11 - Cotação do KNHY11 * 4. https://api.plexa.com.br/json/selic - Histórico completo da taxa Selic * 5. https://api.plexa.com.br/json/selic/ano/2023 - Taxa Selic do ano 2023 * 6. https://api.plexa.com.br/json/selic/range/01-2025:12-2025 - Taxa Selic período 2025 * * ===== REQUISIÇÕES EM LOTE ===== * 7. https://api.plexa.com.br/json/dividendo - Dividendos (batch com tickers) * 8. https://api.plexa.com.br/json/patrimonio - Patrimônio (batch com tickers) * 9. https://api.plexa.com.br/json/historico - Histórico (batch com tickers) * 10. https://api.plexa.com.br/json/cotista - Cotistas (batch com tickers) * * ===== COMO USAR ===== * 1. Configure o ENDPOINT_DESEJADO com a URL desejada * 2. Para lote, defina REQUISICAO_UNICA = false * 3. Para único, defina REQUISICAO_UNICA = true * 4. Configure a QUANTIDADE_DESEJADA para endpoints em lote (dias para séries históricas) * 5. Adicione a LISTA_DE_TICKERS com os tickers a buscar * 6. Insira seu TOKEN_API * 7. Execute o script * * * Avisos: * - Este script é fornecido "como está". O uso é por sua conta e risco. * - Mantenha seu token seguro e nunca o compartilhe. * - O uso da API deve estar de acordo com os Termos de Serviço da Plexa API. * * Última atualização: * - 26/04/2026 * * Contato: * - ctt@plexa.com.br */ // ======================== CONFIGURAÇÃO ======================== const ENDPOINT_DESEJADO = 'https://api.plexa.com.br/json/dividendo; const REQUISICAO_UNICA = false; // true = requisição única | false = requisição em lote const QUANTIDADE_DESEJADA = 3; // Número de meses/dias para requisições em lote const LISTA_DE_TICKERS = ['AFHI11', 'BTLG11', 'KNCR11']; const MAX_REQUISICOES = 30; // Máximo de requisições por lote [Free: 30, Apoiador: 100, Premium: 300] const INTERVALO_REQUISICOES = 60000; // Intervalo entre lotes em milissegundos (60 segundos) const TOKEN_API = ""; // Insira seu token de API aqui let TOKEN = TOKEN_API || null; let DADOS_OBTIDOS = []; // Variável onde os dados serão armazenados // ================== FUNÇÕES AUXILIARES =================== /** * Verifica se o token tem permissão de acesso ao endpoint * @returns {Promise} Retorna objeto com status e dados ou mensagem de erro */ const checkPermission = async () => { if (!TOKEN) { return { ok: false, msg: "Token de autenticação não fornecido" }; } try { // Para requisições em lote, testa com o primeiro ticker e 1 mês/dia const ENDPOINT = REQUISICAO_UNICA ? ENDPOINT_DESEJADO : `${ENDPOINT_DESEJADO}/${LISTA_DE_TICKERS[0]}/1`; console.log(`🔍 Verificando permissão`); const response = await fetch(ENDPOINT, { method: "GET", headers: { "Authorization": `Bearer ${TOKEN}`, "Content-Type": "application/json" } }); const data = await response.json(); if (!response.ok || !data.ok) { return { ok: false, msg: data.msg || `Erro HTTP ${response.status}: Acesso negado` }; } return data; } catch (error) { console.error("❌ Erro ao verificar permissão:", error.message); return { ok: false, msg: "Falha na conexão com a API. Verifique sua internet e tente novamente." }; } }; /** * Processa uma requisição única ao endpoint */ const processSingleRequest = async () => { try { console.log(`📡 Realizando requisição única para: ${ENDPOINT_DESEJADO}`); const response = await fetch(ENDPOINT_DESEJADO, { method: "GET", headers: { "Authorization": `Bearer ${TOKEN}`, "Content-Type": "application/json" } }); const r = await response.json(); if (r.ok) { DADOS_OBTIDOS = r.data; console.log(DADOS_OBTIDOS); } else { console.error("❌ Erro na requisição:", r.msg); DADOS_OBTIDOS = []; } } catch (error) { console.error("❌ Erro ao processar requisição única:", error.message); DADOS_OBTIDOS = []; } }; /** * Processa um lote de tickers * @param {Array} tickers - Lista de tickers para processar no lote * @returns {Promise} Retorna array com os resultados do lote */ const processBatch = async (tickers) => { const promises = tickers.map(TICKER => fetch(`${ENDPOINT_DESEJADO}/${TICKER}/${QUANTIDADE_DESEJADA}`, { method: "GET", headers: { "Authorization": `Bearer ${TOKEN}`, "Content-Type": "application/json" } }) .then(async response => { const r = await response.json(); if (response.ok && r.ok) { return r.data; } throw new Error(r.msg || `Erro na requisição para ${TICKER}`); }) .catch(error => { console.error(`❌ Erro em ${TICKER}: ${error.message}`); return null; }) ); return Promise.all(promises); }; /** * Processa requisições em lote respeitando os limites de taxa */ const processBatchRequests = async () => { if (LISTA_DE_TICKERS.length === 0) { console.warn("⚠️ Lista de tickers vazia. Nada para processar."); return; } const totalLotes = Math.ceil(LISTA_DE_TICKERS.length / MAX_REQUISICOES); console.log(`📊 Processando ${LISTA_DE_TICKERS.length} tickers em ${totalLotes} lote(s)...`); console.log(`📅 Quantidade solicitada: ${QUANTIDADE_DESEJADA} meses`); for (let i = 0; i < LISTA_DE_TICKERS.length; i += MAX_REQUISICOES) { const loteAtual = Math.floor(i / MAX_REQUISICOES) + 1; const batch = LISTA_DE_TICKERS.slice(i, i + MAX_REQUISICOES); console.log(`\n🔄 Processando lote ${loteAtual}/${totalLotes} (${batch.length} tickers)...`); const resultados = await processBatch(batch); const resultadosValidos = resultados.filter(Boolean); DADOS_OBTIDOS.push(...resultadosValidos); console.log(`✅ Lote ${loteAtual} concluído. ${resultadosValidos.length}/${batch.length} tickers processados com sucesso.`); // Aguarda antes do próximo lote, se não for o último if (i + MAX_REQUISICOES < LISTA_DE_TICKERS.length) { console.log(`⏱️ Aguardando ${INTERVALO_REQUISICOES / 1000} segundos antes do próximo lote...`); await new Promise(resolve => setTimeout(resolve, INTERVALO_REQUISICOES)); } } console.log(`\n📈 Processamento concluído! Total de registros obtidos: ${DADOS_OBTIDOS.length}`); if (DADOS_OBTIDOS.length > 0) { console.log(DADOS_OBTIDOS); } }; // ================== FUNÇÃO PRINCIPAL =================== /** * Função principal que orquestra a coleta de dados */ const fetchData = async () => { console.log("🚀 Iniciando coleta de dados...\n"); const permissionCheck = await checkPermission(); if (!permissionCheck.ok) { console.error("❌ Acesso negado:", permissionCheck.msg); DADOS_OBTIDOS = []; return; } // Requisição única if (REQUISICAO_UNICA) { await processSingleRequest(); } else { // Requisições em lote await processBatchRequests(); } }; // ================== EXECUÇÃO =================== if (TOKEN) { fetchData().catch(error => { console.error("❌ Erro fatal durante a execução:", error.message); DADOS_OBTIDOS = []; }); } else { console.error("❌ Token de autenticação ausente. Verifique seu token de API."); }