new endpoints
This commit is contained in:
@@ -16,6 +16,25 @@ func InitDB(db *sql.DB) {
|
||||
name TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS trades (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
company_id INTEGER NOT NULL,
|
||||
currency_id INTEGER NOT NULL,
|
||||
shares INTEGER NOT NULL,
|
||||
product INTEGER NOT NULL CHECK(product IN (0, 1, 2, 3)),
|
||||
type INTEGER NOT NULL CHECK(type IN (0, 1)),
|
||||
price REAL NOT NULL
|
||||
traded_at DATETIME NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS position (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
company_id INTEGER NOT NULL,
|
||||
shares INTEGER NOT NULL,
|
||||
weight REAL NOT NULL,
|
||||
CostBases REAL NOT NULL,
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS companies (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
|
||||
45
internal/database/portfolio.go
Normal file
45
internal/database/portfolio.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"Portifolio/internal/model"
|
||||
"database/sql"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func GetTrades(db *sql.DB) ([]model.Trade, error) {
|
||||
rows, err := db.Query("SELECT id, company_id, currency_id, shares, product, type, price, traded_at FROM trades")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var trades []model.Trade
|
||||
for rows.Next() {
|
||||
var t model.Trade
|
||||
err := rows.Scan(&t.Ticker, &t.Currency, &t.Shares, &t.Product, &t.Type, &t.Price, &t.Date)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
trades = append(trades, t)
|
||||
}
|
||||
if err = rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return trades, nil
|
||||
}
|
||||
|
||||
func InsertTrade(db *sql.DB, trade model.Trade) error {
|
||||
_, err := db.Exec(
|
||||
"INSERT INTO trades (company_id, currency_id, shares, product, type, price, traded_at) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
trade.Ticker.ID,
|
||||
trade.Currency.ID,
|
||||
trade.Shares,
|
||||
trade.Product,
|
||||
trade.Type,
|
||||
trade.Price,
|
||||
trade.Date,
|
||||
)
|
||||
return err
|
||||
}
|
||||
44
internal/handlers/portfolio.go
Normal file
44
internal/handlers/portfolio.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"Portifolio/internal/database"
|
||||
"Portifolio/internal/model"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func AddTradeHandler(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req model.AddTradeRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, "invalid json", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
err := req.Validate()
|
||||
if err != nil {
|
||||
http.Error(w, "invalid json", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func GetTradeListHandler(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
tradeList, err := database.GetTrades(db)
|
||||
if err != nil {
|
||||
http.Error(w, "failed to fetch trades", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(tradeList); err != nil {
|
||||
http.Error(w, "failed to encode trades", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
81
internal/model/portifolio.go
Normal file
81
internal/model/portifolio.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Position struct {
|
||||
Company Company
|
||||
weight float64
|
||||
CostBasis float64
|
||||
Shares int
|
||||
}
|
||||
|
||||
type TradeProduct int
|
||||
|
||||
const (
|
||||
StockTrade TradeProduct = iota // 0
|
||||
OptionCallTrade // 1
|
||||
OptionPutTrade // 2
|
||||
CurrencyTrade // 3
|
||||
BondTrade
|
||||
)
|
||||
|
||||
type TradeType bool
|
||||
|
||||
const (
|
||||
Buy TradeType = true
|
||||
Sell TradeType = false
|
||||
)
|
||||
|
||||
type Trade struct {
|
||||
Ticker Company
|
||||
Shares int
|
||||
Product TradeProduct
|
||||
Type TradeType
|
||||
Price float64
|
||||
Currency Currency
|
||||
Date time.Time
|
||||
}
|
||||
|
||||
type AddTradeRequest struct {
|
||||
TickerId int
|
||||
Shares int
|
||||
Product int
|
||||
Type bool
|
||||
Price float64
|
||||
Currency string
|
||||
Date time.Time
|
||||
}
|
||||
|
||||
func (r *AddTradeRequest) Validate() error {
|
||||
if r.TickerId <= 0 {
|
||||
return errors.New("ticker id must be a positive integer")
|
||||
}
|
||||
if r.Shares <= 0 {
|
||||
return errors.New("shares must be a positive integer")
|
||||
}
|
||||
if r.Product < 0 || r.Product > 3 {
|
||||
return errors.New("product must be between 0 and 3")
|
||||
}
|
||||
if r.Price <= 0 {
|
||||
return errors.New("price must be a positive number")
|
||||
}
|
||||
if r.Currency == "" {
|
||||
return errors.New("currency is required")
|
||||
}
|
||||
if r.Date.IsZero() {
|
||||
return errors.New("date is required")
|
||||
}
|
||||
if r.Date.After(time.Now()) {
|
||||
return errors.New("date cannot be in the future")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// for now trades and none stock position will not be supported.
|
||||
type Portifolio struct {
|
||||
Positions []Position
|
||||
Trades []Trade
|
||||
}
|
||||
Reference in New Issue
Block a user