stonks-cli 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- stonks_cli-0.1.0/LICENSE +21 -0
- stonks_cli-0.1.0/PKG-INFO +285 -0
- stonks_cli-0.1.0/README.md +264 -0
- stonks_cli-0.1.0/pyproject.toml +46 -0
- stonks_cli-0.1.0/src/stonks_cli/__init__.py +3 -0
- stonks_cli-0.1.0/src/stonks_cli/app.py +231 -0
- stonks_cli-0.1.0/src/stonks_cli/fetcher.py +156 -0
- stonks_cli-0.1.0/src/stonks_cli/main.py +155 -0
- stonks_cli-0.1.0/src/stonks_cli/models.py +166 -0
- stonks_cli-0.1.0/src/stonks_cli/storage.py +103 -0
stonks_cli-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Igor Opaniuk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: stonks-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: CLI tool for tracking investment portfolio
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Author: Igor Opaniuk
|
|
7
|
+
Author-email: igor.opaniuk@gmail.com
|
|
8
|
+
Requires-Python: >=3.11,<4.0
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Requires-Dist: click (>=8.0.0,<9.0.0)
|
|
15
|
+
Requires-Dist: pyyaml (>=6.0,<7.0)
|
|
16
|
+
Requires-Dist: rich (>=14.0,<15.0)
|
|
17
|
+
Requires-Dist: textual (>=8.1.0,<9.0.0)
|
|
18
|
+
Requires-Dist: yfinance (>=0.2.0,<0.3.0)
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# stonks-cli
|
|
22
|
+
|
|
23
|
+
Track your investment portfolio directly from the terminal.
|
|
24
|
+
|
|
25
|
+

