DeFi取引の損益計算を自動化!仮想通貨の確定申告時の計算方法と注意点

・仮想通貨の確定申告時の注意点
・DeFi取引の損益通算を自動計算する方法
筆者は税理士ではないため、本記事に含まれる内容は正確ではない可能性があります
本記事を参照して発生した損失・損害は、当サイトでは一切の責任を負いません。

仮想通貨取引で収益を上げたら必ず確定申告を!

仮想通貨取引は「雑所得」扱い

サラリーマンで給与所得以外の収入があった場合、確定申告が必要になります。

例えば不動産投資によって得られた所得は「不動産所得」に分類され、確定申告で収入・支出を明記して報告しなければなりません。

所得は全部で10種類あり、他の9種に当てはまらないものが雑所得に分類されます。他の9種とは給与所得、利子所得、配当所得、事業所得、退職所得、不動産所得、山林所得、譲渡所得、一時所得です。

仮想通貨取引の他にも、事業として認められない副業や、FXなどが雑所得に分類されます。

 

よく『雑所得が20万円以下なら申告は不要』と言われていますが、これは間違いです。

20万円の免税規定はあくまで所得税のみの話で、住民税は対象外になります。

そのため20万円以下の雑所得が発生した場合は、確定申告をするか、各市区町村の役所で住民税の手続きを行う必要があります。

仮想通貨取引の確定申告時の注意点

法定通貨と仮想通貨の取引であれば、確定申告の難易度はそこまで高くありません。

例えば100万円分のビットコインを購入し、価格が1.5倍になったので150万円で売却したとします。

差額の50万円が収益となるので、いったん諸経費のことを忘れれば、この50万円を雑所得として報告すればよいのです。

法定通貨と仮想通貨の取引

※ちゃんと諸経費も計算しましょう!

 

仮想通貨の確定申告で注意すべきは仮想通貨同士の取引です。

例の1.5倍になったビットコインを、日本円ではなく別の仮想通貨に交換した場合、手元に日本円は残っていませんが確定申告が必要になります。

お金の流れとしては「日本円」→「ビットコイン」→「別の仮想通貨」となっていますが、日本の税制上は「日本円」→「ビットコイン」→「日本円」→「別の仮想通貨」とみなされます。

仮想通貨同士の取引

上図の例では150万円分のビットコインをバイナンスコインに変更していますが、日本の税制上では一度日本円に換金したものとみなされるため、手元に日本円は何も残っていませんが、最初の例と同じように100万円と150万円の差額である50万円が雑所得になります。

うさぎさん
手元に日本円が残っていないのに課税されるって酷くない!?
管理人こん
まだ仮想通貨自体、世に出て間もないので、今後制度が変わることに期待しましょう・・・

仮想通貨の確定申告支援ツール「Cryptact」

今まで説明してきたとおり、仮想通貨取引で得た収益は確定申告の対象となり、その計算方法は非常に複雑です。

申告漏れによって突然税務署から電話がかかってくる、なんてことも起こりかねません。

「ブームに乗って気軽に始めてみたけど、確定申告のやり方がわからない!」という方も多いのではないでしょうか。

そんな方にオススメなのが、仮想通貨の確定申告サポートツール「Cryptact(クリプタクト)」です。

クリプタクト

 

 

クリプタクトは仮想通貨の資産管理をはじめ、損益計算や確定申告のサポートを得られる投資ツールです。

58の取引所8,600通貨に対応しているという圧倒的なサポート範囲のおかげか、仮想通貨損益計算サービスでは利用者数No.1となっています。

また後述する仮想通貨のDeFiという、より複雑な計算が必要な取引にも対応しているため、UniswapやPancakeSwapを始めた人にもオススメのサービスです。

 

使用方法も以下の3ステップのみで、もし分からない場合も仮想通貨取引に精通したスタッフが親身に対応してくれます。

  1. 取引履歴の準備
  2. 取引履歴のアップロード
  3. 自動計算された損益をチェック
