P
PipsGrowth
← Back to Libraries

MetaTrader5 Python

Official Python package for MetaTrader 5 integration. Access market data, execute trades, and build automated trading bots directly from Python.

Difficulty: Intermediate
Category: Live Trading

Installation

Install the MetaTrader5 package and ensure MT5 terminal is installed and running.

# Install MetaTrader5 package
$ pip install MetaTrader5
# Install with pandas for data analysis
$ pip install MetaTrader5 pandas
Requirements: MetaTrader 5 terminal must be installed and running on your system. The package works on Windows and Linux (via Wine).

Key Features

Real-Time Data

Access live tick data, quotes, and market depth

Historical Data

Download OHLCV data for any symbol and timeframe

Trade Execution

Place market, limit, and stop orders programmatically

Complete Code Examples

Initialize MT5 Connection

Connect to MetaTrader 5 terminal

Python
import MetaTrader5 as mt5
from datetime import datetime
# Initialize MT5
if not mt5.initialize():
print("initialize() failed, error code =", mt5.last_error())
quit()
# Display connection status
print("MetaTrader5 package author: ", mt5.__author__)
print("MetaTrader5 package version: ", mt5.__version__)
# Get terminal info
terminal_info = mt5.terminal_info()
if terminal_info != None:
print("Terminal: ", terminal_info.name)
print("Company: ", terminal_info.company)
print("Path: ", terminal_info.path)
print("Connected: ", terminal_info.connected)
# Get account info
account_info = mt5.account_info()
if account_info != None:
print("\nAccount Info:")
print(f"Login: {account_info.login}")
print(f"Server: {account_info.server}")
print(f"Balance: ${account_info.balance:.2f}")
print(f"Equity: ${account_info.equity:.2f}")
print(f"Margin: ${account_info.margin:.2f}")
print(f"Free Margin: ${account_info.margin_free:.2f}")
print(f"Leverage: 1:{account_info.leverage}")
# Shutdown connection when done
mt5.shutdown()

Download Historical Data

Get OHLCV data for any symbol and timeframe

Python
import MetaTrader5 as mt5
import pandas as pd
from datetime import datetime
mt5.initialize()
# Define symbol and timeframe
symbol = "EURUSD"
timeframe = mt5.TIMEFRAME_H1 # 1 - hour bars
# Get last 1000 bars
rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, 1000)
# Convert to DataFrame
df = pd.DataFrame(rates)
df['time'] = pd.to_datetime(df['time'], unit = 's')
print(df.head())
print(f"\nTotal bars: {len(df)}")
# Alternative: Get data for specific date range
from_date = datetime(2024, 1, 1)
to_date = datetime(2024, 12, 31)
rates_range = mt5.copy_rates_range(symbol, timeframe, from_date, to_date)
df_range = pd.DataFrame(rates_range)
df_range['time'] = pd.to_datetime(df_range['time'], unit = 's')
print(f"\nBars from {from_date} to {to_date}: {len(df_range)}")
# Available timeframes:
# mt5.TIMEFRAME_M1 - 1 minute
# mt5.TIMEFRAME_M5 - 5 minutes
# mt5.TIMEFRAME_M15 - 15 minutes
# mt5.TIMEFRAME_M30 - 30 minutes
# mt5.TIMEFRAME_H1 - 1 hour
# mt5.TIMEFRAME_H4 - 4 hours
# mt5.TIMEFRAME_D1 - 1 day
# mt5.TIMEFRAME_W1 - 1 week
# mt5.TIMEFRAME_MN1 - 1 month
mt5.shutdown()

Get Real-Time Tick Data

Access live bid/ask prices

