-
Notifications
You must be signed in to change notification settings - Fork 698
Open
Description
<title>Analisis Portofolio Kripto Interaktif</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body {
font-family: 'Inter', sans-serif;
background-color: #F8F7F4; /* Warm neutral background */
}
.main-container {
max-width: 1280px;
margin: auto;
padding: 1rem;
}
.nav-button {
transition: all 0.3s ease;
position: relative;
}
.nav-button.active::after, .nav-button:hover::after {
content: '';
position: absolute;
bottom: -4px;
left: 0;
width: 100%;
height: 2px;
background-color: #3B82F6; /* Accent blue */
}
.nav-button.active {
color: #3B82F6;
}
.chart-container {
position: relative;
width: 100%;
max-width: 600px;
margin-left: auto;
margin-right: auto;
height: 300px;
max-height: 400px;
}
@media (min-width: 768px) {
.chart-container {
height: 350px;
}
}
.card {
background-color: #FFFFFF;
border-radius: 0.75rem;
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
padding: 1.5rem;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -2px rgb(0 0 0 / 0.1);
}
</style>
<div id="app" class="main-container">
<header class="flex flex-col md:flex-row justify-between items-center py-4 border-b border-gray-200">
<h1 class="text-3xl font-bold text-gray-900">Dasbor Analisis Portofolio</h1>
<nav id="mainNav" class="flex flex-wrap justify-center space-x-4 md:space-x-6 mt-4 md:mt-0">
<button data-view="dashboard" class="nav-button text-gray-600 font-semibold py-2">Dasbor</button>
<button data-view="portfolio" class="nav-button text-gray-600 font-semibold py-2">Rincian Portofolio</button>
<button data-view="valuation" class="nav-button text-gray-600 font-semibold py-2">Wawasan Valuasi</button>
<button data-view="security" class="nav-button text-gray-600 font-semibold py-2">Keamanan & Penjagaan</button>
<button data-view="transactions" class="nav-button text-gray-600 font-semibold py-2">Riwayat Transaksi</button>
</nav>
</header>
<main id="content" class="mt-8">
<!-- Sections will be rendered here by JavaScript -->
</main>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const appState = {
currentView: 'dashboard',
portfolio: {
totalValue: 58500.00,
exchangeValue: 42500.00,
walletValue: 16000.00,
holdings: {
exchange: [
{ asset: 'BTC', quantity: 0.5, exchange: 'Coinbase', price: 65000.00 },
{ asset: 'ETH', quantity: 3.0, exchange: 'Kraken', price: 3000.00 },
{ asset: 'CRO', quantity: 1000.0, exchange: 'Coinbase', price: 1.00 },
],
wallet: [
{ asset: 'ETH', quantity: 2.0, network: 'Ethereum', price: 3000.00 },
{ asset: 'BTC', quantity: 0.1, network: 'Bitcoin', price: 65000.00 },
{ asset: 'SOL', quantity: 20.0, network: 'Solana', price: 175.00 },
]
}
},
transactions: [
{ dateTime: '2023-12-01 20:05', type: 'Buy', receivedAsset: 'BTC', receivedAmount: 5, sentAsset: 'USD', sentAmount: 150000, feeAsset: 'BTC', feeAmount: 0.01, netWorth: '150000.00', baseCurrency: 'USD', description: 'Bought BTC' },
{ dateTime: '2022-08-21 12:10', type: 'Outgoing Gift', receivedAsset: '', receivedAmount: '', sentAsset: 'ETH', sentAmount: 2, feeAsset: 'ETH', feeAmount: 0.01, netWorth: '3200.00', baseCurrency: 'USD', description: 'Gift to friend' },
{ dateTime: '2022-06-21 21:55', type: 'Sell', receivedAsset: 'USD', receivedAmount: 12000, sentAsset: 'BTC', sentAmount: 0.5, feeAsset: 'BTC', feeAmount: 0.02, netWorth: '12000.00', baseCurrency: 'USD', description: 'Sold BTC' },
{ dateTime: '2022-06-20 20:57', type: 'Buy', receivedAsset: 'BTC', receivedAmount: 1, sentAsset: 'USD', sentAmount: 20000, feeAsset: 'BTC', feeAmount: 0.02, netWorth: '20000.00', baseCurrency: 'USD', description: 'Initial BTC purchase' },
{ dateTime: '2023-01-15 10:00', type: 'Swap', receivedAsset: 'SOL', receivedAmount: 20, sentAsset: 'ETH', sentAmount: 0.5, feeAsset: 'ETH', feeAmount: 0.005, netWorth: '1000.00', baseCurrency: 'USD', description: 'Swapped ETH for SOL' },
{ dateTime: '2023-05-10 18:30', type: 'Mining', receivedAsset: 'BTC', receivedAmount: 0.05, sentAsset: '', sentAmount: '', feeAsset: '', feeAmount: '', netWorth: '1500.00', baseCurrency: 'USD', description: 'Mining reward' }
]
};
const contentEl = document.getElementById('content');
const navEl = document.getElementById('mainNav');
let charts = {};
function destroyCharts() {
Object.values(charts).forEach(chart => chart.destroy());
charts = {};
}
function formatCurrency(value) {
return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(value);
}
function renderDashboard() {
destroyCharts();
contentEl.innerHTML = `
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="md:col-span-1 card">
<h2 class="text-xl font-semibold text-gray-700 mb-2">Total Nilai Portofolio</h2>
<p class="text-4xl font-bold text-gray-900">${formatCurrency(appState.portfolio.totalValue)}</p>
<p class="text-green-500 mt-2">+2.5% (24j)</p>
<p class="text-sm text-gray-500 mt-4">Ini adalah ringkasan tingkat tinggi dari seluruh portofolio aset kripto Anda, memberikan gambaran instan tentang posisi keuangan Anda secara keseluruhan dan kinerjanya baru-baru ini.</p>
</div>
<div class="md:col-span-2 card">
<h2 class="text-xl font-semibold text-gray-700 mb-4">Distribusi Aset (Bursa vs. Dompet)</h2>
<div class="chart-container mx-auto">
<canvas id="distributionChart"></canvas>
</div>
</div>
</div>
`;
renderDistributionChart();
}
function renderDistributionChart() {
const ctx = document.getElementById('distributionChart').getContext('2d');
charts.distribution = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['Aset di Bursa', 'Aset di Dompet'],
datasets: [{
data: [appState.portfolio.exchangeValue, appState.portfolio.walletValue],
backgroundColor: ['#3B82F6', '#60A5FA'], // Shades of blue
borderColor: ['#FFFFFF', '#FFFFFF'],
borderWidth: 2
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'top',
labels: {
font: {
size: 14,
family: 'Inter'
}
}
},
tooltip: {
callbacks: {
label: function(context) {
let label = context.label || '';
if (label) {
label += ': ';
}
if (context.parsed !== null) {
const total = context.dataset.data.reduce((a, b) => a + b, 0);
const percentage = ((context.parsed / total) * 100).toFixed(2);
label += `${formatCurrency(context.parsed)} (${percentage}%)`;
}
return label;
}
}
}
}
}
});
}
function renderPortfolio() {
destroyCharts();
const renderHoldingsTable = (holdings, isExchange) => {
return `
<table class="w-full text-left table-auto">
<thead>
<tr class="border-b bg-gray-50">
<th class="p-4 font-semibold">Aset</th>
<th class="p-4 font-semibold">Kuantitas</th>
<th class="p-4 font-semibold">${isExchange ? 'Bursa' : 'Jaringan'}</th>
<th class="p-4 font-semibold">Harga Saat Ini (USD)</th>
<th class="p-4 font-semibold">Nilai Terhitung (USD)</th>
</tr>
</thead>
<tbody>
${holdings.map(h => `
<tr class="border-b hover:bg-gray-100">
<td class="p-4 font-medium">${h.asset}</td>
<td class="p-4">${h.quantity.toFixed(4)}</td>
<td class="p-4">${isExchange ? h.exchange : h.network}</td>
<td class="p-4">${formatCurrency(h.price)}</td>
<td class="p-4 font-semibold">${formatCurrency(h.quantity * h.price)}</td>
</tr>
`).join('')}
</tbody>
</table>
`;
};
contentEl.innerHTML = `
<div class="card">
<h2 class="text-2xl font-bold mb-4">Rincian Portofolio</h2>
<p class="text-gray-600 mb-6">Bagian ini memberikan rincian terperinci tentang setiap aset kripto dalam portofolio Anda. Gunakan tab di bawah ini untuk beralih antara aset yang saat ini disimpan di bursa terpusat dan yang disimpan di dompet kustodi mandiri Anda.</p>
<div class="border-b border-gray-200">
<nav id="portfolioTabs" class="-mb-px flex space-x-8" aria-label="Tabs">
<button data-tab="exchange" class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm text-blue-600 border-blue-600">Aset di Bursa</button>
<button data-tab="wallet" class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm text-gray-500 hover:text-gray-700 hover:border-gray-300 border-transparent">Aset di Dompet</button>
</nav>
</div>
<div id="portfolioContent" class="mt-6">
<!-- Content will be rendered here -->
</div>
</div>
`;
const portfolioTabs = document.getElementById('portfolioTabs');
const portfolioContent = document.getElementById('portfolioContent');
const renderTabContent = (tab) => {
portfolioTabs.querySelectorAll('button').forEach(btn => {
if (btn.dataset.tab === tab) {
btn.classList.add('text-blue-600', 'border-blue-600');
btn.classList.remove('text-gray-500', 'hover:text-gray-700', 'hover:border-gray-300', 'border-transparent');
} else {
btn.classList.remove('text-blue-600', 'border-blue-600');
btn.classList.add('text-gray-500', 'hover:text-gray-700', 'hover:border-gray-300', 'border-transparent');
}
});
if (tab === 'exchange') {
portfolioContent.innerHTML = renderHoldingsTable(appState.portfolio.holdings.exchange, true);
} else {
portfolioContent.innerHTML = renderHoldingsTable(appState.portfolio.holdings.wallet, false);
}
};
portfolioTabs.addEventListener('click', (e) => {
if (e.target.tagName === 'BUTTON') {
renderTabContent(e.target.dataset.tab);
}
});
renderTabContent('exchange');
}
function renderValuation() {
destroyCharts();
contentEl.innerHTML = `
<div class="card mb-6">
<h2 class="text-2xl font-bold mb-4">Wawasan Valuasi & Dinamika Pasar</h2>
<p class="text-gray-600 mb-6">Bagian ini membahas faktor-faktor kompleks yang memengaruhi nilai "sebenarnya" dari aset kripto Anda. Grafik di bawah ini membandingkan harga Bitcoin di berbagai sumber untuk menyoroti fragmentasi pasar. Kartu interaktif menjelaskan konsep-konsep kunci seperti VWAP dan slippage yang memengaruhi nilai realisasi aset Anda.</p>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div class="card">
<h3 class="text-xl font-semibold mb-4">Perbandingan Harga Lintas Bursa (BTC/USD)</h3>
<div class="chart-container mx-auto">
<canvas id="priceComparisonChart"></canvas>
</div>
</div>
<div class="flex flex-col space-y-6">
<div class="card">
<h3 class="text-xl font-semibold mb-2">Memahami "Nilai Sebenarnya"</h3>
<p class="text-gray-600">"Nilai Sebenarnya" melampaui harga spot sederhana. Ini mencakup metrik seperti Volume-Weighted Average Price (VWAP), yang memberikan gambaran lebih akurat tentang nilai pasar aset dengan mempertimbangkan volume perdagangan, dan data dari indeks independen yang mengagregasi harga dari banyak bursa.</p>
</div>
<div class="card">
<h3 class="text-xl font-semibold mb-2">Dampak Slippage & Likuiditas</h3>
<p class="text-gray-600">Slippage adalah perbedaan antara harga yang diharapkan dan harga eksekusi. Di pasar yang tidak likuid (sedikit pembeli/penjual), perdagangan besar dapat menyebabkan slippage yang signifikan, mengurangi nilai realisasi dari aset Anda. Likuiditas tinggi meminimalkan risiko ini.</p>
</div>
</div>
</div>
`;
renderPriceComparisonChart();
}
function renderPriceComparisonChart() {
const ctx = document.getElementById('priceComparisonChart').getContext('2d');
const labels = ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'];
charts.priceComparison = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [
{
label: 'Coinbase',
Originally posted by @Welbert5753 in Welbert5753/DICE#1 (comment)
Metadata
Metadata
Assignees
Labels
No labels