うさぎさん
すごく簡単だね!
管理人こん
無料アカウントでデモ体験ができるので、まずは会員登録して使ってみると良いと思います!

DeFiの損益計算を”自分で”自動計算する方法

管理人こん
さて、ここからが本題です!DeFiの確定申告の概要は、以下の記事をご参照ください。
関連記事

筆者は税理士ではないため、本記事に含まれる内容は正確ではない可能性があります。 本記事を参照して発生した損失・損害は、当サイトでは一切の責任を負いません。 管理人こん 確定申告が不安な方は、必ず税理士に相談しましょう![…]

PancakeSwap 確定申告の計算方法

損益自動計算の流れ

【DeFi】PancakeSwapの確定申告手順をまとめてみた」でも説明したとおり、DeFi取引の損益ポイントは以下3点です。

  1. Harvestした時
  2. Farm・Poolをやめた時(アンステークした時)
  3. 仮想通貨取引に関連する全ての手数料

②に関しては、「仮想通貨取引の確定申告時の注意点」でお伝えした内容を守れば、計算すること自体は簡単です。

問題は①と③です。PancakeSwapの場合は、流動性の提供で得られたCakeをHarvestし、Syrup Poolに預けることで複利運用をすることができます。

より複利運用を加速させるために、3日に1度くらいの頻度でHarvestしている人は多いのではないでしょうか。

このHarvestのたびに収益が発生し、使用した取引手数料を経費として計算しなければなりません。

BscScanで見ることができる取引結果は日本円で計算されているわけではないので、各Harvest毎のトランザクションを日本円に直す必要があります。

そこで、世界最大の仮想通貨取引所であるバイナンスが提供するAPIを使用し、取引時間毎のCakeの価値を算出します。

実際にはccxtという各取引所のAPI操作が集約されたPythonのライブラリを使用します。

 

しかしccxtを使ってみたところ、Harvestで得られるCakeと日本円に対応したCAKE/JPY、Harvest毎に発生する取引手数料に使用する通貨であるBNBと日本円に対応したBNB/JPYがありませんでした

そこで、Twelve Dataが提供するAPIを用いて、ccxtで取得できる「CAKE/AUD」とTwelve Dataで取得できる「AUD/JPY」をかけ合わせ、CAKE/JPYを擬似的に作ります。(BNBも同様)

 

あとはBscScanのAPIから、トランザクションデータを出力し、そのデータに基づいてCAKE/JPYをかけ合わせ、損益の計算を行います。

全体の流れは下図の通りです。

自動計算の全体図

うさぎさん
ちょっとよく分からないんですが・・・
管理人こん
Pythonが少しでも触れないとキツいと思うので、そういう方は諦めてクリプタクトを使いましょうね

コードの全体像

管理人こん
私は非エンジニアなので、書き方が汚いのは許してください!!
import ccxt
import requests
import json
import pandas as pd
from twelvedata import TDClient
from datetime import datetime
import time

bsc_api_key  = 'BscScanのAPIキー'
my_address = '自分のウォレットアドレス'

txn_list = []

##########
# 関数
##########

def aud_chart(unix):

	td_api_key = 'Twelve DataのAPIキー'

	ymd = datetime.fromtimestamp(int(unix))
	td = TDClient(apikey=td_api_key)
	aud = td.time_series(
	    symbol='AUD/JPY',
	    interval='1min',
	    outputsize=1,
	    timezone='Japan',
	    end_date=ymd,
	)
	aud = aud.as_json()
	aud_jpy = aud[0]['open']

	return aud_jpy

def crypto_chart(unix):

	binance = ccxt.binance()
	unix = int(unix) * 1000
	cake_bnb = binance.fetch_ohlcv(symbol='CAKE/BNB', timeframe='1m', since=unix, limit=1)
	bnb_aud = binance.fetch_ohlcv(symbol='BNB/AUD', timeframe='1m', since=unix, limit=1)

	cake_bnb = cake_bnb[0][1]
	bnb_aud = bnb_aud[0][1]

	return cake_bnb, bnb_aud

