coinbasis
A pure-Python, stdlib-only crypto tax-lot cost-basis accounting engine.
I built this library to provide a correct, dependency-free accounting engine in Python: eight transaction event types, five cost-basis methods, IRS gift dual-basis rules, per-wallet lot pools, and progressive tax-bracket estimation — all without a single runtime dependency and with Decimal arithmetic throughout for exact decimal precision.
Features
- Five cost-basis methods: FIFO, LIFO, HIFO, Average Cost, Specific ID
- Eight transaction types: Buy, Sell, Trade, Income, Spend, Transfer, GiftSent, GiftReceived
- Per-wallet lot pooling: disposals draw only from the named wallet; transfers move lots between wallets preserving original basis and holding-period clock
- IRS gift dual-basis rule: GiftReceived lots carry donor basis and FMV; the engine applies the correct gain/loss/dead-zone calculation at disposal time
- Short/long-term classification: strict
> 365 daysboundary - Tax-year reports:
CapitalGainsReport(Form 8949-shaped),IncomeReport,PortfolioReportwith unrealized P&L and allocation percentages - Progressive tax estimation: configurable brackets + short-term flat rate; US preset included via
TaxConfig.default() - Portfolio statistics: period returns, volatility, Sharpe ratio, max drawdown, cumulative return
- JSON round-trip: externally-tagged JSON schema (
{"Buy": {...}});Decimalvalues serialized as strings for unambiguous round-trip - Zero runtime dependencies: stdlib only (
decimal,dataclasses,datetime,json,enum,math)
Install
pip install coinbasis
Quickstart
from decimal import Decimal
from datetime import datetime, timezone
from coinbasis import Portfolio, CostBasisMethod, Buy, Sell
def dt(y, m, d):
return datetime(y, m, d, tzinfo=timezone.utc)
txs = [
Buy(timestamp=dt(2020, 1, 1), wallet="hot", asset="btc",
quantity=Decimal("1"), unit_price=Decimal("100"), fee=Decimal("0")),
Buy(timestamp=dt(2021, 1, 1), wallet="hot", asset="btc",
quantity=Decimal("1"), unit_price=Decimal("300"), fee=Decimal("0")),
Sell(timestamp=dt(2022, 1, 1), wallet="hot", asset="btc",
quantity=Decimal("1"), unit_price=Decimal("500"), fee=Decimal("0")),
]
p = Portfolio.from_transactions(txs)
# FIFO: matches oldest lot first -> gain 400
fifo_gain = sum(g.gain for g in p.realized_gains(CostBasisMethod.FIFO))
print(fifo_gain) # Decimal('400')
# HIFO: matches highest-cost lot first -> gain 200
hifo_gain = sum(g.gain for g in p.realized_gains(CostBasisMethod.HIFO))
print(hifo_gain) # Decimal('200')
# Tax-year capital gains report
report = p.capital_gains_report(CostBasisMethod.FIFO, tax_year=2022)
print(report.long_term_gain) # Decimal('400')
print(report.short_term_gain) # Decimal('0')
Income and portfolio valuation
from coinbasis import Income, IncomeSource, Transfer
from coinbasis.tax import TaxConfig
# Staking income creates a lot at its FMV and records an IncomeEvent
txs = [
Income(timestamp=dt(2021, 1, 1), wallet="hot", asset="eth",
quantity=Decimal("2"), value=Decimal("200"), source=IncomeSource.STAKING),
]
p = Portfolio.from_transactions(txs)
print(p.income_report(2021).total_income) # Decimal('200')
# Valuation against live prices
report = p.valuation(CostBasisMethod.FIFO, {"eth": Decimal("150")})
print(report.total_unrealized) # Decimal('100')
# Tax estimate
from coinbasis.tax import estimate, TaxConfig
est = estimate(short_gain=Decimal("10000"), long_gain=Decimal("50000"),
config=TaxConfig.default())
print(est.total_tax)
JSON round-trip
from coinbasis.serialization import ledger_to_json, ledger_from_json
json_str = ledger_to_json(txs, indent=2)
restored = ledger_from_json(json_str)
Examples
Runnable scripts live in examples/. Each is self-contained and offline (coinbasis has no network dependency) and prints clearly labeled output. Run any of them with python examples/<name>.py.
| Example | Shows |
|---|---|
quickstart.py |
Buy 1 BTC, sell it, read the realized gain |
cost_basis_methods.py |
FIFO / LIFO / HIFO / Average on one ledger, each yielding a different gain |
wallet_transfers.py |
A transfer preserving original basis and the holding-period clock |
gifts.py |
Gift dual-basis with a gain case and a loss case |
income.py |
Staking / airdrop income creating lots at FMV plus an income report |
valuation.py |
PortfolioReport unrealized P&L and allocation at supplied prices |
tax_estimate.py |
CapitalGainsReport plus a progressive TaxEstimate |
portfolio_stats.py |
stats module: returns, volatility, Sharpe, drawdown, cumulative return |
json_roundtrip.py |
Serialize a ledger to JSON and read it back losslessly |
Development
git clone https://github.com/Technical-1/coinbasis-py
cd coinbasis-py
pip install -e ".[dev]"
python3 -m pytest # run full test suite
python3 -m ruff check src/ # lint
python3 -m build # build sdist + wheel
Project Structure
src/coinbasis/
__init__.py Public API surface — all re-exports
errors.py PortfolioError exception hierarchy (8 typed errors)
transaction.py Transaction (8 frozen dataclass variants) + IncomeSource
method.py CostBasisMethod enum, LotPick, LotSelection, order_for()
lot.py Internal Lot + GiftBasis dataclasses
engine.py Internal ledger-replay engine (_Engine, run())
report.py Term, RealizedGain, IncomeEvent, Holding, PortfolioReport, ...
portfolio.py Portfolio facade — public query methods
tax.py TaxBracket, TaxConfig, TaxEstimate, estimate()
stats.py returns_from_values, volatility, sharpe_ratio, max_drawdown, cumulative_return
serialization.py JSON (de)serialization — externally-tagged transaction schema
tests/
test_engine.py Engine unit tests
test_end_to_end.py End-to-end numeric checks over representative ledgers
test_portfolio.py Portfolio facade tests
test_serialization.py JSON round-trip tests
test_stats.py Statistics module tests
test_tax.py Tax estimation tests
test_properties.py Property-based invariant tests
(+ more)
Not tax advice
This library computes cost-basis and gain estimates based on the inputs you provide. Consult a qualified tax professional for advice specific to your situation.
License
MIT OR Apache-2.0
Author
Jacob Kanfer — GitHub: Technical-1
Release files for coinbasis 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| coinbasis-0.1.0.tar.gz | 37.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| coinbasis-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 62.9 kB
Release files / coinbasis-0.1.0.tar.gz
| Download URL | coinbasis-0.1.0.tar.gz |
|---|---|
| Size | 37.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
952ad98c6782eb8f7f2fbdba6806f79c0eb2ba23480093d4a6982441b32534e6
|
|
BLAKE2b-256 checksum How to use checksums |
1fe38a94a46b66fe97649caec5ff3e80e2a9d5b5c9e7d187587c4f8b7d83ae4c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 4, 2026.
Transparency logRelease files / coinbasis-0.1.0-py3-none-any.whl
| Download URL | coinbasis-0.1.0-py3-none-any.whl |
|---|---|
| Size | 25.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
336e4c4a25e0dc142d39147cdcaffa2c7209ce9cefeea197841a2779a346aea3
|
|
BLAKE2b-256 checksum How to use checksums |
29bec33368770d2152385f2a1188fa76b095e96fbcafc89ec81f1a1e6f4dbb28
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 4, 2026.
Transparency log