GNU/_PAGE/asset/upbit/chart_line_holding.php
<?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'; ?>