##########
# 処理エリア
##########

url = 'https://api.bscscan.com/api'
params = {'module':'account', 'action':'tokentx', 'address':my_address, 'apikey':bsc_api_key}

r = requests.get(url, params=params)
r = r.json()

df = pd.json_normalize(r['result'])

unstake = (df[df['from'] == '0x009cf7bc57584b7998236eff51b98a168dcea9b0'])
unstake = unstake[['timeStamp', 'value', 'gasPrice', 'gasUsed']]

for data in unstake.itertuples():
	ymd = datetime.fromtimestamp(int(data[1]))
	ymd = ymd.strftime('%Y/%m/%d')
	cake_bnb = float(crypto_chart(data[1])[0])
	bnb_aud = float(crypto_chart(data[1])[1])
	aud_jpy = float(aud_chart(data[1]))

	cake_jpy = cake_bnb * bnb_aud * aud_jpy
	bnb_jpy = bnb_aud * aud_jpy

	inc_cake = float(data[2]) / 1000000000000000000
	inc = inc_cake * cake_jpy
	exp_bnb = float(data[3]) * float(data[4]) / 1000000000000000000
	exp = exp_bnb * bnb_jpy

	txn_inc = dict(Date=ymd, Type='income', value=inc_cake, jpy_value=inc)
	txn_exp = dict(Date=ymd, Type='expense', value=exp_bnb, jpy_value=exp)

	txn_list.append(txn_inc)
	txn_list.append(txn_exp)

	time.sleep(8)


stake = (df[df['to'] == '0xa80240eb5d7e05d3f250cf000eec0891d00b51cc'])
stake = stake[['timeStamp', 'value', 'gasPrice', 'gasUsed']]

for data in stake.itertuples():
	ymd = datetime.fromtimestamp(int(data[1]))
	ymd = ymd.strftime('%Y/%m/%d')
	cake_bnb = float(crypto_chart(data[1])[0])
	bnb_aud = float(crypto_chart(data[1])[1])
	aud_jpy = float(aud_chart(data[1]))

	cake_jpy = cake_bnb * bnb_aud * aud_jpy
	bnb_jpy = bnb_aud * aud_jpy

	exp_bnb = float(data[3]) * float(data[4]) / 1000000000000000000
	exp = exp_bnb * bnb_jpy

	txn_exp = dict(Date=ymd, Type='expense', value=exp_bnb, jpy_value=exp)

	txn_list.append(txn_exp)

	time.sleep(8)


txn_list = pd.DataFrame(txn_list)
txn_list.to_csv("pancake_txn.csv")
うさぎさん
こ、これは・・・

具体的な実装方法

管理人こん
Pythonの使い方は自分で調べてくださいね!

下準備①:APIキーの取得

先述の通り、使用するAPIは3つあります。

  1. Binance API
  2. Twelve Data API
  3. BscScan API

うち、ccxt経由でつなぐBinance APIはパブリックAPIであるため、APIキーは必要ありません。

逆にTwelve Data APIやBscScan APIはプライベートAPIであるため、会員登録が必要です。

個人的に利用するのであれば、どちらも無料プランで問題ないので会員登録を済ませAPIキーを取得しましょう。

Twelve Data公式ページ

BscScan 公式ページ

下準備②:pip install

恐らくこの記事を読んでいるということはccxtやBscScanAPIを始めて使う方だと思います。

今回使用するライブラリは以下の通り。

import ccxt
import requests
import json
import pandas as pd
from twelvedata import TDClient
from datetime import datetime
import time

所有していないものはpip installでインストールしてしまいましょう。

pip install ccxt
pip install twelvedata

 

importの後ろにとりあえず、APIキーやウォレットアドレスを定義しておいたのですが、別に最初に定義する必要はありませんでしたw

関数の定義後にこれらは使用します。

bsc_api_key = 'BscScanのAPIキー' 
my_address = '自分のウォレットアドレス' 
txn_list = []

AUD/JPYの取得

