mcpField
C
cost-basis-engine

cost-basis-engine

github.com/agiprolabsデータ・データベース456426 回インストール8 週間前に更新
リポジトリ

cost-basis-engine について

cost-basis-engineは、暗号資産取引の取得原価を計算し、会計方式ごとの実現損益と推定税額を比較するスキルです。部分売却やエアドロップ、ステーキング報酬、LP、マルチホップスワップを扱いますが、結果は情報提供用であり、税務助言ではありません。

主な機能

  1. 01FIFO、LIFO、HIFOなど5方式の比較
  2. 02部分売却の実現損益計算
  3. 03エアドロップ、報酬、トークン移行への対応
  4. 04LPの入出金をトークンスワップとしてモデル化
  5. 05マルチホップスワップの課税イベント分解

活用シーン

  1. 01年間取引履歴を複数方式で比較
  2. 02積立中の部分売却と残存取得原価を追跡
  3. 03LPの入出金による損益を記録
  4. 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を預け入れ):

  1. 現在のFMVで10 SOLを処分 → キャピタルゲイン/損失のイベント
  2. 現在のFMVで1500 USDCを処分 → 通常、ゲイン/損失はわずかです
  3. 預け入れた資産のFMVを取得原価とするLPトークンを受け取る

LPからの引き出し(LPトークンを12 SOL + 1400 USDCに交換):

  1. 受け取った資産のFMVでLPトークンを処分 → キャピタルゲイン/損失
  2. 引き出し時のFMVを取得原価とする12 SOLを受け取る
  3. 引き出し時の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)

ユースケース

  1. 確定申告の準備:申告方法を選ぶ前に、年間の全取引をすべての方法で処理します。
  2. 積み立て戦略:DCAによる積み立て中の一部売却を追跡し、各方法が残りの取得原価に与える影響を確認します。
  3. LPポジションの追跡:LPへの預け入れ/引き出しをスワップとしてモデル化し、関連するゲイン/損失イベントを記録します。
  4. エアドロップとステーキング収入:収入イベントを適切に記録し、将来の処分に備えて取得原価を設定します。
  5. マルチホップスワップの分解:Jupiterのルートを個別の課税イベントに分解します。

ファイル

ファイル説明
references/planned_features.md方法ごとの計算式、一部売却の計算例、特殊イベントの処理、マルチホップの扱い
scripts/cost_basis_calculator.py5つすべての方法に対応する完全なエンジン、比較表、現実的な取引を使ったデモモード

ご注意:「最適な」方法は、適用される法域、個々の取引履歴、税務状況によって異なります。このエンジンは比較に役立ちます。判断には税務の専門家にご相談ください。

コメント