BTCの確定申告で死にかけてから、管理を自動化した話【2026年版】

Bybitの取引履歴をExcelで3日格闘して追徴課税まで食らった経験から、積立・税務・リスク管理を半自動化するまでの試行錯誤を正直に書きます。

BTCを本格的に「管理」し始めたのは、税務で死にかけてからだった

2024年の暗号資産バブルで適当に利確して、翌年の確定申告で地獄を見た。Bybitの取引履歴をExcelで手作業でまとめようとして、3日かけても計算が合わない。最終的に税理士に頼んで追徴課税も食らった。

そこから「ちゃんと仕組みで管理しないと死ぬ」と悟って、2025年末から本格的にBTC投資の自動化・管理基盤を整え始めた。今は月次で積立・監視・税務記録が半自動で回っている。まだ完璧じゃないけど、少なくとも確定申告で死ぬことはなくなった。

2026年8月時点の状況を書く。相場予測じゃなく、「どう管理するか」の話がメイン。同じように管理で詰まってるエンジニアの参考になれば。

なお、BTCの確定申告まわりは以前書いた「暗号資産の確定申告2026年版|ハマりポイントとPython自動化で乗り越えた話」でも触れているので、税務に絞りたい方はそちらもどうぞ。


2026年のBTC市場、エンジニア視点で整理すると

2026年は現物ETFの普及が本格化した年だった。BlackRockやFidelityのBitcoin ETFが2024年に承認されてから、機関投資家の流入が想定より早かった。個人的には「もう少し先だろう」と思ってたので、正直出遅れた感がある。

2024年5月の半減期後、ブロック報酬が3.125BTCになって供給圧力は理論上は下がった。ただ、短期的な価格インパクトは以前ほど大きくなかったという印象。マーケットが先読みして織り込むのが早くなってる気がする。

xychart-beta
  title "Bitcoin価格推移(2024-2026年、週次終値イメージ)"
  x-axis ["2024Q1", "2024Q2", "2024Q3", "2024Q4", "2025Q1", "2025Q2", "2025Q3", "2025Q4", "2026Q1", "2026Q2"]
  y-axis "価格(万ドル)" 0 --> 20
  line [5.2, 6.8, 5.9, 9.5, 11.2, 8.8, 13.5, 15.1, 17.8, 14.2]

※あくまでイメージ。特定の相場予測ではありません。

現時点(2026年8月)で把握してる主要な変化をまとめるとこんな感じ。

項目2024年以前2026年現在
現物ETF未承認(米)BlackRock・Fidelity等が運用中
税制(日本)雑所得・総合課税改正議論継続中、基本は雑所得のまま
半減期2024年5月実施済み次回は2028年予定
Lightning Network普及途上決済利用は増えているが主流ではない
マイニング難易度上昇傾向過去最高水準付近

税制については「2025年に改正される」という期待が何度も裏切られてきた。正直、雑所得・総合課税が当面続く前提で管理を設計するのが現実的だと思う。「改正されたらラッキー」くらいの気持ちで。


自動積立の設計と実際のコード

DCAで月3回(1日・11日・21日)に分散して積立している。取引所はbitFlyerとGMOコインの2つを使い分けてる。理由は単純で、1つの取引所が障害を起こしたとき全部止まるのが怖かったから。

積立のフローはこんな感じ。

flowchart TD
    A[Cloud Scheduler\n毎月1/11/21日 9:00] --> B[Cloud Run Job起動]
    B --> C{残高チェック}
    C -->|残高不足| D[Slack通知: 入金アラート]
    C -->|残高OK| E[bitFlyer API で購入]
    E --> F[GMO API で購入]
    F --> G[取引記録をBigQueryに保存]
    G --> H[Slack通知: 購入完了レポート]
    D --> I[処理終了]
    H --> I

実際のPythonコード(簡略版)はこちら。

import os
import requests
import hashlib
import hmac
import time
from datetime import datetime
from google.cloud import bigquery

BITFLYER_API_KEY = os.environ["BITFLYER_API_KEY"]
BITFLYER_API_SECRET = os.environ["BITFLYER_API_SECRET"]
BQ_TABLE = os.environ["BQ_TABLE"]  # project.dataset.table