Twelve Data APIを使用してAUD/JPYを取得する関数です。引数は、後のBscScanで取得できるUNIX時間を使用し、戻り値はAUD/JPYとなります。

def aud_chart(unix):

	td_api_key = 'Twelve DataのAPIキー'

	ymd = datetime.fromtimestamp(int(unix)) #UNIXをyyyy-mm-dd hh:mm:ssに変換
	td = TDClient(apikey=td_api_key) #APIの認証
	aud = td.time_series(
	    symbol='AUD/JPY',
	    interval='1min',
	    outputsize=1,
	    timezone='Japan',
	    end_date=ymd, #取引時間のデータを取得
	)
	aud = aud.as_json()
	aud_jpy = aud[0]['open']

	return aud_jpy

Twelve Data APIではUNIX時間ではなく、「yyyy-mm-dd」もしくは「yyyy-mm-dd hh:mm:ss」で日時を指定する必要があります。

ほかはTwelve Data APIの公式ドキュメントに沿って実装したため、特筆すべきポイントはありません。

CAKE/AUD・BNB/AUDの取得

次にccxtを用いて、CAKE/AUDとBNB/AUDを取得する関数です。引数は同じくUNIX時間で、戻り値はCAKE/AUDとBNB/AUDになります。

def crypto_chart(unix):

	binance = ccxt.binance()
	unix = int(unix) * 1000 #ミリ秒を追加
	cake_bnb = binance.fetch_ohlcv(symbol='CAKE/BNB', timeframe='1m', since=unix, limit=1)
	bnb_aud = binance.fetch_ohlcv(symbol='BNB/AUD', timeframe='1m', since=unix, limit=1)

	cake_bnb = cake_bnb[0][1]
	bnb_aud = bnb_aud[0][1]

	return cake_bnb, bnb_aud

これもccxtのGitHubに沿って実装しているので、変わったことをしているわけではありません。

ccxtではミリ秒までのUNIX時間を採用しているため×1000をしていることとくらいですかね。

BscScanのトランザクションデータ取得

BscScanのトランザクションデータを取得します。BscScanもPythonのライブラリが用意されていたのですが、使い方がイマイチ分からなかったので、WebAPIでデータ取得しています。

url = 'https://api.bscscan.com/api'
params = {'module':'account', 'action':'tokentx', 'address':my_address, 'apikey':bsc_api_key}

r = requests.get(url, params=params)
r = r.json()

df = pd.json_normalize(r['result'])

パラメータの「action」を「tokentx」に、「address」を前段に定義した「自身のウォレットアドレス」にすることで、指定のアドレスのトランザクションデータを全部引っ張ってくることができます。

それをフィルターをかけやすいようにpandasでデータフレームの形にします。

HarvestとPool時のトランザクションでフィルターをかける

今回はPancakeSwapのHarvestとPoolにトランザクションを絞りたいので、Harvest時のトランザクションを「from」のカラムを使用し、フィルターをかけます。

Harvestした際は、PancakeSwapの「0x009cf7bc57584b7998236eff51b98a168dcea9b0」というコントラクトアドレスからCakeを受け取るので、このアドレスでフィルターをかけます。

一方でHarvestしたCakeをPoolする際は、PancakeSwapの「0xa80240eb5d7e05d3f250cf000eec0891d00b51cc」というコントラクトアドレスにCakeを送るので、このアドレスを「To」カラムを使用しフィルタをかけます。

unstake = (df[df['from'] == '0x009cf7bc57584b7998236eff51b98a168dcea9b0']) #Harvestのトランザクション
unstake = unstake[['timeStamp', 'value', 'gasPrice', 'gasUsed']] #必要な列のみにする

stake = (df[df['to'] == '0xa80240eb5d7e05d3f250cf000eec0891d00b51cc']) #Poolのトランザクション
stake = stake[['timeStamp', 'value', 'gasPrice', 'gasUsed']] #必要な列のみにする

ちなみに「value」はHarvest or PoolしたCakeで、「gas Price」 × 「gasUsed」が取引手数料になります。

