株式投資の確定申告で一番面倒なのが「損益計算」です。複数の証券会社で取引している場合、損益通算を手作業で行うのは大変です。PythonでCSVを自動集計するツールを作ります。
日本の株式税制の基本
- 株式の譲渡益・配当金の税率:20.315%(所得税15.315%+住民税5%)
- 特定口座(源泉徴収あり):証券会社が自動計算・納付
- 一般口座:確定申告が必要
- 損益通算:同じ年の利益と損失を相殺できる
- 繰越控除:損失を翌年から3年間繰り越せる
取引履歴CSVの読み込み
import pandas as pd
import numpy as np
from datetime import datetime
import os
def load_trades(filepath, encoding="shift-jis"):
"""
証券会社の取引履歴CSVを読み込む
SBI証券: マイページ > 取引履歴 > CSVダウンロード
"""
df = pd.read_csv(filepath, encoding=encoding, skiprows=1)
df["約定日"] = pd.to_datetime(df["約定日"])
return df
損益計算(総平均法)
def calculate_profit_loss(trades_df):
"""
総平均法で株式の損益を計算
"""
results = []
for code in trades_df["銘柄コード"].unique():
stock_trades = trades_df[trades_df["銘柄コード"] == code].sort_values("約定日")
held_shares = 0
total_cost = 0
realized_pnl = 0
for _, row in stock_trades.iterrows():
tx_type = str(row.get("取引区分", ""))
shares = float(row["数量"])
price = float(row["単価"])
fee = float(row.get("手数料", 0))
if "買" in tx_type:
cost = price * shares + fee
held_shares += shares
total_cost += cost
elif "売" in tx_type and held_shares > 0:
avg_cost = total_cost / held_shares
sell_amount = price * shares - fee
profit = sell_amount - avg_cost * shares
realized_pnl += profit
held_shares -= shares
total_cost -= avg_cost * shares
results.append({
"銘柄コード": code,
"銘柄名": stock_trades["銘柄名"].iloc[0] if "銘柄名" in stock_trades.columns else code,
"実現損益": round(realized_pnl, 0),
"残保有株数": round(held_shares, 0),
})
return pd.DataFrame(results)
確定申告サマリーの生成
def generate_tax_report(pnl_df, year=None):
"""確定申告用のサマリーレポートを生成"""
year = year or datetime.now().year
TAX_RATE = 0.20315
total_profit = pnl_df[pnl_df["実現損益"] > 0]["実現損益"].sum()
total_loss = pnl_df[pnl_df["実現損益"] < 0]["実現損益"].sum()
net_pnl = pnl_df["実現損益"].sum()
tax_amount = max(net_pnl * TAX_RATE, 0)
sep = "=" * 50
print(sep)
print(f" {year}年 株式取引 損益計算書")
print(sep)
print(f"総利益 (プラス銘柄計): {total_profit:,.0f}円")
print(f"総損失 (マイナス銘柄計): {total_loss:,.0f}円")
print(f"損益通算後 純損益: {net_pnl:,.0f}円")
print("-" * 50)
if net_pnl > 0:
tax_pct = TAX_RATE * 100
print(f"概算税額 ({tax_pct:.3f}%): {tax_amount:,.0f}円")
print(f"手取り利益: {net_pnl - tax_amount:,.0f}円")
else:
loss_carry = abs(net_pnl)
print(f"損失のため課税なし(翌年繰越可: {loss_carry:,.0f}円)")
print(sep)
print("\n銘柄別損益(上位10銘柄):")
print(pnl_df.sort_values("実現損益", ascending=False).head(10).to_string(index=False))
return {
"year": year, "gross_profit": total_profit,
"gross_loss": total_loss, "net_pnl": net_pnl,
"estimated_tax": tax_amount
}
サンプルデータでのテスト
def create_sample_trades():
"""テスト用のサンプル取引データを生成"""
trades = [
{"約定日": "2024-01-15", "銘柄コード": "7203", "銘柄名": "トヨタ", "取引区分": "現物買", "数量": 100, "単価": 2500, "手数料": 550},
{"約定日": "2024-03-20", "銘柄コード": "7203", "銘柄名": "トヨタ", "取引区分": "現物売", "数量": 100, "単価": 2800, "手数料": 550},
{"約定日": "2024-02-01", "銘柄コード": "9984", "銘柄名": "ソフトバンクG", "取引区分": "現物買", "数量": 50, "単価": 7000, "手数料": 550},
{"約定日": "2024-04-10", "銘柄コード": "9984", "銘柄名": "ソフトバンクG", "取引区分": "現物売", "数量": 50, "単価": 6500, "手数料": 550},
]
df = pd.DataFrame(trades)
df["約定日"] = pd.to_datetime(df["約定日"])
return df
sample = create_sample_trades()
pnl = calculate_profit_loss(sample)
report = generate_tax_report(pnl)
# 期待結果: トヨタ +29,450円, ソフバン -26,100円, 純損益 +3,350円
損益をCSV・Excelにエクスポート
def export_tax_report(pnl_df, report_dict, output_dir="tax_reports"):
"""確定申告用データをCSV・Excelに出力"""
os.makedirs(output_dir, exist_ok=True)
year = report_dict["year"]
# CSVで保存
csv_path = os.path.join(output_dir, f"{year}_pnl.csv")
pnl_df.to_csv(csv_path, index=False, encoding="utf-8-sig")
print(f"CSV出力: {csv_path}")
# Excelで保存(複数シート)
excel_path = os.path.join(output_dir, f"{year}_tax_report.xlsx")
with pd.ExcelWriter(excel_path) as writer:
pnl_df.to_excel(writer, sheet_name="銘柄別損益", index=False)
summary = pd.DataFrame([{
"年度": year,
"総利益": report_dict["gross_profit"],
"総損失": report_dict["gross_loss"],
"純損益": report_dict["net_pnl"],
"概算税額": report_dict["estimated_tax"],
}])
summary.to_excel(writer, sheet_name="サマリー", index=False)
print(f"Excel出力: {excel_path}")
export_tax_report(pnl, report)
まとめ
Pythonで損益計算を自動化することで、確定申告シーズンの大変な手作業から解放されます。実際に使う場合は各証券会社のCSVフォーマットに合わせてカラム名の調整が必要です。
⚠️ 免責事項:このツールはあくまで参考計算です。実際の確定申告には証券会社発行の年間取引報告書を使用し、税務上の判断は税理士にご相談ください。
