Skill: Market Data Ingestion | Domain: trading | Category: data | Level: intermediate
Tags: trading, data, ingestion, mt5, ohlcv, batch
Market Data Ingestion
MT5 Data Fetcher (Primary — your setup)
import MetaTrader5 as mt5
import pandas as pd
from datetime import datetime
def fetch_mt5(symbol: str, timeframe: int, bars: int = 1000) -> pd.DataFrame:
"""Fetch OHLCV from MT5. Timeframe: mt5.TIMEFRAME_M5, H1, D1, etc."""
mt5.initialize()
rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, bars)
mt5.shutdown()
if rates is None:
raise ValueError(f"No data for {symbol}")
df = pd.DataFrame(rates)
df["time"] = pd.to_datetime(df["time"], unit="s")
df.set_index("time", inplace=True)
df.rename(columns={"open":"open","high":"high","low":"low",
"close":"close","tick_volume":"volume"}, inplace=True)
return df[["open","high","low","close","volume"]]
def fetch_multi_mt5(symbols: list, timeframe: int, bars: int = 500) -> dict:
"""Batch fetch multiple symbols from MT5."""
mt5.initialize()
data = {}
for sym in symbols:
rates = mt5.copy_rates_from_pos(sym, timeframe, 0, bars)
if rates is not None:
df = pd.DataFrame(rates)
df["time"] = pd.to_datetime(df["time"], unit="s")
df.set_index("time", inplace=True)
data[sym] = df[["open","high","low","close","tick_volume"]].rename(
columns={"tick_volume": "volume"})
mt5.shutdown()
return data
Your 23 Watched Symbols
WATCHED = [
"XAUUSDm","XAGUSDm","EURUSDm","GBPUSDm","USDJPYm","AUDUSDm","USDCADm","USDCHFm",
"BTCUSDm","ETHUSDm","USOILm","USTECm","US500m","US30m",
"TSLAm","AAPLm","MSFTm","NVDAm","AMZNm","GOOGm","METAm","JPMm","BAm"
]
TIMEFRAMES = {
"M5": mt5.TIMEFRAME_M5, "M15": mt5.TIMEFRAME_M15,
"H1": mt5.TIMEFRAME_H1, "H4": mt5.TIMEFRAME_H4, "D1": mt5.TIMEFRAME_D1,
}
Data Cleaning Pipeline
def clean_ohlcv(df: pd.DataFrame, max_gap_bars: int = 5) -> pd.DataFrame:
"""Remove bad bars, fill small gaps, validate OHLC logic."""
# Drop bars where OHLC relationship is broken
df = df[(df["high"] >= df["low"]) &
(df["high"] >= df["open"]) & (df["high"] >= df["close"]) &
(df["low"] <= df["open"]) & (df["low"] <= df["close"])]
# Drop zero-volume bars (market closed)
df = df[df["volume"] > 0]
# Forward-fill small gaps (weekend gaps etc.)
df = df.resample("1min").asfreq()
gap_size = df["close"].isna().rolling(max_gap_bars + 1).sum()
df = df[gap_size <= max_gap_bars].ffill()
return df.dropna()
yfinance Fallback (for research/backtesting)
import yfinance as yf
def fetch_yf(ticker: str, period: str = "1y", interval: str = "1d") -> pd.DataFrame:
"""Fetch from Yahoo Finance. interval: 1m,5m,15m,1h,1d,1wk."""
df = yf.download(ticker, period=period, interval=interval, auto_adjust=True, progress=False)
df.columns = [c.lower() for c in df.columns]
return df[["open","high","low","close","volume"]]
Related Skills
1---2name: market-data-ingestion3description: Market data ingestion pipelines: OHLCV data fetching from MT5, yfinance, Alpha Vantage, data cleaning, normalization, missing bar handling, multi-symbol batch fetching. USE FOR: market data, OHLCV, fetch data, download data, historical data, MT5 data, yfinance, Alpha Vantage, data pipeline, data ingestion, price data, candle data, bar data, multi-symbol, batch fetch, data cleaning, normalize prices.4---5> **Skill:** Market Data Ingestion | **Domain:** trading | **Category:** data | **Level:** intermediate6> **Tags:** `trading`, `data`, `ingestion`, `mt5`, `ohlcv`, `batch`789# Market Data Ingestion1011## MT5 Data Fetcher (Primary — your setup)12```python13import MetaTrader5 as mt514import pandas as pd15from datetime import datetime1617def fetch_mt5(symbol: str, timeframe: int, bars: int = 1000) -> pd.DataFrame:18 """Fetch OHLCV from MT5. Timeframe: mt5.TIMEFRAME_M5, H1, D1, etc."""19 mt5.initialize()20 rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, bars)21 mt5.shutdown()22 if rates is None:23 raise ValueError(f"No data for {symbol}")24 df = pd.DataFrame(rates)25 df["time"] = pd.to_datetime(df["time"], unit="s")26 df.set_index("time", inplace=True)27 df.rename(columns={"open":"open","high":"high","low":"low",28 "close":"close","tick_volume":"volume"}, inplace=True)29 return df[["open","high","low","close","volume"]]3031def fetch_multi_mt5(symbols: list, timeframe: int, bars: int = 500) -> dict:32 """Batch fetch multiple symbols from MT5."""33 mt5.initialize()34 data = {}35 for sym in symbols:36 rates = mt5.copy_rates_from_pos(sym, timeframe, 0, bars)37 if rates is not None:38 df = pd.DataFrame(rates)39 df["time"] = pd.to_datetime(df["time"], unit="s")40 df.set_index("time", inplace=True)41 data[sym] = df[["open","high","low","close","tick_volume"]].rename(42 columns={"tick_volume": "volume"})43 mt5.shutdown()44 return data45```4647## Your 23 Watched Symbols48```python49WATCHED = [50 "XAUUSDm","XAGUSDm","EURUSDm","GBPUSDm","USDJPYm","AUDUSDm","USDCADm","USDCHFm",51 "BTCUSDm","ETHUSDm","USOILm","USTECm","US500m","US30m",52 "TSLAm","AAPLm","MSFTm","NVDAm","AMZNm","GOOGm","METAm","JPMm","BAm"53]54TIMEFRAMES = {55 "M5": mt5.TIMEFRAME_M5, "M15": mt5.TIMEFRAME_M15,56 "H1": mt5.TIMEFRAME_H1, "H4": mt5.TIMEFRAME_H4, "D1": mt5.TIMEFRAME_D1,57}58```5960## Data Cleaning Pipeline61```python62def clean_ohlcv(df: pd.DataFrame, max_gap_bars: int = 5) -> pd.DataFrame:63 """Remove bad bars, fill small gaps, validate OHLC logic."""64 # Drop bars where OHLC relationship is broken65 df = df[(df["high"] >= df["low"]) &66 (df["high"] >= df["open"]) & (df["high"] >= df["close"]) &67 (df["low"] <= df["open"]) & (df["low"] <= df["close"])]68 # Drop zero-volume bars (market closed)69 df = df[df["volume"] > 0]70 # Forward-fill small gaps (weekend gaps etc.)71 df = df.resample("1min").asfreq()72 gap_size = df["close"].isna().rolling(max_gap_bars + 1).sum()73 df = df[gap_size <= max_gap_bars].ffill()74 return df.dropna()75```7677## yfinance Fallback (for research/backtesting)78```python79import yfinance as yf8081def fetch_yf(ticker: str, period: str = "1y", interval: str = "1d") -> pd.DataFrame:82 """Fetch from Yahoo Finance. interval: 1m,5m,15m,1h,1d,1wk."""83 df = yf.download(ticker, period=period, interval=interval, auto_adjust=True, progress=False)84 df.columns = [c.lower() for c in df.columns]85 return df[["open","high","low","close","volume"]]86```8788---8990## Related Skills9192- [Mt5 Integration](../mt5-integration.md)93- [Tick Data Storage](../tick-data-storage.md)94- [Data Pipelines](../market-data-ingestion.md)95- [News Data Stream](../news-intelligence.md)