Metadata-Version: 2.4
Name: stonks-cli
Version: 0.1.0
Summary: CLI tool for tracking investment portfolio
License-File: LICENSE
Author: Igor Opaniuk
Author-email: igor.opaniuk@gmail.com
Requires-Python: >=3.11,<4.0
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: click (>=8.0.0,<9.0.0)
Requires-Dist: pyyaml (>=6.0,<7.0)
Requires-Dist: rich (>=14.0,<15.0)
Requires-Dist: textual (>=8.1.0,<9.0.0)
Requires-Dist: yfinance (>=0.2.0,<0.3.0)
Description-Content-Type: text/markdown

# stonks-cli

Track your investment portfolio directly from the terminal.

![demo](docs/assets/demo.gif)

## Features

- terminal dashboard (TUI)
- tracks stock portfolio with **live market prices** including **extended-hours**
  quotes
- calculates a total portfolio value converted to USD and unrealized P&L
- Yahoo Finance integration (**no API token required**)
- open source (**MIT licensed**)

---

## Installation

**Requirements:** Python 3.11+

```bash
pip install stonks-cli
```

Or with [pipx](https://pipx.pypa.io/) (recommended — keeps the tool isolated):

```bash
pipx install stonks-cli
```

## Preparing configuration in YAML format

stonks-cli stores your portfolio in a YAML file.  By default the file is read
from `~/.config/stonks/portfolio.yaml`; you can override this with the
`-p` / `--portfolio` option (see [Usage](#usage)).

### File structure

```yaml
portfolio:
  positions:
    - symbol: AAPL
      quantity: 10
      avg_cost: 150.00
      currency: USD

    - symbol: ASML.AS
      quantity: 5
      avg_cost: 680.00
      currency: EUR

    - symbol: 7203.T
      quantity: 100
      avg_cost: 1850.00
      currency: JPY
```

| Field      | Type   | Required | Description                             |
| ---------- | ------ | -------- | --------------------------------------- |
| `symbol`   | string | yes      | Yahoo Finance ticker (case-insensitive) |
| `quantity` | int    | yes      | Shares held (positive integer)          |
| `avg_cost` | float  | yes      | Average cost per share (positive)       |
| `currency` | string | no       | ISO 4217 code; defaults to `USD`        |

> The file is created and updated automatically when you use the `add` and
> `remove` commands, so you only need to create it manually if you prefer to
> seed your positions by hand.

### Ticker symbols and exchange suffixes

Yahoo Finance uses a dot-suffix convention to identify non-US exchanges.
Append the appropriate suffix to the base ticker symbol.

### Americas

| Suffix   | Exchange                    | Country   |
| -------- | --------------------------- | --------- |
| *(none)* | NYSE / NASDAQ / AMEX        | USA       |
| `.SA`    | B3 (São Paulo)              | Brazil    |
| `.BA`    | Buenos Aires Stock Exchange | Argentina |
| `.MX`    | Bolsa Mexicana de Valores   | Mexico    |
| `.SN`    | Santiago Stock Exchange     | Chile     |
| `.LIM`   | Lima Stock Exchange         | Peru      |

### Canada

| Suffix | Exchange               | Country |
| ------ | ---------------------- | ------- |
| `.TO`  | Toronto Stock Exchange | Canada  |
| `.V`   | TSX Venture Exchange   | Canada  |

### Europe

| Suffix | Exchange                 | Country     |
| ------ | ------------------------ | ----------- |
| `.L`   | London Stock Exchange    | UK          |
| `.PA`  | Euronext Paris           | France      |
| `.AS`  | Euronext Amsterdam       | Netherlands |
| `.BR`  | Euronext Brussels        | Belgium     |
| `.LS`  | Euronext Lisbon          | Portugal    |
| `.MI`  | Borsa Italiana           | Italy       |
| `.DE`  | XETRA                    | Germany     |
| `.F`   | Frankfurt Stock Exchange | Germany     |
| `.SW`  | SIX Swiss Exchange       | Switzerland |
| `.ST`  | Nasdaq Stockholm         | Sweden      |
| `.HE`  | Nasdaq Helsinki          | Finland     |
| `.CO`  | Nasdaq Copenhagen        | Denmark     |
| `.OL`  | Oslo Børs                | Norway      |
| `.WA`  | Warsaw Stock Exchange    | Poland      |
| `.AT`  | Athens Stock Exchange    | Greece      |

### Asia-Pacific

| Suffix  | Exchange                       | Country     |
| ------- | ------------------------------ | ----------- |
| `.AX`   | Australian Securities Exchange | Australia   |
| `.NZ`   | New Zealand Exchange           | New Zealand |
| `.HK`   | Hong Kong Stock Exchange       | Hong Kong   |
| `.T`    | Tokyo Stock Exchange           | Japan       |
| `.KS`   | Korea Exchange (KOSPI)         | South Korea |
| `.KQ`   | KOSDAQ                         | South Korea |
| `.TW`   | Taiwan Stock Exchange          | Taiwan      |
| `.TWO`  | Taiwan OTC                     | Taiwan      |
| `.SS`   | Shanghai Stock Exchange        | China       |
| `.SZ`   | Shenzhen Stock Exchange        | China       |
| `.NS`   | National Stock Exchange        | India       |
| `.BO`   | Bombay Stock Exchange          | India       |
| `.JK`   | Indonesia Stock Exchange       | Indonesia   |
| `.SI`   | Singapore Exchange             | Singapore   |
| `.KL`   | Bursa Malaysia                 | Malaysia    |
| `.BK`   | Stock Exchange of Thailand     | Thailand    |
| `.VN`   | Ho Chi Minh Stock Exchange     | Vietnam     |

### Examples

| Symbol       | Instrument                |
| ------------ | ------------------------- |
| `AAPL`       | Apple (NASDAQ)            |
| `ASML.AS`    | ASML (Euronext Amsterdam) |
| `7203.T`     | Toyota (Tokyo SE)         |
| `HSBA.L`     | HSBC (London SE)          |
| `005930.KS`  | Samsung (KOSPI)           |

---

## Usage

```text
stonks [OPTIONS] COMMAND [ARGS]...

Options:
  -p, --portfolio PATH  Portfolio YAML file
                        (default: ~/.config/stonks/portfolio.yaml)
  --help                Show this message and exit.

Commands:
  add     Add QUANTITY shares of SYMBOL at PRICE to the portfolio.
  remove  Remove QUANTITY shares of SYMBOL from the portfolio.
  dashboard  Display the current portfolio with live prices and P&L.
```

### Show the portfolio

```bash
# Launch the TUI with the default 5-second refresh
stonks dashboard

# Refresh prices every 30 seconds
stonks dashboard --refresh 30
```

### Add a position

```bash
# Add 10 shares of Apple at $150.00
stonks add AAPL 10 150.00

# Add a non-US stock (ASML on Euronext Amsterdam)
stonks add ASML.AS 5 680.00

# Use a custom portfolio file
stonks -p ~/my-portfolio.yaml add NVDA 2 800.00
```

When a symbol is added a second time, the quantity is increased and the average
cost is recalculated as a weighted average automatically.

### Remove a position

```bash
# Remove 5 shares (partial close)
stonks remove AAPL 5

# Remove all shares (position deleted)
stonks remove AAPL 10
```

The TUI displays a table with the following columns:

| Column         | Description                                  |
| -------------- | -------------------------------------------- |
| Instrument     | Ticker symbol                                |
| Qty            | Number of shares held                        |
| Avg Cost       | Average purchase price per share             |
| Last Price     | Most recent closing price from Yahoo Finance |
| Mkt Value      | Current market value (Qty × Last Price)      |
| Unrealized P&L | Profit/loss vs. average cost (green/red)     |

A **Total (USD)** line at the bottom converts all positions to USD using live
forex rates and sums them up.

Press `q` to quit.

*Screenshot uses the sample portfolio from
[config/sample_portfolio.yaml](config/sample_portfolio.yaml) — all
positions and costs are fictitious test data.*

![Portfolio TUI](docs/assets/screenshot.png)

---

## Running with Docker

### Build the image

```bash
docker build -t stonks .
```

### Run the container

```bash
docker run --rm -it \
  -v ./config/sample_portfolio.yaml:/data/portfolio.yaml:ro \
  stonks --portfolio /data/portfolio.yaml dashboard
```

The `-v` flag bind-mounts a local YAML file into the container. Replace
`./config/sample_portfolio.yaml` with the path to your own portfolio file.
Drop `:ro` if you want `add` / `remove` commands to persist changes back to
the host.

---

## Market analysis

![stonks](docs/assets/stonks.png)

Looks bullish.

## Contributing

Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for
development setup, coding style, commit message conventions, and the pull
request workflow.

For the release process, see [RELEASING.md](RELEASING.md).

---

## License

MIT License. See [LICENSE](LICENSE) for details.