Python
import MetaTrader5 as mt5
import time
mt5.initialize()
symbol = "EURUSD"
# Get current tick
tick = mt5.symbol_info_tick(symbol)
if tick != None:
print(f"Symbol: {symbol}")
print(f"Bid: {tick.bid}")
print(f"Ask: {tick.ask}")
print(f"Spread: {(tick.ask - tick.bid) * 10000:.1f} pips")
print(f"Last: {tick.last}")
print(f"Volume: {tick.volume}")
print(f"Time: {datetime.fromtimestamp(tick.time)}")
# Monitor ticks in real - time
print("\nMonitoring ticks for 10 seconds...")
for i in range(10):
tick = mt5.symbol_info_tick(symbol)
print(f"{datetime.now().strftime('%H:%M:%S')} - Bid: {tick.bid:.5f}, Ask: {tick.ask:.5f}")
time.sleep(1)
# Get tick history
from_date = datetime.now()
ticks = mt5.copy_ticks_from(symbol, from_date, 100, mt5.COPY_TICKS_ALL)
if ticks is not None:
df_ticks = pd.DataFrame(ticks)
df_ticks['time'] = pd.to_datetime(df_ticks['time'], unit = 's')
print(f"\nReceived {len(df_ticks)} ticks")
print(df_ticks.head())
mt5.shutdown()

Place Market Order

Execute buy/sell orders with SL and TP

Python
import MetaTrader5 as mt5
mt5.initialize()
def place_market_order(symbol, order_type, volume, sl_pips = 50, tp_pips = 100, comment = "Python bot"):
"""
Place a market order
order_type: mt5.ORDER_TYPE_BUY or mt5.ORDER_TYPE_SELL
volume: lot size(0.01 = micro lot, 0.1 = mini lot, 1.0 = standard lot)
"""
# Get symbol info
symbol_info = mt5.symbol_info(symbol)
if symbol_info is None:
print(f"{symbol} not found")
return None
# Ensure symbol is visible in Market Watch
if not symbol_info.visible:
if not mt5.symbol_select(symbol, True):
print(f"Failed to select {symbol}")
return None
# Get current price
point = symbol_info.point
if order_type == mt5.ORDER_TYPE_BUY:
price = mt5.symbol_info_tick(symbol).ask
sl = price - sl_pips * point * 10
tp = price + tp_pips * point * 10
else: # SELL
price = mt5.symbol_info_tick(symbol).bid
sl = price + sl_pips * point * 10
tp = price - tp_pips * point * 10
# Prepare request
request = {
"action": mt5.TRADE_ACTION_DEAL,
"symbol": symbol,
"volume": volume,
"type": order_type,
"price": price,
"sl": sl,
"tp": tp,
"deviation": 10,
"magic": 234000,
"comment": comment,
"type_time": mt5.ORDER_TIME_GTC,
"type_filling": mt5.ORDER_FILLING_IOC,
}
# Send order
result = mt5.order_send(request)
if result.retcode != mt5.TRADE_RETCODE_DONE:
print(f"Order failed: {result.comment}")
return None
print(f"Order successful!")
print(f"Order: {result.order}")
print(f"Volume: {result.volume}")
print(f"Price: {result.price}")
print(f"SL: {sl:.5f}, TP: {tp:.5f}")
return result
# Example: Buy 0.1 lots of EURUSD
order = place_market_order("EURUSD", mt5.ORDER_TYPE_BUY, 0.1, sl_pips = 50, tp_pips = 100)
mt5.shutdown()

Place Pending Orders

Set buy/sell limit and stop orders

Python
import MetaTrader5 as mt5
mt5.initialize()
def place_pending_order(symbol, order_type, volume, price, sl_pips = 50, tp_pips = 100):
"""
Place a pending order
order_type: mt5.ORDER_TYPE_BUY_LIMIT, ORDER_TYPE_SELL_LIMIT,
ORDER_TYPE_BUY_STOP, ORDER_TYPE_SELL_STOP
price: entry price for the pending order
"""
symbol_info = mt5.symbol_info(symbol)
if symbol_info is None:
return None
if not symbol_info.visible:
mt5.symbol_select(symbol, True)
point = symbol_info.point
# Calculate SL and TP based on order type
if order_type in [mt5.ORDER_TYPE_BUY_LIMIT, mt5.ORDER_TYPE_BUY_STOP]:
sl = price - sl_pips * point * 10
tp = price + tp_pips * point * 10
else: # SELL orders
sl = price + sl_pips * point * 10
tp = price - tp_pips * point * 10
request = {
"action": mt5.TRADE_ACTION_PENDING,
"symbol": symbol,
"volume": volume,
"type": order_type,
"price": price,
"sl": sl,
"tp": tp,
"deviation": 10,
"magic": 234000,
"comment": "Pending order",
"type_time": mt5.ORDER_TIME_GTC,
"type_filling": mt5.ORDER_FILLING_RETURN,
}
result = mt5.order_send(request)
if result.retcode != mt5.TRADE_RETCODE_DONE:
print(f"Pending order failed: {result.comment}")
return None
print(f"Pending order placed!")
print(f"Order: {result.order}")
print(f"Entry Price: {price:.5f}")
print(f"SL: {sl:.5f}, TP: {tp:.5f}")
return result
# Example: Buy Limit at 1.0850
current_price = mt5.symbol_info_tick("EURUSD").ask
buy_limit_price = current_price - 0.0050 # 50 pips below
order = place_pending_order(
"EURUSD",
mt5.ORDER_TYPE_BUY_LIMIT,
0.1,
buy_limit_price,
sl_pips = 50,
tp_pips = 100
)
mt5.shutdown()

Manage Open Positions

Get, modify, and close positions

Python
import MetaTrader5 as mt5
mt5.initialize()
# Get all open positions
positions = mt5.positions_get()
if positions is None or len(positions) == 0:
print("No open positions")
else:
print(f"Total positions: {len(positions)}")
for position in positions:
print(f"\nTicket: {position.ticket}")
print(f"Symbol: {position.symbol}")
print(f"Type: {'BUY' if position.type == mt5.ORDER_TYPE_BUY else 'SELL'}")
print(f"Volume: {position.volume}")
print(f"Open Price: {position.price_open}")
print(f"Current Price: {position.price_current}")
print(f"SL: {position.sl}, TP: {position.tp}")
print(f"Profit: ${position.profit:.2f}")
# Get positions for specific symbol
eurusd_positions = mt5.positions_get(symbol = "EURUSD")
print(f"\nEURUSD positions: {len(eurusd_positions) if eurusd_positions else 0}")
# Modify position SL / TP
def modify_position(ticket, new_sl, new_tp):
"""Modify stop loss and take profit"""
position = mt5.positions_get(ticket = ticket)
if position is None or len(position) == 0:
print(f"Position {ticket} not found")
return None
position = position[0]
request = {
"action": mt5.TRADE_ACTION_SLTP,
"position": ticket,
"sl": new_sl,
"tp": new_tp,
}
result = mt5.order_send(request)
if result.retcode != mt5.TRADE_RETCODE_DONE:
print(f"Modify failed: {result.comment}")
return None
print(f"Position {ticket} modified successfully")
return result
# Close position
def close_position(ticket):
"""Close an open position"""
position = mt5.positions_get(ticket = ticket)
if position is None or len(position) == 0:
return None
position = position[0]
# Determine close type(opposite of position type)
if position.type == mt5.ORDER_TYPE_BUY:
order_type = mt5.ORDER_TYPE_SELL
price = mt5.symbol_info_tick(position.symbol).bid
else:
order_type = mt5.ORDER_TYPE_BUY
price = mt5.symbol_info_tick(position.symbol).ask
request = {
"action": mt5.TRADE_ACTION_DEAL,
"position": ticket,
"symbol": position.symbol,
"volume": position.volume,
"type": order_type,
"price": price,
"deviation": 10,
"magic": 234000,
"comment": "Close position",
"type_time": mt5.ORDER_TIME_GTC,
"type_filling": mt5.ORDER_FILLING_IOC,
}
result = mt5.order_send(request)
if result.retcode != mt5.TRADE_RETCODE_DONE:
print(f"Close failed: {result.comment}")
return None
print(f"Position {ticket} closed at {price:.5f}")
return result
mt5.shutdown()

Complete Trading Bot

Automated EA with signal generation and execution

