Changeset ef1c1c7 for server/market.go


Ignore:
Timestamp:
09/24/26 17:43:19 (6 days ago)
Author:
Stefan <trsunovstefan@…>
Branches:
main
Children:
0cee8ec
Parents:
a531b45
Message:

Wiki docs, phase 6 and phase 7 added

File:
1 edited

Legend:

Unmodified
Added
Removed
  • server/market.go

    ra531b45 ref1c1c7  
    44        "database/sql"
    55        "fmt"
     6        "strconv"
    67
    78        "bp_project/server/db"
    … …  
    1617}
    1718
    18 // ListMarkets prints all active markets with their latest price.
    19 func ListMarkets() {
     19// ListMarkets prints all active markets, numbered, with their latest price,
     20// and returns them in the printed order so a caller can pick one by number.
     21func ListMarkets() []Market {
    2022        rows, err := db.DB.Query(`
    21                 SELECT m.id, c.symbol, m.quote_currency,
     23                SELECT m.id, c.id, c.symbol, m.quote_currency,
    2224                       COALESCE(lp.price, 0) AS price
    2325                  FROM markets m
    … …  
    2830        if err != nil {
    2931                fmt.Println("Error:", err)
    30                 return
     32                return nil
    3133        }
    3234        defer rows.Close()
    … …  
    3537        fmt.Printf("  %-4s  %-8s  %-5s  %15s\n", "#", "Symbol", "Quote", "Last price")
    3638        fmt.Println("  -----------------------------------------")
    37         i := 1
     39        var list []Market
    3840        for rows.Next() {
    39                 var id, sym, quote string
     41                var m Market
    4042                var price float64
    41                 if err := rows.Scan(&id, &sym, &quote, &price); err != nil {
     43                if err := rows.Scan(&m.ID, &m.CryptoID, &m.Symbol, &m.Quote, &price); err != nil {
    4244                        fmt.Println("scan error:", err)
    43                         return
     45                        return nil
    4446                }
    45                 fmt.Printf("  %-4d  %-8s  %-5s  %15.6f\n", i, sym, quote, price)
    46                 i++
     47                list = append(list, m)
     48                fmt.Printf("  %-4d  %-8s  %-5s  %15.6f\n", len(list), m.Symbol, m.Quote, price)
    4749        }
     50        return list
    4851}
    4952
    50 // ChooseMarket asks the user to pick a market by symbol and returns it.
     53// pickNumber reads a 1-based choice from a list of n items.
     54func pickNumber(label string, n int) (int, error) {
     55        if n == 0 {
     56                return 0, fmt.Errorf("Nothing to choose from.")
     57        }
     58        k, err := strconv.Atoi(prompt(label))
     59        if err != nil || k < 1 || k > n {
     60                return 0, fmt.Errorf("Invalid choice, enter a number from 1 to %d.", n)
     61        }
     62        return k - 1, nil
     63}
     64
     65// ChooseMarket lists the active markets and lets the user pick one by its
     66// number in the list.
    5167func ChooseMarket() (*Market, error) {
    52         ListMarkets()
    53         sym := prompt("Market symbol (e.g. BTC): ")
    54         if sym == "" {
    55                 return nil, fmt.Errorf("no symbol entered")
    56         }
    57         var m Market
    58         err := db.DB.QueryRow(`
    59                 SELECT m.id, c.id, c.symbol, m.quote_currency
    60                   FROM markets m
    61                   JOIN crypto c ON c.id = m.crypto_id
    62                  WHERE upper(c.symbol) = upper($1)
    63                    AND m.is_active = true
    64                  LIMIT 1`, sym,
    65         ).Scan(&m.ID, &m.CryptoID, &m.Symbol, &m.Quote)
    66         if err == sql.ErrNoRows {
    67                 return nil, fmt.Errorf("market %s not found", sym)
    68         }
     68        list := ListMarkets()
     69        k, err := pickNumber("Market #: ", len(list))
    6970        if err != nil {
    7071                return nil, err
    7172        }
    72         return &m, nil
     73        return &list[k], nil
     74}
     75
     76// ChooseHolding lists only the markets the user can sell in — cryptos they
     77// hold with some quantity still free (not reserved by an open sell order) —
     78// with how much is held and free, and lets them pick one by number.
     79func ChooseHolding(s *Session) (*Market, error) {
     80        rows, err := db.DB.Query(`
     81                SELECT m.id, c.id, c.symbol, m.quote_currency,
     82                       h.quantity, h.quantity - h.reserved_quantity AS free,
     83                       COALESCE(lp.price, 0) AS price
     84                  FROM holdings h
     85                  JOIN crypto  c ON c.id = h.crypto_id
     86                  JOIN markets m ON m.crypto_id = c.id AND m.is_active = true
     87                  LEFT JOIN v_latest_prices lp ON lp.market_id = m.id
     88                 WHERE h.user_id = $1
     89                   AND h.quantity - h.reserved_quantity > 0
     90                 ORDER BY c.symbol`, s.UserID)
     91        if err != nil {
     92                return nil, err
     93        }
     94        defer rows.Close()
     95
     96        fmt.Println()
     97        fmt.Printf("  %-4s  %-8s  %-5s  %12s  %12s  %15s\n", "#", "Symbol", "Quote", "Held", "Free to sell", "Last price")
     98        fmt.Println("  -------------------------------------------------------------------")
     99        var list []Market
     100        for rows.Next() {
     101                var m Market
     102                var held, free, price float64
     103                if err := rows.Scan(&m.ID, &m.CryptoID, &m.Symbol, &m.Quote, &held, &free, &price); err != nil {
     104                        return nil, err
     105                }
     106                list = append(list, m)
     107                fmt.Printf("  %-4d  %-8s  %-5s  %12.4f  %12.4f  %15.6f\n", len(list), m.Symbol, m.Quote, held, free, price)
     108        }
     109        if len(list) == 0 {
     110                return nil, fmt.Errorf("you hold no crypto that is free to sell")
     111        }
     112        k, err := pickNumber("Holding #: ", len(list))
     113        if err != nil {
     114                return nil, err
     115        }
     116        return &list[k], nil
    73117}
    74118
Note: See TracChangeset for help on using the changeset viewer.