$npx -y skills add agiprolabs/claude-trading-skills --skill cost-basis-engineMulti-method cost basis computation including specific identification, FIFO, LIFO, HIFO, and proportional average cost with partial sell handling
| 1 | # Cost Basis Engine |
| 2 | |
| 3 | 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. |
| 4 | |
| 5 | > **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. |
| 6 | |
| 7 | ## Prerequisites |
| 8 | |
| 9 | - Python 3.10+ |
| 10 | - No external dependencies required (standard library only) |
| 11 | - Trade history as a list of dicts or CSV with columns: `date`, `action`, `token`, `quantity`, `price_usd`, `fee_usd` |
| 12 | |
| 13 | ## Methods Overview |
| 14 | |
| 15 | | Method | Logic | Best For | |
| 16 | |--------|-------|----------| |
| 17 | | **FIFO** | First lots purchased are sold first | Simplicity, many jurisdictions' default | |
| 18 | | **LIFO** | Last lots purchased are sold first | Deferring gains when prices rise over time | |
| 19 | | **HIFO** | Highest-cost lots are sold first | Minimizing current tax liability | |
| 20 | | **Specific ID** | Trader selects which lots to sell | Maximum control, requires record-keeping | |
| 21 | | **Average Cost** | Weighted average of all held lots | Simplicity, required in some jurisdictions | |
| 22 | |
| 23 | --- |
| 24 | |
| 25 | ## 1. FIFO (First-In, First-Out) |
| 26 | |
| 27 | Sell the oldest lots first. This is the default method in the US if no other method is elected. |
| 28 | |
| 29 | ```python |
| 30 | def fifo_sell(lots: list[dict], sell_qty: float, sell_price: float) -> list[dict]: |
| 31 | """Sell using FIFO. lots sorted oldest-first.""" |
| 32 | remaining = sell_qty |
| 33 | realized = [] |
| 34 | while remaining > 0 and lots: |
| 35 | lot = lots[0] |
| 36 | used = min(lot["qty"], remaining) |
| 37 | gain = (sell_price - lot["cost_per_unit"]) * used |
| 38 | realized.append({"qty": used, "basis": lot["cost_per_unit"], "gain": gain}) |
| 39 | lot["qty"] -= used |
| 40 | remaining -= used |
| 41 | if lot["qty"] <= 0: |
| 42 | lots.pop(0) |
| 43 | return realized |
| 44 | ``` |
| 45 | |
| 46 | ### Partial sell example |
| 47 | |
| 48 | You hold three lots of TOKEN: |
| 49 | - Lot A: 100 units @ $1.00 (oldest) |
| 50 | - Lot B: 50 units @ $2.00 |
| 51 | - Lot C: 75 units @ $1.50 |
| 52 | |
| 53 | You sell 120 units at $3.00: |
| 54 | - 100 from Lot A: gain = (3.00 - 1.00) * 100 = $200 |
| 55 | - 20 from Lot B: gain = (3.00 - 2.00) * 20 = $20 |
| 56 | - Total realized gain: **$220** |
| 57 | - Lot B remainder: 30 units @ $2.00 |
| 58 | |
| 59 | --- |
| 60 | |
| 61 | ## 2. LIFO (Last-In, First-Out) |
| 62 | |
| 63 | Sell the newest lots first. Reverses the order compared to FIFO. |
| 64 | |
| 65 | ```python |
| 66 | def lifo_sell(lots: list[dict], sell_qty: float, sell_price: float) -> list[dict]: |
| 67 | """Sell using LIFO. Pops from end (newest first).""" |
| 68 | remaining = sell_qty |
| 69 | realized = [] |
| 70 | while remaining > 0 and lots: |
| 71 | lot = lots[-1] |
| 72 | used = min(lot["qty"], remaining) |
| 73 | gain = (sell_price - lot["cost_per_unit"]) * used |
| 74 | realized.append({"qty": used, "basis": lot["cost_per_unit"], "gain": gain}) |
| 75 | lot["qty"] -= used |
| 76 | remaining -= used |
| 77 | if lot["qty"] <= 0: |
| 78 | lots.pop() |
| 79 | return realized |
| 80 | ``` |
| 81 | |
| 82 | Using the same lots and selling 120 at $3.00 with LIFO: |
| 83 | - 75 from Lot C: gain = (3.00 - 1.50) * 75 = $112.50 |
| 84 | - 45 from Lot B: gain = (3.00 - 2.00) * 45 = $45 |
| 85 | - Total realized gain: **$157.50** |
| 86 | |
| 87 | --- |
| 88 | |
| 89 | ## 3. HIFO (Highest-In, First-Out) |
| 90 | |
| 91 | Sell the highest-cost lots first to minimize realized gains. |
| 92 | |
| 93 | ```python |
| 94 | def hifo_sell(lots: list[dict], sell_qty: float, sell_price: float) -> list[dict]: |
| 95 | """Sell using HIFO. Sort by cost descending, consume highest first.""" |
| 96 | lots.sort(key=lambda x: x["cost_per_unit"], reverse=True) |
| 97 | remaining = sell_qty |
| 98 | realized = [] |
| 99 | for lot in lots: |
| 100 | if remaining <= 0: |
| 101 | break |
| 102 | used = min(lot["qty"], remaining) |
| 103 | gain = (sell_price - lot["cost_per_unit"]) * used |
| 104 | realized.append({"qty": used, "basis": lot["cost_per_unit"], "gain": gain}) |
| 105 | lot["qty"] -= used |
| 106 | remaining -= used |
| 107 | lots[:] = [l for l in lots if l["qty"] > 0] |
| 108 | return realized |
| 109 | ``` |
| 110 | |
| 111 | Same lots, selling 120 at $3.00 with HIFO: |
| 112 | - 50 from Lot B ($2.00, highest): gain = (3.00 - 2.00) * 50 = $50 |
| 113 | - 70 from Lot C ($1.50, next highest): gain = (3.00 - 1.50) * 70 = $105 |
| 114 | - Total realized gain: **$155** |
| 115 | - Remaining: Lot A 100 @ $1.00, Lot C 5 @ $1.50 |
| 116 | |
| 117 | --- |
| 118 | |
| 119 | ## 4. Specific Identification |
| 120 | |
| 121 | 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). |
| 122 | |
| 123 | ```python |
| 124 | def specific_id_sell(lots: dict[str, dict], lot_ids: list[tuple[str, float]], |
| 125 | sell_price: float) -> list[dict]: |
| 126 | """Sell specific lots by ID. lot_ids = [(lot_id, qty_to_sell), ...]""" |
| 127 | realized = [] |