mpal-cli 0.0.1__tar.gz → 0.6.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.
- mpal_cli-0.6.0/LICENSE +21 -0
- mpal_cli-0.6.0/PKG-INFO +211 -0
- mpal_cli-0.6.0/README.md +185 -0
- mpal_cli-0.6.0/pyproject.toml +57 -0
- mpal_cli-0.6.0/src/mpal/__init__.py +3 -0
- mpal_cli-0.6.0/src/mpal/__main__.py +12 -0
- mpal_cli-0.6.0/src/mpal/amounts.py +44 -0
- mpal_cli-0.6.0/src/mpal/asset_replay.py +289 -0
- mpal_cli-0.6.0/src/mpal/assets.py +25 -0
- mpal_cli-0.6.0/src/mpal/cli.py +966 -0
- mpal_cli-0.6.0/src/mpal/config.py +31 -0
- mpal_cli-0.6.0/src/mpal/dates.py +26 -0
- mpal_cli-0.6.0/src/mpal/errors.py +81 -0
- mpal_cli-0.6.0/src/mpal/numbers.py +155 -0
- mpal_cli-0.6.0/src/mpal/output/__init__.py +29 -0
- mpal_cli-0.6.0/src/mpal/output/console.py +718 -0
- mpal_cli-0.6.0/src/mpal/output/formatting.py +135 -0
- mpal_cli-0.6.0/src/mpal/output/theme.py +55 -0
- mpal_cli-0.6.0/src/mpal/storage/__init__.py +82 -0
- mpal_cli-0.6.0/src/mpal/storage/asset_logs.py +86 -0
- mpal_cli-0.6.0/src/mpal/storage/asset_transactions.py +723 -0
- mpal_cli-0.6.0/src/mpal/storage/assets.py +273 -0
- mpal_cli-0.6.0/src/mpal/storage/database.py +311 -0
- mpal_cli-0.6.0/src/mpal/storage/entries.py +299 -0
- mpal_cli-0.6.0/src/mpal/storage/logs.py +107 -0
- mpal_cli-0.6.0/src/mpal/storage/portfolios.py +121 -0
- mpal_cli-0.6.0/src/mpal/storage/summaries.py +174 -0
- mpal_cli-0.6.0/src/mpal_cli.egg-info/PKG-INFO +211 -0
- mpal_cli-0.6.0/src/mpal_cli.egg-info/SOURCES.txt +54 -0
- mpal_cli-0.6.0/src/mpal_cli.egg-info/entry_points.txt +2 -0
- mpal_cli-0.6.0/src/mpal_cli.egg-info/requires.txt +10 -0
- mpal_cli-0.6.0/tests/test_amounts.py +32 -0
- mpal_cli-0.6.0/tests/test_asset_accounting_audit.py +412 -0
- mpal_cli-0.6.0/tests/test_asset_cli.py +589 -0
- mpal_cli-0.6.0/tests/test_asset_delete_entry.py +428 -0
- mpal_cli-0.6.0/tests/test_asset_edit.py +578 -0
- mpal_cli-0.6.0/tests/test_asset_log.py +421 -0
- mpal_cli-0.6.0/tests/test_asset_replay.py +409 -0
- mpal_cli-0.6.0/tests/test_asset_summary.py +625 -0
- mpal_cli-0.6.0/tests/test_assets.py +42 -0
- mpal_cli-0.6.0/tests/test_branding.py +34 -0
- mpal_cli-0.6.0/tests/test_buy.py +584 -0
- mpal_cli-0.6.0/tests/test_cli.py +3106 -0
- mpal_cli-0.6.0/tests/test_dates.py +37 -0
- mpal_cli-0.6.0/tests/test_grouped_cli.py +251 -0
- mpal_cli-0.6.0/tests/test_help.py +235 -0
- mpal_cli-0.6.0/tests/test_income.py +406 -0
- mpal_cli-0.6.0/tests/test_numbers.py +183 -0
- mpal_cli-0.6.0/tests/test_output_polish.py +812 -0
- mpal_cli-0.6.0/tests/test_portfolio_allocation.py +238 -0
- mpal_cli-0.6.0/tests/test_release_readiness.py +214 -0
- mpal_cli-0.6.0/tests/test_sell.py +704 -0
- mpal_cli-0.6.0/tests/test_summary.py +629 -0
- mpal_cli-0.0.1/PKG-INFO +0 -9
- mpal_cli-0.0.1/pyproject.toml +0 -20
- mpal_cli-0.0.1/src/mpal/__init__.py +0 -0
- mpal_cli-0.0.1/src/mpal/__main__.py +0 -16
- mpal_cli-0.0.1/src/mpal_cli.egg-info/PKG-INFO +0 -9
- mpal_cli-0.0.1/src/mpal_cli.egg-info/SOURCES.txt +0 -8
- mpal_cli-0.0.1/src/mpal_cli.egg-info/entry_points.txt +0 -2
- {mpal_cli-0.0.1 → mpal_cli-0.6.0}/setup.cfg +0 -0
- {mpal_cli-0.0.1 → mpal_cli-0.6.0}/src/mpal_cli.egg-info/dependency_links.txt +0 -0
- {mpal_cli-0.0.1 → mpal_cli-0.6.0}/src/mpal_cli.egg-info/top_level.txt +0 -0
mpal_cli-0.6.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nasser
|
|
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.
|
mpal_cli-0.6.0/PKG-INFO
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mpal-cli
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: Multi-Portfolio Asset Ledger (mpal) - A minimal CLI tool for manual asset tracking and capital management.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Keywords: assets,capital,cli,ledger,portfolio
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Environment :: Console
|
|
9
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
14
|
+
Requires-Python: >=3.11
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: rich>=13
|
|
18
|
+
Requires-Dist: typer>=0.12
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
21
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
22
|
+
Provides-Extra: release
|
|
23
|
+
Requires-Dist: build>=1; extra == "release"
|
|
24
|
+
Requires-Dist: twine>=5; extra == "release"
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# mpal
|
|
28
|
+
|
|
29
|
+
mpal — Multi-Portfolio Asset Ledger — is a minimal CLI tool for manual asset
|
|
30
|
+
tracking and capital management.
|
|
31
|
+
|
|
32
|
+
The CLI command is `mpal`. The package/distribution name is `mpal-cli`.
|
|
33
|
+
Current version: `0.6.0`. License: MIT.
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
mpal requires Python 3.11 or later.
|
|
38
|
+
|
|
39
|
+
For a future PyPI release:
|
|
40
|
+
|
|
41
|
+
```console
|
|
42
|
+
python -m pip install mpal-cli
|
|
43
|
+
mpal --help
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
From a project checkout:
|
|
47
|
+
|
|
48
|
+
```console
|
|
49
|
+
python -m pip install -e .
|
|
50
|
+
mpal --help
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Storage
|
|
54
|
+
|
|
55
|
+
mpal stores records in a local SQLite database named `mpal.db`. By default it
|
|
56
|
+
uses the platform data directory, but you can set `MPAL_DATA_DIR` to choose a
|
|
57
|
+
different directory:
|
|
58
|
+
|
|
59
|
+
```console
|
|
60
|
+
MPAL_DATA_DIR=/path/to/mpal-data mpal init
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## What mpal is
|
|
64
|
+
|
|
65
|
+
- A manual capital ledger.
|
|
66
|
+
- A portfolio tracker.
|
|
67
|
+
- A deterministic, record-based calculator.
|
|
68
|
+
- A local database-backed CLI.
|
|
69
|
+
- A foundation for future extensions.
|
|
70
|
+
|
|
71
|
+
mpal calculates its results only from manually recorded operations.
|
|
72
|
+
|
|
73
|
+
## Scope
|
|
74
|
+
|
|
75
|
+
mpal is intentionally simple. It does not fetch market data, calculate live
|
|
76
|
+
prices, calculate market value, calculate unrealized PnL, connect to market
|
|
77
|
+
APIs or other external services, or provide financial advice.
|
|
78
|
+
|
|
79
|
+
mpal only works with the records you enter manually.
|
|
80
|
+
|
|
81
|
+
mpal tracks capital, cash, open positions by book cost, manually recorded
|
|
82
|
+
asset income, realized P&L, and return. Portfolio summaries use
|
|
83
|
+
book/accounting values. Book Value is derived from manual records and is not
|
|
84
|
+
market value.
|
|
85
|
+
|
|
86
|
+
## Quick Start
|
|
87
|
+
|
|
88
|
+
```console
|
|
89
|
+
mpal init
|
|
90
|
+
mpal summary
|
|
91
|
+
mpal summary --explain
|
|
92
|
+
mpal portfolio create stocks
|
|
93
|
+
mpal deposit 1000 -p stocks
|
|
94
|
+
mpal withdraw 250 -p stocks
|
|
95
|
+
mpal capital -p stocks
|
|
96
|
+
mpal capital log -p stocks
|
|
97
|
+
mpal asset add AAPL -p stocks
|
|
98
|
+
mpal asset buy AAPL -p stocks --price 234.43 --quantity 3 --fee 2.30
|
|
99
|
+
mpal asset list
|
|
100
|
+
mpal summary -p stocks
|
|
101
|
+
mpal summary -p stocks -a AAPL
|
|
102
|
+
mpal asset log AAPL -p stocks
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Command Hierarchy
|
|
106
|
+
|
|
107
|
+
mpal groups commands by the records they manage:
|
|
108
|
+
|
|
109
|
+
```console
|
|
110
|
+
mpal init
|
|
111
|
+
|
|
112
|
+
mpal summary
|
|
113
|
+
mpal summary --explain
|
|
114
|
+
mpal summary -p stocks
|
|
115
|
+
mpal summary -p stocks -a AAPL
|
|
116
|
+
|
|
117
|
+
mpal portfolio create stocks
|
|
118
|
+
mpal portfolio create stocks --initial 5000
|
|
119
|
+
mpal portfolio list
|
|
120
|
+
mpal portfolio allocation
|
|
121
|
+
mpal portfolio reset stocks --yes
|
|
122
|
+
mpal portfolio delete stocks --yes
|
|
123
|
+
|
|
124
|
+
mpal deposit 1000 -p stocks
|
|
125
|
+
mpal withdraw 250 --portfolio stocks --date 2026-06-19 --note "withdrawal"
|
|
126
|
+
mpal capital -p stocks
|
|
127
|
+
mpal capital log -p stocks
|
|
128
|
+
mpal capital entry edit 2 -p stocks --amount 500
|
|
129
|
+
mpal capital entry delete 2 -p stocks
|
|
130
|
+
|
|
131
|
+
mpal asset add AAPL AMZN MSFT -p stocks
|
|
132
|
+
mpal asset list
|
|
133
|
+
mpal asset list -p stocks
|
|
134
|
+
mpal asset log AAPL -p stocks
|
|
135
|
+
mpal asset delete AAPL -p stocks --yes
|
|
136
|
+
mpal asset entry edit AAPL 2 -p stocks --price 234.50 --quantity 3
|
|
137
|
+
mpal asset entry delete AAPL 2 -p stocks --yes
|
|
138
|
+
mpal asset income AAPL 32 -p stocks --date 2026-06-20 --note "Distribution"
|
|
139
|
+
mpal asset buy AAPL -p stocks --price 234.43 --quantity 3 --fee 2.30
|
|
140
|
+
mpal asset sell AAPL -p stocks --price 235.50 --quantity 1 --fee 1.25
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`mpal summary` is the unified summary/reporting command. With no options it
|
|
144
|
+
shows a global dashboard summary across all active portfolios: total capital,
|
|
145
|
+
total cash, positions, book value, total income, realized P&L, and return.
|
|
146
|
+
`mpal summary --explain` prints concise definitions below that global table.
|
|
147
|
+
`mpal summary -p <portfolio>` summarizes one active portfolio. `mpal summary
|
|
148
|
+
-p <portfolio> -a <asset>` summarizes one active asset within one active
|
|
149
|
+
portfolio; `-a` requires `-p`. Positions are open position book cost, not
|
|
150
|
+
market value. Book Value is total cash plus open position book cost. Summary
|
|
151
|
+
views do not use live prices, market value, or unrealized PnL. Global return
|
|
152
|
+
is computed from global totals, not by averaging portfolio returns.
|
|
153
|
+
|
|
154
|
+
`mpal portfolio allocation` shows active portfolio allocation by book value.
|
|
155
|
+
`BOOK VALUE = TOTAL CASH + POSITIONS`, where positions are open position book
|
|
156
|
+
cost. Allocation is not based on capital, cash alone, market value, live
|
|
157
|
+
prices, or unrealized PnL.
|
|
158
|
+
|
|
159
|
+
Portfolio-scoped capital and asset operations require `--portfolio` or `-p`.
|
|
160
|
+
Global collection views such as `mpal summary` and `mpal asset list` do not
|
|
161
|
+
require `-p`. No compatibility aliases are kept in this CLI redesign.
|
|
162
|
+
|
|
163
|
+
Use `mpal deposit <amount> -p <portfolio>` for external capital deposits and
|
|
164
|
+
`mpal withdraw <amount> -p <portfolio>` for external capital withdrawals. Use
|
|
165
|
+
`mpal capital -p <portfolio>` to inspect current capital and
|
|
166
|
+
`mpal capital log -p <portfolio>` to inspect capital history.
|
|
167
|
+
|
|
168
|
+
Asset list output uses an `Asset/Portfolio` column. Combined labels display
|
|
169
|
+
as `<SYMBOL> • <Portfolio>`, such as `AAPL • Stocks`; portfolio capitalization
|
|
170
|
+
there is display-only, and command syntax still uses `-p <portfolio>`. The
|
|
171
|
+
symbol uses the key style while the portfolio segment is muted for scanning.
|
|
172
|
+
|
|
173
|
+
Entry numbers shown by `mpal capital log` are stable, portfolio-local
|
|
174
|
+
numbers. Internal database IDs are not part of the CLI contract.
|
|
175
|
+
Capital entry correction is under `mpal capital entry edit/delete`; `mpal
|
|
176
|
+
capital log` remains the historical entry view, and `mpal capital -p
|
|
177
|
+
<portfolio>` is the capital-only current-state view.
|
|
178
|
+
|
|
179
|
+
Explicit transaction dates must use `YYYY-MM-DD` and cannot be in the future. If
|
|
180
|
+
`--date` is omitted, mpal uses the current local date.
|
|
181
|
+
|
|
182
|
+
The current release covers initialization, portfolio creation, optional initial capital,
|
|
183
|
+
deposits, withdrawals, summaries, logs, capital-entry correction and deletion,
|
|
184
|
+
portfolio reset, and soft deletion of portfolios. The asset foundation adds
|
|
185
|
+
manual symbol creation, current-state views, and soft deletion under existing
|
|
186
|
+
portfolios. The read-only asset log and its transaction storage foundation are
|
|
187
|
+
also present. Manual asset income updates asset and portfolio summaries.
|
|
188
|
+
Manual buys update open quantity, Cost Basis, portfolio Cash, and Positions.
|
|
189
|
+
Manual sells use moving-average book cost and update open quantity, Cost Basis,
|
|
190
|
+
Cash, Positions, and Realized PnL. Individual asset transactions can be edited
|
|
191
|
+
or soft-deleted by asset-local entry number, with active transactions replayed
|
|
192
|
+
before commit. `asset list` is the current asset collection view, and
|
|
193
|
+
`summary -p <portfolio> -a <asset>` reports current open quantity, Cost Basis,
|
|
194
|
+
Average Cost, Realized PnL, Income, and Realized Return for one asset from
|
|
195
|
+
active manual transactions.
|
|
196
|
+
Asset transaction correction is under `mpal asset entry edit/delete`; `mpal
|
|
197
|
+
asset log` remains the historical transaction view.
|
|
198
|
+
|
|
199
|
+
`summary` owns global, portfolio, and asset summary/reporting views. Daily
|
|
200
|
+
capital actions are top-level commands, and `capital -p` owns the current
|
|
201
|
+
capital view.
|
|
202
|
+
|
|
203
|
+
## Planned capabilities
|
|
204
|
+
|
|
205
|
+
Later releases are planned to extend portfolio tracking, record management, calculations, reporting, backup, import and export, audit tooling, and release automation.
|
|
206
|
+
|
|
207
|
+
See [the roadmap](docs/ROADMAP.md) for the phased plan.
|
|
208
|
+
|
|
209
|
+
## Financial advice disclaimer
|
|
210
|
+
|
|
211
|
+
mpal is a record-keeping and calculation tool. It does not provide financial, investment, tax, or legal advice. Users are responsible for verifying their records and decisions.
|
mpal_cli-0.6.0/README.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# mpal
|
|
2
|
+
|
|
3
|
+
mpal — Multi-Portfolio Asset Ledger — is a minimal CLI tool for manual asset
|
|
4
|
+
tracking and capital management.
|
|
5
|
+
|
|
6
|
+
The CLI command is `mpal`. The package/distribution name is `mpal-cli`.
|
|
7
|
+
Current version: `0.6.0`. License: MIT.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
mpal requires Python 3.11 or later.
|
|
12
|
+
|
|
13
|
+
For a future PyPI release:
|
|
14
|
+
|
|
15
|
+
```console
|
|
16
|
+
python -m pip install mpal-cli
|
|
17
|
+
mpal --help
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
From a project checkout:
|
|
21
|
+
|
|
22
|
+
```console
|
|
23
|
+
python -m pip install -e .
|
|
24
|
+
mpal --help
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Storage
|
|
28
|
+
|
|
29
|
+
mpal stores records in a local SQLite database named `mpal.db`. By default it
|
|
30
|
+
uses the platform data directory, but you can set `MPAL_DATA_DIR` to choose a
|
|
31
|
+
different directory:
|
|
32
|
+
|
|
33
|
+
```console
|
|
34
|
+
MPAL_DATA_DIR=/path/to/mpal-data mpal init
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## What mpal is
|
|
38
|
+
|
|
39
|
+
- A manual capital ledger.
|
|
40
|
+
- A portfolio tracker.
|
|
41
|
+
- A deterministic, record-based calculator.
|
|
42
|
+
- A local database-backed CLI.
|
|
43
|
+
- A foundation for future extensions.
|
|
44
|
+
|
|
45
|
+
mpal calculates its results only from manually recorded operations.
|
|
46
|
+
|
|
47
|
+
## Scope
|
|
48
|
+
|
|
49
|
+
mpal is intentionally simple. It does not fetch market data, calculate live
|
|
50
|
+
prices, calculate market value, calculate unrealized PnL, connect to market
|
|
51
|
+
APIs or other external services, or provide financial advice.
|
|
52
|
+
|
|
53
|
+
mpal only works with the records you enter manually.
|
|
54
|
+
|
|
55
|
+
mpal tracks capital, cash, open positions by book cost, manually recorded
|
|
56
|
+
asset income, realized P&L, and return. Portfolio summaries use
|
|
57
|
+
book/accounting values. Book Value is derived from manual records and is not
|
|
58
|
+
market value.
|
|
59
|
+
|
|
60
|
+
## Quick Start
|
|
61
|
+
|
|
62
|
+
```console
|
|
63
|
+
mpal init
|
|
64
|
+
mpal summary
|
|
65
|
+
mpal summary --explain
|
|
66
|
+
mpal portfolio create stocks
|
|
67
|
+
mpal deposit 1000 -p stocks
|
|
68
|
+
mpal withdraw 250 -p stocks
|
|
69
|
+
mpal capital -p stocks
|
|
70
|
+
mpal capital log -p stocks
|
|
71
|
+
mpal asset add AAPL -p stocks
|
|
72
|
+
mpal asset buy AAPL -p stocks --price 234.43 --quantity 3 --fee 2.30
|
|
73
|
+
mpal asset list
|
|
74
|
+
mpal summary -p stocks
|
|
75
|
+
mpal summary -p stocks -a AAPL
|
|
76
|
+
mpal asset log AAPL -p stocks
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Command Hierarchy
|
|
80
|
+
|
|
81
|
+
mpal groups commands by the records they manage:
|
|
82
|
+
|
|
83
|
+
```console
|
|
84
|
+
mpal init
|
|
85
|
+
|
|
86
|
+
mpal summary
|
|
87
|
+
mpal summary --explain
|
|
88
|
+
mpal summary -p stocks
|
|
89
|
+
mpal summary -p stocks -a AAPL
|
|
90
|
+
|
|
91
|
+
mpal portfolio create stocks
|
|
92
|
+
mpal portfolio create stocks --initial 5000
|
|
93
|
+
mpal portfolio list
|
|
94
|
+
mpal portfolio allocation
|
|
95
|
+
mpal portfolio reset stocks --yes
|
|
96
|
+
mpal portfolio delete stocks --yes
|
|
97
|
+
|
|
98
|
+
mpal deposit 1000 -p stocks
|
|
99
|
+
mpal withdraw 250 --portfolio stocks --date 2026-06-19 --note "withdrawal"
|
|
100
|
+
mpal capital -p stocks
|
|
101
|
+
mpal capital log -p stocks
|
|
102
|
+
mpal capital entry edit 2 -p stocks --amount 500
|
|
103
|
+
mpal capital entry delete 2 -p stocks
|
|
104
|
+
|
|
105
|
+
mpal asset add AAPL AMZN MSFT -p stocks
|
|
106
|
+
mpal asset list
|
|
107
|
+
mpal asset list -p stocks
|
|
108
|
+
mpal asset log AAPL -p stocks
|
|
109
|
+
mpal asset delete AAPL -p stocks --yes
|
|
110
|
+
mpal asset entry edit AAPL 2 -p stocks --price 234.50 --quantity 3
|
|
111
|
+
mpal asset entry delete AAPL 2 -p stocks --yes
|
|
112
|
+
mpal asset income AAPL 32 -p stocks --date 2026-06-20 --note "Distribution"
|
|
113
|
+
mpal asset buy AAPL -p stocks --price 234.43 --quantity 3 --fee 2.30
|
|
114
|
+
mpal asset sell AAPL -p stocks --price 235.50 --quantity 1 --fee 1.25
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
`mpal summary` is the unified summary/reporting command. With no options it
|
|
118
|
+
shows a global dashboard summary across all active portfolios: total capital,
|
|
119
|
+
total cash, positions, book value, total income, realized P&L, and return.
|
|
120
|
+
`mpal summary --explain` prints concise definitions below that global table.
|
|
121
|
+
`mpal summary -p <portfolio>` summarizes one active portfolio. `mpal summary
|
|
122
|
+
-p <portfolio> -a <asset>` summarizes one active asset within one active
|
|
123
|
+
portfolio; `-a` requires `-p`. Positions are open position book cost, not
|
|
124
|
+
market value. Book Value is total cash plus open position book cost. Summary
|
|
125
|
+
views do not use live prices, market value, or unrealized PnL. Global return
|
|
126
|
+
is computed from global totals, not by averaging portfolio returns.
|
|
127
|
+
|
|
128
|
+
`mpal portfolio allocation` shows active portfolio allocation by book value.
|
|
129
|
+
`BOOK VALUE = TOTAL CASH + POSITIONS`, where positions are open position book
|
|
130
|
+
cost. Allocation is not based on capital, cash alone, market value, live
|
|
131
|
+
prices, or unrealized PnL.
|
|
132
|
+
|
|
133
|
+
Portfolio-scoped capital and asset operations require `--portfolio` or `-p`.
|
|
134
|
+
Global collection views such as `mpal summary` and `mpal asset list` do not
|
|
135
|
+
require `-p`. No compatibility aliases are kept in this CLI redesign.
|
|
136
|
+
|
|
137
|
+
Use `mpal deposit <amount> -p <portfolio>` for external capital deposits and
|
|
138
|
+
`mpal withdraw <amount> -p <portfolio>` for external capital withdrawals. Use
|
|
139
|
+
`mpal capital -p <portfolio>` to inspect current capital and
|
|
140
|
+
`mpal capital log -p <portfolio>` to inspect capital history.
|
|
141
|
+
|
|
142
|
+
Asset list output uses an `Asset/Portfolio` column. Combined labels display
|
|
143
|
+
as `<SYMBOL> • <Portfolio>`, such as `AAPL • Stocks`; portfolio capitalization
|
|
144
|
+
there is display-only, and command syntax still uses `-p <portfolio>`. The
|
|
145
|
+
symbol uses the key style while the portfolio segment is muted for scanning.
|
|
146
|
+
|
|
147
|
+
Entry numbers shown by `mpal capital log` are stable, portfolio-local
|
|
148
|
+
numbers. Internal database IDs are not part of the CLI contract.
|
|
149
|
+
Capital entry correction is under `mpal capital entry edit/delete`; `mpal
|
|
150
|
+
capital log` remains the historical entry view, and `mpal capital -p
|
|
151
|
+
<portfolio>` is the capital-only current-state view.
|
|
152
|
+
|
|
153
|
+
Explicit transaction dates must use `YYYY-MM-DD` and cannot be in the future. If
|
|
154
|
+
`--date` is omitted, mpal uses the current local date.
|
|
155
|
+
|
|
156
|
+
The current release covers initialization, portfolio creation, optional initial capital,
|
|
157
|
+
deposits, withdrawals, summaries, logs, capital-entry correction and deletion,
|
|
158
|
+
portfolio reset, and soft deletion of portfolios. The asset foundation adds
|
|
159
|
+
manual symbol creation, current-state views, and soft deletion under existing
|
|
160
|
+
portfolios. The read-only asset log and its transaction storage foundation are
|
|
161
|
+
also present. Manual asset income updates asset and portfolio summaries.
|
|
162
|
+
Manual buys update open quantity, Cost Basis, portfolio Cash, and Positions.
|
|
163
|
+
Manual sells use moving-average book cost and update open quantity, Cost Basis,
|
|
164
|
+
Cash, Positions, and Realized PnL. Individual asset transactions can be edited
|
|
165
|
+
or soft-deleted by asset-local entry number, with active transactions replayed
|
|
166
|
+
before commit. `asset list` is the current asset collection view, and
|
|
167
|
+
`summary -p <portfolio> -a <asset>` reports current open quantity, Cost Basis,
|
|
168
|
+
Average Cost, Realized PnL, Income, and Realized Return for one asset from
|
|
169
|
+
active manual transactions.
|
|
170
|
+
Asset transaction correction is under `mpal asset entry edit/delete`; `mpal
|
|
171
|
+
asset log` remains the historical transaction view.
|
|
172
|
+
|
|
173
|
+
`summary` owns global, portfolio, and asset summary/reporting views. Daily
|
|
174
|
+
capital actions are top-level commands, and `capital -p` owns the current
|
|
175
|
+
capital view.
|
|
176
|
+
|
|
177
|
+
## Planned capabilities
|
|
178
|
+
|
|
179
|
+
Later releases are planned to extend portfolio tracking, record management, calculations, reporting, backup, import and export, audit tooling, and release automation.
|
|
180
|
+
|
|
181
|
+
See [the roadmap](docs/ROADMAP.md) for the phased plan.
|
|
182
|
+
|
|
183
|
+
## Financial advice disclaimer
|
|
184
|
+
|
|
185
|
+
mpal is a record-keeping and calculation tool. It does not provide financial, investment, tax, or legal advice. Users are responsible for verifying their records and decisions.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mpal-cli"
|
|
7
|
+
version = "0.6.0"
|
|
8
|
+
description = "Multi-Portfolio Asset Ledger (mpal) - A minimal CLI tool for manual asset tracking and capital management."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
keywords = ["assets", "capital", "cli", "ledger", "portfolio"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 3 - Alpha",
|
|
15
|
+
"Environment :: Console",
|
|
16
|
+
"Intended Audience :: End Users/Desktop",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Topic :: Office/Business :: Financial",
|
|
21
|
+
]
|
|
22
|
+
dependencies = [
|
|
23
|
+
"rich>=13",
|
|
24
|
+
"typer>=0.12",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
dev = [
|
|
29
|
+
"pytest>=8",
|
|
30
|
+
"ruff>=0.6",
|
|
31
|
+
]
|
|
32
|
+
release = [
|
|
33
|
+
"build>=1",
|
|
34
|
+
"twine>=5",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.scripts]
|
|
38
|
+
mpal = "mpal.cli:app"
|
|
39
|
+
|
|
40
|
+
[tool.setuptools.packages.find]
|
|
41
|
+
where = ["src"]
|
|
42
|
+
|
|
43
|
+
[tool.pytest.ini_options]
|
|
44
|
+
addopts = "-ra"
|
|
45
|
+
pythonpath = ["src"]
|
|
46
|
+
testpaths = ["tests"]
|
|
47
|
+
|
|
48
|
+
[tool.ruff]
|
|
49
|
+
line-length = 88
|
|
50
|
+
target-version = "py311"
|
|
51
|
+
|
|
52
|
+
[tool.ruff.lint]
|
|
53
|
+
select = ["E", "F", "I", "UP"]
|
|
54
|
+
|
|
55
|
+
[tool.ruff.format]
|
|
56
|
+
quote-style = "double"
|
|
57
|
+
indent-style = "space"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Exact monetary parsing and money-specific display formatting."""
|
|
2
|
+
|
|
3
|
+
from decimal import Decimal, InvalidOperation
|
|
4
|
+
|
|
5
|
+
from mpal.errors import InvalidAmountError
|
|
6
|
+
|
|
7
|
+
MINOR_UNITS_PER_UNIT = 100
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def parse_amount_minor(amount: str, *, allow_zero: bool = False) -> int:
|
|
11
|
+
"""Parse money with at most two decimal places."""
|
|
12
|
+
try:
|
|
13
|
+
decimal_amount = Decimal(amount)
|
|
14
|
+
except InvalidOperation as error:
|
|
15
|
+
raise InvalidAmountError(f"Invalid amount: '{amount}'.") from error
|
|
16
|
+
|
|
17
|
+
if not decimal_amount.is_finite():
|
|
18
|
+
raise InvalidAmountError(f"Invalid amount: '{amount}'.")
|
|
19
|
+
if decimal_amount < 0 or (decimal_amount == 0 and not allow_zero):
|
|
20
|
+
comparison = "nonnegative" if allow_zero else "greater than zero"
|
|
21
|
+
raise InvalidAmountError(f"Amount must be {comparison}.")
|
|
22
|
+
if decimal_amount.as_tuple().exponent < -2:
|
|
23
|
+
raise InvalidAmountError("Amount cannot have more than 2 decimal places.")
|
|
24
|
+
|
|
25
|
+
minor_amount = decimal_amount * MINOR_UNITS_PER_UNIT
|
|
26
|
+
if minor_amount != minor_amount.to_integral_value():
|
|
27
|
+
raise InvalidAmountError("Amount cannot have more than 2 decimal places.")
|
|
28
|
+
|
|
29
|
+
return int(minor_amount)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def format_money(amount_minor: int) -> str:
|
|
33
|
+
"""Format integer minor units as money with grouping and two places."""
|
|
34
|
+
sign = "-" if amount_minor < 0 else ""
|
|
35
|
+
whole, fraction = divmod(abs(amount_minor), MINOR_UNITS_PER_UNIT)
|
|
36
|
+
return f"{sign}{whole:,}.{fraction:02d}"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def format_signed_money(amount_minor: int) -> str:
|
|
40
|
+
"""Format profit or loss money with an explicit positive sign."""
|
|
41
|
+
formatted = format_money(amount_minor)
|
|
42
|
+
if amount_minor > 0:
|
|
43
|
+
return f"+{formatted}"
|
|
44
|
+
return formatted
|