def get_bitflyer_signature(timestamp: str, method: str, path: str, body: str = "") -> str:
    text = timestamp + method + path + body
    return hmac.new(
        BITFLYER_API_SECRET.encode("utf-8"),
        text.encode("utf-8"),
        hashlib.sha256,
    ).hexdigest()

def buy_btc_bitflyer(jpy_amount: int) -> dict:
    """bitFlyerで成行買い"""
    path = "/v1/me/sendchildorder"
    timestamp = str(time.time())
    body = {
        "product_code": "BTC_JPY",
        "child_order_type": "MARKET",
        "side": "BUY",
        "size": None,  # sizeではなく金額指定はmarket buy
        "minute_to_expire": 10000,
        "time_in_force": "GTC",
    }
    # 実際はmarket_buy_amountパラメータを使用
    # ここでは概念コードとして示す
    headers = {
        "ACCESS-KEY": BITFLYER_API_KEY,
        "ACCESS-TIMESTAMP": timestamp,
        "ACCESS-SIGN": get_bitflyer_signature(timestamp, "POST", path, str(body)),
        "Content-Type": "application/json",
    }
    resp = requests.post(
        f"https://api.bitflyer.com{path}",
        headers=headers,
        json={"product_code": "BTC_JPY", "child_order_type": "MARKET",
              "side": "BUY", "size": jpy_amount / get_current_btc_price()}
    )
    return resp.json()

def get_current_btc_price() -> float:
    """現在のBTC/JPY価格を取得"""
    resp = requests.get(
        "https://api.bitflyer.com/v1/getticker?product_code=BTC_JPY"
    )
    return float(resp.json()["ltp"])

def save_trade_to_bigquery(trade_data: dict) -> None:
    """取引記録をBigQueryに保存"""
    client = bigquery.Client()
    rows = [{
        "trade_date": datetime.utcnow().isoformat(),
        "exchange": trade_data["exchange"],
        "jpy_amount": trade_data["jpy_amount"],
        "btc_amount": trade_data["btc_amount"],
        "price": trade_data["price"],
        "order_id": trade_data.get("order_id", ""),
    }]
    errors = client.insert_rows_json(BQ_TABLE, rows)
    if errors:
        raise RuntimeError(f"BigQuery insert error: {errors}")

def main():
    monthly_budget = 50000  # 月5万円
    per_trade = monthly_budget // 3  # 1回約16,666円

    price = get_current_btc_price()
    btc_to_buy = per_trade / price

    # bitFlyer購入
    result = buy_btc_bitflyer(per_trade)
    save_trade_to_bigquery({
        "exchange": "bitflyer",
        "jpy_amount": per_trade,
        "btc_amount": btc_to_buy,
        "price": price,
        "order_id": result.get("child_order_acceptance_id", ""),
    })
    print(f"購入完了: {btc_to_buy:.8f} BTC @ {price:,.0f} JPY")

if __name__ == "__main__":
    main()

Cloud RunはCloud Schedulerでキックしている。LambdaじゃなくてCloud Runにしたのは、BigQueryとの相性がいいから。AWSメインの人はLambda + DynamoDB構成でも全然OK。

地味に大事なのがBigQueryへの記録。後述する税務計算のために、取引した瞬間の価格・数量・取引所を全部残すのが本当に重要。「あとで取引所から取得すればいいか」と思ってると、API仕様変更やサービス終了で詰む。これ、経験者は語る、というやつで最初にちゃんとやっておけばよかったと今でも思う。


税務管理をPythonで自動化したら確定申告が2日→4時間になった

日本でのBTC税務の最大の罪は「移動平均法」で計算しないといけないところだ。総平均法も選べるけど、個人は一般的に移動平均法が使われる。取引するたびに平均取得単価が変わるので、手作業はほぼ無理。冒頭で3日かけても計算が合わなかったのは、そういうことだった。

BigQueryに記録した取引データを元に計算するスクリプトを作った。

import pandas as pd
from google.cloud import bigquery
from decimal import Decimal, ROUND_DOWN

