| 1 | # Use-case 0006 Implementation - View portfolio and transaction history
|
|---|
| 2 |
|
|---|
| 3 | **Initiating actor:** Trader
|
|---|
| 4 |
|
|---|
| 5 | **Other actors:** —
|
|---|
| 6 |
|
|---|
| 7 | A logged-in Trader inspects the current state of their account. The portfolio view
|
|---|
| 8 | lists every cryptocurrency the Trader holds with the quantity (also split into the
|
|---|
| 9 | part reserved by open sell orders and the part that is free to sell), the average
|
|---|
| 10 | buy price, the current market price, the market value and the unrealised
|
|---|
| 11 | profit/loss, followed by a totals row and a cash summary (cash available, portfolio
|
|---|
| 12 | value, net worth). The transaction history lists the Trader's last 20 ledger
|
|---|
| 13 | entries — deposits, buys and sells — newest first. Both are read-only: nothing in
|
|---|
| 14 | the database is changed.
|
|---|
| 15 |
|
|---|
| 16 | Original use-case description (P3): [UseCase0006](../P3-UseCaseModel/UseCase0006.md).
|
|---|
| 17 | Implementation: [`server/portfolio.go`](../../server/portfolio.go), function
|
|---|
| 18 | `ShowPortfolio`, and [`server/account.go`](../../server/account.go), function
|
|---|
| 19 | `ShowTransactions`.
|
|---|
| 20 |
|
|---|
| 21 | Precondition: the Trader is logged in ([UseCase0002](UseCase0002Implementation.md)).
|
|---|
| 22 | The run below is alice's, after she bought 0.01 BTC
|
|---|
| 23 | ([UseCase0004](UseCase0004Implementation.md)) and sold 0.2 ETH
|
|---|
| 24 | ([UseCase0005](UseCase0005Implementation.md)) on top of the seed data (0.5 ETH,
|
|---|
| 25 | 8250.00 USD cash).
|
|---|
| 26 |
|
|---|
| 27 | ## Scenario
|
|---|
| 28 |
|
|---|
| 29 | ### Portfolio
|
|---|
| 30 |
|
|---|
| 31 | 1. **Trader** chooses `[6] View portfolio` in the authenticated menu (types `6`).
|
|---|
| 32 | The menu is the one shown in [UseCase0002](UseCase0002Implementation.md), step 7.
|
|---|
| 33 | 2. **System** queries the `v_portfolio` view (`$1` = user id):
|
|---|
| 34 |
|
|---|
| 35 | ```sql
|
|---|
| 36 | SELECT symbol,
|
|---|
| 37 | quantity,
|
|---|
| 38 | COALESCE(reserved_quantity, 0),
|
|---|
| 39 | COALESCE(available_quantity, quantity),
|
|---|
| 40 | COALESCE(avg_price, 0),
|
|---|
| 41 | COALESCE(current_price, 0),
|
|---|
| 42 | COALESCE(market_value, 0),
|
|---|
| 43 | COALESCE(unrealized_pnl, 0)
|
|---|
| 44 | FROM v_portfolio
|
|---|
| 45 | WHERE user_id = $1 AND quantity > 0
|
|---|
| 46 | ORDER BY symbol
|
|---|
| 47 | ```
|
|---|
| 48 |
|
|---|
| 49 | 3. **System** displays the rows and a `TOTAL` row (sums of the value and P/L columns,
|
|---|
| 50 | computed in Go), then reads the cash balance for the summary (`$1` = user id):
|
|---|
| 51 |
|
|---|
| 52 | ```sql
|
|---|
| 53 | SELECT available_balance, invested_balance FROM users WHERE id = $1
|
|---|
| 54 | ```
|
|---|
| 55 |
|
|---|
| 56 | and prints `Cash available` (= `available_balance`), `Portfolio value`
|
|---|
| 57 | (= the total market value) and `Net worth` (= their sum).
|
|---|
| 58 |
|
|---|
| 59 | The screenshot shows the result of steps 2–3. The table is wider than the
|
|---|
| 60 | terminal window, so each long line wraps and the header row has scrolled out of
|
|---|
| 61 | the top of the window; the complete output of this run is reproduced below it.
|
|---|
| 62 |
|
|---|
| 63 | 
|
|---|
| 64 |
|
|---|
| 65 | ```
|
|---|
| 66 | Symbol Quantity Reserved Available Avg buy Current Value Unrealised P/L
|
|---|
| 67 | ------------------------------------------------------------------------------------------------------------------
|
|---|
| 68 | BTC 0.0100 0.0000 0.0100 67140.000000 67140.000000 671.4000 +0.0000
|
|---|
| 69 | ETH 0.3000 0.0000 0.3000 3500.000000 3520.000000 1056.0000 +6.0000
|
|---|
| 70 | ------------------------------------------------------------------------------------------------------------------
|
|---|
| 71 | TOTAL 1727.4000 +6.0000
|
|---|
| 72 |
|
|---|
| 73 | Cash available : 8282.6000 USD
|
|---|
| 74 | Portfolio value: 1727.4000 USD
|
|---|
| 75 | Net worth : 10010.0000 USD
|
|---|
| 76 | ```
|
|---|
| 77 |
|
|---|
| 78 | Checking the figures: ETH is 0.5 − 0.2 = 0.3 at an average buy price of 3500 and
|
|---|
| 79 | a current price of 3520, so value 1056.00 and P/L 0.3 × 20 = +6.00; BTC was just
|
|---|
| 80 | bought at the current price 67140, so its P/L is 0. Cash is
|
|---|
| 81 | 8250.00 − 671.40 (buy) + 704.00 (sell) = 8282.60. `Reserved` is 0.0000 for both
|
|---|
| 82 | because the market orders executed immediately — a quantity is reserved only
|
|---|
| 83 | while a sell order is still open.
|
|---|
| 84 |
|
|---|
| 85 | ### Transaction history
|
|---|
| 86 |
|
|---|
| 87 | 1. **Trader** chooses `[7] View transaction history` in the authenticated menu
|
|---|
| 88 | (types `7`).
|
|---|
| 89 | 2. **System** queries the last 20 ledger entries of the Trader (`$1` = user id) and
|
|---|
| 90 | prints them, newest first (the time is shown as the first 19 characters of
|
|---|
| 91 | `created_at`):
|
|---|
| 92 |
|
|---|
| 93 | ```sql
|
|---|
| 94 | SELECT created_at, type, amount, currency, COALESCE(description, '')
|
|---|
| 95 | FROM transactions
|
|---|
| 96 | WHERE user_id = $1
|
|---|
| 97 | ORDER BY created_at DESC
|
|---|
| 98 | LIMIT 20
|
|---|
| 99 | ```
|
|---|
| 100 |
|
|---|
| 101 | The screenshot shows steps 1–2: the choice `7` and the four ledger rows of this
|
|---|
| 102 | run — the sell of 0.2 ETH (+704.0000 USD), the buy of 0.01 BTC (−671.4000 USD),
|
|---|
| 103 | and the two seed rows, the initial deposit of 10000.0000 USD and the seed buy of
|
|---|
| 104 | 0.5 ETH (−1750.0000 USD). Buys are stored with a negative amount, deposits and
|
|---|
| 105 | sells with a positive one. The two seed rows were inserted by `data_load.sql` in
|
|---|
| 106 | one statement and have the same `created_at`, so their relative order is not
|
|---|
| 107 | determined by the `ORDER BY`.
|
|---|
| 108 |
|
|---|
| 109 | 
|
|---|
| 110 |
|
|---|
| 111 | All statements run on the `project` schema (the connection sets
|
|---|
| 112 | `search_path=project,public`).
|
|---|
| 113 |
|
|---|
| 114 | ### Reference — how `v_portfolio` is defined
|
|---|
| 115 |
|
|---|
| 116 | From `server/db/schema_creation.sql`:
|
|---|
| 117 |
|
|---|
| 118 | ```sql
|
|---|
| 119 | CREATE OR REPLACE VIEW project.v_portfolio AS
|
|---|
| 120 | SELECT h.user_id,
|
|---|
| 121 | c.symbol,
|
|---|
| 122 | h.quantity,
|
|---|
| 123 | h.reserved_quantity,
|
|---|
| 124 | (h.quantity - h.reserved_quantity) AS available_quantity,
|
|---|
| 125 | h.avg_price,
|
|---|
| 126 | lp.price AS current_price,
|
|---|
| 127 | (h.quantity * lp.price) AS market_value,
|
|---|
| 128 | (h.quantity * (lp.price - h.avg_price)) AS unrealized_pnl
|
|---|
| 129 | FROM project.holdings h
|
|---|
| 130 | JOIN project.crypto c ON c.id = h.crypto_id
|
|---|
| 131 | LEFT JOIN project.markets m ON m.crypto_id = c.id AND m.quote_currency = 'USD'
|
|---|
| 132 | LEFT JOIN project.v_latest_prices lp ON lp.market_id = m.id;
|
|---|
| 133 | ```
|
|---|
| 134 |
|
|---|
| 135 | ## How to reproduce
|
|---|
| 136 |
|
|---|
| 137 | ```sh
|
|---|
| 138 | ./eduberza -init
|
|---|
| 139 | ./eduberza
|
|---|
| 140 | # [2] Login: alice / test123
|
|---|
| 141 | # [4] buy 0.01 BTC, [5] sell 0.2 ETH (UseCase0004 / UseCase0005)
|
|---|
| 142 | # [6] View portfolio
|
|---|
| 143 | # [7] View transaction history
|
|---|
| 144 | ```
|
|---|
| 145 |
|
|---|
| 146 | Both screenshots come from one real run (portfolio and history taken right after
|
|---|
| 147 | the buy and sell runs).
|
|---|