Metadata-Version: 2.4
Name: coinbasis
Version: 0.1.0
Summary: Crypto tax lot cost-basis accounting library
Project-URL: Homepage, https://pypi.org/project/coinbasis
Project-URL: Repository, https://github.com/Technical-1/coinbasis-py
Project-URL: Issues, https://github.com/Technical-1/coinbasis-py/issues
Project-URL: Documentation, https://github.com/Technical-1/coinbasis-py#readme
Author-email: Jacob Kanfer <51518860+Technical-1@users.noreply.github.com>
License-Expression: MIT OR Apache-2.0
License-File: LICENSE-APACHE
License-File: LICENSE-MIT
Keywords: accounting,cost-basis,crypto,fifo,tax
Classifier: License :: OSI Approved :: Apache Software License
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business :: Financial
Classifier: Typing :: Typed
Requires-Python: >=3.10
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

# coinbasis

[![PyPI version](https://img.shields.io/pypi/v/coinbasis)](https://pypi.org/project/coinbasis/)
[![Python versions](https://img.shields.io/pypi/pyversions/coinbasis)](https://pypi.org/project/coinbasis/)
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue)](#license)
[![CI](https://github.com/Technical-1/coinbasis-py/actions/workflows/ci.yml/badge.svg)](https://github.com/Technical-1/coinbasis-py/actions/workflows/ci.yml)

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

```bash
pip install coinbasis
```

## Quickstart

```python
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

```python
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

```python
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/`](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`](examples/quickstart.py) | Buy 1 BTC, sell it, read the realized gain |
| [`cost_basis_methods.py`](examples/cost_basis_methods.py) | FIFO / LIFO / HIFO / Average on one ledger, each yielding a different gain |
| [`wallet_transfers.py`](examples/wallet_transfers.py) | A transfer preserving original basis and the holding-period clock |
| [`gifts.py`](examples/gifts.py) | Gift dual-basis with a gain case and a loss case |
| [`income.py`](examples/income.py) | Staking / airdrop income creating lots at FMV plus an income report |
| [`valuation.py`](examples/valuation.py) | `PortfolioReport` unrealized P&L and allocation at supplied prices |
| [`tax_estimate.py`](examples/tax_estimate.py) | `CapitalGainsReport` plus a progressive `TaxEstimate` |
| [`portfolio_stats.py`](examples/portfolio_stats.py) | `stats` module: returns, volatility, Sharpe, drawdown, cumulative return |
| [`json_roundtrip.py`](examples/json_roundtrip.py) | Serialize a ledger to JSON and read it back losslessly |

## Development

```bash
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](https://github.com/Technical-1)
