coinbasis
Comprehensive crypto tax-lot cost-basis accounting as a pure Rust library.
Feed it a ledger of transactions (buys, sells, crypto-to-crypto trades, income, spends, wallet transfers, gifts) and current prices; it returns realized capital gains (short/long-term classified), ordinary income, unrealized P/L, portfolio valuation, and per-tax-year reports. No network access, no file I/O — you supply the data.
Features
- Cost-basis methods: FIFO, LIFO, HIFO, Average, Specific-ID
- Per-wallet lot pools (US per-account rule); transfers preserve basis and the holding-period clock
- Crypto-to-crypto trades, income (staking/mining/airdrop/interest), spends, and gifts with the full IRS dual-basis rule
- Holding-period (short/long-term) classification
- Form-8949-shaped capital-gains report + income report, filtered by tax year
- Exact decimal math (
rust_decimal) — never floats for money - Optional
serdesupport on every public type
Install
[]
= "0.1"
# with serialization (Serialize/Deserialize on all public types):
= { = "0.1", = ["serde"] }
Quickstart
use ;
use ;
use dec;
let txs = vec!;
let portfolio = from_transactions.unwrap;
let gains = portfolio.realized_gains.unwrap;
assert_eq!;
Examples
Runnable, self-contained examples live in examples/. Run any with
cargo run --example <name>:
| Example | What it shows |
|---|---|
quickstart |
One buy and sell; a realized gain under FIFO |
cost_basis_methods |
The same ledger through FIFO/LIFO/HIFO/Average/Specific-ID, producing different gains |
wallet_transfers |
Moving lots between wallets; an in-asset network fee as a taxable disposal |
gifts |
The IRS dual-basis rule — gain, loss, and the no-gain/no-loss "dead zone" |
tax_reports |
Per-tax-year capital-gains (short/long split) and income reports |
valuation |
Mark-to-market across wallets, with missing-price handling |
portfolio_stats |
Volatility, Sharpe, max drawdown, and returns over a value series |
Tax estimation
coinbasis 0.2.0 adds a tax module that turns a year's realized gains into an
estimated tax liability using a configurable [TaxConfig] — a flat short-term
rate plus progressive long-term brackets.
use ;
use ;
use Decimal;
let txs = vec!;
let p = from_transactions.unwrap;
let est = p.tax_estimate.unwrap;
println!; // 50000
println!;
Key points:
TaxConfig::default()ships US 2024 federal rates (35% short-term flat; 0%/15%/20% long-term progressive brackets).- The
long_term_threshold_daysfield (default 365) controls the short/long reclassification. If the config threshold differs from the method used to build theCapitalGainsReport, rows are reclassified against the config threshold — thetermstored on each row is re-derived from actual holding days. - Rows with no
acquired_at(Average method) fall back to the row's storedterm. - Losses never produce tax; only positive net gains are taxed.
- Call
coinbasis::tax::estimate(&report, &config)directly if you already have aCapitalGainsReport, or usePortfolio::tax_estimateas a one-shot convenience.
See examples/tax_brackets.rs for a runnable demo: cargo run --example tax_brackets.
Not tax advice — see below.
Not tax advice
coinbasis is a calculation library. It does not file taxes or give legal
advice, and makes no guarantee of conformance with any jurisdiction's rules. The
default model follows current US federal treatment. Provided "as is", without
warranty.
Development
Project structure
src/
├── lib.rs # crate docs + public re-exports
├── transaction.rs # Transaction event model + field validation
├── method.rs # CostBasisMethod, Specific-ID selection, lot ordering
├── lot.rs # internal per-(asset, wallet) lot model
├── engine.rs # ledger-replay engine — the core
├── portfolio.rs # public Portfolio facade (all queries)
├── report.rs # output types (gains, income, holdings, reports)
├── stats.rs # pure portfolio statistics over a value series
└── error.rs # PortfolioError
examples/ # runnable usage examples
Minimum supported Rust version
Rust 1.74.
License
Licensed under either of MIT or Apache-2.0 at your option.
Author
Jacob Kanfer — GitHub