def calculate_moving_average_cost(trades_df: pd.DataFrame) -> pd.DataFrame:
    """
    移動平均法でBTCの取得原価を計算する
    
    trades_df columns:
      - trade_date: datetime
      - side: 'BUY' or 'SELL'
      - btc_amount: float
      - jpy_amount: float
    """
    results = []
    total_btc = Decimal("0")
    total_cost = Decimal("0")
    avg_cost = Decimal("0")

    for _, row in trades_df.sort_values("trade_date").iterrows():
        btc = Decimal(str(row["btc_amount"]))
        jpy = Decimal(str(row["jpy_amount"]))

        if row["side"] == "BUY":
            total_btc += btc
            total_cost += jpy
            avg_cost = total_cost / total_btc
            profit_loss = Decimal("0")

        elif row["side"] == "SELL":
            acquisition_cost = btc * avg_cost
            profit_loss = jpy - acquisition_cost
            total_btc -= btc
            total_cost = total_btc * avg_cost  # 売却後に保有コストを更新

        results.append({
            "trade_date": row["trade_date"],
            "side": row["side"],
            "btc_amount": float(btc),
            "jpy_amount": float(jpy),
            "avg_cost_per_btc": float(avg_cost),
            "profit_loss": float(profit_loss),
            "total_btc_held": float(total_btc),
        })

    return pd.DataFrame(results)


def fetch_trades_from_bq(year: int) -> pd.DataFrame:
    client = bigquery.Client()
    query = f"""
    SELECT
        trade_date,
        exchange,
        CASE
            WHEN btc_amount > 0 THEN 'BUY'
            ELSE 'SELL'
        END AS side,
        ABS(btc_amount) AS btc_amount,
        ABS(jpy_amount) AS jpy_amount
    FROM `{BQ_TABLE}`
    WHERE EXTRACT(YEAR FROM trade_date) = {year}
    ORDER BY trade_date
    """
    return client.query(query).to_dataframe()


if __name__ == "__main__":
    trades = fetch_trades_from_bq(2025)
    result = calculate_moving_average_cost(trades)
    
    total_profit = result[result["side"] == "SELL"]["profit_loss"].sum()
    print(f"2025年 暗号資産所得: {total_profit:,.0f} 円")
    
    # CSV出力して確定申告書の参考に
    result.to_csv("btc_tax_2025.csv", index=False, encoding="utf-8-bom")

これを1月に回して結果を確認する。取引ごとの損益がすべて出るので、確定申告書への転記が格段に楽になった。2日かかっていた作業が4時間になったのは、ほぼこのスクリプトのおかげと言っていい。

ただし、送金・取引所間の移動は別途記録が必要。たとえば「bitFlyerからハードウェアウォレットに移動」「bitFlyer→GMOコインへの移動」はコードでは追えないので、別のスプレッドシートで手動記録している。完全自動化まではまだ至ってない。ここは正直課題。

なお、投資信託・NISAとの税務の組み合わせについては「NISA・iDeCoをPythonで理解|エンジニアの複利効果完全攻略2026」に書いたので、トータルの資産管理を考えてる方はそちらも参照してほしい。


リスク管理:実際にやってること・やめたこと

正直、最初は「ドルコスト平均法さえやれば大丈夫」くらいに思ってた。でも2025年の急落(-40%近く)を経験してから、リスク管理の設計を見直した。あのときは本当に肝が冷えた。

今やってること

  • 投資上限を金融資産の15%以下に設定。超えそうになったら積立を一時停止。
  • ハードウェアウォレット(Ledger)でコールドウォレット管理。取引所残高は「近々使う分」だけ。
  • 月次でリバランス確認。BTCが全体の20%を超えたら売却検討。
  • ストップロスは設定しない。長期DCAなので短期の価格変動に反応しないポリシー。

やめたこと

  • レバレッジ取引:2024年に試してみて1回退場しかけた。完全撤退。
  • アルトコイン分散:管理コストが見合わない。今はBTCとETHだけ。
  • 裁量取引:テクニカルで勝てる自信がない。「FXで半年失敗して気づいた、為替を読むコツ」に書いたのと同じ結論。
pie title 現在のポートフォリオ構成(金融資産全体)
    "日本株・米国ETF(NISA)" : 45
    "現金・MMF" : 30
    "BTC" : 12
    "ETH" : 5
    "その他" : 8

