cost-basis-engine について
cost-basis-engineは、暗号資産取引の取得原価を計算し、会計方式ごとの実現損益と推定税額を比較するスキルです。部分売却やエアドロップ、ステーキング報酬、LP、マルチホップスワップを扱いますが、結果は情報提供用であり、税務助言ではありません。
主な機能
- 01FIFO、LIFO、HIFOなど5方式の比較
- 02部分売却の実現損益計算
- 03エアドロップ、報酬、トークン移行への対応
- 04LPの入出金をトークンスワップとしてモデル化
- 05マルチホップスワップの課税イベント分解
活用シーン
- 01年間取引履歴を複数方式で比較
- 02積立中の部分売却と残存取得原価を追跡
- 03LPの入出金による損益を記録
- 04エアドロップや報酬の収入と後続取得原価を計上
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ agiprolabs/ claude-trading-skills --skill cost-basis-engineインストール後、Claude Code で/cost-basis-engineを入力して読み込まれたか確認します。
同梱ファイルreferences/planned_features.mdscripts/cost_basis_calculator.py
詳細
取得原価計算エンジン
複数の会計方法を使って暗号資産取引の取得原価を計算し、各方法で生じる納税額を比較します。このスキルは、部分売却、トークン移行、エアドロップ、ステーキング報酬、LPへの預け入れ・引き出し、複数段階のスワップなど、オンチェーン取引のあらゆる複雑な処理に対応します。
免責事項:このスキルは、情報提供のみを目的とした計算ツールを提供するものです。税務、法律、財務に関する助言を構成するものではありません。個別の状況については、資格を持つ税務専門家にご相談ください。税法は管轄地域によって異なり、頻繁に変更されます。
前提条件
- Python 3.10+
- 外部依存関係は不要です(標準ライブラリのみ)
- 取引履歴は、辞書のリストまたは次の列を含む CSV で用意します:
date、action、token、quantity、price_usd、fee_usd
方法の概要
| 方法 | 仕組み | 適した用途 |
|---|---|---|
| FIFO | 最初に購入したロットから売却します | シンプルさ、多くの管轄地域での標準方式 |
| LIFO | 最後に購入したロットから売却します | 価格が長期的に上昇する場合の利益繰り延べ |
| HIFO | 取得原価が最も高いロットから売却します | 現在の納税額の最小化 |
| 特定 ID | トレーダーが売却するロットを選択します | 最大限の管理、記録の保持が必要 |
| 平均取得原価 | 保有するすべてのロットの加重平均を使用します | シンプルさ、一部の管轄地域で必須 |
1. FIFO(先入先出)
最も古いロットから売却します。他の方法を選択していない場合、米国での標準方式です。
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
部分売却の例
TOKEN のロットを 3 つ保有しています。
- ロット A:100 単位 @ $1.00(最古)
- ロット B:50 単位 @ $2.00
- ロット C:75 単位 @ $1.50
$3.00 で 120 単位を売却します。
- ロット A から 100:利益 = (3.00 - 1.00) * 100 = $200
- ロット B から 20:利益 = (3.00 - 2.00) * 20 = $20
- 実現利益の合計:$220
- ロット B の残り:30 単位 @ $2.00
2. LIFO(後入先出)
最も新しいロットから売却します。FIFO とは順序が逆になります。
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
同じロットを使い、LIFO で $3.00 にて 120 単位を売却します。
- ロット C から 75:利益 = (3.00 - 1.50) * 75 = $112.50
- ロット B から 45:利益 = (3.00 - 2.00) * 45 = $45
- 実現利益の合計:$157.50
3. HIFO(取得原価が高い順)
実現利益を最小限に抑えるため、取得原価が最も高いロットから売却します。
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
同じロットを使い、HIFO で $3.00 にて 120 単位を売却します。
- ロット B から 50($2.00、最も高い):利益 = (3.00 - 2.00) * 50 = $50
- ロット C から 70($1.50、次に高い):利益 = (3.00 - 1.50) * 70 = $105
- 実現利益の合計:$155
- 残り:ロット A は 100 @ $1.00、ロット C は 5 @ $1.50
4. 特定 ID 法
トレーダーが売却するロットを明示的に選択します。最大限の管理が可能ですが、細心の注意を払った記録管理が必要です。各ロットは、購入日時やロット ID などで一意に識別できる必要があります。
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. 比例配分/平均取得原価法
保有するすべてのロットについて、単位あたりの加重平均取得原価を 1 つ計算します。売却のたびに、この平均取得原価を使用します。購入のたびに平均は更新されます。
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}
平均取得原価を使った部分売却
ロット:100 @ $1.00、50 @ $2.00、75 @ $1.50。合計:225 単位、総取得原価 $312.50。
平均取得原価 = $312.50 / 225 = $1.3889/単位
$3.00 で 120 単位を売却します:利益 = (3.00 - 1.3889) * 120 = $193.33
売却後は、平均取得原価 $1.3889 のまま 105 単位が残ります。
6. 特殊なイベント
エアドロップ
エアドロップは、受領日の公正市場価値(FMV)で所得として扱われます。その FMV が、将来の売却における取得原価になります。
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"
}
ステーキング報酬
ステーキング報酬は、受領時の FMV で所得として扱われます(エアドロップと同様です)。報酬を受け取るたびに、新しいロットが作成されます。
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"
}
トークンの分割と移行
トークンの分割や移行(旧トークンから新トークンへの 1:1 または N:M の交換)は、一般に課税対象のイベントではありません。取得原価の合計は新しいトークンに引き継がれます。
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
$5.00 のトークン 100 枚を 1:10 で分割した場合:結果は $0.50 のトークン 1000 枚です。取得原価の合計は $500 のまま変わりません。
7. トークンスワップとしてのLPへの預け入れ/引き出し
LPポジションへの預け入れは、預け入れたトークンを売却してLPトークンを受け取るものとして扱います。引き出しはその逆です。
LPへの預け入れ(SOL/USDCプールに10 SOL + 1500 USDCを預け入れ):
- 現在のFMVで10 SOLを処分 → キャピタルゲイン/損失のイベント
- 現在のFMVで1500 USDCを処分 → 通常、ゲイン/損失はわずかです
- 預け入れた資産のFMVを取得原価とするLPトークンを受け取る
LPからの引き出し(LPトークンを12 SOL + 1400 USDCに交換):
- 受け取った資産のFMVでLPトークンを処分 → キャピタルゲイン/損失
- 引き出し時のFMVを取得原価とする12 SOLを受け取る
- 引き出し時のFMVを取得原価とする1400 USDCを受け取る
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. マルチホップスワップ
マルチホップスワップ(例:SOL -> USDC -> TOKEN)では、中間ステップごとに複数の課税イベントが発生します。Jupiterでは、中間トークンを経由するルートがよく使われます。
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
例:1 SOL($150)をスワップ → 150 USDC → 10,000 TOKEN(各$0.015)
- イベント1:1 SOLを処分(取得原価と$150の売却額を比較) → SOLのゲイン/損失
- イベント2:150 USDCを処分(取得原価と$150の売却額を比較) → 通常、ゲインは約$0
- 結果:取得原価が1単位あたり$0.015の10,000 TOKEN
9. 比較ビュー
このスキルの主な価値は、同じ取引履歴を5つすべての方法で処理し、実現損益の合計と推定納税額を比較できることです。
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
一部売却を含む現実的な取引データを使った、実行可能な比較の全容については、scripts/cost_basis_calculator.py を参照してください。
クイックスタート
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)
ユースケース
- 確定申告の準備:申告方法を選ぶ前に、年間の全取引をすべての方法で処理します。
- 積み立て戦略:DCAによる積み立て中の一部売却を追跡し、各方法が残りの取得原価に与える影響を確認します。
- LPポジションの追跡:LPへの預け入れ/引き出しをスワップとしてモデル化し、関連するゲイン/損失イベントを記録します。
- エアドロップとステーキング収入:収入イベントを適切に記録し、将来の処分に備えて取得原価を設定します。
- マルチホップスワップの分解:Jupiterのルートを個別の課税イベントに分解します。
ファイル
| ファイル | 説明 |
|---|---|
references/planned_features.md | 方法ごとの計算式、一部売却の計算例、特殊イベントの処理、マルチホップの扱い |
scripts/cost_basis_calculator.py | 5つすべての方法に対応する完全なエンジン、比較表、現実的な取引を使ったデモモード |
ご注意:「最適な」方法は、適用される法域、個々の取引履歴、税務状況によって異なります。このエンジンは比較に役立ちます。判断には税務の専門家にご相談ください。