193 lines
6.2 KiB
Python
193 lines
6.2 KiB
Python
|
import MetaTrader5 as mt5
|
||
|
import json
|
||
|
import os
|
||
|
import requests
|
||
|
import logging
|
||
|
from datetime import datetime, timedelta, timezone
|
||
|
import smtplib
|
||
|
from email.mime.text import MIMEText
|
||
|
from email.mime.multipart import MIMEMultipart
|
||
|
|
||
|
# ===========================
|
||
|
# Logging Configuration
|
||
|
# ===========================
|
||
|
logging.basicConfig(
|
||
|
level=logging.INFO,
|
||
|
format="%(asctime)s | %(levelname)s | %(message)s",
|
||
|
datefmt="%Y-%m-%d %H:%M:%S"
|
||
|
)
|
||
|
log = logging.getLogger(__name__)
|
||
|
|
||
|
# ===========================
|
||
|
# Load Config
|
||
|
# ===========================
|
||
|
def load_config(config_path="config.json"):
|
||
|
if not os.path.exists(config_path):
|
||
|
raise FileNotFoundError(f"Config file not found at {config_path}")
|
||
|
with open(config_path, "r") as f:
|
||
|
config = json.load(f)
|
||
|
log.info(
|
||
|
f"Config loaded: Username={config['username']} | "
|
||
|
f"Server={config['server']} | Path={config['mt5Pathway']}"
|
||
|
)
|
||
|
return config
|
||
|
|
||
|
# ===========================
|
||
|
# Initialize MT5
|
||
|
# ===========================
|
||
|
def initialize_mt5(config):
|
||
|
log.info("Starting MetaTrader 5 initialization...")
|
||
|
if mt5.initialize(
|
||
|
path=config["mt5Pathway"],
|
||
|
login=int(config["username"]),
|
||
|
password=config["password"],
|
||
|
server=config["server"]
|
||
|
):
|
||
|
log.info("MT5 initialized successfully!")
|
||
|
else:
|
||
|
error_code, error_msg = mt5.last_error()
|
||
|
log.error(f"MT5 initialization failed → Code {error_code}: {error_msg}")
|
||
|
raise RuntimeError(f"MT5 initialize failed: {mt5.last_error()}")
|
||
|
|
||
|
# ===========================
|
||
|
# Fetch TradingView USD High Impact News
|
||
|
# ===========================
|
||
|
def fetch_tradingview_news(start_date, end_date, label="Events"):
|
||
|
"""
|
||
|
Pull ONLY high-impact USD economic news using TradingView's public API.
|
||
|
"""
|
||
|
try:
|
||
|
url = "https://economic-calendar.tradingview.com/events"
|
||
|
|
||
|
# Strict filter: USD + High Impact only
|
||
|
params = {
|
||
|
"from": start_date.strftime("%Y-%m-%d"),
|
||
|
"to": end_date.strftime("%Y-%m-%d"),
|
||
|
"currencies": "USD", # USD only
|
||
|
"importance": 3 # 3 = High impact only
|
||
|
}
|
||
|
|
||
|
log.info(f"Fetching {label} for USD High Impact from {params['from']} to {params['to']}")
|
||
|
|
||
|
response = requests.get(url, params=params, timeout=10)
|
||
|
if response.status_code != 200:
|
||
|
log.error(f"{label} API HTTP error: {response.status_code}")
|
||
|
return []
|
||
|
|
||
|
try:
|
||
|
data = response.json()
|
||
|
except Exception as e:
|
||
|
log.error(f"{label} JSON decode failed: {e}")
|
||
|
log.error(f"Raw Response: {response.text}")
|
||
|
return []
|
||
|
|
||
|
# Filter and format events
|
||
|
events = []
|
||
|
for e in data.get("result", []):
|
||
|
# Extra safety check to ensure it's USD and high impact
|
||
|
if e.get("currency") != "USD" or e.get("importance") != 3:
|
||
|
continue
|
||
|
event_time = datetime.fromtimestamp(e["timestamp"], tz=timezone.utc)
|
||
|
events.append(
|
||
|
f"{event_time.strftime('%Y-%m-%d %H:%M UTC')} | {e['title']} | "
|
||
|
f"Actual: {e.get('actual', 'N/A')} | Forecast: {e.get('forecast', 'N/A')}"
|
||
|
)
|
||
|
|
||
|
return events
|
||
|
except Exception as e:
|
||
|
log.error(f"Error fetching {label}: {e}")
|
||
|
return []
|
||
|
|
||
|
# ===========================
|
||
|
# Get Past and Forward News
|
||
|
# ===========================
|
||
|
def get_past_month_news():
|
||
|
now = datetime.now(timezone.utc)
|
||
|
last_month = now - timedelta(days=30)
|
||
|
return fetch_tradingview_news(last_month, now, label="Past Month USD High Impact News")
|
||
|
|
||
|
def get_forward_news():
|
||
|
now = datetime.now(timezone.utc)
|
||
|
next_month = now + timedelta(days=30)
|
||
|
return fetch_tradingview_news(now, next_month, label="Upcoming USD High Impact News")
|
||
|
|
||
|
# ===========================
|
||
|
# Email Sending
|
||
|
# ===========================
|
||
|
def send_email(subject, body, smtp_config):
|
||
|
try:
|
||
|
msg = MIMEMultipart()
|
||
|
msg['From'] = smtp_config["sender_email"]
|
||
|
msg['To'] = smtp_config["recipient_email"]
|
||
|
msg['Subject'] = subject
|
||
|
msg.attach(MIMEText(body, "plain"))
|
||
|
|
||
|
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 {smtp_config['recipient_email']}")
|
||
|
except Exception as e:
|
||
|
log.error(f"Error sending email: {e}")
|
||
|
|
||
|
# ===========================
|
||
|
# Build Report
|
||
|
# ===========================
|
||
|
def build_report(past_news, forward_news):
|
||
|
now_ny = datetime.now(timezone.utc) - timedelta(hours=4) # Convert to NY time (UTC-4 approx)
|
||
|
report = f"Report generated at NY Time: {now_ny.strftime('%Y-%m-%d %H:%M:%S')}\n\n"
|
||
|
|
||
|
report += "=== Past Month USD High Impact News ===\n"
|
||
|
report += "\n".join(past_news) if past_news else "No data found for the past month."
|
||
|
report += "\n\n"
|
||
|
|
||
|
report += "=== Forward 30-Day USD High Impact News ===\n"
|
||
|
report += "\n".join(forward_news) if forward_news else "No forward events found."
|
||
|
|
||
|
return report
|
||
|
|
||
|
# ===========================
|
||
|
# Main Function
|
||
|
# ===========================
|
||
|
def main():
|
||
|
log.info("===== Starting USD High Impact News Script =====")
|
||
|
try:
|
||
|
# Load configuration
|
||
|
config = load_config()
|
||
|
|
||
|
# Initialize MT5
|
||
|
try:
|
||
|
initialize_mt5(config)
|
||
|
except RuntimeError as e:
|
||
|
log.error(f"Fatal error in MT5 initialization: {e}")
|
||
|
return
|
||
|
|
||
|
# Fetch news
|
||
|
past_news = get_past_month_news()
|
||
|
forward_news = get_forward_news()
|
||
|
|
||
|
# Build report
|
||
|
report = build_report(past_news, forward_news)
|
||
|
|
||
|
# Send email
|
||
|
send_email(
|
||
|
subject="USD High Impact Economic News Report",
|
||
|
body=report,
|
||
|
smtp_config=config["email"]
|
||
|
)
|
||
|
|
||
|
except Exception as e:
|
||
|
log.error(f"Fatal error in main(): {e}")
|
||
|
finally:
|
||
|
log.info("Shutting down MetaTrader 5...")
|
||
|
mt5.shutdown()
|
||
|
log.info("MT5 shutdown complete.")
|
||
|
log.info("===== Script Finished =====")
|
||
|
|
||
|
# ===========================
|
||
|
# Run Script
|
||
|
# ===========================
|
||
|
if __name__ == "__main__":
|
||
|
main()
|