new endpoints
This commit is contained in:
BIN
Portifolio
BIN
Portifolio
Binary file not shown.
211
README.md
211
README.md
@@ -1,15 +1,16 @@
|
|||||||
# Portfolio Engine
|
# Portfolio Engine
|
||||||
|
|
||||||
A lightweight portfolio and financial data backend written in Go. Tracks companies, currencies, and revenue reports across configurable time periods — replacing spreadsheets with a proper database, REST API, and interactive shell.
|
A lightweight portfolio and financial data backend written in Go. Tracks companies, currencies, revenue reports, and trades across configurable time periods — replacing spreadsheets with a proper database, REST API, and interactive shell.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- SQLite database with foreign key enforcement
|
* SQLite database with foreign key enforcement
|
||||||
- REST API on port `8080`
|
* REST API on port `8080`
|
||||||
- Interactive shell for managing data without an HTTP client
|
* Interactive shell for managing data without an HTTP client
|
||||||
- Revenue tracking by period (quarterly, half-year, full year)
|
* Revenue tracking by period (quarterly, half-year, full year)
|
||||||
- Revenue broken down by custom categories (product, location, segment...)
|
* Revenue broken down by custom categories (product, location, segment...)
|
||||||
- Health endpoint with DB latency, memory, and uptime stats
|
* Trade tracking (stocks, options, currency trades)
|
||||||
|
* Health endpoint with DB latency, memory, and uptime stats
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
@@ -25,12 +26,14 @@ A lightweight portfolio and financial data backend written in Go. Tracks compani
|
|||||||
├── handlers/
|
├── handlers/
|
||||||
│ ├── main.go # HealthHandler
|
│ ├── main.go # HealthHandler
|
||||||
│ ├── currency.go # AddCurrencyHandler, GetCurrenciesHandler
|
│ ├── currency.go # AddCurrencyHandler, GetCurrenciesHandler
|
||||||
│ └── revenue.go # AddRevenueEntryHandler, GetRevenueReportHandler, GetRevenueSumHandler
|
│ ├── revenue.go # AddRevenueEntryHandler, GetRevenueReportHandler, GetRevenueSumHandler
|
||||||
|
│ └── trade.go # AddTradeHandler, GetTradeListHandler
|
||||||
├── model/
|
├── model/
|
||||||
│ ├── company.go # Company struct + SQL (InsertCompany, GetAllCompanies)
|
│ ├── company.go # Company struct + SQL (InsertCompany, GetAllCompanies)
|
||||||
│ ├── currency.go # Currency struct + SQL (InsertCurrency, GetAllCurrencies)
|
│ ├── currency.go # Currency struct + SQL (InsertCurrency, GetAllCurrencies)
|
||||||
│ ├── periode.go # Period struct + helpers (QuarterPeriod, HalfYearPeriod, FullYearPeriod)
|
│ ├── periode.go # Period struct + helpers (QuarterPeriod, HalfYearPeriod, FullYearPeriod)
|
||||||
│ └── revenue.go # Revenue, RevenueReport, RevSum structs + SQL
|
│ ├── revenue.go # Revenue, RevenueReport, RevSum structs + SQL
|
||||||
|
│ └── trade.go # Trade struct, TradeType, TradeProduct enums + SQL
|
||||||
├── service/
|
├── service/
|
||||||
│ ├── main.go # Service wiring
|
│ ├── main.go # Service wiring
|
||||||
│ ├── company.go # Company business logic
|
│ ├── company.go # Company business logic
|
||||||
@@ -46,14 +49,14 @@ A lightweight portfolio and financial data backend written in Go. Tracks compani
|
|||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- Go 1.21+
|
* Go 1.21+
|
||||||
- GCC (required for SQLite CGO bindings)
|
* GCC (required for SQLite CGO bindings)
|
||||||
- Ubuntu/Debian: `sudo apt install gcc`
|
+ Ubuntu/Debian: `sudo apt install gcc`
|
||||||
- macOS: comes with Xcode Command Line Tools
|
+ macOS: comes with Xcode Command Line Tools
|
||||||
|
|
||||||
### Install & Run
|
### Install & Run
|
||||||
|
|
||||||
```bash
|
```
|
||||||
git clone git@git.samantha42.xyz:samantha/Portifolio-Engine.git
|
git clone git@git.samantha42.xyz:samantha/Portifolio-Engine.git
|
||||||
cd Portifolio-Engine
|
cd Portifolio-Engine
|
||||||
go mod download
|
go mod download
|
||||||
@@ -62,7 +65,7 @@ go run main.go
|
|||||||
|
|
||||||
Or build first:
|
Or build first:
|
||||||
|
|
||||||
```bash
|
```
|
||||||
chmod +x build.sh
|
chmod +x build.sh
|
||||||
./build.sh
|
./build.sh
|
||||||
./Portifolio
|
./Portifolio
|
||||||
@@ -89,7 +92,7 @@ The HTTP server and shell run concurrently — the API is live while you type sh
|
|||||||
|
|
||||||
Returns server status, DB connection info, memory usage, and uptime.
|
Returns server status, DB connection info, memory usage, and uptime.
|
||||||
|
|
||||||
```bash
|
```
|
||||||
curl http://localhost:8080/health
|
curl http://localhost:8080/health
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -120,7 +123,7 @@ Returns `503` with `"status": "degraded"` if the database is unreachable.
|
|||||||
|
|
||||||
### `POST /add/company`
|
### `POST /add/company`
|
||||||
|
|
||||||
```bash
|
```
|
||||||
curl -X POST http://localhost:8080/add/company \
|
curl -X POST http://localhost:8080/add/company \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"name":"Novo Nordisk","shares_outstanding":4442064180,"price":251.00,"currency_id":1}'
|
-d '{"name":"Novo Nordisk","shares_outstanding":4442064180,"price":251.00,"currency_id":1}'
|
||||||
@@ -130,7 +133,7 @@ curl -X POST http://localhost:8080/add/company \
|
|||||||
|
|
||||||
### `GET /companies`
|
### `GET /companies`
|
||||||
|
|
||||||
```bash
|
```
|
||||||
curl http://localhost:8080/companies
|
curl http://localhost:8080/companies
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -138,7 +141,7 @@ curl http://localhost:8080/companies
|
|||||||
|
|
||||||
### `POST /add/currency`
|
### `POST /add/currency`
|
||||||
|
|
||||||
```bash
|
```
|
||||||
curl -X POST http://localhost:8080/add/currency \
|
curl -X POST http://localhost:8080/add/currency \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"code":"DKK","name":"Danish Krone"}'
|
-d '{"code":"DKK","name":"Danish Krone"}'
|
||||||
@@ -148,17 +151,77 @@ curl -X POST http://localhost:8080/add/currency \
|
|||||||
|
|
||||||
### `GET /currencies`
|
### `GET /currencies`
|
||||||
|
|
||||||
```bash
|
```
|
||||||
curl http://localhost:8080/currencies
|
curl http://localhost:8080/currencies
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### `POST /trade/add`
|
||||||
|
|
||||||
|
Add a new trade. `product` and `type` are integer enums (see tables below).
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -X POST http://localhost:8080/trade/add \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"ticker_id": 1,
|
||||||
|
"currency": "DKK",
|
||||||
|
"shares": 100,
|
||||||
|
"product": 0,
|
||||||
|
"type": false,
|
||||||
|
"price": 251.00,
|
||||||
|
"date": "2025-03-01T00:00:00Z"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
**`product` values:**
|
||||||
|
|
||||||
|
| Value | Meaning |
|
||||||
|
|-------|------------------|
|
||||||
|
| `0` | StockTrade |
|
||||||
|
| `1` | OptionTradeCall |
|
||||||
|
| `2` | OptionTradePut |
|
||||||
|
| `3` | CurrencyTrade |
|
||||||
|
|
||||||
|
**`type` values:**
|
||||||
|
|
||||||
|
| Value | Meaning |
|
||||||
|
|---------|---------|
|
||||||
|
| `false` | Buy |
|
||||||
|
| `true` | Sell |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `GET /trade/list`
|
||||||
|
|
||||||
|
Returns all trades as a JSON array.
|
||||||
|
|
||||||
|
```
|
||||||
|
curl http://localhost:8080/trade/list
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Ticker": { "id": 1, "name": "Novo Nordisk", ... },
|
||||||
|
"Shares": 100,
|
||||||
|
"Product": 0,
|
||||||
|
"Type": false,
|
||||||
|
"Price": 251.00,
|
||||||
|
"Currency": { "id": 1, "code": "DKK", "name": "Danish Krone" },
|
||||||
|
"Date": "2025-03-01T00:00:00Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `POST /add/revenue/entry`
|
### `POST /add/revenue/entry`
|
||||||
|
|
||||||
Add a single revenue line to a report. The period is created automatically if it doesn't exist.
|
Add a single revenue line to a report. The period is created automatically if it doesn't exist.
|
||||||
|
|
||||||
```bash
|
```
|
||||||
curl -X POST http://localhost:8080/add/revenue/entry \
|
curl -X POST http://localhost:8080/add/revenue/entry \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{
|
-d '{
|
||||||
@@ -187,7 +250,7 @@ curl -X POST http://localhost:8080/add/revenue/entry \
|
|||||||
|
|
||||||
Get all revenue entries for a company and period.
|
Get all revenue entries for a company and period.
|
||||||
|
|
||||||
```bash
|
```
|
||||||
curl "http://localhost:8080/revenue/report?company_id=1&period_type=Q&year=2025&index=1"
|
curl "http://localhost:8080/revenue/report?company_id=1&period_type=Q&year=2025&index=1"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -197,7 +260,7 @@ curl "http://localhost:8080/revenue/report?company_id=1&period_type=Q&year=2025&
|
|||||||
|
|
||||||
Sum all revenue entries for a company across all periods of a given type in a year.
|
Sum all revenue entries for a company across all periods of a given type in a year.
|
||||||
|
|
||||||
```bash
|
```
|
||||||
curl "http://localhost:8080/revenue/sum?company_id=1&period_type=Q&year=2025"
|
curl "http://localhost:8080/revenue/sum?company_id=1&period_type=Q&year=2025"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -205,63 +268,17 @@ curl "http://localhost:8080/revenue/sum?company_id=1&period_type=Q&year=2025"
|
|||||||
|
|
||||||
## Shell Commands
|
## Shell Commands
|
||||||
|
|
||||||
| Command | Description |
|
| Command | Description |
|
||||||
|------------------|-----------------------------------------------|
|
|------------------|--------------------------------------------------|
|
||||||
| `add-company` | Add a new company interactively |
|
| `add-company` | Add a new company interactively |
|
||||||
| `list-companies` | List all companies with price and share count |
|
| `list-companies` | List all companies with price and share count |
|
||||||
| `add-currency` | Add a new currency interactively |
|
| `add-currency` | Add a new currency interactively |
|
||||||
| `list-currency` | List all currencies with their IDs |
|
| `list-currency` | List all currencies with their IDs |
|
||||||
| `add-revenue` | Add a revenue entry interactively |
|
| `add-revenue` | Add a revenue entry interactively |
|
||||||
| `list-revenue` | List revenue entries for a company/period |
|
| `list-revenue` | List revenue entries for a company/period |
|
||||||
| `sum-revenue` | Sum revenue across all periods in a year |
|
| `sum-revenue` | Sum revenue across all periods in a year |
|
||||||
| `help` | Show all available commands |
|
| `help` | Show all available commands |
|
||||||
| `exit` | Quit |
|
| `exit` | Quit |
|
||||||
|
|
||||||
### Example session
|
|
||||||
|
|
||||||
```
|
|
||||||
> add-currency
|
|
||||||
Code (e.g. DKK): DKK
|
|
||||||
Name (e.g. Danish Krone): Danish Krone
|
|
||||||
✓ Currency 'Danish Krone' (DKK) added with ID 1
|
|
||||||
|
|
||||||
> add-company
|
|
||||||
Name: Novo Nordisk
|
|
||||||
Shares outstanding: 4442064180
|
|
||||||
Price: 251.00
|
|
||||||
Currency ID: 1
|
|
||||||
✓ Company 'Novo Nordisk' added.
|
|
||||||
|
|
||||||
> add-revenue
|
|
||||||
Company ID: 1
|
|
||||||
Currency ID: 1
|
|
||||||
Period type (Q/H/Y): Q
|
|
||||||
Year: 2025
|
|
||||||
Index (Q: 1-4 | H: 1-2 | Y: 1): 1
|
|
||||||
Category (product/location/total): product
|
|
||||||
Label (e.g. iPhone, Americas): Diabetes Care
|
|
||||||
Value: 54200
|
|
||||||
✓ Revenue entry added: product / Diabetes Care = 54200.00 (Q1 2025)
|
|
||||||
|
|
||||||
> sum-revenue
|
|
||||||
Company ID: 1
|
|
||||||
Period type to sum (Q/H/Y): Q
|
|
||||||
Year: 2025
|
|
||||||
|
|
||||||
Revenue Sum — FY2025
|
|
||||||
Total: 54200.00
|
|
||||||
|
|
||||||
By Category:
|
|
||||||
product 54200.00
|
|
||||||
|
|
||||||
By Label:
|
|
||||||
Diabetes Care 54200.00
|
|
||||||
|
|
||||||
> list-companies
|
|
||||||
ID NAME CURRENCY PRICE SHARES
|
|
||||||
------------------------------------------------------------
|
|
||||||
1 Novo Nordisk DKK 251.00 4442064180
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -313,20 +330,15 @@ CREATE TABLE revenue_entries (
|
|||||||
FOREIGN KEY (currency_id) REFERENCES currencies(id)
|
FOREIGN KEY (currency_id) REFERENCES currencies(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE category_defs (
|
CREATE TABLE trades (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
company_id INTEGER NOT NULL,
|
company_id INTEGER NOT NULL,
|
||||||
name TEXT NOT NULL,
|
currency_id INTEGER NOT NULL,
|
||||||
FOREIGN KEY (company_id) REFERENCES companies(id),
|
shares INTEGER NOT NULL,
|
||||||
UNIQUE(company_id, name)
|
product INTEGER NOT NULL CHECK(product IN (0, 1, 2, 3)),
|
||||||
);
|
type INTEGER NOT NULL CHECK(type IN (0, 1)),
|
||||||
|
price REAL NOT NULL,
|
||||||
CREATE TABLE category_labels (
|
traded_at DATETIME NOT NULL
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
category_def_id INTEGER NOT NULL,
|
|
||||||
label TEXT NOT NULL,
|
|
||||||
FOREIGN KEY (category_def_id) REFERENCES category_defs(id),
|
|
||||||
UNIQUE(category_def_id, label)
|
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -334,8 +346,9 @@ CREATE TABLE category_labels (
|
|||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
- `GET /company/{id}/revenue` — full revenue history for a company
|
* `GET /company/{id}/revenue` — full revenue history for a company
|
||||||
- Price update endpoint
|
* `GET /trade/list?ticker_id=1` — filter trades by company
|
||||||
- Market cap calculation (price × shares outstanding)
|
* Price update endpoint
|
||||||
- Multi-currency conversion
|
* Market cap calculation (price × shares outstanding)
|
||||||
- Frontend dashboard
|
* Multi-currency conversion
|
||||||
|
* Frontend dashboard
|
||||||
@@ -16,6 +16,25 @@ func InitDB(db *sql.DB) {
|
|||||||
name TEXT NOT NULL
|
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 (
|
CREATE TABLE IF NOT EXISTS companies (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL UNIQUE,
|
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
|
||||||
|
}
|
||||||
4
main.go
4
main.go
@@ -35,6 +35,10 @@ func main() {
|
|||||||
|
|
||||||
http.HandleFunc("/health", handlers.HealthHandler(db))
|
http.HandleFunc("/health", handlers.HealthHandler(db))
|
||||||
|
|
||||||
|
//Trades
|
||||||
|
http.HandleFunc("POST /trade/add", handlers.AddTradeHandler(db))
|
||||||
|
http.HandleFunc("GET /trade/list", handlers.GetTradeListHandler(db))
|
||||||
|
|
||||||
// Company
|
// Company
|
||||||
http.HandleFunc("POST /add/company", handlers.AddCompanyHandler(db))
|
http.HandleFunc("POST /add/company", handlers.AddCompanyHandler(db))
|
||||||
http.HandleFunc("GET /companies", handlers.GetCompaniesHandler(db))
|
http.HandleFunc("GET /companies", handlers.GetCompaniesHandler(db))
|
||||||
|
|||||||
Reference in New Issue
Block a user