forのループでぶん回す

データフレームは整ったのであとは各トランザクション毎に、UNIX時間を取得し、AUD/JPY・CAKE/AUD・BNB/AUDを戻す関数に値を渡すだけです。

for data in unstake.itertuples():
	ymd = datetime.fromtimestamp(int(data[1]))
	ymd = ymd.strftime('%Y/%m/%d') #扱いやすいようにyyyy/mm/ddの形式に変更
	cake_bnb = float(crypto_chart(data[1])[0])
	bnb_aud = float(crypto_chart(data[1])[1])
	aud_jpy = float(aud_chart(data[1]))

	cake_jpy = cake_bnb * bnb_aud * aud_jpy #CAKE/JPYの算出
	bnb_jpy = bnb_aud * aud_jpy #BNB/JPYの算出

	inc_cake = float(data[2]) / 1000000000000000000 
	inc = inc_cake * cake_jpy #収入の計算
	exp_bnb = float(data[3]) * float(data[4]) / 1000000000000000000
	exp = exp_bnb * bnb_jpy #支出の計算

  #辞書型にする
	txn_inc = dict(Date=ymd, Type='income', value=inc_cake, jpy_value=inc) #収入の辞書
	txn_exp = dict(Date=ymd, Type='expense', value=exp_bnb, jpy_value=exp) #支出の辞書
  
  #リストに追加し、辞書リストにする
	txn_list.append(txn_inc)
	txn_list.append(txn_exp)

  #Twelve Data APIの制約
	time.sleep(8)

forでぶん回すだけなのですが、いくつか注意点があります。

1つめはBscScan APIで出力されるValueは、小数点を無視して出力されます。そのため1e+18で割る必要があります。

次にこれはBscScanではなくTwelve Data APIの問題なのですが、Twelve Data APIは無料プランだと1分間に8リクエストしかできません。

そのため「time.sleep(8)」で1分間に大量のリクエストがいかないように制御しています。

Pool時の手数料を取得するコードは以下です。

for data in stake.itertuples():
	ymd = datetime.fromtimestamp(int(data[1]))
	ymd = ymd.strftime('%Y/%m/%d')
	cake_bnb = float(crypto_chart(data[1])[0])
	bnb_aud = float(crypto_chart(data[1])[1])
	aud_jpy = float(aud_chart(data[1]))

	cake_jpy = cake_bnb * bnb_aud * aud_jpy
	bnb_jpy = bnb_aud * aud_jpy

	exp_bnb = float(data[3]) * float(data[4]) / 1000000000000000000
	exp = exp_bnb * bnb_jpy

	txn_exp = dict(Date=ymd, Type='expense', value=exp_bnb, jpy_value=exp)

	txn_list.append(txn_exp)

	time.sleep(8)

CSVに出力

最後にCSVに出力します。

txn_list = pd.DataFrame(txn_list) #辞書リストをデータフレームに変換
txn_list.to_csv("pancake_txn.csv") #CSVダウンロード

これで実行ディレクトリ内にcsvが作成されたら完了です!

作成されたcsvをGoogleスプレッドシートでみてみます。

自動計算されたCSV

ポチポチ手動で計算した数値と差がない結果となりました!

うさぎさん
最初から最後まで全く分からなかった・・・
管理人こん
そういう方は無理して自分でやらないほうが良いと思いますw
今回紹介したスクリプトはあくまでサンプルです。このスクリプトを利用して発生した、いかなる損失や損害などの被害が発生しても当サイトでは責任を負いかねますので、ご了承ください。

まとめ

私が非エンジニアということもあるのですが、この自動計算機を作るのに5~6時間くらいかかったと思います・・・。(ほとんどが調査の時間でしたが・・・)

私の場合、とりあえず今年はこのツールで乗り越えることができそうですが、この実装に自身がない人はやっぱりクリプタクトが良いと思います。

管理人こん
テキトーな申告で税務署から連絡くるよりも、プロに任せましょう!
うさぎさん
プロに全投げします!