Add show-latest-report utility
- show-latest-report.sh: Auto-finds and displays latest MT5 report - parse-report.py: Python parser for HTML reports with full stats - Updated UTILS.md with documentation - No browser needed - prevents VM crashes - Shows account info, P&L, trade stats, performance assessment
This commit is contained in:
35
UTILS.md
35
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/MQL5/Logs/YYYYMMDD.log
|
||||||
~/mt5-docker/config/.wine/drive_c/Program Files/MetaTrader 5/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
|
||||||
|
|
||||||
|
|||||||
176
parse-report.py
Executable file
176
parse-report.py
Executable file
@@ -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)
|
||||||
55
show-latest-report.sh
Executable file
55
show-latest-report.sh
Executable file
@@ -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
|
||||||
Reference in New Issue
Block a user