Mesin Portofolio Investasi & HPP Moving Average
Modul manajemen aset investasi yang menghitung harga pokok pembelian rata-rata tertimbang (Moving Average), laba/rugi penjualan, dan menyinkronkan setiap transaksi beli/jual ke arus kas.
Membaca sekitar 2 menit
Modul manajemen aset investasi yang menghitung harga pokok pembelian rata-rata tertimbang (Moving Average), laba/rugi penjualan, dan menyinkronkan setiap transaksi beli/jual ke arus kas.
Pembelian dan top-up aset otomatis memotong saldo melalui tabel pengeluaran serta memperbarui avg_price, sedangkan penjualan aset menghitung selisih terhadap HPP dan mencatat uang masuk ke tabel pendapatan.
Transaksi investasi dijaga oleh guardrail: sistem menolak pembelian (HTTP 422) jika kantong belum memiliki anggaran kategori 'Investasi' dan menolak penjualan jika belum ada sumber pendapatan 'Investasi'.
Masalahnya dulu
Mencatat investasi (seperti membeli emas 2,5 gram, saham 10 lot, atau unit reksa dana) tidak bisa diperlakukan sama seperti membeli makanan. Saat pengguna melakukan top-up (beli lagi) di harga yang berbeda, Harga Pokok Pembelian (HPP / avg_price) per unit harus dihitung ulang secara proporsional. Sebaliknya, saat sebagian aset dijual, uang hasil penjualan harus masuk kembali ke saldo tabungan dan sistem harus tahu persis berapa keuntungan atau kerugian (realized P/L) dari penjualan tersebut.
Perhitungan HPP Rata-Rata Tertimbang & Sinkronisasi Dua Arah
Setiap kali pengguna membeli atau menambah kepemilikan aset, sistem menjalankan tiga langkah terintegrasi: (1) memotong saldo tabungan dengan menyisipkan baris ke tabel pengeluaran berkategori 'Investasi', (2) menghitung ulang kepemilikan dan HPP rata-rata tertimbang (Moving Average) di tabel investasi, serta (3) mencatat riwayat transaksi di tabel histori investasi yang menyimpan referensi transaksi arus kasnya.
Uang yang dipakai membeli aset tidak hilang dari pembukuan; ia berubah bentuk menjadi kepemilikan unit dengan HPP yang terus diperbarui.
Implementasi di ngodingan ini
Berikut adalah logika perhitungan HPP baru saat top-up serta perhitungan laba/rugi dan penutupan otomatis status aset saat penjualan:
// Saat Top-Up Beli: hitung ulang HPP Moving Average
const oldQty = Number(existing.qty);
const oldAvg = Number(existing.avg_price);
const newQty = oldQty + safeQtyNum;
const newAvg = (oldQty * oldAvg + safeTotalNum) / newQty;
await query(
`UPDATE investment SET qty=?, avg_price=?, status='active', updatedat=NOW() WHERE uuid=?`,
[newQty.toString(), newAvg.toString(), investmentId]
);
// Saat Jual Aset: hitung HPP, Realized P/L, dan tutup otomatis jika unit = 0
const newQty = Number(inv.qty) - safeQtyNum;
const hpp = Number(inv.avg_price) * safeQtyNum;
const pl = safeTotalNum - hpp;
await recordInvestmentIncome(inv.uuidbank, user.uuid, safeTotalNum, tx_date, incomeNote);
await query(
`UPDATE investment SET qty=?, status=IF(?=0,'closed','active'), updatedat=NOW() WHERE uuid=?`,
[newQty.toString(), newQty.toString(), investmentId]
);Jebakan dan detail yang harus dijaga
- Memasang guardrail prasyarat kategori anggaran: sebelum mengizinkan pembelian aset, sistem mengecek apakah kantong tabungan sudah memiliki anggaran kategori 'Investasi' (dan sumber pendapatan 'Investasi' sebelum menjual). Jika belum ada, server mengembalikan status 422 beserta instruksi jelas agar laporan anggaran tidak timpang.
- Menangani kuantitas pecahan (desimal) gaya Indonesia: untuk aset seperti emas atau kripto, pengguna terbiasa mengetik koma (misal '4,5' gram). Input divalidasi dengan regex /^[0-9]*(,[0-9]*)?$/ lalu dikonversi dengan replace(',', '.') agar perhitungan angka desimal di JavaScript dan MySQL tetap akurat.