File size: 7,681 Bytes
c99df4c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | """
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}")
|