|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
- terminal dashboard (TUI)
|
|
30
|
+
- tracks stock portfolio with **live market prices** including **extended-hours**
|
|
31
|
+
quotes
|
|
32
|
+
- calculates a total portfolio value converted to USD and unrealized P&L
|
|
33
|
+
- Yahoo Finance integration (**no API token required**)
|
|
34
|
+
- open source (**MIT licensed**)
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
**Requirements:** Python 3.11+
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install stonks-cli
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Or with [pipx](https://pipx.pypa.io/) (recommended — keeps the tool isolated):
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pipx install stonks-cli
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Preparing configuration in YAML format
|
|
53
|
+
|
|
54
|
+
stonks-cli stores your portfolio in a YAML file. By default the file is read
|
|
55
|
+
from `~/.config/stonks/portfolio.yaml`; you can override this with the
|
|
56
|
+
`-p` / `--portfolio` option (see [Usage](#usage)).
|
|
57
|
+
|
|
58
|
+
### File structure
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
portfolio:
|
|
62
|
+
positions:
|
|
63
|
+
- symbol: AAPL
|
|
64
|
+
quantity: 10
|
|
65
|
+
avg_cost: 150.00
|
|
66
|
+
currency: USD
|
|
67
|
+
|
|
68
|
+
- symbol: ASML.AS
|
|
69
|
+
quantity: 5
|
|
70
|
+
avg_cost: 680.00
|
|
71
|
+
currency: EUR
|
|
72
|
+
|
|
73
|
+
- symbol: 7203.T
|
|
74
|
+
quantity: 100
|
|
75
|
+
avg_cost: 1850.00
|
|
76
|
+
currency: JPY
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
| Field | Type | Required | Description |
|
|
80
|
+
| ---------- | ------ | -------- | --------------------------------------- |
|
|
81
|
+
| `symbol` | string | yes | Yahoo Finance ticker (case-insensitive) |
|
|
82
|
+
| `quantity` | int | yes | Shares held (positive integer) |
|
|
83
|
+
| `avg_cost` | float | yes | Average cost per share (positive) |
|
|
84
|
+
| `currency` | string | no | ISO 4217 code; defaults to `USD` |
|
|
85
|
+
|
|
86
|
+
> The file is created and updated automatically when you use the `add` and
|
|
87
|
+
> `remove` commands, so you only need to create it manually if you prefer to
|
|
88
|
+
> seed your positions by hand.
|
|
89
|
+
|
|
90
|
+
### Ticker symbols and exchange suffixes
|
|
91
|
+
|
|
92
|
+
Yahoo Finance uses a dot-suffix convention to identify non-US exchanges.
|
|
93
|
+
Append the appropriate suffix to the base ticker symbol.
|
|
94
|
+
|
|
95
|
+
### Americas
|
|
96
|
+
|
|
97
|
+
| Suffix | Exchange | Country |
|
|
98
|
+
| -------- | --------------------------- | --------- |
|
|
99
|
+
| *(none)* | NYSE / NASDAQ / AMEX | USA |
|
|
100
|
+
| `.SA` | B3 (São Paulo) | Brazil |
|
|
101
|
+
| `.BA` | Buenos Aires Stock Exchange | Argentina |
|
|
102
|
+
| `.MX` | Bolsa Mexicana de Valores | Mexico |
|
|
103
|
+
| `.SN` | Santiago Stock Exchange | Chile |
|
|
104
|
+
| `.LIM` | Lima Stock Exchange | Peru |
|
|
105
|
+
|
|
106
|
+
### Canada
|
|
107
|
+
|
|
108
|
+
| Suffix | Exchange | Country |
|
|
109
|
+
| ------ | ---------------------- | ------- |
|
|
110
|
+
| `.TO` | Toronto Stock Exchange | Canada |
|
|
111
|
+
| `.V` | TSX Venture Exchange | Canada |
|
|
112
|
+
|
|
113
|
+
### Europe
|
|
114
|
+
|
|
115
|
+
| Suffix | Exchange | Country |
|
|
116
|
+
| ------ | ------------------------ | ----------- |
|
|
117
|
+
| `.L` | London Stock Exchange | UK |
|
|
118
|
+
| `.PA` | Euronext Paris | France |
|
|
119
|
+
| `.AS` | Euronext Amsterdam | Netherlands |
|
|
120
|
+
| `.BR` | Euronext Brussels | Belgium |
|
|
121
|
+
| `.LS` | Euronext Lisbon | Portugal |
|
|
122
|
+
| `.MI` | Borsa Italiana | Italy |
|
|
123
|
+
| `.DE` | XETRA | Germany |
|
|
124
|
+
| `.F` | Frankfurt Stock Exchange | Germany |
|
|
125
|
+
| `.SW` | SIX Swiss Exchange | Switzerland |
|
|
126
|
+
| `.ST` | Nasdaq Stockholm | Sweden |
|
|
127
|
+
| `.HE` | Nasdaq Helsinki | Finland |
|
|
128
|
+
| `.CO` | Nasdaq Copenhagen | Denmark |
|
|
129
|
+
| `.OL` | Oslo Børs | Norway |
|
|
130
|
+
| `.WA` | Warsaw Stock Exchange | Poland |
|
|
131
|
+
| `.AT` | Athens Stock Exchange | Greece |
|
|
132
|
+
|
|
133
|
+
### Asia-Pacific
|
|
134
|
+
|
|
135
|
+
| Suffix | Exchange | Country |
|
|
136
|
+
| ------- | ------------------------------ | ----------- |
|
|
137
|
+
| `.AX` | Australian Securities Exchange | Australia |
|
|
138
|
+
| `.NZ` | New Zealand Exchange | New Zealand |
|
|
139
|
+
| `.HK` | Hong Kong Stock Exchange | Hong Kong |
|
|
140
|
+
| `.T` | Tokyo Stock Exchange | Japan |
|
|
141
|
+
| `.KS` | Korea Exchange (KOSPI) | South Korea |
|
|
142
|
+
| `.KQ` | KOSDAQ | South Korea |
|
|
143
|
+
| `.TW` | Taiwan Stock Exchange | Taiwan |
|
|
144
|
+
| `.TWO` | Taiwan OTC | Taiwan |
|
|
145
|
+
| `.SS` | Shanghai Stock Exchange | China |
|
|
146
|
+
| `.SZ` | Shenzhen Stock Exchange | China |
|
|
147
|
+
| `.NS` | National Stock Exchange | India |
|
|
148
|
+
| `.BO` | Bombay Stock Exchange | India |
|
|
149
|
+
| `.JK` | Indonesia Stock Exchange | Indonesia |
|
|
150
|
+
| `.SI` | Singapore Exchange | Singapore |
|
|
151
|
+
| `.KL` | Bursa Malaysia | Malaysia |
|
|
152
|
+
| `.BK` | Stock Exchange of Thailand | Thailand |
|
|
153
|
+
| `.VN` | Ho Chi Minh Stock Exchange | Vietnam |
|
|
154
|
+
|
|
155
|
+
### Examples
|
|
156
|
+
|
|
157
|
+
| Symbol | Instrument |
|
|
158
|
+
| ------------ | ------------------------- |
|
|
159
|
+
| `AAPL` | Apple (NASDAQ) |
|
|
160
|
+
| `ASML.AS` | ASML (Euronext Amsterdam) |
|
|
161
|
+
| `7203.T` | Toyota (Tokyo SE) |
|
|
162
|
+
| `HSBA.L` | HSBC (London SE) |
|
|
163
|
+
| `005930.KS` | Samsung (KOSPI) |
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Usage
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
stonks [OPTIONS] COMMAND [ARGS]...
|
|
171
|
+
|
|
172
|
+
Options:
|
|
173
|
+
-p, --portfolio PATH Portfolio YAML file
|
|
174
|
+
(default: ~/.config/stonks/portfolio.yaml)
|
|
175
|
+
--help Show this message and exit.
|
|
176
|
+
|
|
177
|
+
Commands:
|
|
178
|
+
add Add QUANTITY shares of SYMBOL at PRICE to the portfolio.
|
|
179
|
+
remove Remove QUANTITY shares of SYMBOL from the portfolio.
|
|
180
|
+
dashboard Display the current portfolio with live prices and P&L.
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Show the portfolio
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
# Launch the TUI with the default 5-second refresh
|
|
187
|
+
stonks dashboard
|
|
188
|
+
|
|
189
|
+
# Refresh prices every 30 seconds
|
|
190
|
+
stonks dashboard --refresh 30
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Add a position
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
# Add 10 shares of Apple at $150.00
|
|
197
|
+
stonks add AAPL 10 150.00
|
|
198
|
+
|
|
199
|
+
# Add a non-US stock (ASML on Euronext Amsterdam)
|
|
200
|
+
stonks add ASML.AS 5 680.00
|
|
201
|
+
|
|
202
|
+
# Use a custom portfolio file
|
|
203
|
+
stonks -p ~/my-portfolio.yaml add NVDA 2 800.00
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
When a symbol is added a second time, the quantity is increased and the average
|
|
207
|
+
cost is recalculated as a weighted average automatically.
|
|
208
|
+
|
|
209
|
+
### Remove a position
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
# Remove 5 shares (partial close)
|
|
213
|
+
stonks remove AAPL 5
|
|
214
|
+
|
|
215
|
+
# Remove all shares (position deleted)
|
|
216
|
+
stonks remove AAPL 10
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
The TUI displays a table with the following columns:
|
|
220
|
+
|
|
221
|
+
| Column | Description |
|
|
222
|
+
| -------------- | -------------------------------------------- |
|
|
223
|
+
| Instrument | Ticker symbol |
|
|
224
|
+
| Qty | Number of shares held |
|
|
225
|
+
| Avg Cost | Average purchase price per share |
|
|
226
|
+
| Last Price | Most recent closing price from Yahoo Finance |
|
|
227
|
+
| Mkt Value | Current market value (Qty × Last Price) |
|
|
228
|
+
| Unrealized P&L | Profit/loss vs. average cost (green/red) |
|
|
229
|
+
|
|
230
|
+
A **Total (USD)** line at the bottom converts all positions to USD using live
|
|
231
|
+
forex rates and sums them up.
|
|
232
|
+
|
|
233
|
+
Press `q` to quit.
|
|
234
|
+
|
|
235
|
+
*Screenshot uses the sample portfolio from
|
|
236
|
+
[config/sample_portfolio.yaml](config/sample_portfolio.yaml) — all
|
|
237
|
+
positions and costs are fictitious test data.*
|
|
238
|
+
|
|
239
|
+

|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Running with Docker
|
|
244
|
+
|
|
245
|
+
### Build the image
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
docker build -t stonks .
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Run the container
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
docker run --rm -it \
|
|
255
|
+
-v ./config/sample_portfolio.yaml:/data/portfolio.yaml:ro \
|
|
256
|
+
stonks --portfolio /data/portfolio.yaml dashboard
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The `-v` flag bind-mounts a local YAML file into the container. Replace
|
|
260
|
+
`./config/sample_portfolio.yaml` with the path to your own portfolio file.
|
|
261
|
+
Drop `:ro` if you want `add` / `remove` commands to persist changes back to
|
|
262
|
+
the host.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Market analysis
|
|
267
|
+
|
|
268
|
+

|
|
269
|
+
|
|
270
|
+
Looks bullish.
|
|
271
|
+
|
|
272
|
+
## Contributing
|
|
273
|
+
|
|
274
|
+
Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for
|
|
275
|
+
development setup, coding style, commit message conventions, and the pull
|
|
276
|
+
request workflow.
|
|
277
|
+
|
|
278
|
+
For the release process, see [RELEASING.md](RELEASING.md).
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## License
|
|
283
|
+
|
|
284
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
285
|
+
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# stonks-cli
|
|
2
|
+
|
|
3
|
+
Track your investment portfolio directly from the terminal.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- terminal dashboard (TUI)
|
|
10
|
+
- tracks stock portfolio with **live market prices** including **extended-hours**
|
|
11
|
+
quotes
|
|
12
|
+
- calculates a total portfolio value converted to USD and unrealized P&L
|
|
13
|
+
- Yahoo Finance integration (**no API token required**)
|
|
14
|
+
- open source (**MIT licensed**)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
**Requirements:** Python 3.11+
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install stonks-cli
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or with [pipx](https://pipx.pypa.io/) (recommended — keeps the tool isolated):
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pipx install stonks-cli
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Preparing configuration in YAML format
|
|
33
|
+
|
|
34
|
+
stonks-cli stores your portfolio in a YAML file. By default the file is read
|
|
35
|
+
from `~/.config/stonks/portfolio.yaml`; you can override this with the
|
|
36
|
+
`-p` / `--portfolio` option (see [Usage](#usage)).
|
|
37
|
+
|
|
38
|
+
### File structure
|
|
39
|
+
|
|
40
|
+
```yaml
|
|
41
|
+
portfolio:
|
|
42
|
+
positions:
|
|
43
|
+
- symbol: AAPL
|
|
44
|
+
quantity: 10
|
|
45
|
+
avg_cost: 150.00
|
|
46
|
+
currency: USD
|
|
47
|
+
|
|
48
|
+
- symbol: ASML.AS
|
|
49
|
+
quantity: 5
|
|
50
|
+
avg_cost: 680.00
|
|
51
|
+
currency: EUR
|
|
52
|
+
|
|
53
|
+
- symbol: 7203.T
|
|
54
|
+
quantity: 100
|
|
55
|
+
avg_cost: 1850.00
|
|
56
|
+
currency: JPY
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
| Field | Type | Required | Description |
|
|
60
|
+
| ---------- | ------ | -------- | --------------------------------------- |
|
|
61
|
+
| `symbol` | string | yes | Yahoo Finance ticker (case-insensitive) |
|
|
62
|
+
| `quantity` | int | yes | Shares held (positive integer) |
|
|
63
|
+
| `avg_cost` | float | yes | Average cost per share (positive) |
|
|
64
|
+
| `currency` | string | no | ISO 4217 code; defaults to `USD` |
|
|
65
|
+
|
|
66
|
+
> The file is created and updated automatically when you use the `add` and
|
|
67
|
+
> `remove` commands, so you only need to create it manually if you prefer to
|
|
68
|
+
> seed your positions by hand.
|
|
69
|
+
|
|
70
|
+
### Ticker symbols and exchange suffixes
|
|
71
|
+
|
|
72
|
+
Yahoo Finance uses a dot-suffix convention to identify non-US exchanges.
|
|
73
|
+
Append the appropriate suffix to the base ticker symbol.
|
|
74
|
+
|
|
75
|
+
### Americas
|
|
76
|
+
|
|
77
|
+
| Suffix | Exchange | Country |
|
|
78
|
+
| -------- | --------------------------- | --------- |
|
|
79
|
+
| *(none)* | NYSE / NASDAQ / AMEX | USA |
|
|
80
|
+
| `.SA` | B3 (São Paulo) | Brazil |
|
|
81
|
+
| `.BA` | Buenos Aires Stock Exchange | Argentina |
|
|
82
|
+
| `.MX` | Bolsa Mexicana de Valores | Mexico |
|
|
83
|
+
| `.SN` | Santiago Stock Exchange | Chile |
|
|
84
|
+
| `.LIM` | Lima Stock Exchange | Peru |
|
|
85
|
+
|
|
86
|
+
### Canada
|
|
87
|
+
|
|
88
|
+
| Suffix | Exchange | Country |
|
|
89
|
+
| ------ | ---------------------- | ------- |
|
|
90
|
+
| `.TO` | Toronto Stock Exchange | Canada |
|
|
91
|
+
| `.V` | TSX Venture Exchange | Canada |
|
|
92
|
+
|
|
93
|
+
### Europe
|
|
94
|
+
|
|
95
|
+
| Suffix | Exchange | Country |
|
|
96
|
+
| ------ | ------------------------ | ----------- |
|
|
97
|
+
| `.L` | London Stock Exchange | UK |
|
|
98
|
+
| `.PA` | Euronext Paris | France |
|
|
99
|
+
| `.AS` | Euronext Amsterdam | Netherlands |
|
|
100
|
+
| `.BR` | Euronext Brussels | Belgium |
|
|
101
|
+
| `.LS` | Euronext Lisbon | Portugal |
|
|
102
|
+
| `.MI` | Borsa Italiana | Italy |
|
|
103
|
+
| `.DE` | XETRA | Germany |
|
|
104
|
+
| `.F` | Frankfurt Stock Exchange | Germany |
|
|
105
|
+
| `.SW` | SIX Swiss Exchange | Switzerland |
|
|
106
|
+
| `.ST` | Nasdaq Stockholm | Sweden |
|
|
107
|
+
| `.HE` | Nasdaq Helsinki | Finland |
|
|
108
|
+
| `.CO` | Nasdaq Copenhagen | Denmark |
|
|
109
|
+
| `.OL` | Oslo Børs | Norway |
|
|
110
|
+
| `.WA` | Warsaw Stock Exchange | Poland |
|
|
111
|
+
| `.AT` | Athens Stock Exchange | Greece |
|
|
112
|
+
|
|
113
|
+
### Asia-Pacific
|
|
114
|
+
|
|
115
|
+
| Suffix | Exchange | Country |
|
|
116
|
+
| ------- | ------------------------------ | ----------- |
|
|
117
|
+
| `.AX` | Australian Securities Exchange | Australia |
|
|
118
|
+
| `.NZ` | New Zealand Exchange | New Zealand |
|
|
119
|
+
| `.HK` | Hong Kong Stock Exchange | Hong Kong |
|
|
120
|
+
| `.T` | Tokyo Stock Exchange | Japan |
|
|
121
|
+
| `.KS` | Korea Exchange (KOSPI) | South Korea |
|
|
122
|
+
| `.KQ` | KOSDAQ | South Korea |
|
|
123
|
+
| `.TW` | Taiwan Stock Exchange | Taiwan |
|
|
124
|
+
| `.TWO` | Taiwan OTC | Taiwan |
|
|
125
|
+
| `.SS` | Shanghai Stock Exchange | China |
|
|
126
|
+
| `.SZ` | Shenzhen Stock Exchange | China |
|
|
127
|
+
| `.NS` | National Stock Exchange | India |
|
|
128
|
+
| `.BO` | Bombay Stock Exchange | India |
|
|
129
|
+
| `.JK` | Indonesia Stock Exchange | Indonesia |
|
|
130
|
+
| `.SI` | Singapore Exchange | Singapore |
|
|
131
|
+
| `.KL` | Bursa Malaysia | Malaysia |
|
|
132
|
+
| `.BK` | Stock Exchange of Thailand | Thailand |
|
|
133
|
+
| `.VN` | Ho Chi Minh Stock Exchange | Vietnam |
|
|
134
|
+
|
|
135
|
+
### Examples
|
|
136
|
+
|
|
137
|
+
| Symbol | Instrument |
|
|
138
|
+
| ------------ | ------------------------- |
|
|
139
|
+
| `AAPL` | Apple (NASDAQ) |
|
|
140
|
+
| `ASML.AS` | ASML (Euronext Amsterdam) |
|
|
141
|
+
| `7203.T` | Toyota (Tokyo SE) |
|
|
142
|
+
| `HSBA.L` | HSBC (London SE) |
|
|
143
|
+
| `005930.KS` | Samsung (KOSPI) |
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Usage
|
|
148
|
+
|
|
149
|
+
```text
|
|
150
|
+
stonks [OPTIONS] COMMAND [ARGS]...
|
|
151
|
+
|
|
152
|
+
Options:
|
|
153
|
+
-p, --portfolio PATH Portfolio YAML file
|
|
154
|
+
(default: ~/.config/stonks/portfolio.yaml)
|
|
155
|
+
--help Show this message and exit.
|
|
156
|
+
|
|
157
|
+
Commands:
|
|
158
|
+
add Add QUANTITY shares of SYMBOL at PRICE to the portfolio.
|
|
159
|
+
remove Remove QUANTITY shares of SYMBOL from the portfolio.
|
|
160
|
+
dashboard Display the current portfolio with live prices and P&L.
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Show the portfolio
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
# Launch the TUI with the default 5-second refresh
|
|
167
|
+
stonks dashboard
|
|
168
|
+
|
|
169
|
+
# Refresh prices every 30 seconds
|
|
170
|
+
stonks dashboard --refresh 30
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Add a position
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Add 10 shares of Apple at $150.00
|
|
177
|
+
stonks add AAPL 10 150.00
|
|
178
|
+
|
|
179
|
+
# Add a non-US stock (ASML on Euronext Amsterdam)
|
|
180
|
+
stonks add ASML.AS 5 680.00
|
|
181
|
+
|
|
182
|
+
# Use a custom portfolio file
|
|
183
|
+
stonks -p ~/my-portfolio.yaml add NVDA 2 800.00
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
When a symbol is added a second time, the quantity is increased and the average
|
|
187
|
+
cost is recalculated as a weighted average automatically.
|
|
188
|
+
|
|
189
|
+
### Remove a position
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
# Remove 5 shares (partial close)
|
|
193
|
+
stonks remove AAPL 5
|
|
194
|
+
|
|
195
|
+
# Remove all shares (position deleted)
|
|
196
|
+
stonks remove AAPL 10
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The TUI displays a table with the following columns:
|
|
200
|
+
|
|
201
|
+
| Column | Description |
|
|
202
|
+
| -------------- | -------------------------------------------- |
|
|
203
|
+
| Instrument | Ticker symbol |
|
|
204
|
+
| Qty | Number of shares held |
|
|
205
|
+
| Avg Cost | Average purchase price per share |
|
|
206
|
+
| Last Price | Most recent closing price from Yahoo Finance |
|
|
207
|
+
| Mkt Value | Current market value (Qty × Last Price) |
|
|
208
|
+
| Unrealized P&L | Profit/loss vs. average cost (green/red) |
|
|
209
|
+
|
|
210
|
+
A **Total (USD)** line at the bottom converts all positions to USD using live
|
|
211
|
+
forex rates and sums them up.
|
|
212
|
+
|
|
213
|
+
Press `q` to quit.
|
|
214
|
+
|
|
215
|
+
*Screenshot uses the sample portfolio from
|
|
216
|
+
[config/sample_portfolio.yaml](config/sample_portfolio.yaml) — all
|
|
217
|
+
positions and costs are fictitious test data.*
|
|
218
|
+
|
|
219
|
+

|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Running with Docker
|
|
224
|
+
|
|
225
|
+
### Build the image
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
docker build -t stonks .
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Run the container
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
docker run --rm -it \
|
|
235
|
+
-v ./config/sample_portfolio.yaml:/data/portfolio.yaml:ro \
|
|
236
|
+
stonks --portfolio /data/portfolio.yaml dashboard
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
The `-v` flag bind-mounts a local YAML file into the container. Replace
|
|
240
|
+
`./config/sample_portfolio.yaml` with the path to your own portfolio file.
|
|
241
|
+
Drop `:ro` if you want `add` / `remove` commands to persist changes back to
|
|
242
|
+
the host.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Market analysis
|
|
247
|
+
|
|
248
|
+

|
|
249
|
+
|
|
250
|
+
Looks bullish.
|
|
251
|
+
|
|
252
|
+
## Contributing
|
|
253
|
+
|
|
254
|
+
Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for
|
|
255
|
+
development setup, coding style, commit message conventions, and the pull
|
|
256
|
+
request workflow.
|
|
257
|
+
|
|
258
|
+
For the release process, see [RELEASING.md](RELEASING.md).
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## License
|
|
263
|
+
|
|
264
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "stonks-cli"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "CLI tool for tracking investment portfolio"
|
|
5
|
+
authors = ["Igor Opaniuk <igor.opaniuk@gmail.com>"]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
packages = [{include = "stonks_cli", from = "src"}]
|
|
8
|
+
|
|
9
|
+
[tool.poetry.dependencies]
|
|
10
|
+
python = "^3.11"
|
|
11
|
+
click = "^8.0.0"
|
|
12
|
+
pyyaml = "^6.0"
|
|
13
|
+
yfinance = "^0.2.0"
|
|
14
|
+
textual = "^8.1.0"
|
|
15
|
+
rich = "^14.0"
|
|
16
|
+
|
|
17
|
+
[tool.poetry.group.dev.dependencies]
|
|
18
|
+
pytest = "^8.2.0"
|
|
19
|
+
pytest-asyncio = "^1.3.0"
|
|
20
|
+
isort = ">=7.0.0,<8.0.0"
|
|
21
|
+
mypy = ">=1.19.0,<2.0.0"
|
|
22
|
+
ruff = ">=0.14.8,<0.15.0"
|
|
23
|
+
types-PyYAML = "^6.0"
|
|
24
|
+
pre-commit = "^4.5.0"
|
|
25
|
+
|
|
26
|
+
[tool.ruff.lint]
|
|
27
|
+
select = ["E", "F", "I"]
|
|
28
|
+
|
|
29
|
+
[tool.poetry.scripts]
|
|
30
|
+
stonks = "stonks_cli.main:main"
|
|
31
|
+
|
|
32
|
+
[build-system]
|
|
33
|
+
requires = ["poetry-core"]
|
|
34
|
+
build-backend = "poetry.core.masonry.api"
|
|
35
|
+
|
|
36
|
+
[tool.pytest.ini_options]
|
|
37
|
+
asyncio_mode = "auto"
|
|
38
|
+
|
|
39
|
+
[tool.mypy]
|
|
40
|
+
python_version = "3.11"
|
|
41
|
+
plugins = []
|
|
42
|
+
files = ["src"]
|
|
43
|
+
ignore_missing_imports = true
|
|
44
|
+
show_error_codes = true
|
|
45
|
+
pretty = true
|
|
46
|
+
strict_optional = true
|