How to pull data from MetaTrader 5 with Python

Share:

Python is one of the most popular programming languages having seen huge adoption in the financial and research sectors, and there is a good reason for that. With a quick programming interface and access to an almost unsurmountable number community and academic maintained modules, it as easy running pip and adding import to the start of your python code and you are good to go.

A Metatrader 5 Trading Terminal
Copyright, MetaQuotes Ltd.

If you don’t like the name of the module or want to make it shorter, you can even use “import as” to change the function calling synthax to be a little bit shorter. I.e.

Import Pandas as pd

This quick snippet in the begining of your code is intuitive and lets you change a function call from something like:

df = pandas.read_csv(‘file.csv’)

to

df = pd.read_csv(‘file.csv’)

Pandas is a realtive small word, but the larger they are, the more space they occupy on your screen not really giving you much in the way of useful information. I.e. import metatrader5 as mt5.
It’s this quick and intuitive access to changes that allows for a range of options to be tested. No wonder so many people are using python.

So, how do you pull trade, instrument or account data from the MetaTrader 5 terminal using Python?

Logo for the python 3 programming language.
Copyright Python Software Foundation

The first step is to make sure you have the installed dependencies. You will, at the very least, need the MetaTrader 5 module and a MT5 terminal connected to some kind of broker. In my case, I use FXOpen.
You will probably also use other modules. For now lets stick with mt5 and pandas.

You can install them using:

pip3 install metatrader5
pip3 install pandas

Okay, so you now have these two dependencies installed. Let’s get started with some code. First, let’s import pandas and mt5 modules.

import Pandas as pd
import MetaTrader5 as mt5

The very first thing we need to do is initialize our comunication with the terminal where the data is going to be pulled from with.
We will beging by initializing with mt5.initialize and the print terminal info to see if our connection was succesful.

mt5.initialize()
print(mt5.terminal_info())

It’s a good idea to already have your terminal open and only have ONE instance of it installed and running on your computer. If you have more than one, you can specify which terminal you want to open with:

mt5.initialize('path to exe')

Or you can even go further and even specify which account you want to login to:

initialize('path to exe', login= 'account number', password='your password', server = 'the trading server')

Personally, I am not a fan of storing login and password information in plain text even in memory. But you can always skip this step by having the login info stored in the terminal. Otherwise, you can ask for the login credentials on start of your script.
Not bulletproof, but you can specify if your project requires you to.

Moving on. After a succesful intialization, with the print function, you should see something like this:

TerminalInfo(community_account=True, community_connection=False, connected=True, dlls_allowed=False, trade_allowed=False, tradeapi_disabled=False, email_enabled=False, ftp_enabled=False, notifications_enabled=False, mqid=True, build=3391, maxbars=100000, codepage=0, ping_last=258801, community_balance=0.0, retransmission=0.0, company='FXOpen Investments Inc.', name='MetaTrader 5 - FXOpen', language='English', path='your path', data_path='your data path', commondata_path='your common data path')

Which… looks awful. We can using Pandas to format our data into a dataframe and format it as such so we can easily look at it and retrive information.

import pandas as pd
import MetaTrader5 as mt5
mt5.initialize()terminal_info = mt5.terminal_info()
terminal_info_df = pd.DataFrame(terminal_info)
#print(terminal_info)
print(terminal_info_df)

We now get a much nicer:

 0
0 True
1 True
2 True
3 False
4 False
5 False
6 False
7 False
8 False
9 True
10 3391
11 100000
12 0
13 249855
14 2.822966
15 2.293864
16 FXOpen Investments Inc.
17 MetaTrader 5 - FXOpen
18 English
19 C:\Program Files\MetaTrader 5
20 C:\Users\user\AppData\Roaming\MetaQuotes\Term...
21 C:\Users\user\AppData\Roaming\MetaQuotes\Term...

Now we are getting there. The terminal info is now looking more organized and we can easily pull from the pandas dataframe with iat commands. But, if we are printing this information, we probably want it to be a little clearer. How about we do this, let’s call the terminal info as namedtuple using the ._asdict() command.

terminal_info = mt5.terminal_info()._asdict()
terminal_info_df = pd.DataFrame(list(terminal_info.items()),columns=['Property','Value'])

Now when we print, we can readily read what the dataframe is showing us!

 Property Value
0 community_account True
1 community_connection True
2 connected True
3 dlls_allowed False
4 trade_allowed False
5 tradeapi_disabled False
6 email_enabled False
7 ftp_enabled False
8 notifications_enabled False
9 mqid True
10 build 3391
11 maxbars 100000
12 codepage 0
13 ping_last 249855
14 community_balance 2.822966
15 retransmission 2.293864
16 company FXOpen Investments Inc.
17 name MetaTrader 5 - FXOpen
18 language English
19 path C:\Program Files\MetaTrader 5
20 data_path C:\Users\user\AppData\Roaming\MetaQuotes\Term...
21 commondata_path C:\Users\user\AppData\Roaming\MetaQuotes\Term...

This is awesome, so we can run a check, for example, if trades are allowed:

trade_allowed = terminal_info_df.iat[4,1] #Retrive trade allow data from dataframe matrix.#Check if trades permited
if trade_allowed == False:
print("Trades not allowed.")
elif trade_allowed == True:
print("Trades are permited.")
else:
print("Unkown trade status.")
#End of mt5 interactions
mt5.shutdown()

Now we get a nice output. In our case.

Trades not allowed.

You can go further and run different code, request user intervention or use an automated exception management. It’s all up to you.

Let’s finish with some more information that we can pull and the full code.

We can pull Account Info with mt5.account_info(). Which will tell us:

 Property Value
0 login 20500106
1 trade_mode 2
2 leverage 10
3 limit_orders 0
4 margin_so_mode 0
5 trade_allowed True
6 trade_expert True
7 margin_mode 2
8 currency_digits 2
9 fifo_close False
10 balance 1000.00
11 credit 0.0
12 profit 0.0
13 equity 1000.00
14 margin 0.0
15 margin_free 0.0
16 margin_level 0.0
17 margin_so_call 0.0
18 margin_so_so 0.0
19 margin_initial 0.0
20 margin_maintenance 0.0
21 assets 0.0
22 liabilities 0.0
23 commission_blocked 0.0
24 name Test
25 server FXOpen-MT5
26 currency USD
27 company FXOpen Investments Inc.

With symbol_info(), we get over 90 rows! So it will probably be compressed like this:

 Property Value
0 custom False
1 chart_mode 0
2 select True
3 visible True
4 session_deals 0
.. ... ...
91 formula
92 isin US0378331005
93 name AAPL
94 page
95 path US Stocks & ETFs\AAPL

So we add the following snippet to request a full print and just double click when priting to the IDLE Shell.

with pd.option_context('display.max_rows', None, 'display.max_columns', None):
print(instrument_info_df)

And now we get the full matrix:

Property Value
0 custom False
1 chart_mode 0
2 select True
3 visible True
4 session_deals 0
5 session_buy_orders 0
6 session_sell_orders 0
7 volume 0
8 volumehigh 0
9 volumelow 0
10 time 1659740099
11 digits 2
12 spread 27
13 spread_float True
14 ticks_bookdepth 10
15 trade_calc_mode 2
16 trade_mode 4
17 start_time 0
18 expiration_time 0
19 trade_stops_level 0
20 trade_freeze_level 0
21 trade_exemode 2
22 swap_mode 5
23 swap_rollover3days 3
.
.
.
etc...

Here is the full code with indentation and some comments.

#Script that imports Terminal, Account and Instrument data from a MT5 Terminal
#By Eduardo Bogosian - 2022
import pandas as pd
import MetaTrader5 as mt5
#Starts connection with the terminal based on synthax
mt5.initialize()
#Terminal Information
terminal_info = mt5.terminal_info()._asdict()
terminal_info_df = pd.DataFrame(list(terminal_info.items()),columns=['Property','Value'])
print("Terminal Info:\n",terminal_info_df)#Retrive if trade is allowed from dataframe matrix.
trade_allowed_bool = terminal_info_df.iat[4,1]
#Check if trades permited
if trade_allowed_bool == False:
print("\nTrades are not allowed.")
elif trade_allowed_bool == True:
print("\nTrades permited.")
else:
print("\nUnkown trade status.")
#Account information
account_info = mt5.account_info()._asdict()
account_info_df = pd.DataFrame(list(account_info.items()),columns=['Property','Value'])
print("\nAccount Info:\n",account_info_df)#Instrument Information
instrument = 'AAPL'
instrument_info = mt5.symbol_info(instrument)._asdict()
instrument_info_df = pd.DataFrame(list(instrument_info.items()),columns=['Property','Value'])
with pd.option_context('display.max_rows', None, 'display.max_columns', None):
print("\nData for:",instrument)
print(instrument_info_df)
#End of interactions with the terimanl
mt5.shutdown()

And if you want to know more, you can checkout MetaQuotes official website reference for python at: https://www.mql5.com/en/docs/integration/python_metatrader5

Be sure to follow me to stay up to date with new Python, MT5, and Investing coding!
Thank you.