Bulk currency conversion for Splitwise expenses
Project description
splitwise-fx
Bulk currency conversion for Splitwise expenses.
Pulls a Splitwise group's expenses, converts every foreign-currency line to a target currency at the UnionPay transaction-date rate (the rate Chinese banks actually used to settle), and writes the converted values back via the Splitwise API.
Install
uv tool install splitwise-fx
(Or pipx install splitwise-fx, or any other tool that installs Python CLIs into isolated venvs.)
After install, splitwise-fx is on your PATH.
Setup
Get a Splitwise API key from https://secure.splitwise.com/apps and export it:
export SPLITWISE_API_KEY=your-key-here
(Add to ~/.zshrc / ~/.bashrc to persist. You can also pass --api-key per-invocation, or drop a .env file in the directory you run from.)
Usage
# preview, then prompt y/N to apply
splitwise-fx --group "东京旅行" --to CNY
# preview only — exit without prompting
splitwise-fx --group "东京旅行" --to CNY --dry-run
# skip the prompt (automation)
splitwise-fx --group "东京旅行" --to CNY --yes
# date window
splitwise-fx --group "东京旅行" --to CNY --after 2026-04-01 --before 2026-05-01
# bypass the on-disk rate cache
splitwise-fx --group "东京旅行" --to CNY --no-cache
--group accepts either the group's name (case-insensitive) or its numeric ID. If the name is ambiguous or missing, the CLI lists matches and exits.
How it works
- Pulls expenses from the chosen group, paginating Splitwise's API.
- For each foreign-currency expense, looks up that day's rate.
- Skips settle-up payments and same-currency lines.
- Converts cost + each user's
paid_shareandowed_shareusingDecimal. Distributes ±0.01 rounding residuals to the largest non-zero shares sosum(paid) == sum(owed) == costholds (Splitwise rejects updates that violate this). - Renders a Rich preview with rate source per line (
UPIorFRA). - On confirm, posts each update via
POST /update_expense/{id}, sleeping 1 s between writes.
Rate sources
| Source | When used | Notes |
|---|---|---|
UnionPay (unionpayintl.com/upload/jfimg/{YYYYMMDD}.json) |
Target currency is one of: AUD CAD CNY EUR GBP HKD HUF JPY MNT MOP NZD SGD THB USD VND | Files exist for every day including weekends/CN holidays (Friday rate carries through). |
Frankfurter (api.frankfurter.dev/v2/rate/{src}/{dst}) |
Target outside UnionPay's 15 base currencies, or pair missing from UnionPay file | Free, ECB-backed. |
Rates are cached on disk under ${XDG_CACHE_HOME:-~/.cache}/splitwise-fx/. Past dates never expire (historical rates are immutable); today's date refreshes every hour.
Caveats
- Idempotency: re-running with a different
--toafter a first conversion will re-convert already-converted expenses. The filter only skips lines whosecurrency_codealready matches the target. - Settle-up payments are skipped — converting them would corrupt the ledger.
- Splitwise rate limits are undocumented; the CLI sleeps 1 s between writes and backs off on 429s.
Development
git clone https://github.com/whtsky/splitwise-fx
cd splitwise-fx
uv sync
# linters / type-checker / tests
uv run ruff check
uv run ruff format --check
uv run mypy src tests
uv run pytest
Releasing (maintainer notes)
Releases publish to PyPI via GitHub Actions Trusted Publishing on tag push:
# bump version in pyproject.toml and src/splitwise_fx/__init__.py
git commit -am "release: vX.Y.Z"
git tag vX.Y.Z
git push origin main vX.Y.Z
The release.yml workflow builds with uv build and publishes via pypa/gh-action-pypi-publish. Trusted publishing is configured one-time at https://pypi.org/manage/account/publishing/.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file splitwise_fx-0.0.1.tar.gz.
File metadata
- Download URL: splitwise_fx-0.0.1.tar.gz
- Upload date:
- Size: 14.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5060e2c631732ea3cfc5cc4e4f2d84e36b338c356d40e4009e408e0b1ffc6657
|
|
| MD5 |
d24e31b88a89587f2b82afd973f809bd
|
|
| BLAKE2b-256 |
e85de9f59d719940dbb818b9b30c62c8dbe8557a9a6e817e9a4bc78ed5e50cf8
|
Provenance
The following attestation bundles were made for splitwise_fx-0.0.1.tar.gz:
Publisher:
release.yml on whtsky/splitwise-fx
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
splitwise_fx-0.0.1.tar.gz -
Subject digest:
5060e2c631732ea3cfc5cc4e4f2d84e36b338c356d40e4009e408e0b1ffc6657 - Sigstore transparency entry: 1459848185
- Sigstore integration time:
-
Permalink:
whtsky/splitwise-fx@f6b7250509727f17a8873bb9306bbfe17b2a14f0 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/whtsky
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f6b7250509727f17a8873bb9306bbfe17b2a14f0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file splitwise_fx-0.0.1-py3-none-any.whl.
File metadata
- Download URL: splitwise_fx-0.0.1-py3-none-any.whl
- Upload date:
- Size: 18.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4e94eadbdcdefcbdc2a831cc17ac0a05694a99e8baad353ce8efe594995f4d8b
|
|
| MD5 |
a727433b624e5582ff26433a6eed7c61
|
|
| BLAKE2b-256 |
a2ef5145020539e27d814996c37467d5fe1391103c14088945e87e13c2983f31
|
Provenance
The following attestation bundles were made for splitwise_fx-0.0.1-py3-none-any.whl:
Publisher:
release.yml on whtsky/splitwise-fx
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
splitwise_fx-0.0.1-py3-none-any.whl -
Subject digest:
4e94eadbdcdefcbdc2a831cc17ac0a05694a99e8baad353ce8efe594995f4d8b - Sigstore transparency entry: 1459848317
- Sigstore integration time:
-
Permalink:
whtsky/splitwise-fx@f6b7250509727f17a8873bb9306bbfe17b2a14f0 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/whtsky
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f6b7250509727f17a8873bb9306bbfe17b2a14f0 -
Trigger Event:
push
-
Statement type: