MT5のストラテジーテスターレポート結果を変換するやつ
はじめに
ストラテジーテスターの結果って出力できる形式が限られていて不便ですよね。
折角結果が出せるのでcsvとかにしてAIとかに食わせたりしたいじゃないですか。
結論
以下のPythonコードを利用すれば解決。
サンプル数少なくあまりテストしてないので何かあれば教えてください。
以下でインストールして出力したhtmlファイルを指定するだけ。
pip install beautifulsoup4 pandas
python3 convert_mt5_report.py ReportTester-xxxxxxxx.html```
import re
from bs4 import BeautifulSoup
import pandas as pd
import sys
def extract_trades_from_html(html_content):
soup = BeautifulSoup(html_content, 'html.parser')
trades = []
# テーブルの行を取得
rows = soup.find_all('tr', {'bgcolor': ['#F7F7F7', '#FFFFFF']})
for row in rows:
cols = row.find_all('td')
if len(cols) >= 13: # 必要なカラム数を確認
try:
# 数値データの安全な変換
def safe_float(value):
try:
return float(value.strip()) if value.strip() else 0.0
except (ValueError, AttributeError):
return 0.0
trade = {
'datetime': cols[0].text.strip(),
'ticket': cols[1].text.strip(),
'symbol': cols[2].text.strip(),
'type': cols[3].text.strip(),
'direction': cols[4].text.strip(),
'volume': safe_float(cols[5].text),
'price': safe_float(cols[6].text),
'order': cols[7].text.strip(),
'commission': safe_float(cols[8].text),
'swap': safe_float(cols[9].text),
'profit': safe_float(cols[10].text),
'balance': safe_float(cols[11].text),
'comment': cols[12].text.strip()
}
trades.append(trade)
except Exception as e:
print(f"行の処理中にエラー: {str(e)}")
print(f"問題のある行: {[col.text.strip() for col in cols]}")
continue
if not trades:
print("警告: 抽出されたトレードがありません")
else:
print(f"抽出されたトレード数: {len(trades)}")
return trades
def extract_parameters_from_html(html_content):
soup = BeautifulSoup(html_content, 'html.parser')
params = {}
# パラメータ行を取得
param_rows = soup.find_all('tr', {'align': 'right'})
for row in param_rows:
cols = row.find_all('td')
if len(cols) >= 2:
param_text = cols[-1].text.strip()
if param_text.startswith('='):
continue
if param_text.startswith('b>'):
continue
params[param_text.split('=')[0].strip()] = param_text.split('=')[1].strip() if '=' in param_text else param_text
return params
def convert_to_csv(input_file, output_trades_file, output_params_file):
# HTMLファイルをバイナリモードで読み込む
try:
with open(input_file, 'rb') as f:
raw_content = f.read()
# デバッグ情報を表示
print(f"ファイルサイズ: {len(raw_content)} bytes")
print(f"先頭20バイト: {raw_content[:20].hex()}")
# BOMチェックとデコード
if raw_content.startswith(b'\xff\xfe'):
try:
# UTF-16LE with BOM
html_content = raw_content.decode('utf-16')
print("デコード成功: UTF-16 (with BOM)")
except UnicodeDecodeError:
try:
# UTF-16LE specific
html_content = raw_content.decode('utf-16le')
print("デコード成功: UTF-16LE")
except UnicodeDecodeError:
print("UTF-16LEデコード失敗")
raise
else:
# その他のエンコーディングを試す
encodings = [
'utf-16le',
'utf-16be',
'utf-16',
'utf-8-sig',
'utf-8',
'shift_jis',
'cp932',
'euc-jp',
'latin1' # 最後の手段として追加
]
for encoding in encodings:
try:
html_content = raw_content.decode(encoding)
print(f"デコード成功: {encoding}")
break
except UnicodeDecodeError:
print(f"{encoding}でのデコード失敗")
html_content = None
continue
if html_content is None:
raise ValueError(f"すべてのエンコーディングのデコードに失敗しました")
# デコードされたコンテンツの最初の部分を表示(デバッグ用)
print("\nデコードされたコンテンツの先頭:")
print(html_content[:200])
# トレード情報を抽出
trades = extract_trades_from_html(html_content)
trades_df = pd.DataFrame(trades)
# パラメータ情報を抽出
params = extract_parameters_from_html(html_content)
params_df = pd.DataFrame(list(params.items()), columns=['Parameter', 'Value'])
# CSVファイルとして保存
trades_df.to_csv(output_trades_file, index=False, encoding='utf-8-sig')
params_df.to_csv(output_params_file, index=False, encoding='utf-8-sig')
return trades_df, params_df
except Exception as e:
print(f"エラーの詳細: {str(e)}")
raise
def analyze_trades(trades_df):
"""トレード分析を行う関数"""
if trades_df.empty:
print("警告: トレードデータが空です")
return pd.DataFrame([['データなし', 'N/A']], columns=['指標', '値'])
try:
total_trades = len(trades_df)
profitable_trades = len(trades_df[trades_df['profit'] > 0])
losing_trades = len(trades_df[trades_df['profit'] < 0])
win_rate = profitable_trades / total_trades * 100 if total_trades > 0 else 0
total_profit = trades_df['profit'].sum()
max_profit = trades_df['profit'].max()
max_loss = trades_df['profit'].min()
avg_profit = trades_df[trades_df['profit'] > 0]['profit'].mean()
avg_loss = trades_df[trades_df['profit'] < 0]['profit'].mean()
analysis = {
'総トレード数': total_trades,
'勝ちトレード数': profitable_trades,
'負けトレード数': losing_trades,
'勝率': f'{win_rate:.2f}%',
'総利益': f'{total_profit:.2f}',
'最大利益': f'{max_profit:.2f}',
'最大損失': f'{max_loss:.2f}',
'平均利益': f'{avg_profit:.2f}' if not pd.isna(avg_profit) else 'N/A',
'平均損失': f'{avg_loss:.2f}' if not pd.isna(avg_loss) else 'N/A',
'プロフィットファクター': f'{abs(avg_profit / avg_loss):.2f}' if not pd.isna(avg_loss) and avg_loss != 0 else 'N/A'
}
return pd.DataFrame(list(analysis.items()), columns=['指標', '値'])
except Exception as e:
print(f"分析中にエラー: {str(e)}")
return pd.DataFrame([['エラー', str(e)]], columns=['指標', '値'])
def main():
if len(sys.argv) < 2:
print("使用方法: python convert_mt5_report.py <input_html_file>")
return
input_file = sys.argv[1]
output_trades_file = input_file.replace('.html', '_trades.csv')
output_params_file = input_file.replace('.html', '_params.csv')
output_analysis_file = input_file.replace('.html', '_analysis.csv')
try:
trades_df, params_df = convert_to_csv(input_file, output_trades_file, output_params_file)
analysis_df = analyze_trades(trades_df)
analysis_df.to_csv(output_analysis_file, index=False, encoding='utf-8-sig')
print(f"\n変換完了:")
print(f"トレード情報: {output_trades_file}")
print(f"パラメータ情報: {output_params_file}")
print(f"分析結果: {output_analysis_file}")
print("\n分析結果:")
print(analysis_df.to_string(index=False))
except Exception as e:
print(f"処理中にエラーが発生しました: {str(e)}")
sys.exit(1)
if __name__ == "__main__":
main()
以上