cost-basis-engine
Multi-method cost basis computation including specific identification, FIFO, LIFO, HIFO, and proportional average cost with partial sell handling
Best use case
cost-basis-engine is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Multi-method cost basis computation including specific identification, FIFO, LIFO, HIFO, and proportional average cost with partial sell handling
Teams using cost-basis-engine should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/cost-basis-engine/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How cost-basis-engine Compares
| Feature / Agent | cost-basis-engine | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Multi-method cost basis computation including specific identification, FIFO, LIFO, HIFO, and proportional average cost with partial sell handling
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Cost Basis Engine
Compute cost basis for crypto trades using multiple accounting methods and compare the resulting tax liability across methods. This skill handles the full complexity of on-chain activity: partial sells, token migrations, airdrops, staking rewards, LP entry/exit, and multi-hop swaps.
> **Disclaimer**: This skill provides computational tools for informational purposes only. It does not constitute tax, legal, or financial advice. Consult a qualified tax professional for your specific situation. Tax law varies by jurisdiction and changes frequently.
## Prerequisites
- Python 3.10+
- No external dependencies required (standard library only)
- Trade history as a list of dicts or CSV with columns: `date`, `action`, `token`, `quantity`, `price_usd`, `fee_usd`
## Methods Overview
| Method | Logic | Best For |
|--------|-------|----------|
| **FIFO** | First lots purchased are sold first | Simplicity, many jurisdictions' default |
| **LIFO** | Last lots purchased are sold first | Deferring gains when prices rise over time |
| **HIFO** | Highest-cost lots are sold first | Minimizing current tax liability |
| **Specific ID** | Trader selects which lots to sell | Maximum control, requires record-keeping |
| **Average Cost** | Weighted average of all held lots | Simplicity, required in some jurisdictions |
---
## 1. FIFO (First-In, First-Out)
Sell the oldest lots first. This is the default method in the US if no other method is elected.
```python
def fifo_sell(lots: list[dict], sell_qty: float, sell_price: float) -> list[dict]:
"""Sell using FIFO. lots sorted oldest-first."""
remaining = sell_qty
realized = []
while remaining > 0 and lots:
lot = lots[0]
used = min(lot["qty"], remaining)
gain = (sell_price - lot["cost_per_unit"]) * used
realized.append({"qty": used, "basis": lot["cost_per_unit"], "gain": gain})
lot["qty"] -= used
remaining -= used
if lot["qty"] <= 0:
lots.pop(0)
return realized
```
### Partial sell example
You hold three lots of TOKEN:
- Lot A: 100 units @ $1.00 (oldest)
- Lot B: 50 units @ $2.00
- Lot C: 75 units @ $1.50
You sell 120 units at $3.00:
- 100 from Lot A: gain = (3.00 - 1.00) * 100 = $200
- 20 from Lot B: gain = (3.00 - 2.00) * 20 = $20
- Total realized gain: **$220**
- Lot B remainder: 30 units @ $2.00
---
## 2. LIFO (Last-In, First-Out)
Sell the newest lots first. Reverses the order compared to FIFO.
```python
def lifo_sell(lots: list[dict], sell_qty: float, sell_price: float) -> list[dict]:
"""Sell using LIFO. Pops from end (newest first)."""
remaining = sell_qty
realized = []
while remaining > 0 and lots:
lot = lots[-1]
used = min(lot["qty"], remaining)
gain = (sell_price - lot["cost_per_unit"]) * used
realized.append({"qty": used, "basis": lot["cost_per_unit"], "gain": gain})
lot["qty"] -= used
remaining -= used
if lot["qty"] <= 0:
lots.pop()
return realized
```
Using the same lots and selling 120 at $3.00 with LIFO:
- 75 from Lot C: gain = (3.00 - 1.50) * 75 = $112.50
- 45 from Lot B: gain = (3.00 - 2.00) * 45 = $45
- Total realized gain: **$157.50**
---
## 3. HIFO (Highest-In, First-Out)
Sell the highest-cost lots first to minimize realized gains.
```python
def hifo_sell(lots: list[dict], sell_qty: float, sell_price: float) -> list[dict]:
"""Sell using HIFO. Sort by cost descending, consume highest first."""
lots.sort(key=lambda x: x["cost_per_unit"], reverse=True)
remaining = sell_qty
realized = []
for lot in lots:
if remaining <= 0:
break
used = min(lot["qty"], remaining)
gain = (sell_price - lot["cost_per_unit"]) * used
realized.append({"qty": used, "basis": lot["cost_per_unit"], "gain": gain})
lot["qty"] -= used
remaining -= used
lots[:] = [l for l in lots if l["qty"] > 0]
return realized
```
Same lots, selling 120 at $3.00 with HIFO:
- 50 from Lot B ($2.00, highest): gain = (3.00 - 2.00) * 50 = $50
- 70 from Lot C ($1.50, next highest): gain = (3.00 - 1.50) * 70 = $105
- Total realized gain: **$155**
- Remaining: Lot A 100 @ $1.00, Lot C 5 @ $1.50
---
## 4. Specific Identification
The trader explicitly selects which lots to sell. Provides maximum control but requires meticulous record-keeping. Each lot must be uniquely identifiable (e.g., by purchase date and time, or a lot ID).
```python
def specific_id_sell(lots: dict[str, dict], lot_ids: list[tuple[str, float]],
sell_price: float) -> list[dict]:
"""Sell specific lots by ID. lot_ids = [(lot_id, qty_to_sell), ...]"""
realized = []
for lot_id, sell_qty in lot_ids:
lot = lots[lot_id]
used = min(lot["qty"], sell_qty)
gain = (sell_price - lot["cost_per_unit"]) * used
realized.append({"lot_id": lot_id, "qty": used, "basis": lot["cost_per_unit"], "gain": gain})
lot["qty"] -= used
if lot["qty"] <= 0:
del lots[lot_id]
return realized
```
---
## 5. Proportional / Average Cost Method
Compute a single weighted-average cost per unit across all held lots. Every sell uses that average cost. The average updates after each buy.
```python
def average_cost_basis(lots: list[dict]) -> float:
"""Compute weighted average cost per unit across all lots."""
total_cost = sum(l["qty"] * l["cost_per_unit"] for l in lots)
total_qty = sum(l["qty"] for l in lots)
if total_qty == 0:
return 0.0
return total_cost / total_qty
def average_cost_sell(lots: list[dict], sell_qty: float, sell_price: float) -> dict:
"""Sell using average cost. Reduces all lots proportionally."""
avg = average_cost_basis(lots)
total_qty = sum(l["qty"] for l in lots)
sell_qty = min(sell_qty, total_qty)
gain = (sell_price - avg) * sell_qty
# Reduce each lot proportionally
ratio = sell_qty / total_qty
for lot in lots:
lot["qty"] *= (1 - ratio)
lots[:] = [l for l in lots if l["qty"] > 1e-12]
return {"qty": sell_qty, "avg_basis": avg, "gain": gain}
```
### Partial sell with average cost
Lots: 100 @ $1.00, 50 @ $2.00, 75 @ $1.50. Total: 225 units, total cost $312.50.
Average cost = $312.50 / 225 = **$1.3889/unit**
Sell 120 at $3.00: gain = (3.00 - 1.3889) * 120 = **$193.33**
After the sell, 105 units remain at the same $1.3889 average.
---
## 6. Special Events
### Airdrops
Airdrops are treated as income at fair market value (FMV) on the date received. The FMV becomes the cost basis for future sales.
```python
airdrop_lot = {
"date": "2025-03-15",
"qty": 1000,
"cost_per_unit": 0.05, # FMV at time of receipt
"income_recognized": 50.0, # 1000 * 0.05 reported as income
"source": "airdrop"
}
```
### Staking Rewards
Staking rewards are income at FMV when received (similar to airdrops). Each reward event creates a new lot.
```python
staking_lot = {
"date": "2025-04-01",
"qty": 5.2,
"cost_per_unit": 150.0, # SOL price at receipt
"income_recognized": 780.0,
"source": "staking_reward"
}
```
### Token Splits and Migrations
A token split or migration (old token to new token 1:1 or N:M) is generally not a taxable event. The total cost basis transfers to the new tokens.
```python
def apply_split(lots: list[dict], split_ratio: float) -> None:
"""Apply a token split. split_ratio > 1 means more tokens."""
for lot in lots:
lot["qty"] *= split_ratio
lot["cost_per_unit"] /= split_ratio
```
For a 1:10 split of 100 tokens @ $5.00: result is 1000 tokens @ $0.50. Total basis unchanged at $500.
---
## 7. LP Entry/Exit as Token Swaps
Entering an LP position is treated as selling the deposited tokens and receiving LP tokens. Exiting is the reverse.
**LP Entry** (deposit 10 SOL + 1500 USDC into SOL/USDC pool):
1. Dispose of 10 SOL at current FMV → capital gain/loss event
2. Dispose of 1500 USDC at current FMV → usually negligible gain/loss
3. Receive LP tokens with cost basis = FMV of deposited assets
**LP Exit** (redeem LP tokens for 12 SOL + 1400 USDC):
1. Dispose of LP tokens at FMV of received assets → capital gain/loss
2. Receive 12 SOL with cost basis = FMV at redemption
3. Receive 1400 USDC with cost basis = FMV at redemption
```python
def lp_entry(sol_qty: float, sol_price: float, usdc_qty: float,
lp_tokens_received: float) -> dict:
"""Model LP entry as disposal of component tokens."""
total_value = sol_qty * sol_price + usdc_qty * 1.0
lp_cost_basis = total_value / lp_tokens_received
return {
"disposals": [
{"token": "SOL", "qty": sol_qty, "price": sol_price},
{"token": "USDC", "qty": usdc_qty, "price": 1.0},
],
"lp_lot": {"qty": lp_tokens_received, "cost_per_unit": lp_cost_basis}
}
```
---
## 8. Multi-Hop Swaps
A multi-hop swap (e.g., SOL -> USDC -> TOKEN) creates **multiple taxable events**, one for each intermediate step. Jupiter often routes through intermediate tokens.
```python
def multi_hop_events(hops: list[dict]) -> list[dict]:
"""
Each hop is: {"sell_token", "sell_qty", "sell_price",
"buy_token", "buy_qty", "buy_price"}
Each hop is a separate taxable event.
"""
events = []
for i, hop in enumerate(hops):
events.append({
"event": i + 1,
"dispose": hop["sell_token"],
"dispose_qty": hop["sell_qty"],
"dispose_value": hop["sell_qty"] * hop["sell_price"],
"acquire": hop["buy_token"],
"acquire_qty": hop["buy_qty"],
"acquire_basis": hop["buy_qty"] * hop["buy_price"],
})
return events
```
**Example**: Swap 1 SOL ($150) -> 150 USDC -> 10,000 TOKEN ($0.015 each)
- Event 1: Dispose 1 SOL (basis vs. $150 proceeds) → gain/loss on SOL
- Event 2: Dispose 150 USDC (basis vs. $150 proceeds) → usually ~$0 gain
- Result: 10,000 TOKEN with cost basis = $0.015/unit
---
## 9. Comparison View
The core value of this skill: run the same trade history through all five methods and compare total realized gain and estimated tax liability.
```python
methods = ["FIFO", "LIFO", "HIFO", "Specific ID", "Average Cost"]
# After processing all trades through each method:
comparison = {
"FIFO": {"total_gain": 220.00, "tax_at_30pct": 66.00},
"LIFO": {"total_gain": 157.50, "tax_at_30pct": 47.25},
"HIFO": {"total_gain": 155.00, "tax_at_30pct": 46.50},
"Specific ID": {"total_gain": 160.00, "tax_at_30pct": 48.00},
"Average Cost":{"total_gain": 193.33, "tax_at_30pct": 58.00},
}
# HIFO minimizes liability in this example
```
See `scripts/cost_basis_calculator.py` for a full runnable comparison with realistic trade data including partial sells.
---
## Quick Start
```python
from scripts.cost_basis_calculator import CostBasisEngine
engine = CostBasisEngine()
# Add purchases
engine.add_buy("2025-01-10", "TOKEN", 100, 1.00)
engine.add_buy("2025-02-15", "TOKEN", 50, 2.00)
engine.add_buy("2025-03-01", "TOKEN", 75, 1.50)
# Sell and compare methods
results = engine.sell_compare("2025-04-01", "TOKEN", 120, 3.00)
engine.print_comparison(results)
```
---
## Use Cases
1. **Tax season preparation**: Run your full year of trades through all methods before choosing one to report.
2. **Accumulation strategy**: Track partial sells during DCA accumulation, see how each method affects remaining basis.
3. **LP position tracking**: Model LP entry/exit as swaps and capture the associated gain/loss events.
4. **Airdrop and staking income**: Properly record income events and set cost basis for future disposals.
5. **Multi-hop swap decomposition**: Break down Jupiter routes into individual taxable events.
---
## Files
| File | Description |
|------|-------------|
| `references/planned_features.md` | Method formulas, partial sell worked examples, special event handling, multi-hop treatment |
| `scripts/cost_basis_calculator.py` | Full engine with all 5 methods, comparison table, demo mode with realistic trades |
---
> **Remember**: The "best" method depends on your jurisdiction, your specific trade history, and your tax situation. This engine helps you compare — a tax professional helps you decide.Related Skills
feature-engineering
Feature construction from market data for ML trading models including price, volume, on-chain, and microstructure features
yield-analysis
DeFi yield evaluation including fee APR, real vs nominal yield, net APY after costs, and yield sustainability analysis
yellowstone-grpc
Real-time Solana transaction and account streaming via Yellowstone gRPC (Geyser plugin)
whale-tracking
Large wallet monitoring, accumulation and distribution detection, and smart money signal generation for Solana tokens
wash-sale-detection
Wash sale detection under 2025 US crypto rules with 61-day window monitoring, disallowed loss tracking, and safe re-entry countdown
wallet-profiling
Behavioral classification, performance analysis, and trading style detection for Solana wallets
walk-forward-validation
Walk-forward validation framework for trading strategies and ML models with time-series-aware splits, overfit detection, and regime-aware validation
volatility-modeling
Volatility estimation, forecasting, and regime classification using GARCH, EWMA, realized volatility, and volatility cones
vectorbt
High-performance vectorized backtesting with parameter optimization, portfolio simulation, and rich performance metrics
trading-visualization
Professional trading charts including candlesticks, equity curves, drawdowns, correlation heatmaps, and return distributions
trade-journal
Structured trade logging, performance review, behavioral pattern detection, and strategy attribution for systematic improvement
trade-accounting
Double-entry bookkeeping for trading operations with ledger management, P&L statements, balance sheets, and cash flow reporting