package main import ( "fmt" "strings" "bp_project/server/db" ) // ShowPortfolio - UC0006 // Uses the v_portfolio view to list holdings with current market value and P&L. func ShowPortfolio(s *Session) { rows, err := db.DB.Query( `SELECT symbol, quantity, COALESCE(reserved_quantity, 0), COALESCE(available_quantity, quantity), COALESCE(avg_price, 0), COALESCE(current_price, 0), COALESCE(market_value, 0), COALESCE(unrealized_pnl, 0) FROM v_portfolio WHERE user_id = $1 AND quantity > 0 ORDER BY symbol`, s.UserID, ) if err != nil { fmt.Println("Error:", err) return } defer rows.Close() header := fmt.Sprintf(" %-8s %12s %12s %12s %14s %14s %14s %14s", "Symbol", "Quantity", "Reserved", "Available", "Avg buy", "Current", "Value", "Unrealised P/L") fmt.Println() fmt.Println(header) fmt.Println(" " + strings.Repeat("-", len(header)-2)) var totalValue, totalPnL float64 empty := true for rows.Next() { var sym string var qty, reserved, avail, avg, cur, val, pnl float64 if err := rows.Scan(&sym, &qty, &reserved, &avail, &avg, &cur, &val, &pnl); err != nil { fmt.Println("scan error:", err) return } fmt.Printf(" %-8s %12.4f %12.4f %12.4f %14.6f %14.6f %14.4f %+14.4f\n", sym, qty, reserved, avail, avg, cur, val, pnl) totalValue += val totalPnL += pnl empty = false } if empty { fmt.Println(" (no holdings yet)") return } fmt.Println(" " + strings.Repeat("-", len(header)-2)) fmt.Printf(" %-8s %12s %12s %12s %14s %14s %14.4f %+14.4f\n", "TOTAL", "", "", "", "", "", totalValue, totalPnL) // cash summary var avail, invested float64 _ = db.DB.QueryRow( `SELECT available_balance, invested_balance FROM users WHERE id = $1`, s.UserID, ).Scan(&avail, &invested) fmt.Printf("\n Cash available : %.4f USD\n", avail) fmt.Printf(" Portfolio value: %.4f USD\n", totalValue) fmt.Printf(" Net worth : %.4f USD\n", avail+totalValue) }