BTCの比率は現在12%くらい。これ以上増やすつもりは今のところない。理由は単純で、BTCは寝てる間に30%動く資産だから。ポートフォリオの中で大きくしすぎると、価格が気になりすぎて仕事に集中できなくなる。笑い話じゃなくて、本当に精神衛生の話として重要で、個人的にはこれが一番大事なルールかもしれない。

セキュリティまわりでは、取引所のAPIキーは読み取り専用と取引用で分けている。自動積立用のAPIキーは「特定IPアドレスからのみ」に制限して、Cloud Runの固定IPからしか叩けないようにしてある。構成図がこちら。

flowchart LR
    subgraph 取引所管理
        A[bitFlyer] --> A1[APIキー①\n積立専用\n出金不可]
        A --> A2[APIキー②\n残高確認専用]
        B[GMOコイン] --> B1[APIキー①\n積立専用]
    end
    subgraph 自動化基盤
        C[Cloud Run\n固定IP] --> A1
        C --> B1
        D[BigQuery] --> E[税務計算Script]
    end
    subgraph ウォレット
        F[Ledger\nコールドウォレット]
        G[MetaMask\n少額ホット]
    end
    A -->|手動送金| F

これは最低限やったほうがいい。鍵を開けっ放しにしてるのと同じ状態でAPIを運用してる人、意外と多い気がする。


2026年時点でビットコイン投資に向いてる人・向いてない人

これは完全に主観だけど、参考まで。

向いてると思う人

  • 5年以上の長期ホールドができる人。「-40%でも持ち続けられる」かどうかが分水嶺。
  • ある程度の技術力があって、税務管理・セキュリティを自分で実装できる人。外部ツールへの丸投げは怖い。
  • 既に株・投信などベースの資産を持っていて、「上乗せの賭け」として位置づけられる人。

正直向かないと思う人

  • 価格が気になりすぎる人。スマホで毎時間チェックするようになったらたぶん合ってない。
  • 「今すぐ金が必要」な状況の人。流動性はあるけど、タイミング悪く-50%の時に売る羽目になったら悲惨。
  • 税務をちゃんとやる気がない人。日本の雑所得課税は最高55%。管理しないと本当に大変なことになる。

DeFiについては「DeFiを半年触ってわかったこと|エンジニア視点で読み解く分散金融の現実」で書いたように、技術は面白いけど一般人の資産運用として使うにはまだリスクが高い。エンジニアの「実験」としては面白いけど、メインの投資先にするつもりはない。


まとめ

2026年のビットコイン投資をエンジニア視点で整理すると、こういう感じになる。

  1. 相場より管理が先:ETFでの参入が増えて価格ボラティリティは多少落ち着いてきたけど、税務・セキュリティの管理コストは変わらない。ここをサボると確定申告で死ぬ。

  2. 取引記録は取引した瞬間に自動保存:BigQueryに全記録するだけで確定申告の地獄が天国になる。手作業での取引履歴整理は本当に無駄すぎる。

  3. DCA自動化はCloud Run + Schedulerで十分:複雑なシステムは不要。シンプルに月3回の積立を自動化して、あとは放置できる仕組みを作るのが大事。

  4. ポートフォリオ比率の上限を決めて守る:BTC15%ルールみたいに自分の中のルールを決めないと、上がったときに全額突っ込みたくなる。感情で動かないための仕組み。

  5. APIキーのセキュリティは最低限やる:IPアドレス制限・取引専用キーの分離・出金権限なし。これをやってないのは鍵を開けっ放しにしてるのと同じ。

次のアクション:まだ管理できていない「取引所間送金のコスト記録」を自動化したい。あとDeFiのステーキング報酬の税務処理がまだ手動なので、ここも整備したい。正直まだ課題は多い。

皆さんはBTCの税務管理、どうやってます?ツールに任せてる人が多いのかな。気になるのでぜひコメントで教えてほしい。

U

Untanbaby

ソフトウェアエンジニア|AWS / クラウドアーキテクチャ / DevOps

10年以上のIT実務経験をもとに、現場で使える技術情報を発信しています。 記事の誤りや改善点があればお問い合わせからお気軽にご連絡ください。

関連記事