Python
import MetaTrader5 as mt5
import pandas as pd
from datetime import datetime
import time
class SimpleTradingBot:
def __init__(self, symbol, timeframe, volume = 0.1):
self.symbol = symbol
self.timeframe = timeframe
self.volume = volume
self.magic = 234000
if not mt5.initialize():
raise Exception("MT5 initialization failed")
def get_data(self, bars = 100):
"""Get historical data"""
rates = mt5.copy_rates_from_pos(self.symbol, self.timeframe, 0, bars)
df = pd.DataFrame(rates)
df['time'] = pd.to_datetime(df['time'], unit = 's')
return df
def calculate_signals(self, df):
"""Calculate trading signals"""
# Simple SMA crossover
df['sma_fast'] = df['close'].rolling(window = 20).mean()
df['sma_slow'] = df['close'].rolling(window = 50).mean()
# Generate signal
if df['sma_fast'].iloc[-1] > df['sma_slow'].iloc[-1]:
return 'BUY'
elif df['sma_fast'].iloc[-1] < df['sma_slow'].iloc[-1]:
return 'SELL'
return 'NEUTRAL'
def get_open_position(self):
"""Check if we have an open position"""
positions = mt5.positions_get(symbol = self.symbol, magic = self.magic)
if positions and len(positions) > 0:
return positions[0]
return None
def open_position(self, order_type):
"""Open a new position"""
point = mt5.symbol_info(self.symbol).point
if order_type == 'BUY':
price = mt5.symbol_info_tick(self.symbol).ask
sl = price - 50 * point * 10
tp = price + 100 * point * 10
trade_type = mt5.ORDER_TYPE_BUY
else: # SELL
price = mt5.symbol_info_tick(self.symbol).bid
sl = price + 50 * point * 10
tp = price - 100 * point * 10
trade_type = mt5.ORDER_TYPE_SELL
request = {
"action": mt5.TRADE_ACTION_DEAL,
"symbol": self.symbol,
"volume": self.volume,
"type": trade_type,
"price": price,
"sl": sl,
"tp": tp,
"deviation": 10,
"magic": self.magic,
"comment": "Bot trade",
"type_time": mt5.ORDER_TIME_GTC,
"type_filling": mt5.ORDER_FILLING_IOC,
}
result = mt5.order_send(request)
if result.retcode == mt5.TRADE_RETCODE_DONE:
print(f"{order_type} order opened at {price:.5f}")
return True
else:
print(f"Order failed: {result.comment}")
return False
def close_position(self, position):
"""Close existing position"""
if position.type == mt5.ORDER_TYPE_BUY:
order_type = mt5.ORDER_TYPE_SELL
price = mt5.symbol_info_tick(self.symbol).bid
else:
order_type = mt5.ORDER_TYPE_BUY
price = mt5.symbol_info_tick(self.symbol).ask
request = {
"action": mt5.TRADE_ACTION_DEAL,
"position": position.ticket,
"symbol": self.symbol,
"volume": position.volume,
"type": order_type,
"price": price,
"deviation": 10,
"magic": self.magic,
"comment": "Bot close",
"type_time": mt5.ORDER_TIME_GTC,
"type_filling": mt5.ORDER_FILLING_IOC,
}
result = mt5.order_send(request)
if result.retcode == mt5.TRADE_RETCODE_DONE:
print(f"Position closed. Profit: ${position.profit:.2f}")
return True
return False
def run(self, check_interval = 60):
"""Main bot loop"""
print(f"Bot started for {self.symbol}")
while True:
try:
# Get data and calculate signals
df = self.get_data()
signal = self.calculate_signals(df)
# Check current position
position = self.get_open_position()
print(f"\n{datetime.now()} - Signal: {signal}")
if position:
print(f"Current position: {position.type}, Profit: ${position.profit:.2f}")
# Close if signal changed
if (position.type == mt5.ORDER_TYPE_BUY and signal == 'SELL') or \
(position.type == mt5.ORDER_TYPE_SELL and signal == 'BUY'):
self.close_position(position)
else:
# Open new position if signal present
if signal in ['BUY', 'SELL']:
self.open_position(signal)
# Wait before next check
time.sleep(check_interval)
except KeyboardInterrupt:
print("\nBot stopped by user")
break
except Exception as e:
print(f"Error: {e}")
time.sleep(check_interval)
mt5.shutdown()
# Run the bot
bot = SimpleTradingBot("EURUSD", mt5.TIMEFRAME_M15, volume = 0.1)
bot.run(check_interval = 60) # Check every 60 seconds

Best Practices

Always Shutdown

Call mt5.shutdown() when done to release resources

Error Handling

Check return codes and handle errors gracefully

Test on Demo

Always test your bot on demo account first

Connection Management

Monitor connection status and reconnect if needed