""" Script 1 — Raw Microsecond Bid-Ask Unit Data Visualization Fetches XAUUSDc data from MetaTrader 5 for February 12, 2026 (full day), and produces a 4-panel figure: Top-left: Bid Y-distribution histogram (blue, 0.01-unit bins) Top-right: Bid line chart with dot markers (blue) Bottom-left: Ask Y-distribution histogram (red, 0.01-unit bins) Bottom-right:Ask line chart with dot markers (red) 0.01 unit = $0.01 XAU price change. The 'c' suffix in XAUUSDc is an Exness broker account-type indicator (standard cent live account), not related to XAU pricing. """ import MetaTrader5 as mt5 import pandas as pd import numpy as np import matplotlib matplotlib.use('Agg') # Headless backend — no GUI window import matplotlib.pyplot as plt import matplotlib.dates as mdates from datetime import datetime, timezone # ────────────────────────────────────────────── # 1. Connect to MT5 # ────────────────────────────────────────────── if not mt5.initialize(): print(f"MT5 initialize() failed, error code = {mt5.last_error()}") quit() # ────────────────────────────────────────────── # 2. Define time range (Feb 12 2026, full day UTC) # ────────────────────────────────────────────── utc_from = datetime(2026, 2, 12, 0, 0, 0, tzinfo=timezone.utc) utc_to = datetime(2026, 2, 12, 23, 59, 59, tzinfo=timezone.utc) SYMBOL = "XAUUSDc" UNIT_SIZE = 0.01 # the binsize (0.01 unit = $0.01 XAU price change) # ────────────────────────────────────────────── # 3. Fetch data from MT5 # ────────────────────────────────────────────── ticks = mt5.copy_ticks_range(SYMBOL, utc_from, utc_to, mt5.COPY_TICKS_ALL) if ticks is None or len(ticks) == 0: print(f"No data retrieved for {SYMBOL}. Error: {mt5.last_error()}") mt5.shutdown() quit() df = pd.DataFrame(ticks) # MT5 returns time in seconds since epoch; time_msc is milliseconds df['datetime'] = pd.to_datetime(df['time_msc'], unit='ms', utc=True) print(f"Fetched {len(df):,} data points for {SYMBOL}") print(f"Time range: {df['datetime'].iloc[0]} → {df['datetime'].iloc[-1]}") print(f"Bid range : {df['bid'].min():.2f} – {df['bid'].max():.2f}") print(f"Ask range : {df['ask'].min():.2f} – {df['ask'].max():.2f}") mt5.shutdown() # ────────────────────────────────────────────── # 3b. Save raw unit data to CSV # ────────────────────────────────────────────── csv_path = "raw_ticks_XAUUSDc_20260212.csv" df[['datetime', 'bid', 'ask', 'last', 'volume', 'flags']].to_csv(csv_path, index=False) print(f"Saved CSV → {csv_path} ({len(df):,} rows)") # ────────────────────────────────────────────── # 4. Build histogram bins (1 bin = 0.01 unit) # ────────────────────────────────────────────── overall_min = min(df['bid'].min(), df['ask'].min()) overall_max = max(df['bid'].max(), df['ask'].max()) bin_lo = np.floor(overall_min / UNIT_SIZE) * UNIT_SIZE - UNIT_SIZE bin_hi = np.ceil(overall_max / UNIT_SIZE) * UNIT_SIZE + UNIT_SIZE bins = np.arange(bin_lo, bin_hi + UNIT_SIZE, UNIT_SIZE) bins = np.round(bins, 2) # ────────────────────────────────────────────── # 5. Convert datetimes to float (much faster for plotting) # ────────────────────────────────────────────── bid_times = mdates.date2num(df['datetime'].values) ask_times = bid_times # same timestamps print("Plotting...") # ────────────────────────────────────────────── # 6. Plot 4-panel figure # ────────────────────────────────────────────── fig, axes = plt.subplots( 2, 2, figsize=(20, 12), gridspec_kw={'width_ratios': [1, 4]}, sharey='row', ) fig.suptitle( f'{SYMBOL} — Raw Microsecond Unit Data | {utc_from.strftime("%Y-%m-%d")}', fontsize=16, fontweight='bold', ) # Colors — 100% blue and 100% red per IDEA.md BID_COLOR = '#0000FF' ASK_COLOR = '#FF0000' # ── Row 0: BID ───────────────────────────── ax_hist_bid = axes[0, 0] ax_line_bid = axes[0, 1] # Histogram (horizontal) ax_hist_bid.hist( df['bid'].values, bins=bins, orientation='horizontal', color=BID_COLOR, alpha=1.0, edgecolor='white', linewidth=0.3, ) ax_hist_bid.set_xlabel('Count', fontsize=10) ax_hist_bid.set_ylabel('Bid Price', fontsize=10) ax_hist_bid.set_title('Bid Y-Distribution (0.01-unit bins)', fontsize=12) # histogram grows left-to-right (starts from 0) # Line chart — use line only (no markers) for massive data, rasterized ax_line_bid.plot( bid_times, df['bid'].values, color=BID_COLOR, linewidth=0.5, alpha=1.0, rasterized=True, ) ax_line_bid.xaxis_date() ax_line_bid.set_title('Bid Price (Time Series)', fontsize=12) ax_line_bid.set_xlabel('Time (UTC)', fontsize=10) ax_line_bid.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) ax_line_bid.xaxis.set_major_locator(mdates.HourLocator(interval=2)) plt.setp(ax_line_bid.xaxis.get_majorticklabels(), rotation=45, ha='right') ax_line_bid.grid(True, alpha=0.3) # ── Row 1: ASK ───────────────────────────── ax_hist_ask = axes[1, 0] ax_line_ask = axes[1, 1] # Histogram (horizontal) ax_hist_ask.hist( df['ask'].values, bins=bins, orientation='horizontal', color=ASK_COLOR, alpha=1.0, edgecolor='white', linewidth=0.3, ) ax_hist_ask.set_xlabel('Count', fontsize=10) ax_hist_ask.set_ylabel('Ask Price', fontsize=10) ax_hist_ask.set_title('Ask Y-Distribution (0.01-unit bins)', fontsize=12) # histogram grows left-to-right (starts from 0) # Line chart — line only, rasterized ax_line_ask.plot( ask_times, df['ask'].values, color=ASK_COLOR, linewidth=0.5, alpha=1.0, rasterized=True, ) ax_line_ask.xaxis_date() ax_line_ask.set_title('Ask Price (Time Series)', fontsize=12) ax_line_ask.set_xlabel('Time (UTC)', fontsize=10) ax_line_ask.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) ax_line_ask.xaxis.set_major_locator(mdates.HourLocator(interval=2)) plt.setp(ax_line_ask.xaxis.get_majorticklabels(), rotation=45, ha='right') ax_line_ask.grid(True, alpha=0.3) # ── Final layout ─────────────────────────── plt.tight_layout(rect=[0, 0, 1, 0.95]) output_path = "raw_ticks_4panel.png" fig.savefig(output_path, dpi=150, bbox_inches='tight') print(f"Saved → {output_path}")