source: docs/P3-UseCaseModel/UseCase0004.md@ 9577c79

main
Last change on this file since 9577c79 was 9577c79, checked in by Stefan <trsunovstefan@…>, 13 days ago

add reserved_quantity and modify the phases, add v_03.png and v_03.xml for P1

  • Property mode set to 100644
File size: 3.5 KB
Line 
1# Use-case 0004 — Place market BUY order
2
3**Initiating actor:** Trader
4
5**Other actors:** Market Simulator (indirect — supplies the current price via `market_trades`).
6
7A Trader buys a crypto asset at the current market price. The operation touches five tables (`orders`, `users`, `holdings`, `transactions`, `market_trades`) and must either all succeed or all roll back.
8
9## Scenario
10
111. Trader chooses "Place market BUY order".
122. System lists the available markets with their latest price:
13
14 ```sql
15 SELECT m.id, c.symbol, m.quote_currency, COALESCE(lp.price, 0)
16 FROM project.markets m
17 JOIN project.crypto c ON c.id = m.crypto_id
18 LEFT JOIN project.v_latest_prices lp ON lp.market_id = m.id
19 WHERE m.is_active = true
20 ORDER BY c.symbol;
21 ```
223. Trader enters a market symbol, e.g. `ETH`.
234. System resolves the market and looks up the latest price:
24
25 ```sql
26 SELECT m.id, c.id AS crypto_id, c.symbol, m.quote_currency
27 FROM project.markets m
28 JOIN project.crypto c ON c.id = m.crypto_id
29 WHERE upper(c.symbol) = upper($1) AND m.is_active = true;
30
31 SELECT price FROM project.v_latest_prices WHERE market_id = $2;
32 ```
335. Trader enters a quantity.
346. System computes notional = quantity × price, opens a transaction, and does:
35
36 ```sql
37 BEGIN;
38
39 -- (a) record intent — no trade has happened yet.
40 INSERT INTO project.orders
41 (user_id, market_id, side, type, status, quantity, price)
42 VALUES
43 ($user_id, $market_id, 'buy', 'market', 'open', $qty, $price)
44 RETURNING id; -- captured as $order_id
45
46 -- (b) lock and check the user balance
47 SELECT available_balance FROM project.users WHERE id = $user_id FOR UPDATE;
48 -- abort if available_balance < notional
49
50 -- (c) move cash from available to invested. A buy never reserves crypto
51 -- the way a sell does — it only ever adds to the position, so there
52 -- is nothing on the holdings side to commit before settling.
53 UPDATE project.users
54 SET available_balance = available_balance - $notional,
55 invested_balance = invested_balance + $notional,
56 updated_at = now()
57 WHERE id = $user_id;
58
59 -- (d) upsert holding with running weighted-average price:
60 SELECT quantity, avg_price
61 FROM project.holdings
62 WHERE user_id = $user_id AND crypto_id = $crypto_id
63 FOR UPDATE;
64
65 -- Either INSERT (new holding) or UPDATE (existing), computing
66 -- new_avg = (old_qty*old_avg + $qty*$price) / (old_qty + $qty)
67
68 -- (e) ledger entry
69 INSERT INTO project.transactions
70 (user_id, type, amount, currency, related_order, description)
71 VALUES
72 ($user_id, 'buy', -$notional, 'USD', $order_id, 'Market buy ...');
73
74 -- (f) record the resulting market trade
75 INSERT INTO project.market_trades
76 (market_id, executed_at, price, quantity, side, source)
77 VALUES
78 ($market_id, now(), $price, $qty, 'buy', 'user');
79
80 -- (g) settle the order itself — it has now actually been filled.
81 UPDATE project.orders
82 SET status = 'executed', executed_at = now()
83 WHERE id = $order_id;
84
85 COMMIT;
86 ```
877. System confirms: `Order executed: buy 0.0100 BTC @ 67140.000000 (notional 671.4000 USD)`.
88
89### Alternate flow 6a — insufficient funds
90
91If `available_balance < notional`, the entire transaction rolls back and system shows "Insufficient funds: need X, have Y."
92
93### Alternate flow 4a — market not found
94
95If the entered symbol does not match any active market, system shows "market X not found" and returns to the authenticated menu without opening a transaction.
Note: See TracBrowser for help on using the repository browser.