Este arquivo documenta funcionalidades avançadas que podem ser implementadas.
<!-- Adicionar antes do </head> -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- Adicionar após section-title -->
<h2 class="section-title">📈 Evolução do Portfólio (Últimos 30 dias)</h2>
<div class="chart-container">
<canvas id="chartEvolucao"></canvas>
</div>
<!-- Adicionar antes do </body> -->
<script>
const ctx = document.getElementById("chartEvolucao").getContext("2d");
// Dados de exemplo - substituir com query do banco de dados
const dados = {
labels: ["Dia 1", "Dia 2", "Dia 3", "Dia 4", "Dia 5"],
datasets: [{
label: "Valor do Portfólio (USDT)",
data: [1000, 1050, 1100, 1075, 1150],
borderColor: "#64b5f6",
backgroundColor: "rgba(100, 181, 246, 0.1)",
fill: true,
tension: 0.4,
pointRadius: 4,
pointBackgroundColor: "#64b5f6"
}]
};
new Chart(ctx, {
type: "line",
data: dados,
options: {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: {
labels: { color: "#e0e0e0" }
}
},
scales: {
y: {
grid: { color: "#2a3f5f" },
ticks: { color: "#9e9e9e" }
},
x: {
grid: { color: "#2a3f5f" },
ticks: { color: "#9e9e9e" }
}
}
}
});
</script>
Arquivos necessários: Chart.js (CDN), banco de dados
Dados necessários: portfolio_snapshots.data, portfolio_snapshots.valor_total
<h2 class="section-title">🎯 Distribuição de Portfólio</h2>
<div class="grid-2">
<div class="chart-container">
<h3 style="text-align: center; margin-bottom: 10px; color: #64b5f6;">Distribuição Atual</h3>
<canvas id="chartDistribuicaoAtual"></canvas>
</div>
<div class="chart-container">
<h3 style="text-align: center; margin-bottom: 10px; color: #64b5f6;">Distribuição Alvo</h3>
<canvas id="chartDistribuicaoAlvo"></canvas>
</div>
</div>
<script>
const cores = ["#FF6384", "#36A2EB", "#FFCE56", "#4BC0C0", "#9966FF", "#FF9F40"];
// Gráfico Atual
const ctxAtual = document.getElementById("chartDistribuicaoAtual").getContext("2d");
const dadosAtual = {
labels: ["BTC", "ETH", "HBAR", "ADA", "SOL"],
datasets: [{
data: [25.5, 24.8, 25.2, 12.3, 12.2],
backgroundColor: cores,
borderColor: "#1a2332",
borderWidth: 2
}]
};
new Chart(ctxAtual, {
type: "doughnut",
data: dadosAtual,
options: {
responsive: true,
plugins: {
legend: {
labels: { color: "#e0e0e0" }
}
}
}
});
// Gráfico Alvo
const ctxAlvo = document.getElementById("chartDistribuicaoAlvo").getContext("2d");
const dadosAlvo = {
labels: ["BTC", "ETH", "HBAR", "ADA", "SOL"],
datasets: [{
data: [25, 25, 25, 12.5, 12.5],
backgroundColor: cores,
borderColor: "#1a2332",
borderWidth: 2
}]
};
new Chart(ctxAlvo, {
type: "doughnut",
data: dadosAlvo,
options: {
responsive: true,
plugins: {
legend: {
labels: { color: "#e0e0e0" }
}
}
}
});
</script>
Atualização: A cada ciclo do robô
// Conexão com banco de dados
$db_host = "localhost";
$db_user = "root";
$db_pass = "";
$db_name = "balanceamento_db";
$conn = new mysqli($db_host, $db_user, $db_pass, $db_name);
if ($conn->connect_error) {
die("Erro: " . $conn->connect_error);
}
// Query 1: Últimos 30 dias de evolução
$sql_evolucao = "
SELECT data, valor_total, ganho_percentual
FROM portfolio_snapshots
WHERE data >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
ORDER BY data ASC
";
$resultado = $conn->query($sql_evolucao);
$dados_evolucao = [];
while ($row = $resultado->fetch_assoc()) {
$dados_evolucao[] = $row;
}
// Query 2: Performance por moeda (últimos 7 dias)
$sql_moedas = "
SELECT moeda,
AVG(percentual_portfolio) as pct_media,
SUM(ganho_moeda) as ganho_total,
AVG(ganho_percentual_moeda) as ganho_pct
FROM coin_performance
WHERE data >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP BY moeda
ORDER BY ganho_total DESC
";
$resultado_moedas = $conn->query($sql_moedas);
// Query 3: Resumo de rebalanceamentos (últimos 7 dias)
$sql_rebalance = "
SELECT DATE(data_hora) as dia,
COUNT(*) as total_ops,
SUM(CASE WHEN tipo = \"compra\" THEN 1 ELSE 0 END) as compras,
SUM(CASE WHEN tipo = \"venda\" THEN 1 ELSE 0 END) as vendas,
SUM(valor_usdt) as volume_total
FROM rebalancing_transactions
WHERE data_hora >= DATE_SUB(NOW(), INTERVAL 7 DAY)
GROUP BY DATE(data_hora)
ORDER BY dia DESC
";
$resultado_rebalance = $conn->query($sql_rebalance);
// Verificar desvios críticos
function verificar_desvios_criticos($saldos_portfolio, $threshold = 5) {
$alertas = [];
foreach ($saldos_portfolio as $moeda => $dados) {
$desvio = abs($dados["percentual_atual"] - $dados["percentual_alvo"]);
if ($desvio > $threshold) {
$alertas[] = [
"moeda" => $moeda,
"tipo" => "desvio_critico",
"desvio" => $desvio,
"percentual_atual" => $dados["percentual_atual"],
"percentual_alvo" => $dados["percentual_alvo"]
];
// Gravar no banco de dados
$sql = "INSERT INTO portfolio_events
(data_hora, tipo_evento, moeda, descricao, severidade)
VALUES (NOW(),
\"rebalanceamento_grande\",
?,
?,
\"critico\")";
$descricao = "Desvio de " . number_format($desvio, 2) . "% detectado";
}
}
return $alertas;
}
// Enviar notificação por email
function enviar_email_alerta($destinatario, $alertas) {
$assunto = "🚨 Alerta de Desvio - Robô de Balanceamento";
$mensagem = "<h2>Alertas de Desvio Crítico</h2><ul>";
foreach ($alertas as $alerta) {
$mensagem .= "<li>" . $alerta["moeda"] .
": " . number_format($alerta["desvio"], 2) .
"% de desvio</li>";
}
$mensagem .= "</ul>";
$headers = "Content-Type: text/html; charset=UTF-8\r\n";
mail($destinatario, $assunto, $mensagem, $headers);
}
// Enviar webhook para Discord
function enviar_webhook_discord($webhook_url, $titulo, $mensagem, $cor = 16711680) {
$data = json_encode([
"embeds" => [[
"title" => $titulo,
"description" => $mensagem,
"color" => $cor,
"timestamp" => date("c")
]]
]);
$ch = curl_init($webhook_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
}
Canais: Email, Discord, Telegram, webhook customizado
<div class="section-title">⚙️ Painel de Controle</div>
<div class="grid-3">
<div class="card">
<div class="card-title">Status do Robô</div>
<div style="margin: 15px 0;">
<button style="background: #4caf50; color: white; padding: 10px 20px;
border: none; border-radius: 4px; cursor: pointer; width: 100%;">
▶️ Iniciar Robô
</button>
<button style="background: #ff9800; color: white; padding: 10px 20px;
border: none; border-radius: 4px; cursor: pointer; width: 100%;
margin-top: 5px;">
⏸ Pausar Robô
</button>
</div>
</div>
<div class="card">
<div class="card-title">Rebalanceamento Manual</div>
<div style="margin: 15px 0;">
<button style="background: #2196f3; color: white; padding: 10px 20px;
border: none; border-radius: 4px; cursor: pointer; width: 100%;">
🔄 Rebalancear Agora
</button>
</div>
</div>
<div class="card">
<div class="card-title">Exportar Dados</div>
<div style="margin: 15px 0;">
<button style="background: #9c27b0; color: white; padding: 10px 20px;
border: none; border-radius: 4px; cursor: pointer; width: 100%;">
📥 Baixar CSV
</button>
</div>
</div>
</div>
<script>
// Exemplo de integração API
document.querySelector("button").addEventListener("click", function() {
fetch("/projetos/balanceamento/api_controle.php?acao=iniciar", {
method: "POST"
})
.then(response => response.json())
.then(data => alert("Robô iniciado: " + data.status))
.catch(error => console.error("Erro:", error));
});
</script>
<?php
// api_controle.php - Endpoints para controle do robô
header("Content-Type: application/json");
$acao = $_GET["acao"] ?? "";
switch($acao) {
case "status":
// Retorna status atual do robô
echo json_encode([
"ativo" => verificar_robo_ativo($log_file),
"fase" => $metricas["fase"],
"valor_portfolio" => $metricas["valor_total"],
"ganho_percentual" => $metricas["ganho_percentual"]
]);
break;
case "iniciar":
// Inicia o robô em background
$cmd = "python /path/to/robobalanceamento/robo_balanceamento.py > /dev/null 2>&1 &";
shell_exec($cmd);
echo json_encode(["status" => "iniciado"]);
break;
case "parar":
// Para a execução do robô
shell_exec("pkill -f robo_balanceamento.py");
echo json_encode(["status" => "parado"]);
break;
case "historico":
// Retorna histórico de últimos N dias
$dias = $_GET["dias"] ?? 7;
$sql = "SELECT data, valor_total, ganho_percentual
FROM portfolio_snapshots
WHERE data >= DATE_SUB(CURDATE(), INTERVAL $dias DAY)";
// Executar query e retornar JSON
break;
default:
http_response_code(400);
echo json_encode(["erro" => "Ação não reconhecida"]);
}
?>
Endpoints: /status, /iniciar, /parar, /historico, /alertas
<?php
// export_csv.php
header("Content-Type: text/csv; charset=utf-8");
header("Content-Disposition: attachment; filename=portfolio_".date("Y-m-d").".csv");
$output = fopen("php://output", "w");
// Cabeçalho
fputcsv($output, ["Data", "Moeda", "Saldo", "Preço", "Valor USDT", "% Portfolio", "% Alvo"]);
// Dados de portfolio_snapshots e coin_performance
$sql = "SELECT cp.data, cp.moeda, cp.saldo_quantidade, cp.preco_atual,
cp.valor_total_usdt, cp.percentual_portfolio, cp.percentual_alvo
FROM coin_performance cp
ORDER BY cp.data DESC, cp.moeda ASC";
$resultado = $conn->query($sql);
while ($row = $resultado->fetch_assoc()) {
fputcsv($output, $row);
}
fclose($output);
?>
Espera: Volte em log_balanceamento.php para usar a interfacebase