mBA-Terminal / Python /mt5_raw_ticks.py
algorembrant's picture
Upload 29 files
c99df4c verified
"""
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}")