Skip to main content

Crypto tax lot cost-basis accounting library

Project description

coinbasis

PyPI version Python versions License: MIT OR Apache-2.0 CI

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 days boundary
  • Tax-year reports: CapitalGainsReport (Form 8949-shaped), IncomeReport, PortfolioReport with 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": {...}}); Decimal values 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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

coinbasis-0.1.0.tar.gz (37.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

coinbasis-0.1.0-py3-none-any.whl (25.3 kB view details)

Uploaded Python 3

File details

Details for the file coinbasis-0.1.0.tar.gz.

File metadata

  • Download URL: coinbasis-0.1.0.tar.gz
  • Upload date:
  • Size: 37.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for coinbasis-0.1.0.tar.gz
Algorithm Hash digest
SHA256 952ad98c6782eb8f7f2fbdba6806f79c0eb2ba23480093d4a6982441b32534e6
MD5 ad6a5ddc6f34ddb363dd37184e208277
BLAKE2b-256 1fe38a94a46b66fe97649caec5ff3e80e2a9d5b5c9e7d187587c4f8b7d83ae4c

See more details on using hashes here.

Provenance

The following attestation bundles were made for coinbasis-0.1.0.tar.gz:

Publisher: publish.yml on Technical-1/coinbasis-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file coinbasis-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: coinbasis-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 25.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for coinbasis-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 336e4c4a25e0dc142d39147cdcaffa2c7209ce9cefeea197841a2779a346aea3
MD5 f0af8b3bbb42fd521350d856553a0c9f
BLAKE2b-256 29bec33368770d2152385f2a1188fa76b095e96fbcafc89ec81f1a1e6f4dbb28

See more details on using hashes here.

Provenance

The following attestation bundles were made for coinbasis-0.1.0-py3-none-any.whl:

Publisher: publish.yml on Technical-1/coinbasis-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page