from flask import Flask, render_template_string
from bs4 import BeautifulSoup
import pandas as pd
from datetime import datetime
def extract_all_transactions(html_content):
"""HTMLから全ての取引を抽出"""
soup = BeautifulSoup(html_content, 'html.parser')
rows = soup.find_all('tr', align='right')
transactions = []
for row in rows:
cols = row.find_all('td')
if len(cols) >= 3:
try:
transaction_type = cols[2].text.strip()
if transaction_type == 'balance':
amount = float(cols[-1].text.strip().replace(',', ''))
date = datetime.strptime(cols[1].text.strip(), '%Y.%m.%d %H:%M:%S')
transactions.append({
'date': date,
'type': transaction_type,
'amount': amount,
'swap': 0,
'profit': 0
})
else:
swap = float(cols[-2].text.strip().replace(',', ''))
profit = float(cols[-1].text.strip().replace(',', ''))
date = datetime.strptime(cols[1].text.strip(), '%Y.%m.%d %H:%M:%S')
transactions.append({
'date': date,
'type': transaction_type,
'amount': profit,
'swap': swap,
'profit': profit
})
except (ValueError, IndexError):
continue
df = pd.DataFrame(transactions)
if not df.empty:
df = df.sort_values('date', ascending=False)
return df
def calculate_detailed_summary(df):
"""詳細な取引集計の計算"""
balance_df = df[df['type'] == 'balance']
deposits = balance_df[balance_df['amount'] > 0]['amount'].sum()
withdrawals = abs(balance_df[balance_df['amount'] < 0]['amount'].sum())
swap_profit = df['swap'].sum()
trading_profit = df[df['type'] != 'balance']['profit'].sum()
total = deposits - withdrawals + trading_profit + swap_profit
return {
'deposits': deposits if pd.notnull(deposits) else 0,
'withdrawals': withdrawals if pd.notnull(withdrawals) else 0,
'trading_profit': trading_profit if pd.notnull(trading_profit) else 0,
'swap_profit': swap_profit if pd.notnull(swap_profit) else 0,
'total': total if pd.notnull(total) else 0
}
HTML_TEMPLATE = '''
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>取引分析</title>
<style>
body {
font-family: "Yu Gothic", "メイリオ", sans-serif;
margin: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
.summary {
margin-top: 20px;
padding: 20px;
background-color: #f8f9fa;
border-radius: 5px;
font-weight: bold;
}
.summary-item {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 10px;
margin: 10px 0;
padding: 5px 0;
border-bottom: 1px solid #eee;
}
.summary-total {
margin-top: 20px;
padding-top: 10px;
border-top: 2px solid #333;
}
.amount { text-align: right; }
.positive { color: #28a745; }
.negative { color: #dc3545; }
</style>
</head>
<body>
<div class="container">
<h1>取引分析サマリー</h1>
<div class="summary">
<h2>取引集計</h2>
<div class="summary-item">
<div>入金合計</div>
<div class="amount positive">
¥{{ "{:,.0f}".format(summary['deposits']) }}
</div>
</div>
<div class="summary-item">
<div>出金合計</div>
<div class="amount negative">
¥{{ "{:,.0f}".format(summary['withdrawals']) }}
</div>
</div>
<div class="summary-item">
<div>取引損益</div>
<div class="amount {{ 'positive' if summary['trading_profit'] >= 0 else 'negative' }}">
¥{{ "{:,.0f}".format(summary['trading_profit']) }}
</div>
</div>
<div class="summary-item">
<div>スワップ損益</div>
<div class="amount {{ 'positive' if summary['swap_profit'] >= 0 else 'negative' }}">
¥{{ "{:,.0f}".format(summary['swap_profit']) }}
</div>
</div>
<div class="summary-item summary-total">
<div>総合収支(入金 - 出金 + 取引損益 + スワップ)</div>
<div class="amount {{ 'positive' if summary['total'] >= 0 else 'negative' }}">
¥{{ "{:,.0f}".format(summary['total']) }}
</div>
</div>
</div>
</div>
</body>
</html>
'''
app = Flask(__name__)
@app.route('/')
def home():
with open('44103576_tax_report.html', 'r', encoding='utf-8') as file:
html_content = file.read()
df = extract_all_transactions(html_content)
summary = calculate_detailed_summary(df)
return render_template_string(HTML_TEMPLATE, summary=summary)
if __name__ == '__main__':
app.run(debug=True, port=8000)
