Update README.md
This commit is contained in:
341
README.md
341
README.md
@@ -12,343 +12,16 @@ A lightweight portfolio and financial data backend written in Go. Tracks compani
|
|||||||
* Trade tracking (stocks, options, currency trades)
|
* Trade tracking (stocks, options, currency trades)
|
||||||
* Health endpoint with DB latency, memory, and uptime stats
|
* Health endpoint with DB latency, memory, and uptime stats
|
||||||
|
|
||||||
## Project Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
.
|
|
||||||
├── main.go # Entry point — HTTP routes + shell loop
|
|
||||||
├── app.db # SQLite database (auto-created on first run)
|
|
||||||
├── build.sh # Build script
|
|
||||||
├── go.mod / go.sum
|
|
||||||
└── internal/
|
|
||||||
├── database/
|
|
||||||
│ └── main.go # Schema init (InitDB) — all CREATE TABLE statements
|
|
||||||
├── handlers/
|
|
||||||
│ ├── main.go # HealthHandler
|
|
||||||
│ ├── currency.go # AddCurrencyHandler, GetCurrenciesHandler
|
|
||||||
│ ├── revenue.go # AddRevenueEntryHandler, GetRevenueReportHandler, GetRevenueSumHandler
|
|
||||||
│ └── trade.go # AddTradeHandler, GetTradeListHandler
|
|
||||||
├── model/
|
|
||||||
│ ├── company.go # Company struct + SQL (InsertCompany, GetAllCompanies)
|
|
||||||
│ ├── currency.go # Currency struct + SQL (InsertCurrency, GetAllCurrencies)
|
|
||||||
│ ├── periode.go # Period struct + helpers (QuarterPeriod, HalfYearPeriod, FullYearPeriod)
|
|
||||||
│ ├── revenue.go # Revenue, RevenueReport, RevSum structs + SQL
|
|
||||||
│ └── trade.go # Trade struct, TradeType, TradeProduct enums + SQL
|
|
||||||
├── service/
|
|
||||||
│ ├── main.go # Service wiring
|
|
||||||
│ ├── company.go # Company business logic
|
|
||||||
│ ├── currency.go # Currency business logic
|
|
||||||
│ └── revenue.go # Revenue aggregation logic
|
|
||||||
└── shell/
|
|
||||||
├── company.go # add-company, list-companies
|
|
||||||
├── currency.go # add-currency, list-currency
|
|
||||||
└── revenue.go # add-revenue, list-revenue, sum-revenue
|
|
||||||
```
|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
* Go 1.21+
|
|
||||||
* GCC (required for SQLite CGO bindings)
|
|
||||||
+ Ubuntu/Debian: `sudo apt install gcc`
|
|
||||||
+ macOS: comes with Xcode Command Line Tools
|
|
||||||
|
|
||||||
### Install & Run
|
|
||||||
|
|
||||||
```
|
|
||||||
git clone git@git.samantha42.xyz:samantha/Portifolio-Engine.git
|
|
||||||
cd Portifolio-Engine
|
|
||||||
go mod download
|
|
||||||
go run main.go
|
|
||||||
```
|
|
||||||
|
|
||||||
Or build first:
|
|
||||||
|
|
||||||
```
|
|
||||||
chmod +x build.sh
|
|
||||||
./build.sh
|
|
||||||
./Portifolio
|
|
||||||
```
|
|
||||||
|
|
||||||
On startup:
|
|
||||||
|
|
||||||
```
|
|
||||||
Connected to SQLite database
|
|
||||||
Tables ready
|
|
||||||
Server running on :8080
|
|
||||||
|
|
||||||
Shell ready. Type 'help' for commands.
|
|
||||||
>
|
|
||||||
```
|
|
||||||
|
|
||||||
The HTTP server and shell run concurrently — the API is live while you type shell commands.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## REST API
|
|
||||||
|
|
||||||
### `GET /health`
|
|
||||||
|
|
||||||
Returns server status, DB connection info, memory usage, and uptime.
|
|
||||||
|
|
||||||
```
|
|
||||||
curl http://localhost:8080/health
|
|
||||||
```
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"status": "ok",
|
|
||||||
"uptime": "4m32s",
|
|
||||||
"database": {
|
|
||||||
"status": "ok",
|
|
||||||
"latency": "121µs",
|
|
||||||
"open_connections": 1,
|
|
||||||
"in_use": 0,
|
|
||||||
"idle": 1
|
|
||||||
},
|
|
||||||
"memory": {
|
|
||||||
"alloc_mb": 2.31,
|
|
||||||
"sys_mb": 9.44,
|
|
||||||
"num_gc": 3
|
|
||||||
},
|
|
||||||
"go_version": "go1.22.0",
|
|
||||||
"goroutines": 4
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Returns `503` with `"status": "degraded"` if the database is unreachable.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `POST /add/company`
|
|
||||||
|
|
||||||
```
|
|
||||||
curl -X POST http://localhost:8080/add/company \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"name":"Novo Nordisk","shares_outstanding":4442064180,"price":251.00,"currency_id":1}'
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `GET /companies`
|
|
||||||
|
|
||||||
```
|
|
||||||
curl http://localhost:8080/companies
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `POST /add/currency`
|
|
||||||
|
|
||||||
```
|
|
||||||
curl -X POST http://localhost:8080/add/currency \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"code":"DKK","name":"Danish Krone"}'
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `GET /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`
|
|
||||||
|
|
||||||
Add a single revenue line to a report. The period is created automatically if it doesn't exist.
|
|
||||||
|
|
||||||
```
|
|
||||||
curl -X POST http://localhost:8080/add/revenue/entry \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{
|
|
||||||
"company_id": 1,
|
|
||||||
"currency_id": 1,
|
|
||||||
"period_type": "Q",
|
|
||||||
"year": 2025,
|
|
||||||
"index": 1,
|
|
||||||
"category": "product",
|
|
||||||
"label": "iPhone",
|
|
||||||
"value": 69143
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
`period_type` is one of:
|
|
||||||
|
|
||||||
| Value | Meaning | `index` range |
|
|
||||||
|-------|-----------|---------------|
|
|
||||||
| `Q` | Quarter | 1–4 |
|
|
||||||
| `H` | Half-year | 1–2 |
|
|
||||||
| `Y` | Full year | 1 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `GET /revenue/report`
|
|
||||||
|
|
||||||
Get all revenue entries for a company and period.
|
|
||||||
|
|
||||||
```
|
|
||||||
curl "http://localhost:8080/revenue/report?company_id=1&period_type=Q&year=2025&index=1"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### `GET /revenue/sum`
|
|
||||||
|
|
||||||
Sum all revenue entries for a company across all periods of a given type in a year.
|
|
||||||
|
|
||||||
```
|
|
||||||
curl "http://localhost:8080/revenue/sum?company_id=1&period_type=Q&year=2025"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Shell Commands
|
|
||||||
|
|
||||||
| Command | Description |
|
|
||||||
|------------------|--------------------------------------------------|
|
|
||||||
| `add-company` | Add a new company interactively |
|
|
||||||
| `list-companies` | List all companies with price and share count |
|
|
||||||
| `add-currency` | Add a new currency interactively |
|
|
||||||
| `list-currency` | List all currencies with their IDs |
|
|
||||||
| `add-revenue` | Add a revenue entry interactively |
|
|
||||||
| `list-revenue` | List revenue entries for a company/period |
|
|
||||||
| `sum-revenue` | Sum revenue across all periods in a year |
|
|
||||||
| `help` | Show all available commands |
|
|
||||||
| `exit` | Quit |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Database Schema
|
|
||||||
|
|
||||||
```sql
|
|
||||||
CREATE TABLE currencies (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
code TEXT NOT NULL UNIQUE,
|
|
||||||
name TEXT NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE companies (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
name TEXT NOT NULL UNIQUE,
|
|
||||||
shares_outstanding INTEGER NOT NULL,
|
|
||||||
price REAL NOT NULL,
|
|
||||||
currency_id INTEGER NOT NULL,
|
|
||||||
FOREIGN KEY (currency_id) REFERENCES currencies(id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE periods (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
type TEXT NOT NULL CHECK(type IN ('Q', 'H', 'Y')),
|
|
||||||
year INTEGER NOT NULL,
|
|
||||||
idx INTEGER NOT NULL,
|
|
||||||
start_date TEXT NOT NULL,
|
|
||||||
end_date TEXT NOT NULL,
|
|
||||||
UNIQUE(type, year, idx)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE revenue_reports (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
company_id INTEGER NOT NULL,
|
|
||||||
period_id INTEGER NOT NULL,
|
|
||||||
FOREIGN KEY (company_id) REFERENCES companies(id),
|
|
||||||
FOREIGN KEY (period_id) REFERENCES periods(id),
|
|
||||||
UNIQUE(company_id, period_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE revenue_entries (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
report_id INTEGER NOT NULL,
|
|
||||||
currency_id INTEGER NOT NULL,
|
|
||||||
category TEXT NOT NULL,
|
|
||||||
label TEXT NOT NULL,
|
|
||||||
value REAL NOT NULL,
|
|
||||||
FOREIGN KEY (report_id) REFERENCES revenue_reports(id),
|
|
||||||
FOREIGN KEY (currency_id) REFERENCES currencies(id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE 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
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
* `GET /company/{id}/revenue` — full revenue history for a company
|
|
||||||
* `GET /trade/list?ticker_id=1` — filter trades by company
|
|
||||||
* Price update endpoint
|
* Price update endpoint
|
||||||
* Market cap calculation (price × shares outstanding)
|
* Market cap calculation (price × shares outstanding)
|
||||||
* Multi-currency conversion
|
* Multi-currency conversion
|
||||||
* Frontend dashboard
|
* Frontend dashboard
|
||||||
|
* Shares outstanding history db table
|
||||||
|
* EPS since ownership of shares held
|
||||||
|
* First In First Out, gain realized
|
||||||
|
* Dividends earned and taxes
|
||||||
|
* Total tax obligations
|
||||||
|
|
||||||
|
## Learn More WIKI
|
||||||
|
|||||||
Reference in New Issue
Block a user