<?php
date_default_timezone_set('Asia/Seoul');
$db_upbit = null;
@include '/home/www/DB/db_upbit.php';
$pdo = $db_upbit;
$range = isset($_GET['range']) ? $_GET['range'] : '1m';
/**
* [정리] 8시간 및 7일 이상의 장기 구간 삭제
* 오직 DB에 자체 값이 박혀 있는 단기 패턴 구간만 유지
*/
$range_map = [
'1m' => ['table' => 'daemon_upbit_user_1m', 'interval' => 'INTERVAL 2 HOUR'],
'5m' => ['table' => 'daemon_upbit_user_5m', 'interval' => 'INTERVAL 6 HOUR'],
'30m' => ['table' => 'daemon_upbit_user_30m', 'interval' => 'INTERVAL 24 HOUR'],
'1h' => ['table' => 'daemon_upbit_user_1h', 'interval' => 'INTERVAL 3 DAY'],
'4h' => ['table' => 'daemon_upbit_user_4h', 'interval' => 'INTERVAL 7 DAY'],
'1d' => ['table' => 'daemon_upbit_user_24h', 'interval' => 'INTERVAL 30 DAY'],
];
if (!isset($range_map[$range])) $range = '1m';
$table = $range_map[$range]['table'];
$interval = $range_map[$range]['interval'];
/**
* [정리] 8h 평균(AVG) 로직 삭제 -> 순수 데이터 호출 쿼리로 단일화
*/
$sql = "
SELECT collected_at, total_asset_value, cash_balance, total_profit_amount
FROM {$table}
WHERE collected_at >= DATE_SUB(NOW(), {$interval})
GROUP BY collected_at
ORDER BY collected_at ASC
";
$rows = [];
try {
$stmt = $pdo->query($sql);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Throwable $e) {}
$latest = !empty($rows) ? end($rows) : null;
$labels = $asset_data = $cash_data = $profit_data = [];
foreach ($rows as $row) {
$labels[] = $row['collected_at'];
$asset_data[] = (float)$row['total_asset_value'];
$cash_data[] = (float)$row['cash_balance'];
$profit_data[] = (float)$row['total_profit_amount'];
}
$labels_json = json_encode($labels, JSON_UNESCAPED_UNICODE);
$asset_json = json_encode($asset_data, JSON_UNESCAPED_UNICODE);
$cash_json = json_encode($cash_data, JSON_UNESCAPED_UNICODE);
$profit_json = json_encode($profit_data, JSON_UNESCAPED_UNICODE);
if (isset($_GET['ajax'])) {
header('Content-Type: application/json');
echo json_encode([
'labels' => $labels,
'asset' => $asset_data,
'cash' => $cash_data,
'profit' => $profit_data,
'latest' => $latest
]);
exit;
}
require_once '/home/www/GNU/_PAGE/head.php';
include G5_PATH."/_PAGE/asset/upbit/chart_line_holding_data_bookmark.php";
?>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
body { background-color: #020617 !important; color: #f8fafc; font-family: 'Pretendard', sans-serif; margin: 0; padding: 0; }
.main-content-wrapper { padding: 40px 50px; min-height: 80vh; }
.summary { display: flex; gap: 15px; margin-bottom: 25px; flex-wrap: wrap; }
.card {
background: #1a2436; border: 1px solid #232e42; border-radius: 7px; padding: 18px;
flex: 1; min-width: 200px; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
}
.card .label { font-size: 12px; color: #94a3b8; margin-bottom: 6px; font-weight: 500; }
.card .value { font-size: 22px; font-weight: 800; letter-spacing: -0.5px; }
.plus { color: #fb7185; }
.minus { color: #60a5fa; }
.range-group {
background: #0c1224; padding: 12px 20px; border-radius: 7px; margin-bottom: 15px;
border: 1px solid #181e2f; display: flex; align-items: center; gap: 30px; flex-wrap: wrap;
}
.range-item { display: flex; align-items: center; gap: 10px; }
.group-label { font-size: 11px; color: #475569; font-weight: 700; text-transform: uppercase; white-space: nowrap; }
.range-btn { display: flex; gap: 5px; }
.range-btn a {
padding: 6px 12px; border-radius: 4px; text-decoration: none;
background: #181e2f; color: #94a3b8; font-size: 12px; transition: all 0.2s;
border: 1px solid transparent;
}
.range-btn a:hover { background: #232e42; color: #fff; }
.range-btn a.active { background: #3b82f6; color: #fff; font-weight: bold; box-shadow: 0 0 10px rgba(59,130,246,0.3); }
.chart-wrap { background: #0c1224; border-radius: 7px; padding: 25px; border: 1px solid #181e2f; height: 550px; position: relative; }
.data-count { font-size: 12px; color: #475569; margin-bottom: 10px; text-align: right; }
h2 { font-size: 26px; font-weight: 800; margin-bottom: 25px; color: #fff; letter-spacing: -1px; margin-left: 20px;}
h2 i { color: #3b82f6; margin-right: 10px; }
</style>
<div class="main-content-wrapper">
<h2><i class="fa-solid fa-chart-line"></i> UPBIT ASSETS DASHBOARD (Monitoring)</h2>
<div class="summary">
<?php if ($latest):
$asset_val = (float)$latest['total_asset_value'];
$cash_val = (float)$latest['cash_balance'];
$profit_val = (float)$latest['total_profit_amount'];
$investment_val = $asset_val - $cash_val;
$roc = ($asset_val > 0) ? ($profit_val / $asset_val) * 100 : 0;
$roi = ($investment_val > 0) ? ($profit_val / $investment_val) * 100 : 0;
$weight = ($asset_val > 0) ? ($investment_val / $asset_val) * 100 : 0;
$profit_cls = $profit_val >= 0 ? 'plus' : 'minus';
?>
<div class="card"><div class="label">총 자산 Value</div><div class="value"><?= number_format($asset_val) ?></div></div>
<div class="card"><div class="label">총 매수 Investment</div><div class="value" style="color:#e2e8f0;"><?= number_format($investment_val) ?></div></div>
<div class="card"><div class="label">투자 비중 Share</div><div class="value" style="color:#e2e8f0;"><?= number_format($weight, 1) ?>%</div></div>
<div class="card"><div class="label">현금 잔고 Cash</div><div class="value" style="color:#cbd5e1;"><?= number_format($cash_val) ?></div></div>
<div class="card"><div class="label">평가 손익 P/L</div><div class="value <?= $profit_cls ?>"><?= ($profit_val>=0?'+':'').number_format($profit_val) ?></div></div>
<div class="card"><div class="label">수익률 (ROC)</div><div class="value <?= $profit_cls ?>"><?= number_format($roc, 4) ?>%</div></div>
<div class="card"><div class="label">수익률 (ROI)</div><div class="value <?= $profit_cls ?>"><?= number_format($roi, 4) ?>%</div></div>
<?php endif; ?>
</div>
<div class="range-group">
<div class="range-item">
<div class="group-label">SHORT</div>
<div class="range-btn">
<?php foreach (['1m'=>'1분','5m'=>'5분','30m'=>'30분'] as $k=>$v): ?>
<a href="?range=<?=$k?>" class="<?=($range===$k)?'active':''?>"><?=$v?></a>
<?php endforeach; ?>
</div>
</div>
<div class="range-item">
<div class="group-label">MID</div>
<div class="range-btn">
<?php foreach (['1h'=>'1시간','4h'=>'4시간','1d'=>'1일'] as $k=>$v): ?>
<a href="?range=<?=$k?>" class="<?=($range===$k)?'active':''?>"><?=$v?></a>
<?php endforeach; ?>
</div>
</div>
<!-- [정리] LONG 그룹 삭제 -->
<div style="margin-left:auto;" class="data-count">
<span id="refresh-timer" style="color:#3b82f6; font-weight:bold;">60</span>s refresh
</div>
</div>
<div class="chart-wrap">
<canvas id="assetChart"></canvas>
</div>
</div>
<script>
let timer = 60;
setInterval(() => {
timer--;
if(document.getElementById('refresh-timer')) document.getElementById('refresh-timer').innerText = timer;
if(timer <= 0) location.reload();
}, 1000);
const ctx = document.getElementById('assetChart').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: <?= $labels_json ?>,
datasets: [
{ label: '총 자산', data: <?= $asset_json ?>, borderColor: '#3b82f6', borderWidth: 3, pointRadius: 0, tension: 0.4, fill: false },
{ label: '현금 잔고', data: <?= $cash_json ?>, borderColor: '#94a3b8', borderDash: [5, 5], borderWidth: 1.5, pointRadius: 0, tension: 0.4 },
{ label: '평가금', data: <?= $asset_json ?>.map((v, i) => v + (<?= $profit_json ?>[i] * 2)), borderColor: '#10b981', borderWidth: 2, pointRadius: 0, tension: 0.4 }
]
},
options: {
responsive: true,
maintainAspectRatio: false,
interaction: { mode: 'index', intersect: false },
plugins: {
legend: { position: 'top', align: 'end', labels: { color: '#94a3b8', usePointStyle: true } }
},
scales: {
x: { ticks: { color:'#475569', maxTicksLimit:12 }, grid: { display: false } },
y: { position: 'right', ticks: { color:'#475569', callback: v => (v / 10000).toLocaleString() + '만' }, grid: { color:'#1e293b' } }
}
}
});
</script>
<?php require_once '/home/www/GNU/_PAGE/tail.php'; ?>