diff --git a/UTILS.md b/UTILS.md index fa65897..10739a6 100644 --- a/UTILS.md +++ b/UTILS.md @@ -56,3 +56,38 @@ These scripts work around that limitation. ~/mt5-docker/config/.wine/drive_c/Program Files/MetaTrader 5/MQL5/Logs/YYYYMMDD.log ~/mt5-docker/config/.wine/drive_c/Program Files/MetaTrader 5/logs/YYYYMMDD.log ``` + +## show-latest-report.sh + +Automatically finds and displays the latest MT5 trading report. + +```bash +./show-latest-report.sh # Show latest report +./show-latest-report.sh --save # Save to text file +``` + +**Features:** +- Automatically finds the most recent `ReportHistory-*.html` file +- Displays formatted summary with colors +- Shows account info, P&L, trade stats, and performance assessment +- No browser needed (prevents VM crash) + +## parse-report.py + +Python parser for MT5 HTML reports (used by show-latest-report.sh). + +```bash +python3 parse-report.py # Auto-find latest +python3 parse-report.py /path/to/file.html # Parse specific file +``` + +**Output includes:** +- Account name and company +- Net profit, gross profit/loss +- Profit factor +- Total trades, win/loss count +- Win rate percentage +- Largest win/loss +- Balance and return calculation +- Performance assessment + diff --git a/parse-report.py b/parse-report.py new file mode 100755 index 0000000..de80b47 --- /dev/null +++ b/parse-report.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python3 +"""Parse MT5 HTML report and display formatted output""" + +import re +import sys +import os + +def extract_value(pattern, text, group=1): + match = re.search(pattern, text) + return match.group(group).strip() if match else None + +def parse_num(s): + if not s: + return 0 + # Handle European format (space as thousands, comma as decimal) + s = s.replace(' ', '').replace(',', '.') + # Handle multiple dots (take last as decimal) + parts = s.split('.') + if len(parts) > 2: + s = ''.join(parts[:-1]) + '.' + parts[-1] + try: + return float(s) + except: + return 0 + +def parse_report(html_file): + try: + with open(html_file, 'rb') as f: + content = f.read().decode('utf-16-le', errors='ignore') + except Exception as e: + print(f"Error reading file: {e}") + sys.exit(1) + + # Clean text + text = re.sub('<[^<]+?>', ' ', content) + text = text.replace(' ', ' ') + + # Color codes + GREEN = '\033[0;32m' + YELLOW = '\033[1;33m' + RED = '\033[0;31m' + BLUE = '\033[0;34m' + NC = '\033[0m' + BOLD = '\033[1m' + + # Extract account number from filename + account_num = os.path.basename(html_file).split('-')[1].split('.')[0] if '-' in html_file else 'Unknown' + + print(f"{BOLD}{'='*70}{NC}") + print(f"{BOLD} MT5 TRADING REPORT - Account {account_num}{NC}") + print(f"{BOLD}{'='*70}{NC}") + + # Account info + print(f"\n{BLUE}📊 ACCOUNT INFORMATION{NC}") + print("-" * 50) + + name = extract_value(r'Name:\s*([^\d]+?)(?:\s+Account|\s*$)', text) + if name: + print(f"Name: {name}") + + company = extract_value(r'Company:\s*([^\d]+?)(?:\s+Date|\s*$)', text) + if company: + print(f"Company: {company}") + + # Financial results + print(f"\n{GREEN}💰 FINANCIAL RESULTS{NC}") + print("-" * 50) + + net_profit_str = extract_value(r'Total Net Profit[^\d\-]*([\-\d\s,\.]+)', text) + gross_profit_str = extract_value(r'Gross Profit[^\d]*([\d\s,\.]+)', text) + gross_loss_str = extract_value(r'Gross Loss[^\d\-]*([\-\d\s,\.]+)', text) + profit_factor_str = extract_value(r'Profit Factor[^\d]*([\d\.]+)', text) + + if net_profit_str: + val = parse_num(net_profit_str) + color = GREEN if val > 0 else RED + print(f"{color}Total Net Profit: ${val:>12,.2f}{NC}") + + if gross_profit_str: + val = parse_num(gross_profit_str) + print(f"Gross Profit: ${val:>12,.2f}") + + if gross_loss_str: + val = parse_num(gross_loss_str) + print(f"Gross Loss: ${val:>12,.2f}") + + if profit_factor_str: + val = parse_num(profit_factor_str) + color = GREEN if val > 1.5 else YELLOW if val > 1 else RED + print(f"{color}Profit Factor: {val:>12.2f}{NC}") + + # Trade stats + print(f"\n{YELLOW}📈 TRADE STATISTICS{NC}") + print("-" * 50) + + trades = extract_value(r'Total Trades[^\d]*(\d+)', text) + profit_trades = extract_value(r'Profit Trades \(%[^)]*\)[^\d]*(\d+)', text) + loss_trades = extract_value(r'Loss Trades \(%[^)]*\)[^\d]*(\d+)', text) + win_pct = extract_value(r'Profit Trades \(%[^)]*\)[^\d]*\d+[^\d]*\((\d+\.?\d*)%', text) + largest_profit = extract_value(r'Largest profit trade[^\d]*([\d\s,\.]+)', text) + largest_loss = extract_value(r'Largest loss trade[^\d\-]*([\-\d\s,\.]+)', text) + + if trades: + print(f"Total Trades: {trades:>12}") + if profit_trades: + print(f"{GREEN}Winning Trades: {profit_trades:>12}{NC}") + if loss_trades: + print(f"{RED}Losing Trades: {loss_trades:>12}{NC}") + if win_pct: + val = parse_num(win_pct) + color = GREEN if val > 60 else YELLOW if val > 40 else RED + print(f"{color}Win Rate: {val:>11.2f}%{NC}") + if largest_profit: + val = parse_num(largest_profit) + print(f"Largest Win: ${val:>12,.2f}") + if largest_loss: + val = parse_num(largest_loss) + print(f"Largest Loss: ${val:>12,.2f}") + + # Calculate return + if net_profit_str: + profit = parse_num(net_profit_str) + return_pct = (profit / 100000) * 100 + + print(f"\n{BOLD}{'='*70}{NC}") + print(f"{BOLD} STARTING BALANCE: $100,000.00{NC}") + print(f"{GREEN}{BOLD} CURRENT BALANCE: ${100000 + profit:>12,.2f}{NC}") + print(f"{GREEN}{BOLD} NET PROFIT: ${profit:>12,.2f}{NC}") + color = GREEN if return_pct > 0 else RED + print(f"{color}{BOLD} RETURN: {return_pct:>11.2f}%{NC}") + print(f"{BOLD}{'='*70}{NC}") + + print(f"\n{BLUE}🎯 STRATEGY{NC}") + print("-" * 50) + print("EA: MultiSignal Confluence EA") + print("Signal: Confluence BUY (0.70+)") + + # Performance assessment + print(f"\n{BOLD}✅ PERFORMANCE ASSESSMENT{NC}") + print("-" * 50) + + assessment = [] + if win_pct and parse_num(win_pct) > 80: + assessment.append("• Excellent win rate (80%+)") + elif win_pct and parse_num(win_pct) > 60: + assessment.append("• Good win rate (60%+)") + + if profit_factor_str and parse_num(profit_factor_str) > 2: + assessment.append("• Strong profit factor (2.0+)") + elif profit_factor_str and parse_num(profit_factor_str) > 1.5: + assessment.append("• Good profit factor (1.5+)") + + if net_profit_str and parse_num(net_profit_str) > 0: + assessment.append("• Profitable strategy") + + if assessment: + for item in assessment: + print(item) + else: + print("• Review strategy performance") + +if __name__ == "__main__": + if len(sys.argv) > 1: + parse_report(sys.argv[1]) + else: + # Find latest report + import glob + report_dir = os.path.expanduser("~/mt5-docker/config/.wine/drive_c/users/abc/Desktop") + reports = glob.glob(f"{report_dir}/ReportHistory-*.html") + if reports: + latest = max(reports, key=os.path.getmtime) + parse_report(latest) + else: + print("No report files found!") + print(f"Searched: {report_dir}") + sys.exit(1) diff --git a/show-latest-report.sh b/show-latest-report.sh new file mode 100755 index 0000000..1cc8358 --- /dev/null +++ b/show-latest-report.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# show-latest-report.sh - Display the latest MT5 trading report +# Usage: ./show-latest-report.sh [--save] + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPORT_DIR="${HOME}/mt5-docker/config/.wine/drive_c/users/abc/Desktop" + +# Colors +BLUE='\033[0;34m' +GREEN='\033[0;32m' +NC='\033[0m' + +echo -e "${BLUE}=== MT5 Latest Report Finder ===${NC}" +echo "" + +# Find latest report +LATEST_REPORT=$(find "${REPORT_DIR}" -name "ReportHistory-*.html" -type f -printf '%T@ %p\n' 2>/dev/null | sort -n | tail -1 | cut -d' ' -f2-) + +if [ -z "${LATEST_REPORT}" ]; then + echo "❌ No report files found!" + echo "" + echo "To generate a report:" + echo " 1. MT5 → History tab → Right-click" + echo " 2. Select 'Save as Report'" + echo " 3. Save to Desktop" + exit 1 +fi + +# Get file info +FILENAME=$(basename "${LATEST_REPORT}") +FILE_DATE=$(stat -c %y "${LATEST_REPORT}" 2>/dev/null | cut -d' ' -f1) +FILE_SIZE=$(stat -c %s "${LATEST_REPORT}" 2>/dev/null | numfmt --to=iec 2>/dev/null || echo "unknown") + +echo -e "${GREEN}✅ Found latest report:${NC}" +echo " File: ${FILENAME}" +echo " Date: ${FILE_DATE}" +echo " Size: ${FILE_SIZE}" +echo "" + +# Parse and display +if [ -f "${SCRIPT_DIR}/parse-report.py" ]; then + python3 "${SCRIPT_DIR}/parse-report.py" "${LATEST_REPORT}" +else + echo "Error: parse-report.py not found" + exit 1 +fi + +# Save option +if [ "$1" = "--save" ]; then + OUTPUT="${HOME}/report-$(date +%Y%m%d-%H%M%S).txt" + echo "" + echo "💾 Saving to: ${OUTPUT}" + python3 "${SCRIPT_DIR}/parse-report.py" "${LATEST_REPORT}" > "${OUTPUT}" + echo "Saved!" +fi