Gr8/tradeprogress.py
2025-09-10 15:02:31 +03:00

132 lines
4.7 KiB
Python

import MetaTrader5 as mt5
import logging
import time
from datetime import datetime
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import smtplib
import json
# ================================
# Logging setup
# ================================
logging.basicConfig(level=logging.INFO, format="%(asctime)s | %(levelname)s | %(message)s")
log = logging.getLogger()
# ================================
# Load config
# ================================
def load_config(filepath="config.json"):
with open(filepath, "r") as f:
return json.load(f)
# ================================
# Send Email (Multiple Recipients)
# ================================
def send_email(subject, body, smtp_config):
recipients = smtp_config["recipient_email"]
if isinstance(recipients, str):
recipients = [recipients]
msg = MIMEMultipart()
msg["From"] = smtp_config["sender_email"]
msg["To"] = ", ".join(recipients)
msg["Subject"] = subject
msg.attach(MIMEText(body, "plain"))
try:
with smtplib.SMTP(smtp_config["smtp_server"], smtp_config["smtp_port"]) as server:
server.starttls()
server.login(smtp_config["sender_email"], smtp_config["sender_password"])
server.send_message(msg)
log.info(f"Email sent to: {', '.join(recipients)}")
except Exception as e:
log.error(f"Error sending email: {e}")
# ================================
# Fetch Position Data
# ================================
def fetch_open_positions():
positions = mt5.positions_get()
if positions is None or len(positions) == 0:
log.info("No open positions")
return []
data = []
for pos in positions:
tick = mt5.symbol_info_tick(pos.symbol)
if tick is None:
current_price = None
else:
current_price = tick.last
distance_sl = (current_price - pos.sl) if pos.sl else None
distance_tp = (pos.tp - current_price) if pos.tp else None
profit = pos.profit
relative = "N/A"
if current_price and pos.volume:
if pos.type == mt5.ORDER_TYPE_BUY:
relative = "Above Open" if current_price > pos.price_open else ("Below Open" if current_price < pos.price_open else "At Open")
elif pos.type == mt5.ORDER_TYPE_SELL:
relative = "Below Open" if current_price < pos.price_open else ("Above Open" if current_price > pos.price_open else "At Open")
data.append({
"ticket": pos.ticket,
"symbol": pos.symbol,
"type": "BUY" if pos.type == mt5.ORDER_TYPE_BUY else "SELL",
"volume": pos.volume,
"open_price": pos.price_open,
"current_price": current_price,
"sl": pos.sl,
"tp": pos.tp,
"distance_sl": distance_sl,
"distance_tp": distance_tp,
"profit": profit,
"relative_to_open": relative
})
return data
# ================================
# Main monitoring loop
# ================================
def main():
config = load_config()
smtp_config = config["email"]
update_interval = config.get("update_interval_sec", 60) # default 60 sec
# Connect to running MT5 terminal
if not mt5.initialize():
log.error(f"MT5 initialize failed: {mt5.last_error()}")
return
log.info("Connected to MT5 terminal")
try:
while True:
positions_data = fetch_open_positions()
if positions_data:
report_lines = [f"Open Positions Report - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"]
for p in positions_data:
report_lines.append(f"Ticket: {p['ticket']}, Symbol: {p['symbol']}, Type: {p['type']}, Volume: {p['volume']}")
report_lines.append(f"Open Price: {p['open_price']}, Current Price: {p['current_price']}")
report_lines.append(f"SL: {p['sl']}, TP: {p['tp']}")
report_lines.append(f"Distance to SL: {p['distance_sl']}, Distance to TP: {p['distance_tp']}")
report_lines.append(f"Profit: {p['profit']}, Relative to Open: {p['relative_to_open']}\n")
log.info("\n".join(report_lines))
send_email(subject="Live Positions Update", body="\n".join(report_lines), smtp_config=smtp_config)
else:
log.info("No positions to report")
time.sleep(update_interval)
except KeyboardInterrupt:
log.info("Monitoring stopped by user")
finally:
mt5.shutdown()
log.info("MT5 connection closed")
# ================================
# Run
# ================================
if __name__ == "__main__":
main()